OpenDNSSEC-enforcer
1.3.4
|
00001 /* 00002 * $Id: ksm_request.c 4489 2011-02-17 10:17:39Z rb $ 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 * ksm_request.c - Handle Request Keys Processing 00031 * 00032 * Description: 00033 * The REQUEST command asks KSM to list the keys to be included in the 00034 * zone when it is next signed. It can optionally force a rollover by 00035 * marking the active key as retired. 00036 -*/ 00037 00038 #include <assert.h> 00039 #include <stdio.h> 00040 #include <string.h> 00041 00042 #include "ksm/database.h" 00043 #include "ksm/database_statement.h" 00044 #include "ksm/db_fields.h" 00045 #include "ksm/debug.h" 00046 #include "ksm/ksm.h" 00047 #include "ksm/kmedef.h" 00048 #include "ksm/ksmdef.h" 00049 #include "ksm/message.h" 00050 #include "ksm/memory.h" 00051 #include "ksm/string_util.h" 00052 #include "ksm/string_util2.h" 00053 00054 /* TODO The nomenclature needs to be updated to agree with that in the timing draft */ 00055 00056 /*+ 00057 * KsmRequestKeys - Request Keys for Output 00058 * 00059 * Description: 00060 * Updates the key times and then calls KsmRequestKeysByType to process 00061 * keys of the type chosen by the keytype argument. 00062 * 00063 * Arguments: 00064 * int keytype 00065 * Key type for which the request should happen. 00066 * 00067 * KSM_TYPE_KSK KSKs 00068 * KSM_TYPE_ZSK ZSKs 00069 * Other Both KSK and ZSK 00070 * 00071 * int rollover 00072 * 1 to force a rollover, 0 to ignore 00073 * 00074 * const char* datetime 00075 * Time at which the request is issued. Comparisons for key 00076 * expirations etc. will be against this time. 00077 * 00078 * KSM_REQUEST_CALLBACK callback 00079 * Callback function called for every key that will be issued. 00080 * 00081 * void* context 00082 * Context argument passed uninterpreted to the callback function. 00083 * 00084 * int policy_id 00085 * ID of policy that we are looking at 00086 * 00087 * int zone_id 00088 * ID of zone that we are looking at (-1 == all zones) 00089 * 00090 * int run_interval 00091 * how frequently do we run? 00092 * 00093 * int* NewDS 00094 * were new DS records needed? 00095 -*/ 00096 00097 int KsmRequestKeys(int keytype, int rollover, const char* datetime, 00098 KSM_REQUEST_CALLBACK callback, void* context, int policy_id, int zone_id, 00099 int run_interval, int* NewDS) 00100 { 00101 int status; /* Status return */ 00102 00103 /* Start the transaction */ 00104 status = DbBeginTransaction(); 00105 if (status != 0) { 00106 /* Something went wrong */ 00107 00108 MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00109 return status; 00110 } 00111 00112 /* Update the estimated times of state change */ 00113 status = KsmUpdate(policy_id, zone_id); 00114 if (status == 0) { 00115 00116 /* Process all key types */ 00117 00118 if ((keytype == KSM_TYPE_KSK) || (keytype == KSM_TYPE_ZSK)) { 00119 status = KsmRequestKeysByType(keytype, rollover, datetime, 00120 callback, context, policy_id, zone_id, run_interval, NewDS); 00121 00122 if (status != 0) { 00123 DbRollback(); 00124 return status; 00125 } 00126 } 00127 else { 00128 status = KsmRequestKeysByType(KSM_TYPE_KSK, rollover, datetime, 00129 callback, context, policy_id, zone_id, run_interval, NewDS); 00130 if (status != 0) { 00131 DbRollback(); 00132 return status; 00133 } 00134 00135 status = KsmRequestKeysByType(KSM_TYPE_ZSK, rollover, datetime, 00136 callback, context, policy_id, zone_id, run_interval, NewDS); 00137 if (status != 0) { 00138 DbRollback(); 00139 return status; 00140 } 00141 } 00142 00143 /* 00144 * Finally, update the key times again, in case any keys were 00145 * moved between states. 00146 */ 00147 00148 status = KsmUpdate(policy_id, zone_id); 00149 if (status != 0) { 00150 DbRollback(); 00151 return status; 00152 } 00153 else 00154 { 00155 /* Everything worked by the looks of it */ 00156 DbCommit(); 00157 } 00158 } 00159 else 00160 { 00161 /* Whatever happened, it was not good */ 00162 DbRollback(); 00163 } 00164 00165 return status; 00166 } 00167 00168 00169 /*+ 00170 * KsmRequestKeysByType - Request Keys for Output 00171 * 00172 * Description: 00173 * Does REQUEST KEYS processing for keys of a given type. 00174 * 00175 * Arguments: 00176 * int keytype 00177 * Key type for which the request should happen. 00178 * 00179 * KSM_TYPE_KSK KSKs 00180 * KSM_TYPE_ZSK ZSKs 00181 * 00182 * int rollover 00183 * 1 to force a rollover, 0 to ignore 00184 * 00185 * const char* datetime 00186 * Time to insert into database. 00187 * 00188 * KSM_REQUEST_CALLBACK callback 00189 * Callback function called for every key that will be issued. 00190 * 00191 * void* context 00192 * Context argument passed uninterpreted to the callback function. 00193 * 00194 * int policy_id 00195 * ID of policy that we are looking at 00196 * 00197 * int zone_id 00198 * ID of zone that we are looking at 00199 * 00200 * int run_interval 00201 * how frequently do we run? 00202 * 00203 * int* NewDS 00204 * were new DS records needed? 00205 * 00206 * Returns: 00207 * int 00208 * Status return. 0 = Success, other = error (in which case a message 00209 * will have been output). 00210 -*/ 00211 00212 int KsmRequestKeysByType(int keytype, int rollover, const char* datetime, 00213 KSM_REQUEST_CALLBACK callback, void* context, int policy_id, int zone_id, 00214 int run_interval, int* NewDS) 00215 { 00216 int active; /* Number of active keys to be retired */ 00217 KSM_PARCOLL collection; /* Parameters collection */ 00218 int ready; /* Number of keys in the "ready" state */ 00219 int first_pass = 0; /* Indicates if this zone has been published before */ 00220 int status; /* Status return */ 00221 char* zone_name = NULL; /* For rollover message, if needed */ 00222 int manual_rollover = 0; /* Flag specific to keytype */ 00223 00224 /* Check that we have a valid key type */ 00225 00226 if ((keytype != KSM_TYPE_KSK) && (keytype != KSM_TYPE_ZSK)) { 00227 status = MsgLog(KME_UNKEYTYPE, keytype); 00228 return status; 00229 } 00230 00231 DbgLog(DBG_M_REQUEST, KME_REQKEYTYPE, 00232 (keytype == KSM_TYPE_KSK) ? "key" : "zone"); 00233 00234 /* Get list of parameters */ 00235 00236 status = KsmParameterCollection(&collection, policy_id); 00237 if (status != 0) { 00238 return status; 00239 } 00240 00241 if (keytype == KSM_TYPE_KSK) { 00242 manual_rollover = collection.kskmanroll; 00243 } 00244 else if (keytype == KSM_TYPE_ZSK) { 00245 manual_rollover = collection.zskmanroll; 00246 } 00247 00248 /* Check to see if this zone has been published before */ 00249 status = KsmRequestCheckFirstPass(keytype, &first_pass, zone_id); 00250 if (status != 0) { 00251 return status; 00252 } 00253 00254 /* 00255 * Step 0: If rolling over the key, set the expected retirement date of 00256 * active keys to the given date/time. 00257 */ 00258 00259 if (rollover) { 00260 status = KsmRequestSetActiveExpectedRetire(keytype, datetime, zone_id); 00261 if (status != 0) { 00262 return status; 00263 } 00264 } else { 00265 /* Check for the compromised flag on the currently active key; 00266 if set then force rollover to 1 (could set manual_rollover to 0) 00267 NOTE: because of where this is called from we can not overwrite 00268 the incoming rollover flag if set */ 00269 status = KsmRequestCheckCompromisedFlag(keytype, zone_id, &rollover); 00270 if (status != 0) { 00271 return status; 00272 } 00273 } 00274 /* 00275 * Step 0a: Complete Key rollover of standbykeys in KEYPUBLISH state 00276 * if we are after their active time, move them into the active state 00277 */ 00278 if (keytype == KSM_TYPE_KSK) { 00279 status = KsmRequestChangeStateKeyPublishActive(datetime, zone_id, policy_id, NewDS); 00280 if (status != 0) { 00281 return status; 00282 } 00283 00284 if (*NewDS == 1) { 00285 /* Standby Key has become active, retire the old key */ 00286 status = KsmRequestChangeStateActiveRetire(keytype, datetime, zone_id, policy_id); 00287 if (status != 0) { 00288 StrFree(zone_name); 00289 return status; 00290 } 00291 *NewDS = 0; /* We were naughty when we used this flag, clean up */ 00292 /* DS set won't change until the old active key moves to dead */ 00293 } 00294 } 00295 00296 00297 /* 00298 * Step 1. For each retired key, mark it as dead if it past the given 00299 * time. 00300 */ 00301 00302 status = KsmRequestChangeStateRetireDead(keytype, datetime, zone_id, policy_id, collection.kskroll, NewDS); 00303 if (status != 0) { 00304 return status; 00305 } 00306 00307 /* 00308 * Step 2. For each key in the published state, set it ready if it has 00309 * been in the zone long enough. 00310 */ 00311 00312 if (keytype == KSM_TYPE_ZSK || 00313 collection.kskroll == KSM_ROLL_DNSKEY || 00314 first_pass == 1) { 00315 status = KsmRequestChangeStatePublishReady(keytype, datetime, zone_id, policy_id, NewDS); 00316 if (status != 0) { 00317 return status; 00318 } 00319 } 00320 00321 /* 00322 * Step 2a. For each key in the dspublished state, set it dsready if it has 00323 * been in the zone long enough. 00324 */ 00325 00326 if (keytype == KSM_TYPE_KSK) { 00327 status = KsmRequestChangeStateDSPublishDSReady(keytype, datetime, zone_id, policy_id); 00328 if (status != 0) { 00329 return status; 00330 } 00331 } 00332 00333 /* 00334 * Step 3a. make sure that we have enough standby KSKs 00335 * Doing this before 3. 00336 */ 00337 00338 if (keytype == KSM_TYPE_KSK) { 00339 status = KsmRequestChangeStateGenerateDSSubConditional(keytype, datetime, &collection, zone_id, NewDS); 00340 00341 /* Reset this flag; TODO is this correct? */ 00342 if (first_pass == 1) { 00343 *NewDS = 0; 00344 } 00345 if (status != 0) { 00346 return status; 00347 } 00348 } 00349 00350 /* 00351 * Step 3. We are within the appropriate interval of the retirement 00352 * of the active key, move keys from the generate state into the 00353 * publish state. 00354 */ 00355 00356 status = KsmRequestChangeStateGeneratePublishConditional(keytype, datetime, &collection, zone_id, run_interval); 00357 if (status != 0) { 00358 return status; 00359 } 00360 00361 /* 00362 * Step 4. If there is an active key and the date on which this procedure 00363 * is run is earlier than the retire time of that key, exit the procedure. 00364 */ 00365 00366 status = KsmRequestCheckActiveKey(keytype, datetime, &active, zone_id); 00367 if (status != 0) { 00368 return status; 00369 } 00370 00371 /* 00372 * Step 5: Unless we are forcing a rollover, if there are some keys that 00373 * will be active after the cut-off, end the modification of key states and 00374 * times now. Otherwise continue. 00375 * 00376 * Note that we don't return if keys are active - we still need to issue 00377 * the keys. 00378 */ 00379 00380 if ((active <= 0) || (rollover)) { 00381 00382 /* Get some info that we need for logging later */ 00383 status = KsmZoneNameFromId(zone_id, &zone_name); 00384 if (status != 0) { 00385 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00386 if (zone_name != NULL) { 00387 StrFree(zone_name); 00388 } 00389 return(status); 00390 } 00391 00392 /* 00393 * Step 6. If there are keys to be made active, count the number of keys 00394 * in the "READY" state. 00395 */ 00396 00397 status = KsmRequestCountReadyKey(keytype, datetime, &ready, zone_id); 00398 if (status != 0) { 00399 StrFree(zone_name); 00400 return status; 00401 } 00402 00403 /* 00404 * Step 7. We can only promote a key if there is at least one key in the 00405 * READY state. Otherwise, just issue what we have. 00406 */ 00407 00408 if (ready <= 0) { 00409 00410 /* 00411 * If this is the first pass for this zone. Then we can promote a key 00412 * to active from published 00413 * NB: A consequence of this is that these keys will have no "ready" 00414 * time as they are never in the "ready" state. 00415 */ 00416 00417 if (first_pass == 1) { 00418 /* We have to wait until the KSK is ready before we can 00419 * publish the DS record */ 00420 if (keytype == KSM_TYPE_KSK) { 00421 /* status = KsmRequestChangeStateN(keytype, datetime, 1, 00422 KSM_STATE_READY, KSM_STATE_ACTIVE, zone_id);*/ 00423 } else { 00424 (void) MsgLog(KME_PROM_PUB, "ZSK"); 00425 status = KsmRequestChangeStateN(keytype, datetime, 1, 00426 KSM_STATE_PUBLISH, KSM_STATE_ACTIVE, zone_id); 00427 } 00428 00429 if (status != 0) { 00430 StrFree(zone_name); 00431 return status; 00432 } 00433 } 00434 else { 00435 /* Move standby key from DSready to KEYPUBLISH if we can */ 00436 if (keytype == KSM_TYPE_KSK) { 00437 status = KsmRequestChangeStateDSReadyKeyPublish(datetime, zone_id, policy_id); 00438 if (status != 0) { 00439 return status; 00440 } 00441 } 00442 00443 (void) MsgLog(KME_NOREADYKEY, (keytype == KSM_TYPE_KSK ? "KSK" : "ZSK"), zone_name); 00444 /* TODO return here? */ 00445 } 00446 } 00447 else if (manual_rollover == 1 && rollover == 0) { 00448 (void) MsgLog(KME_MAN_ROLL_REQUIRED, (keytype == KSM_TYPE_KSK ? "KSK" : "ZSK"), zone_name); 00449 } 00450 /* TODO I think that this is no longer true... */ 00451 /* Check where we need this to happen */ 00452 else if (keytype == KSM_TYPE_KSK) { 00453 /* A rollover should be occuring... For KSKs we just prompt for 00454 * the user to submit their DS record 00455 * TODO Include the keytag or cka-id in the message 00456 * TODO Do we still need this? */ 00457 (void) MsgLog(KME_DS_SUBMISSION, zone_name); 00458 } 00459 else { 00460 00461 /* Step 8. Make a key active. */ 00462 status = KsmRequestChangeStateReadyActive(keytype, datetime, 1, zone_id); 00463 /* 00464 * If we didn't complete due to non-backed up keys then skip the 00465 * retire step; otherwise carry on. 00466 */ 00467 if (status != KME_BACK_FATAL) { 00468 if (status != 0) { 00469 StrFree(zone_name); 00470 return status; 00471 } 00472 00473 /* Step 9. ... and retire old active keys */ 00474 status = KsmRequestChangeStateActiveRetire(keytype, datetime, zone_id, policy_id); 00475 if (status != 0) { 00476 StrFree(zone_name); 00477 return status; 00478 } 00479 00480 /* Log that a rollover has happened */ 00481 (void) MsgLog(KME_ROLL_ZONE, (keytype == KSM_TYPE_KSK ? "KSK" : "ZSK"), zone_name); 00482 } 00483 } 00484 StrFree(zone_name); 00485 } 00486 00487 /* Step 10. Issue the keys */ 00488 00489 status = KsmRequestIssueKeys(keytype, callback, context, zone_id); 00490 00491 return status; 00492 } 00493 00494 00495 00496 /*+ 00497 * KsmRequestSetActiveExpectedRetire - Set Expected Retire Date 00498 * 00499 * Description: 00500 * Sets the expected retire date for active keys to the date specified. 00501 * Note that this does change not the state from active - it only changes 00502 * the expected retire date. 00503 * 00504 * Arguments: 00505 * int keytype 00506 * Type of keys being changed. 00507 * 00508 * const char* datetime 00509 * Date/time for which the calculation is being done. This can be 00510 * the string "NOW()". 00511 * 00512 * int zone_id 00513 * Zone we are looking at (-1 == all zones) 00514 * 00515 * Returns: 00516 * int 00517 * Status return. 0 => success, Other => failure, in which case an 00518 * error message will have been output. 00519 -*/ 00520 00521 int KsmRequestSetActiveExpectedRetire(int keytype, const char* datetime, int zone_id) 00522 { 00523 int count = 0; /* Count of keys whose date will be set */ 00524 char* sql = NULL; /* For creating the SQL command */ 00525 int status = 0; /* Status return */ 00526 int where = 0; /* For the SQL selection */ 00527 int i = 0; /* A counter */ 00528 int j = 0; /* Another counter */ 00529 char* insql = NULL; /* SQL "IN" clause */ 00530 int* keyids; /* List of IDs of keys to promote */ 00531 DB_RESULT result; /* List result set */ 00532 KSM_KEYDATA data; /* Data for this key */ 00533 char buffer[32]; /* For integer conversion */ 00534 00535 /* Count how many keys will have the retire date set */ 00536 00537 sql = DqsCountInit("KEYDATA_VIEW"); 00538 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, where++); 00539 DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, where++); 00540 if (zone_id != -1) { 00541 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++); 00542 } 00543 DqsEnd(&sql); 00544 00545 status = DbIntQuery(DbHandle(), &count, sql); 00546 DqsFree(sql); 00547 00548 if (status != 0) { 00549 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00550 return status; 00551 } 00552 00553 if (count == 0) { 00554 /* Nothing to do NO ACTIVE KEYS! */ 00555 return status; 00556 } 00557 00558 /* Allocate space for the list of key IDs */ 00559 keyids = MemMalloc(count * sizeof(int)); 00560 00561 /* Get the list of IDs */ 00562 00563 where = 0; 00564 sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS); 00565 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, where++); 00566 DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, where++); 00567 if (zone_id != -1) { 00568 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++); 00569 } 00570 DqsEnd(&sql); 00571 00572 status = KsmKeyInitSql(&result, sql); 00573 DqsFree(sql); 00574 00575 if (status == 0) { 00576 while (status == 0) { 00577 status = KsmKey(result, &data); 00578 if (status == 0) { 00579 keyids[i] = data.keypair_id; 00580 i++; 00581 } 00582 } 00583 00584 /* Convert EOF status to success */ 00585 00586 if (status == -1) { 00587 status = 0; 00588 } else { 00589 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00590 StrFree(keyids); 00591 return status; 00592 } 00593 00594 KsmKeyEnd(result); 00595 00596 } else { 00597 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00598 StrFree(keyids); 00599 return status; 00600 } 00601 00602 /* 00603 * Now construct the "IN" statement listing the IDs of the keys we 00604 * are planning to change the state of. 00605 */ 00606 00607 StrAppend(&insql, "("); 00608 for (j = 0; j < i; ++j) { 00609 if (j != 0) { 00610 StrAppend(&insql, ","); 00611 } 00612 snprintf(buffer, sizeof(buffer), "%d", keyids[j]); 00613 StrAppend(&insql, buffer); 00614 } 00615 StrAppend(&insql, ")"); 00616 00617 /* 00618 * Update the keys. This is done after a status check, as the debug 00619 * code may have hit a database error, in which case we won't query the 00620 * database again. ("status" is initialized to success in case the debug 00621 * code is not executed.) 00622 */ 00623 00624 sql = DusInit("keypairs"); 00625 DusSetInt(&sql, "fixedDate", 1, 0); 00626 DusSetInt(&sql, "compromisedflag", 1, 1); 00627 00628 DusConditionKeyword(&sql, "ID", DQS_COMPARE_IN, insql, 0); 00629 DusEnd(&sql); 00630 00631 status = DbExecuteSqlNoResult(DbHandle(), sql); 00632 DusFree(sql); 00633 00634 /* Report any errors */ 00635 if (status != 0) { 00636 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00637 } 00638 00639 sql = DusInit("dnsseckeys"); 00640 DusSetString(&sql, "RETIRE", datetime, 0); 00641 00642 DusConditionKeyword(&sql, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0); 00643 /* NO ZONE_ID !!! We want to retire ALL instances of this key */ 00644 StrFree(insql); 00645 DusEnd(&sql); 00646 00647 status = DbExecuteSqlNoResult(DbHandle(), sql); 00648 DusFree(sql); 00649 00650 /* Report any errors */ 00651 if (status != 0) { 00652 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00653 } 00654 00655 StrFree(keyids); 00656 00657 return status; 00658 } 00659 00660 00661 00662 /*+ 00663 * KsmRequestChangeStatePublishReady - Change State from PUBLISH to READY 00664 * KsmRequestChangeStateActiveRetire - Change State from ACTIVE to RETIRE 00665 * KsmRequestChangeStateRetireDead - Change State from RETIRE to DEAD 00666 * 00667 * Description: 00668 * Changes the state of keys of a particular type in the given zone 00669 * between two states. 00670 * 00671 * Arguments: 00672 * int keytype 00673 * Type of keys being changed. 00674 * 00675 * const char* datetime 00676 * Date/time for which the calculation is being done. This ancan be 00677 * the string "NOW()". 00678 * 00679 * int zone_id 00680 * ID of zone that we are looking at (-1 == all zones) 00681 * 00682 * Returns: 00683 * int 00684 * Status return. 0 => success, Other => failure, in which case an 00685 * error message will have been output. 00686 -*/ 00687 00688 int KsmRequestChangeStatePublishReady(int keytype, const char* datetime, int zone_id, int policy_id, int* NewDS) 00689 { 00690 return KsmRequestChangeState(keytype, datetime, 00691 KSM_STATE_PUBLISH, KSM_STATE_READY, zone_id, policy_id, -1, NewDS); 00692 } 00693 00694 int KsmRequestChangeStateDSPublishDSReady(int keytype, const char* datetime, int zone_id, int policy_id) 00695 { 00696 int* dummy = NULL; 00697 return KsmRequestChangeState(keytype, datetime, 00698 KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY, zone_id, policy_id, -1, dummy); 00699 } 00700 00701 int KsmRequestChangeStateDSReadyKeyPublish(const char* datetime, int zone_id, int policy_id) 00702 { 00703 int* dummy = NULL; 00704 return KsmRequestChangeState(KSM_TYPE_KSK, datetime, 00705 KSM_STATE_DSREADY, KSM_STATE_KEYPUBLISH, zone_id, policy_id, -1, dummy); 00706 } 00707 00708 int KsmRequestChangeStateKeyPublishActive(const char* datetime, int zone_id, int policy_id, int* NewDS) 00709 { 00710 return KsmRequestChangeState(KSM_TYPE_KSK, datetime, 00711 KSM_STATE_KEYPUBLISH, KSM_STATE_ACTIVE, zone_id, policy_id, -1, NewDS); 00712 } 00713 00714 int KsmRequestChangeStateActiveRetire(int keytype, const char* datetime, int zone_id, int policy_id) 00715 { 00716 int* dummy = NULL; 00717 return KsmRequestChangeState(keytype, datetime, 00718 KSM_STATE_ACTIVE, KSM_STATE_RETIRE, zone_id, policy_id, -1, dummy); 00719 } 00720 00721 int KsmRequestChangeStateRetireDead(int keytype, const char* datetime, int zone_id, int policy_id, int rollover_scheme, int* NewDS) 00722 { 00723 return KsmRequestChangeState(keytype, datetime, 00724 KSM_STATE_RETIRE, KSM_STATE_DEAD, zone_id, policy_id, rollover_scheme, NewDS); 00725 } 00726 00727 00728 00729 /*+ 00730 * KsmRequestChangeState - Change State of a Key 00731 * 00732 * Description: 00733 * Changes the state of a key between two states if the estimated time of 00734 * entering the target state is equal to or earlier than the given time. 00735 * The time of entering the state is updated to the given time as well. 00736 * 00737 * Arguments: 00738 * int keytype 00739 * Type of keys being changed. 00740 * 00741 * const char* datetime 00742 * Date/time for which the calculation is being done. This can be 00743 * the string "NOW()". 00744 * 00745 * int src_state 00746 * ID of the state that the key is moving from. 00747 * 00748 * int dst_state 00749 * ID of the state that the key is moving to. 00750 * 00751 * int zone_id 00752 * ID of zone that we are looking at (-1 == all zones) 00753 * 00754 * int policy_id 00755 * ID of the policy that we are looking at 00756 * 00757 * int rollover_scheme 00758 * what KSK rollover scheme are we using 00759 * 00760 * Returns: 00761 * int 00762 * Status return. 0 => success, Other => failure, in which case an 00763 * error message will have been output. 00764 -*/ 00765 00766 int KsmRequestChangeState(int keytype, const char* datetime, 00767 int src_state, int dst_state, int zone_id, int policy_id, 00768 int rollover_scheme, int* NewDS) 00769 { 00770 int where = 0; /* for the SELECT statement */ 00771 char* dst_col = NULL; /* Destination column */ 00772 int set = 0; /* For UPDATE */ 00773 char* sql = NULL; /* SQL statement (when verifying) */ 00774 int status = 0; /* Status return */ 00775 int count = 0; /* How many keys fit our select? */ 00776 int i = 0; /* A counter */ 00777 int j = 0; /* Another counter */ 00778 char* insql = NULL; /* SQL "IN" clause */ 00779 int* keyids; /* List of IDs of keys to promote */ 00780 DB_RESULT result; /* List result set */ 00781 KSM_KEYDATA data; /* Data for this key */ 00782 char buffer[32]; /* For integer conversion */ 00783 char* zone_name = NULL; /* For DS removal message, if needed */ 00784 00785 /* Unused parameter */ 00786 (void)policy_id; 00787 00788 /* Create the destination column name */ 00789 if (dst_state == KSM_STATE_DSREADY) { 00790 StrAppend(&dst_col, KSM_STATE_READY_STRING); 00791 } else if (dst_state == KSM_STATE_KEYPUBLISH) { 00792 StrAppend(&dst_col, KSM_STATE_PUBLISH_STRING); 00793 } else { 00794 dst_col = StrStrdup(KsmKeywordStateValueToName(dst_state)); 00795 } 00796 (void) StrToUpper(dst_col); 00797 00798 /* First up we need to count how many keys will move */ 00799 sql = DqsCountInit("KEYDATA_VIEW"); 00800 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, where++); 00801 DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, src_state, where++); 00802 if (zone_id != -1) { 00803 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++); 00804 } 00805 DqsConditionString(&sql, dst_col, DQS_COMPARE_LE, datetime, where++); 00806 DqsEnd(&sql); 00807 00808 status = DbIntQuery(DbHandle(), &count, sql); 00809 DqsFree(sql); 00810 00811 if (status != 0) { 00812 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00813 StrFree(dst_col); 00814 return status; 00815 } 00816 00817 if (count == 0) { 00818 /* Nothing to do */ 00819 StrFree(dst_col); 00820 return status; 00821 } 00822 00823 /* Allocate space for the list of key IDs */ 00824 keyids = MemMalloc(count * sizeof(int)); 00825 00826 /* Get the list of IDs */ 00827 00828 where = 0; 00829 sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS); 00830 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, where++); 00831 DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, src_state, where++); 00832 if (zone_id != -1) { 00833 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++); 00834 } 00835 DqsConditionString(&sql, dst_col, DQS_COMPARE_LE, datetime, where++); 00836 DqsEnd(&sql); 00837 00838 status = KsmKeyInitSql(&result, sql); 00839 DqsFree(sql); 00840 00841 if (status == 0) { 00842 while (status == 0) { 00843 status = KsmKey(result, &data); 00844 if (status == 0) { 00845 keyids[i] = data.keypair_id; 00846 i++; 00847 } 00848 } 00849 00850 /* Convert EOF status to success */ 00851 00852 if (status == -1) { 00853 status = 0; 00854 } else { 00855 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00856 StrFree(dst_col); 00857 StrFree(keyids); 00858 return status; 00859 } 00860 00861 KsmKeyEnd(result); 00862 00863 } else { 00864 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00865 StrFree(dst_col); 00866 StrFree(keyids); 00867 return status; 00868 } 00869 00870 /* Notify progress if debugging */ 00871 00872 DbgLog(DBG_M_REQUEST, KME_KEYCHSTATE, count, 00873 KsmKeywordStateValueToName(src_state), 00874 KsmKeywordStateValueToName(dst_state)); 00875 00876 /* 00877 * Now construct the "IN" statement listing the IDs of the keys we 00878 * are planning to change the state of. 00879 */ 00880 00881 StrAppend(&insql, "("); 00882 for (j = 0; j < i; ++j) { 00883 if (j != 0) { 00884 StrAppend(&insql, ","); 00885 } 00886 snprintf(buffer, sizeof(buffer), "%d", keyids[j]); 00887 StrAppend(&insql, buffer); 00888 } 00889 StrAppend(&insql, ")"); 00890 00891 StrFree(keyids); 00892 00893 /* 00894 * Update the keys. This is done after a status check, as the debug 00895 * code may have hit a database error, in which case we won't query the 00896 * database again. ("status" is initialized to success in case the debug 00897 * code is not executed.) 00898 */ 00899 00900 sql = DusInit("dnsseckeys"); 00901 DusSetInt(&sql, "STATE", dst_state, set++); 00902 DusSetString(&sql, dst_col, datetime, set++); 00903 00904 DusConditionKeyword(&sql, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0); 00905 DusConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1); 00906 DusEnd(&sql); 00907 StrFree(dst_col); 00908 00909 status = DbExecuteSqlNoResult(DbHandle(), sql); 00910 DusFree(sql); 00911 00912 /* Report any errors */ 00913 if (status != 0) { 00914 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00915 } 00916 00917 /* See if we need to log a message about the DS records */ 00918 if (keytype == KSM_TYPE_KSK && ((dst_state == KSM_STATE_DEAD && rollover_scheme == KSM_ROLL_DS) || dst_state == KSM_STATE_READY)) 00919 { 00920 /* Set our flag */ 00921 *NewDS = 1; 00922 00923 /* Get common info we need for either message */ 00924 status = KsmZoneNameFromId(zone_id, &zone_name); 00925 if (status != 0) { 00926 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00927 if (zone_name != NULL) { 00928 StrFree(insql); 00929 StrFree(zone_name); 00930 } 00931 return(status); 00932 } 00933 00934 /* If we moved a KSK from retire to dead then the DS can be removed */ 00935 if (dst_state == KSM_STATE_DEAD && rollover_scheme == KSM_ROLL_DS) { 00936 (void) MsgLog(KME_DS_REM_ZONE, zone_name); 00937 } 00938 else if (dst_state == KSM_STATE_READY) { 00939 (void) MsgLog(KME_NEW_DS, zone_name); 00940 00941 } 00942 } 00943 else if (keytype == KSM_TYPE_KSK && src_state == KSM_STATE_KEYPUBLISH) { 00944 /* Set our flag, we are completing an emergency rollover */ 00945 *NewDS = 1; 00946 } 00947 00948 StrFree(insql); 00949 StrFree(zone_name); 00950 00951 return status; 00952 } 00953 00954 00955 00956 /*+ 00957 * KsmRequestChangeStateGeneratePublish - Change State from GENERATE to PUBLISH 00958 * KsmRequestChangeStateGenerateDSPublish - Change State from GENERATE to DSPUBLISH 00959 * KsmRequestChangeStateReadyActive - Change State from READY to ACTIVE 00960 * 00961 * Description: 00962 * Changes the state of a number of keys from one state to another. 00963 * 00964 * Arguments: 00965 * int keytype 00966 * Type of keys being changed. 00967 * 00968 * const char* datetime 00969 * Date/time for which this request is being made. 00970 * 00971 * int count 00972 * Number of keys to be promoted to the publish state. There is no 00973 * check as to whether that number of keys are available in the 00974 * GENERATE state - it is assumed that that check has already been 00975 * carried out. 00976 * 00977 * int zone_id 00978 * ID of zone that we are looking at (-1 == all zones) 00979 * 00980 * Returns: 00981 * int 00982 * Status return. 0 => success, Other => failure, in which case an 00983 * error message will have been output. 00984 -*/ 00985 00986 int KsmRequestChangeStateGeneratePublish(int keytype, const char* datetime, 00987 int count, int zone_id) 00988 { 00989 return KsmRequestChangeStateN(keytype, datetime, count, 00990 KSM_STATE_GENERATE, KSM_STATE_PUBLISH, zone_id); 00991 } 00992 00993 int KsmRequestChangeStateGenerateDSSub(int keytype, const char* datetime, 00994 int count, int zone_id) 00995 { 00996 return KsmRequestChangeStateN(keytype, datetime, count, 00997 KSM_STATE_GENERATE, KSM_STATE_DSSUB, zone_id); 00998 } 00999 01000 int KsmRequestChangeStateReadyActive(int keytype, const char* datetime, 01001 int count, int zone_id) 01002 { 01003 return KsmRequestChangeStateN(keytype, datetime, count, 01004 KSM_STATE_READY, KSM_STATE_ACTIVE, zone_id); 01005 } 01006 01007 01008 /*+ 01009 * KsmRequestChangeStateN - Change State of N Keys 01010 * 01011 * Description: 01012 * Changes the state of a given number of keys from one state to another. 01013 * 01014 * Arguments: 01015 * int keytype 01016 * Type of keys being changed. 01017 * 01018 * const char* datetime 01019 * Date/time for which this request is being made. 01020 * 01021 * int count 01022 * Number of keys to be promoted to the destination state. There is no 01023 * check as to whether that number of keys are available in the 01024 * state - it is assumed that that check has already been carried out. 01025 * 01026 * int src_state 01027 * State from which keys are being prompted. 01028 * 01029 * int dst_state 01030 * State to which keys are being promoted. 01031 * 01032 * int zone_id 01033 * ID of zone that we are looking at (-1 == all zones) 01034 * 01035 * Returns: 01036 * int 01037 * Status return. 0 => success, Other => failure, in which case an 01038 * error message will have been output. 01039 -*/ 01040 01041 int KsmRequestChangeStateN(int keytype, const char* datetime, int count, 01042 int src_state, int dst_state, int zone_id) 01043 { 01044 char buffer[32]; /* For integer conversion */ 01045 DQS_QUERY_CONDITION condition[4]; /* Condition codes */ 01046 KSM_KEYDATA data; /* Data for this key */ 01047 char* dst_name = NULL; /* Dest state name uppercase */ 01048 DB_RESULT result; /* List result set */ 01049 int i; /* Loop counter */ 01050 char* insql = NULL; /* SQL "IN" clause */ 01051 int* keyids; /* List of IDs of keys to promote */ 01052 int setclause = 0; /* For the "SET" clauses */ 01053 char* sql1 = NULL; /* SQL statement */ 01054 char* sql2 = NULL; /* SQL statement */ 01055 char* sql3 = NULL; /* SQL statement */ 01056 int status; /* Status return */ 01057 int whereclause = 0; /* For the "WHERE" clauses */ 01058 int count1 = 0; /* No. of non-backed up keys */ 01059 int count2 = 0; /* No. of non-backed up keys which should be */ 01060 01061 /* Just checking */ 01062 if (count <= 0) { 01063 status = MsgLog(KSM_INVARG, "Asked to move 0 keys"); 01064 return status; 01065 } 01066 01067 /* Notify progress if debugging */ 01068 01069 DbgLog(DBG_M_REQUEST, KME_KEYCHSTATE, count, 01070 KsmKeywordStateValueToName(src_state), 01071 KsmKeywordStateValueToName(dst_state)); 01072 01073 /* Allocate space for the list of key IDs */ 01074 keyids = MemMalloc(count * sizeof(int)); 01075 01076 /* Get the list of IDs */ 01077 01078 condition[0].code = DB_KEYDATA_KEYTYPE; 01079 condition[0].data.number = keytype; 01080 condition[0].compare = DQS_COMPARE_EQ; 01081 01082 condition[1].code = DB_KEYDATA_STATE; 01083 condition[1].data.number = src_state; 01084 condition[1].compare = DQS_COMPARE_EQ; 01085 01086 condition[2].compare = DQS_END_OF_LIST; 01087 01088 if (zone_id != -1) { 01089 condition[2].code = DB_KEYDATA_ZONE_ID; 01090 condition[2].data.number = zone_id; 01091 condition[2].compare = DQS_COMPARE_EQ; 01092 01093 condition[3].compare = DQS_END_OF_LIST; 01094 } 01095 01096 01097 status = KsmKeyInit(&result, condition); 01098 for (i = 0; ((i < count) && (status == 0)); ++i) { 01099 status = KsmKey(result, &data); 01100 if (status == 0) { 01101 keyids[i] = data.keypair_id; 01102 } 01103 } 01104 KsmKeyEnd(result); 01105 01106 /* Did we get everything? */ 01107 01108 if (status == 0) { 01109 01110 /* 01111 * Yes: construct the "IN" statement listing the IDs of the keys we 01112 * are planning to change the state of. 01113 */ 01114 01115 StrAppend(&insql, "("); 01116 for (i = 0; i < count; ++i) { 01117 if (i != 0) { 01118 StrAppend(&insql, ","); 01119 } 01120 snprintf(buffer, sizeof(buffer), "%d", keyids[i]); 01121 StrAppend(&insql, buffer); 01122 } 01123 StrAppend(&insql, ")"); 01124 01125 /* Get upper case names of the states (= names of date columns) */ 01126 01127 if (dst_state == KSM_STATE_DSSUB) { 01128 StrAppend(&dst_name, KSM_STATE_PUBLISH_STRING); 01129 } else { 01130 dst_name = StrStrdup(KsmKeywordStateValueToName(dst_state)); 01131 } 01132 (void) StrToUpper(dst_name); 01133 01134 if (dst_state == KSM_STATE_ACTIVE) { 01135 /* 01136 * We are making the key(s) active so check the backedupness of these keys, 01137 * and compare with the requirebackup flag on their repository 01138 */ 01139 /* 01140 * First see if we have any which are not backed up 01141 */ 01142 StrAppend(&sql1, "select count(*) from keypairs where id in "); 01143 StrAppend(&sql1, insql); 01144 StrAppend(&sql1, " and backup is null"); 01145 01146 status = DbIntQuery(DbHandle(), &count1, sql1); 01147 DqsFree(sql1); 01148 01149 if (status != 0) 01150 { 01151 status = MsgLog(KSM_SQLFAIL, DbErrmsg(DbHandle())); 01152 StrFree(insql); 01153 MemFree(keyids); 01154 StrFree(dst_name); 01155 return status; 01156 } 01157 01158 if (count1 != 0) { 01159 /* 01160 * See if any of these are supposed to be backed up 01161 */ 01162 01163 StrAppend(&sql2, "select count(*) from keypairs k, securitymodules s where s.id = k.securitymodule_id and k.id in "); 01164 StrAppend(&sql2, insql); 01165 StrAppend(&sql2, " and k.backup is null and s.requirebackup = 1"); 01166 01167 status = DbIntQuery(DbHandle(), &count2, sql2); 01168 DqsFree(sql2); 01169 01170 if (status != 0) 01171 { 01172 status = MsgLog(KSM_SQLFAIL, DbErrmsg(DbHandle())); 01173 StrFree(insql); 01174 MemFree(keyids); 01175 StrFree(dst_name); 01176 return status; 01177 } 01178 01179 if (count2 != 0) { 01180 /* 01181 * This is bad; log an error and return 01182 */ 01183 status = MsgLog(KME_BACK_FATAL, (keytype == KSM_TYPE_KSK) ? "KSK" : "ZSK"); 01184 StrFree(insql); 01185 MemFree(keyids); 01186 StrFree(dst_name); 01187 return status; 01188 } 01189 01190 /* 01191 * We allow this, but with a strong warning 01192 */ 01193 (void) MsgLog(KME_BACK_NON_FATAL, (keytype == KSM_TYPE_KSK) ? "KSK" : "ZSK"); 01194 } 01195 } 01196 01197 /* 01198 * Now construct the "UPDATE" statement and execute it. This relies on 01199 * the fact that the name of the state is the same as the name of 01200 * the column in KEYDATA holding the date at which the key moved to 01201 * that state. 01202 */ 01203 01204 sql3 = DusInit("dnsseckeys"); 01205 DusSetInt(&sql3, "STATE", dst_state, setclause++); 01206 DusSetString(&sql3, dst_name, datetime, setclause++); 01207 StrFree(dst_name); 01208 01209 DusConditionKeyword(&sql3, "KEYPAIR_ID", DQS_COMPARE_IN, insql, whereclause++); 01210 DusConditionInt(&sql3, "ZONE_ID", DQS_COMPARE_EQ, zone_id, whereclause++); 01211 StrFree(insql); 01212 DusEnd(&sql3); 01213 01214 status = DbExecuteSqlNoResult(DbHandle(), sql3); 01215 DusFree(sql3); 01216 01217 /* Report any errors */ 01218 01219 if (status != 0) { 01220 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 01221 } 01222 } 01223 01224 /* Free up resources */ 01225 01226 MemFree(keyids); 01227 01228 return status; 01229 } 01230 01231 /*+ 01232 * KsmRequestChangeStateGenerateDSSubConditional - 01233 * Change State from Generate to DSSub 01234 * 01235 * Description: 01236 * Make sure that the zone has the correct number of standby keys. 01237 * 01238 * Arguments: 01239 * int keytype 01240 * Key type for which the request should happen. 01241 * 01242 * KSM_TYPE_KSK KSKs 01243 * KSM_TYPE_ZSK ZSKs 01244 * 01245 * const char* datetime 01246 * Date/time for which this request is taking place. 01247 * 01248 * KSM_PARCOLL* collection 01249 * Pointer to parameter collection for this zone. 01250 * 01251 * int zone_id 01252 * ID of zone that we are looking at (-1 == all zones) 01253 * 01254 * Returns: 01255 * int 01256 * Status return. 0 => success, Other => failure, in which case an 01257 * error message will have been output. 01258 -*/ 01259 01260 int KsmRequestChangeStateGenerateDSSubConditional(int keytype, 01261 const char* datetime, KSM_PARCOLL* collection, int zone_id, int* NewDS) 01262 { 01263 int gencnt; /* Number of keys in generate state */ 01264 int newkeys; /* New keys required */ 01265 int standby; /* Number of standby keys */ 01266 int reqkeys; /* Number of keys required */ 01267 int status; /* Status return */ 01268 01269 /* How many standby keys we have */ 01270 status = KsmRequestStandbyKSKCount(&standby, zone_id); 01271 if (status != 0) { 01272 return status; 01273 } 01274 01275 reqkeys = KsmParameterStandbyKSKeys(collection); 01276 01277 /* 01278 * So, if we remove "pendret" keys from the number of "available" 01279 * keys, how many are we short of the required number? This is how many 01280 * we need to promote from "generate" to "publish" 01281 */ 01282 01283 newkeys = reqkeys - standby; 01284 01285 if (newkeys > 0) { 01286 01287 /* Are there enough generated keys available */ 01288 01289 status = KsmRequestGenerateCount(keytype, &gencnt, zone_id); 01290 if (status == 0) { 01291 if (gencnt < newkeys) { 01292 status = MsgLog(KME_INSFGENKEY, gencnt, 01293 KsmKeywordTypeValueToName(keytype), newkeys); 01294 } 01295 DbgLog(DBG_M_REQUEST, KME_GENERATECNT, gencnt, 01296 KsmKeywordTypeValueToName(keytype)); 01297 01298 if (status == 0) { 01299 01300 /* There are enough keys, so move them to "dssub" state */ 01301 01302 status = KsmRequestChangeStateGenerateDSSub(keytype, 01303 datetime, newkeys, zone_id); 01304 01305 /* Set our flag */ 01306 *NewDS = 1; 01307 } 01308 } 01309 } 01310 01311 return 0; 01312 } 01313 01314 /*+ 01315 * KsmRequestChangeStateGeneratePublishConditional - 01316 * Change State from Generate to Pubish 01317 * 01318 * Description: 01319 * Unlike the other "Change State" functions, this is conditional. It 01320 * promotes keys in the "Generate" state to the "Publish" state to maintain 01321 * the required number of keys active/standby keys when the active keys 01322 * are retired. 01323 * 01324 * a) For the given time, work out how many "active" keys have a retire 01325 * date within this time + "publication interval". Call this number 01326 * Npr (Number pending retirement). 01327 * 01328 * This should be 1 or 0, as there is an assumption that there is only 01329 * ever one active key. 01330 * 01331 * b) Work out how many keys are in the active, publish and ready states. 01332 * Call this Nt (Number total). 01333 * 01334 * c) Now look at the difference (Nt - Npr). This is the number of keys 01335 * that will be (potentially) usable after the active key retires. 01336 * If this number is less than (1 + Ne) (where Ne is the number of 01337 * standby keys), move the difference from the generated state into 01338 * the published state. 01339 * 01340 * Arguments: 01341 * int keytype 01342 * Key type for which the request should happen. 01343 * 01344 * KSM_TYPE_KSK KSKs 01345 * KSM_TYPE_ZSK ZSKs 01346 * 01347 * const char* datetime 01348 * Date/time for which this request is taking place. 01349 * 01350 * KSM_PARCOLL* collection 01351 * Pointer to parameter collection for this zone. 01352 * 01353 * int zone_id 01354 * ID of zone that we are looking at (-1 == all zones) 01355 * 01356 * int run_interval 01357 * how frequently do we run? 01358 * 01359 * Returns: 01360 * int 01361 * Status return. 0 => success, Other => failure, in which case an 01362 * error message will have been output. 01363 -*/ 01364 01365 int KsmRequestChangeStateGeneratePublishConditional(int keytype, 01366 const char* datetime, KSM_PARCOLL* collection, int zone_id, int run_interval) 01367 { 01368 int availkeys; /* Number of availkeys keys */ 01369 int gencnt; /* Number of keys in generate state */ 01370 int newkeys; /* New keys required */ 01371 int pendret; /* Number of keys that will be retired */ 01372 int reqkeys; /* Number of keys required */ 01373 int status; /* Status return */ 01374 01375 /* How many active keys will be retired in the immediate future */ 01376 status = KsmRequestPendingRetireCount(keytype, datetime, collection, 01377 &pendret, zone_id, run_interval); 01378 if (status != 0) { 01379 return status; 01380 } 01381 DbgLog(DBG_M_REQUEST, KME_RETIRECNT, pendret); 01382 01383 /* How many available keys are there */ 01384 01385 status = KsmRequestAvailableCount(keytype, datetime, collection, 01386 &availkeys, zone_id); 01387 if (status != 0) { 01388 return status; 01389 } 01390 DbgLog(DBG_M_REQUEST, KME_AVAILCNT, availkeys); 01391 01392 /* 01393 * We need at least one active key and "number of standby keys" ready 01394 * keys at any one time. 01395 */ 01396 01397 if (keytype == KSM_TYPE_KSK) { 01398 /* For KSKs we sort out standby keys separately */ 01399 reqkeys = 1; /*+ KsmParameterStandbyKSKeys(collection);*/ 01400 } 01401 else if (keytype == KSM_TYPE_ZSK) { 01402 reqkeys = 1 + KsmParameterStandbyZSKeys(collection); 01403 } 01404 else { 01405 /* should not get here */ 01406 return -1; 01407 } 01408 01409 /* 01410 * So, if we remove "pendret" keys from the number of "available" 01411 * keys, how many are we short of the required number? This is how many 01412 * we need to promote from "generate" to "publish" 01413 */ 01414 01415 newkeys = reqkeys - (availkeys - pendret); 01416 /* fprintf(stderr, "%s: keytype(%d): newkeys(%d) = reqkeys(%d) - (availkeys(%d) - pendret(%d))\n", datetime, keytype, newkeys, reqkeys, availkeys, pendret); */ 01417 DbgLog(DBG_M_REQUEST, KME_KEYCNTSUMM, reqkeys, newkeys); 01418 01419 if (newkeys > 0) { 01420 01421 /* Are there enough generated keys available */ 01422 01423 status = KsmRequestGenerateCount(keytype, &gencnt, zone_id); 01424 if (status == 0) { 01425 if (gencnt < newkeys) { 01426 status = MsgLog(KME_INSFGENKEY, gencnt, 01427 KsmKeywordTypeValueToName(keytype), newkeys); 01428 } 01429 DbgLog(DBG_M_REQUEST, KME_GENERATECNT, gencnt, 01430 KsmKeywordTypeValueToName(keytype)); 01431 01432 if (status == 0) { 01433 01434 /* There are enough keys, so move them to "publish" state */ 01435 01436 status = KsmRequestChangeStateGeneratePublish(keytype, 01437 datetime, newkeys, zone_id); 01438 } 01439 } 01440 } 01441 01442 return 0; 01443 } 01444 01445 01446 01447 /*+ 01448 * KsmRequestPendingRetireCount - Get Count of Keys Pending Retirement 01449 * 01450 * Description: 01451 * For the given time, works out how many "active" keys have a retire 01452 * date within this time + "publication interval". 01453 * 01454 * This should be 1 or 0, as there is an assumption that there is only 01455 * ever one active key. 01456 * 01457 * Arguments: 01458 * int keytype 01459 * Key type for which the request should happen. 01460 * 01461 * KSM_TYPE_KSK KSKs 01462 * KSM_TYPE_ZSK ZSKs 01463 * 01464 * const char* datetime 01465 * Date/time for which this request is taking place. 01466 * 01467 * KSM_PARCOLL* parameters 01468 * Parameters associated with this zone. 01469 * 01470 * int* count (returned) 01471 * Number of active keys that will retire within that period. 01472 * 01473 * int zone_id 01474 * ID of zone that we are looking at (-1 == all zones) 01475 * 01476 * Returns: 01477 * int 01478 * Status return. 0 => success, <>0 => error, in which case a message 01479 * will have been output. 01480 -*/ 01481 01482 int KsmRequestPendingRetireCount(int keytype, const char* datetime, 01483 KSM_PARCOLL* parameters, int* count, int zone_id, int interval) 01484 { 01485 char buffer[256]; /* For constructing part of the command */ 01486 int clause = 0; /* Used in constructing SQL statement */ 01487 size_t nchar; /* Number of characters written */ 01488 char* sql; /* SQL command to be isssued */ 01489 int status; /* Status return */ 01490 int total_interval; /* The PublicationInterval + interval (when we will run again) */ 01491 01492 if (keytype == KSM_TYPE_ZSK) 01493 { 01494 total_interval = KsmParameterZskTtl(parameters) + 01495 KsmParameterPropagationDelay(parameters) + 01496 KsmParameterPubSafety(parameters) + 01497 interval; 01498 } else { 01499 total_interval = KsmParameterKskTtl(parameters) + 01500 KsmParameterKskPropagationDelay(parameters) + 01501 KsmParameterPubSafety(parameters) + 01502 interval; 01503 /* 01504 if (DOUBLEDNSKEY) { 01505 total_interval = KsmParameterKskTtl(parameters) + 01506 KsmParameterPropagationDelay(parameters) + 01507 KsmParameterDSTtl(parameters) + 01508 KsmParameterKskPropagationDelay(parameters) + 01509 KsmParameterPubSafety(parameters) + 01510 interval; 01511 } 01512 if (DOUBLEDS) { 01513 total_interval = KsmParameterDSTtl(parameters) + 01514 KsmParameterKskPropagationDelay(parameters) + 01515 KsmParameterPubSafety(parameters) + 01516 interval; 01517 } 01518 if (DOUBLERRSET) { 01519 temp = MAX( 01520 (KsmParameterKskTtl(parameters) + KsmParameterPropagationDelay(parameters)), 01521 (KsmParameterDSTtl(parameters) + KsmParameterKskPropagationDelay(parameters))); 01522 if (RFC5011) { 01523 temp = max(temp, 30*24*60*60); 01524 } 01525 total_interval = temp + KsmParameterPubSafety(parameters) + 01526 interval; 01527 } 01528 */ 01529 } 01530 /* Create the SQL command to interrogate the database */ 01531 01532 sql = DqsCountInit("KEYDATA_VIEW"); 01533 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++); 01534 DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, clause++); 01535 if (zone_id != -1) { 01536 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++); 01537 } 01538 01539 /* Calculate the initial publication interval & add to query */ 01540 01541 /* 01542 * TODO is there an alternative to DATE_ADD which is more generic? 01543 */ 01544 #ifdef USE_MYSQL 01545 nchar = snprintf(buffer, sizeof(buffer), 01546 "DATE_ADD('%s', INTERVAL %d SECOND)", 01547 datetime, total_interval); 01548 #else 01549 nchar = snprintf(buffer, sizeof(buffer), 01550 "DATETIME('%s', '+%d SECONDS')", 01551 datetime, total_interval); 01552 #endif /* USE_MYSQL */ 01553 if (nchar >= sizeof(buffer)) { 01554 status = MsgLog(KME_BUFFEROVF, "KsmRequestKeys"); 01555 return status; 01556 } 01557 01558 #ifdef USE_MYSQL 01559 DqsConditionKeyword(&sql, "RETIRE", DQS_COMPARE_LE, buffer, clause++); 01560 #else 01561 DqsConditionKeyword(&sql, "DATETIME(RETIRE)", DQS_COMPARE_LE, buffer, clause++); 01562 #endif /* USE_MYSQL */ 01563 01564 DqsEnd(&sql); 01565 01566 /* Execute the query and free resources */ 01567 01568 status = DbIntQuery(DbHandle(), count, sql); 01569 DqsFree(sql); 01570 01571 /* Report any errors */ 01572 01573 if (status != 0) { 01574 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 01575 } 01576 01577 return status; 01578 } 01579 01580 01581 01582 /*+ 01583 * KsmRequestAvailableCount - Get Count of Available Keys 01584 * 01585 * Description: 01586 * By "available", is the number of keys in the "published", "ready" 01587 * and "active" state. 01588 * 01589 * Arguments: 01590 * int keytype 01591 * Key type for which the request should happen. 01592 * 01593 * KSM_TYPE_KSK KSKs 01594 * KSM_TYPE_ZSK ZSKs 01595 * 01596 * const char* datetime 01597 * Date/time for which this request is taking place. 01598 * 01599 * KSM_PARCOLL* parameters 01600 * Parameters associated with this zone. 01601 * 01602 * int* count (returned) 01603 * Number of available keys. 01604 * 01605 * int zone_id 01606 * ID of zone that we are looking at (-1 == all zones) 01607 * 01608 * Returns: 01609 * int 01610 * Status return. 0 => success, <>0 => error, in which case a message 01611 * will have been output. 01612 -*/ 01613 01614 int KsmRequestAvailableCount(int keytype, const char* datetime, KSM_PARCOLL* parameters, int* count, int zone_id) 01615 { 01616 char buffer[256]; /* For constructing part of the command */ 01617 int clause = 0; /* Used in constructing SQL statement */ 01618 size_t nchar; /* Number of characters written */ 01619 char* sql; /* SQL command to be isssued */ 01620 int status; /* Status return */ 01621 01622 /* Unused parameters */ 01623 (void)datetime; 01624 (void)parameters; 01625 01626 /* Create the SQL command to interrogate the database */ 01627 01628 sql = DqsCountInit("KEYDATA_VIEW"); 01629 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++); 01630 01631 /* Calculate the initial publication interval & add to query */ 01632 01633 nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d, %d)", 01634 KSM_STATE_PUBLISH, KSM_STATE_READY, KSM_STATE_ACTIVE, KSM_STATE_KEYPUBLISH); 01635 if (nchar >= sizeof(buffer)) { 01636 status = MsgLog(KME_BUFFEROVF, "KsmRequestKeys"); 01637 return status; 01638 } 01639 DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, clause++); 01640 if (zone_id != -1) { 01641 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++); 01642 } 01643 DqsEnd(&sql); 01644 01645 /* Execute the query and free resources */ 01646 01647 status = DbIntQuery(DbHandle(), count, sql); 01648 DqsFree(sql); 01649 01650 /* Report any errors */ 01651 01652 if (status != 0) { 01653 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 01654 } 01655 01656 return status; 01657 } 01658 01659 01660 /*+ 01661 * KsmRequestGenerateCount - Return Number of Keys in Generate State 01662 * 01663 * Description: 01664 * Returns the retire time of the currently active key. If there are 01665 * multiple active keys, returns the earliest time. 01666 * 01667 * Arguments: 01668 * int keytype 01669 * Time of key to search for. 01670 * 01671 * int* count (returned) 01672 * Number of available keys. 01673 * 01674 * int zone_id 01675 * ID of zone that we are looking at (-1 == all zones) 01676 * 01677 * Returns: 01678 * int 01679 * Status return. 0 => success, Other implies error, in which case a 01680 * message will have been output. 01681 -*/ 01682 01683 int KsmRequestGenerateCount(int keytype, int* count, int zone_id) 01684 { 01685 int clause = 0; /* Clause count */ 01686 char* sql = NULL; /* SQL to interrogate database */ 01687 int status = 0; /* Status return */ 01688 01689 /* Create the SQL */ 01690 01691 sql = DqsCountInit("KEYDATA_VIEW"); 01692 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++); 01693 DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_GENERATE, clause++); 01694 if (zone_id != -1) { 01695 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++); 01696 } 01697 DqsEnd(&sql); 01698 01699 /* Execute the query and free resources */ 01700 01701 status = DbIntQuery(DbHandle(), count, sql); 01702 DqsFree(sql); 01703 01704 /* Report any errors */ 01705 01706 if (status != 0) { 01707 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 01708 } 01709 01710 return status; 01711 } 01712 01713 /*+ 01714 * KsmRequestStandbyKSKCount - Get Count of Standby Keys 01715 * 01716 * Description: 01717 * The number of keys in the "dspublished" and "dsready" states. 01718 * 01719 * Arguments: 01720 * 01721 * int* count (returned) 01722 * Number of standby keys. 01723 * 01724 * int zone_id 01725 * ID of zone that we are looking at (-1 == all zones) 01726 * 01727 * Returns: 01728 * int 01729 * Status return. 0 => success, <>0 => error, in which case a message 01730 * will have been output. 01731 -*/ 01732 01733 int KsmRequestStandbyKSKCount(int* count, int zone_id) 01734 { 01735 char buffer[256]; /* For constructing part of the command */ 01736 int clause = 0; /* Used in constructing SQL statement */ 01737 size_t nchar; /* Number of characters written */ 01738 char* sql; /* SQL command to be isssued */ 01739 int status; /* Status return */ 01740 01741 /* Create the SQL command to interrogate the database */ 01742 01743 sql = DqsCountInit("KEYDATA_VIEW"); 01744 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, clause++); 01745 01746 /* Calculate the initial publication interval & add to query */ 01747 01748 nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d)", 01749 KSM_STATE_DSSUB, KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY); 01750 if (nchar >= sizeof(buffer)) { 01751 status = MsgLog(KME_BUFFEROVF, "KsmRequestKeys"); 01752 return status; 01753 } 01754 DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, clause++); 01755 if (zone_id != -1) { 01756 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++); 01757 } 01758 DqsEnd(&sql); 01759 01760 /* Execute the query and free resources */ 01761 01762 status = DbIntQuery(DbHandle(), count, sql); 01763 DqsFree(sql); 01764 01765 /* Report any errors */ 01766 01767 if (status != 0) { 01768 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 01769 } 01770 01771 return status; 01772 } 01773 01774 /* 01775 * KsmRequestCheckActiveKey - Check Active Key 01776 * 01777 * Description: 01778 * Checks: 01779 * 01780 * a) If there is an active key. 01781 * b) If a key is present, what the retire time of it is. This is compared 01782 * against the specified date/time. 01783 * 01784 * A flag is returned indicating whether the key (if active) should be 01785 * replaced. 01786 * 01787 * Arguments: 01788 * int keytype 01789 * Either KSK or ZSK, depending on the key type 01790 * 01791 * const char* datetime 01792 * Date/time at which the check is being carried out. 01793 * 01794 * int* count 01795 * Number of active keys of the appropriate type and in the zone 01796 * that will be active AFTER the given date and time. 01797 * 01798 * int zone_id 01799 * ID of zone that we are looking at (-1 == all zones) 01800 * 01801 * This negative form (i.e. keys not meeting the specified condition) 01802 * is used to ensure that if there are no active keys, this fact is 01803 * reported. 01804 * 01805 * Returns: 01806 * int 01807 * Status return. 0 => success, Other => error, in which case a message 01808 * will have been output. 01809 -*/ 01810 01811 int KsmRequestCheckActiveKey(int keytype, const char* datetime, int* count, int zone_id) 01812 { 01813 int clause = 0; /* Clause counter */ 01814 char* sql = NULL; /* SQL command */ 01815 int status; /* Status return */ 01816 #ifdef USE_MYSQL 01817 #else 01818 char buf[256]; /* For constructing part of the command */ 01819 #endif /* USE_MYSQL */ 01820 sql = DqsCountInit("KEYDATA_VIEW"); 01821 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++); 01822 DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, clause++); 01823 if (zone_id != -1) { 01824 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++); 01825 } 01826 01827 #ifdef USE_MYSQL 01828 DqsConditionString(&sql, "RETIRE", DQS_COMPARE_GT, datetime, clause++); 01829 #else 01830 snprintf(buf, sizeof(buf), "DATETIME('%s')", datetime); 01831 DqsConditionKeyword(&sql, "DATETIME(RETIRE)", DQS_COMPARE_GT, buf, clause++); 01832 #endif /* USE_MYSQL */ 01833 01834 DqsEnd(&sql); 01835 01836 status = DbIntQuery(DbHandle(), count, sql); 01837 DqsFree(sql); 01838 01839 if (status != 0) { 01840 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 01841 } 01842 DbgLog(DBG_M_REQUEST, KME_REMAINACT, *count, 01843 KsmKeywordTypeValueToName(keytype)); 01844 01845 return status; 01846 } 01847 01848 01849 01850 /* 01851 * KsmRequestCountReadyKey - Count Keys in READY state 01852 * 01853 * Description: 01854 * Counts the number of keys in the "READY" state. 01855 * 01856 * Arguments: 01857 * int keytype 01858 * Either KSK or ZSK, depending on the key type 01859 * 01860 * const char* datetime 01861 * Date/time at which the check is being carried out. 01862 * 01863 * int* count 01864 * Number of keys meeting the condition. 01865 * 01866 * int zone_id 01867 * ID of zone that we are looking at (-1 == all zones) 01868 * 01869 * Returns: 01870 * int 01871 * Status return. 0 => success, Other => error, in which case a message 01872 * will have been output. 01873 -*/ 01874 01875 int KsmRequestCountReadyKey(int keytype, const char* datetime, int* count, int zone_id) 01876 { 01877 int clause = 0; /* Clause counter */ 01878 char* sql = NULL; /* SQL command */ 01879 int status; /* Status return */ 01880 01881 /* Unused parameter */ 01882 (void)datetime; 01883 01884 sql = DqsCountInit("KEYDATA_VIEW"); 01885 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++); 01886 DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_READY, clause++); 01887 if (zone_id != -1) { 01888 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++); 01889 } 01890 DqsEnd(&sql); 01891 01892 status = DbIntQuery(DbHandle(), count, sql); 01893 DqsFree(sql); 01894 01895 if (status != 0) { 01896 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 01897 } 01898 DbgLog(DBG_M_REQUEST, KME_READYCNT, *count, 01899 KsmKeywordTypeValueToName(keytype)); 01900 01901 return status; 01902 } 01903 01904 /* 01905 * KsmRequestCheckFirstPass - Work out if this zone has been processed before 01906 * 01907 * Description: 01908 * Counts the number of keys above the PUBLISH state; if this is 0 then this is 01909 * a new zone. 01910 * 01911 * Arguments: 01912 * int keytype 01913 * Either KSK or ZSK, depending on the key type 01914 * 01915 * int* first_pass_flag 01916 * Indicator as to the result 01917 * 01918 * int zone_id 01919 * ID of zone that we are looking at (-1 == all zones) 01920 * 01921 * Returns: 01922 * int 01923 * Status return. 0 => success, Other => error, in which case a message 01924 * will have been output. 01925 -*/ 01926 01927 int KsmRequestCheckFirstPass(int keytype, int* first_pass_flag, int zone_id) 01928 { 01929 int clause = 0; /* Clause counter */ 01930 char* sql = NULL; /* SQL command */ 01931 int status; /* Status return */ 01932 int count = 0; /* Number of matching keys */ 01933 01934 sql = DqsCountInit("KEYDATA_VIEW"); 01935 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++); 01936 DqsConditionInt(&sql, "STATE", DQS_COMPARE_GE, KSM_STATE_PUBLISH, clause++); 01937 if (zone_id != -1) { 01938 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++); 01939 } 01940 DqsEnd(&sql); 01941 01942 status = DbIntQuery(DbHandle(), &count, sql); 01943 DqsFree(sql); 01944 01945 if (status != 0) { 01946 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 01947 } 01948 01949 if (count == 0) { 01950 /* No "ready, active, retired or dead" keys */ 01951 *first_pass_flag = 1; 01952 } 01953 else { 01954 *first_pass_flag = 0; 01955 } 01956 01957 return status; 01958 } 01959 01960 /* 01961 * KsmRequestCheckCompromisedFlag - Work out if this zone is rolling 01962 * 01963 * Description: 01964 * Counts the number of "compromised" active keys, if > 0 then force 01965 * the zone to roll if we can. 01966 * 01967 * Arguments: 01968 * int keytype 01969 * Either KSK or ZSK, depending on the key type 01970 * 01971 * int zone_id 01972 * ID of zone that we are looking at (-1 == all zones) 01973 * 01974 * int* comp_flag 01975 * Force rollover behaviour if the active key is marked as compromised 01976 * 01977 * Returns: 01978 * int 01979 * Status return. 0 => success, Other => error, in which case a message 01980 * will have been output. 01981 -*/ 01982 01983 int KsmRequestCheckCompromisedFlag(int keytype, int zone_id, int* comp_flag) 01984 { 01985 int clause = 0; /* Clause counter */ 01986 char* sql = NULL; /* SQL command */ 01987 int status; /* Status return */ 01988 int count = 0; /* Number of matching keys */ 01989 01990 sql = DqsCountInit("KEYDATA_VIEW"); 01991 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++); 01992 DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, clause++); 01993 if (zone_id != -1) { 01994 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++); 01995 } 01996 DqsConditionInt(&sql, "compromisedflag", DQS_COMPARE_EQ, 1, clause++); 01997 DqsEnd(&sql); 01998 01999 status = DbIntQuery(DbHandle(), &count, sql); 02000 DqsFree(sql); 02001 02002 if (status != 0) { 02003 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 02004 } 02005 02006 if (count == 0) { 02007 /* No "compromised" keys; i.e. keys waiting to roll */ 02008 /* We actually don't need to do this as it can only be 0 already */ 02009 *comp_flag = 0; 02010 } 02011 else { 02012 *comp_flag = 1; 02013 } 02014 02015 return status; 02016 } 02017 02018 /*+ 02019 * KsmRequestIssueKeys - Issue Keys 02020 * 02021 * Description: 02022 * Done as the last step in the "REQUEST KEYS" operation, this actually 02023 * issues the keys that should be in the current zone file. All keys in 02024 * the "publish", "ready", "active" and "retire" states are included. 02025 * 02026 * Arguments: 02027 * int keytype 02028 * Type of keys required. 02029 * 02030 * KSM_REQUEST_CALLBACK callback 02031 * Callback function called for every key that will be issued. 02032 * 02033 * void* context 02034 * Context argument passed uninterpreted to the callback function. 02035 * 02036 * int zone_id 02037 * ID of zone that we are looking at (-1 == all zones) 02038 * 02039 * Returns: 02040 * int 02041 * Status return. 0 => success, <>0 => error (in which case a message 02042 * will have been output). 02043 -*/ 02044 02045 int KsmRequestIssueKeys(int keytype, KSM_REQUEST_CALLBACK callback, 02046 void* context, int zone_id) 02047 { 02048 int clause = 0; /* For the WHERE clause */ 02049 KSM_KEYDATA data; /* Data for this key */ 02050 DB_RESULT result; /* Result set from query */ 02051 char in[128]; /* Easily large enought for four keys */ 02052 size_t nchar; /* Number of output characters */ 02053 char* sql = NULL; /* SQL statement to get listing */ 02054 int status; /* Status return */ 02055 02056 /* 02057 * Construct the "IN" statement listing the states of the keys that 02058 * are included in the output. 02059 */ 02060 02061 nchar = snprintf(in, sizeof(in), "(%d, %d, %d, %d, %d)", 02062 KSM_STATE_PUBLISH, KSM_STATE_READY, KSM_STATE_ACTIVE, KSM_STATE_RETIRE, KSM_STATE_KEYPUBLISH); 02063 if (nchar >= sizeof(in)) { 02064 status = MsgLog(KME_BUFFEROVF, "KsmRequestIssueKeys"); 02065 return status; 02066 } 02067 02068 /* Create the SQL command to interrogate the database */ 02069 02070 sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS); 02071 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++); 02072 DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, in, clause++); 02073 if (zone_id != -1) { 02074 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++); 02075 } 02076 DqsEnd(&sql); 02077 02078 /* Now iterate round the keys meeting the condition and print them */ 02079 02080 status = KsmKeyInitSql(&result, sql); 02081 if (status == 0) { 02082 status = KsmKey(result, &data); 02083 while (status == 0) { 02084 status = (*callback)(context, &data); 02085 if (status == 0) { 02086 status = KsmKey(result, &data); 02087 } 02088 } 02089 02090 /* Convert EOF status to success */ 02091 02092 if (status == -1) { 02093 status = 0; 02094 } 02095 02096 KsmKeyEnd(result); 02097 } 02098 02099 DqsFree(sql); 02100 return status; 02101 } 02102 02103 02104 02105 /*+ 02106 * KsmRequestPrintKey - Print Key Data 02107 * 02108 * Description: 02109 * Suitable callback function for KsmRequest, this prints a summary of the 02110 * key information to stdout. 02111 * 02112 * Arguments: 02113 * void* context 02114 * Context passed to KsmUpdate. This is unused. 02115 * 02116 * KSM_KEYDATA* data 02117 * Data about the key to be isssued. 02118 * 02119 * Returns: 02120 * int 02121 * Always 0. 02122 -*/ 02123 02124 int KsmRequestPrintKey(void* context, KSM_KEYDATA* data) 02125 { 02126 /* Unused parameter */ 02127 (void)context; 02128 02129 printf("%s %lu %d %d %s\n", KsmKeywordStateValueToName(data->state), 02130 data->keypair_id, data->keytype, data->algorithm, data->location); 02131 02132 return 0; 02133 }