OpenDNSSEC-enforcer  1.3.4
/build/buildd/opendnssec-1.3.4/enforcer/ksm/ksm_request.c
Go to the documentation of this file.
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 }