OpenDNSSEC-enforcer 1.3.0
/build/buildd/opendnssec-1.3.0/enforcer/ksm/ksm_update.c
Go to the documentation of this file.
00001 /*
00002  * $Id: ksm_update.c 5320 2011-07-12 10:42:26Z jakob $
00003  *
00004  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00019  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00021  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00023  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00024  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00025  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  *
00027  */
00028 
00029 /*+
00030  * ksm_update.c - Update Times
00031  *
00032  * Description:
00033  *      Given a set of zones, this module updates all the estimated times in
00034  *      the keys associated with the zone.
00035  *
00036  *      The estimated times are updated using the current state of the key and
00037  *      the actual time the key entered that state.  The key is updated using
00038  *      the values of the various parameters.
00039  *
00040  *      SO FAR, THIS ONLY APPLIES TO ZSKS
00041 -*/
00042 
00043 #include <stdio.h>
00044 #include <limits.h>
00045 
00046 #include "ksm/database.h"
00047 #include "ksm/db_fields.h"
00048 #include "ksm/debug.h"
00049 #include "ksm/ksm.h"
00050 #include "ksm/kmedef.h"
00051 #include "ksm/ksmdef.h"
00052 #include "ksm/message.h"
00053 
00054 #define MAX(a, b) ((a) > (b) ? (a) : (b))
00055 #define MIN(a, b) ((a) < (b) ? (a) : (b))
00056 
00057 
00058 /*+
00059  * KsmUpdate - Update Times for Keys
00060  *
00061  * Description:
00062  *      Obtains the times for the specified zone and process each key in it.
00063  *
00064  * Arguments:
00065  *      None.
00066  *
00067  * Returns:
00068  *      int
00069  *          Always 0.
00070 -*/
00071 
00072 int KsmUpdate(int policy_id, int zone_id)
00073 {
00074     KSM_PARCOLL         collection;     /* Collection of parameters for zone */
00075     KSM_KEYDATA         data;           /* Data about the key */
00076     DB_RESULT           result;         /* For iterating through keys */
00077     int                 status = 0;         /* Status return */
00078     DQS_QUERY_CONDITION condition[2];       /* Condition codes */
00079 
00080     /* Set collection defaults */
00081     KsmCollectionInit(&collection);
00082 
00083     /* Get the values of the parameters */
00084     status = KsmParameterCollection(&collection, policy_id);
00085     if (status == 0) {
00086 
00087         /*
00088          * Iterate round, updating each key.  As always, an error causes a
00089          * message to be output, so we don't need to handle error conditions.
00090          * Abandon updates if the update of a single key fails.
00091          */
00092 
00093         /* zone_id of -1 means all zones */
00094         if (zone_id == -1) {
00095             status = KsmKeyInit(&result, NULL);
00096         } 
00097         else {
00098             condition[0].code = DB_KEYDATA_ZONE_ID;
00099             condition[0].data.number = zone_id;
00100             condition[0].compare = DQS_COMPARE_EQ;
00101 
00102             condition[1].compare = DQS_END_OF_LIST;
00103 
00104             status = KsmKeyInit(&result, condition);
00105         }
00106 
00107         if (status == 0) {
00108             /* Transaction handling is one level up (in KsmRequestKeys) */
00109             status = KsmKey(result, &data);
00110             while (status == 0) {
00111                 (void) KsmUpdateKey(&data, &collection, zone_id);
00112                 status = KsmKey(result, &data);
00113             }
00114             (void) KsmKeyEnd(result);
00115 
00116             /* Change end of list status to a success */
00117 
00118             if (status == -1) {
00119                 status = 0;
00120             }
00121         }
00122     }
00123     /*
00124      * else {
00125      *      Unable to get parameter collection information.  If we can't do
00126      *      this, something must be seriously wrong.
00127      * }
00128      */
00129 
00130     return status;
00131 }
00132 
00133 
00134 /*+
00135  * KsmUpdateKey - Update Key Times
00136  *
00137  * Description:
00138  *      Updates the estimated times in a key based on the current state and the
00139  *      parameters.
00140  *
00141  * Arguments:
00142  *      KSM_KEYDATA* data
00143  *          Key to update.
00144  *
00145  *      KSM_PARCOLL* collection
00146  *          Parameter collection.
00147  *
00148  *      int zone_id
00149  *          zone we are looking at
00150 -*/
00151 
00152 void KsmUpdateKey(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
00153 {
00154     /* check the argument */
00155     if (data == NULL) {
00156         MsgLog(KSM_INVARG, "NULL data");
00157         return;
00158     }
00159 
00160     switch (data->state) {
00161     case KSM_STATE_GENERATE:
00162         KsmUpdateGenerateKeyTime(data);
00163         break;
00164 
00165     case KSM_STATE_PUBLISH:
00166         KsmUpdatePublishKeyTime(data, collection, zone_id);
00167         break;
00168 
00169     case KSM_STATE_READY:
00170         KsmUpdateReadyKeyTime(data);
00171         break;
00172 
00173     case KSM_STATE_ACTIVE:
00174         KsmUpdateActiveKeyTime(data, collection, zone_id);
00175         break;
00176 
00177     case KSM_STATE_RETIRE:
00178         KsmUpdateRetireKeyTime(data, collection, zone_id);
00179         break;
00180 
00181     case KSM_STATE_DEAD:
00182         KsmUpdateDeadKeyTime(data);
00183         break;
00184 
00185     case KSM_STATE_DSSUB:
00186         /* Do nothing, wait for ds-seen before moving to DSPUBLISH */
00187         break;
00188 
00189     case KSM_STATE_DSPUBLISH:
00190         KsmUpdateDSPublishKeyTime(data, collection, zone_id);
00191         break;
00192 
00193     case KSM_STATE_DSREADY:
00194         /* Do nothing, hold the standby key in this state */
00195         break;
00196 
00197     case KSM_STATE_KEYPUBLISH:
00198         KsmUpdateKEYPublishKeyTime(data, collection, zone_id);
00199         break;
00200     default:
00201 
00202         /* Should not have a key in an unknown state */
00203 
00204         MsgLog(KME_UNRKEYSTA, (int) data->keypair_id, data->state);
00205     }
00206 
00207     return;
00208 }
00209 
00210 
00211 /*+
00212  * KsmUpdateXxxxKeyTime - Update Key Time for Key In Xxxx State
00213  *
00214  * Description:
00215  *      Handles the update of a key in the specified state.
00216  *
00217  * Arguments:id
00218  *      KSM_KEYDATA* data
00219  *          Key to update.
00220  *
00221 -*/
00222 
00223 void KsmUpdateGenerateKeyTime(KSM_KEYDATA* data)
00224 {
00225     /*
00226      * Keys in the generated state don't automatically change their state -
00227      * they wait until a request is made to publish them.
00228      */
00229 
00230     /* check the argument */
00231     if (data == NULL) {
00232         MsgLog(KSM_INVARG, "NULL data");
00233         return;
00234     }
00235     DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'generate' - not updated\n",
00236         (int) data->keypair_id);
00237 
00238     return;
00239 }
00240 
00241 void KsmUpdatePublishKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
00242 {
00243     int deltat = 0;  /* Time interval */
00244     int Ipc;     /* Child zone publication interval */
00245 
00246     /* check the argument */
00247     if (data == NULL || collection == NULL) {
00248         MsgLog(KSM_INVARG, "NULL argument");
00249         return;
00250     }
00251     DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'publish' - updating\n",
00252         (int) data->keypair_id);
00253 
00254     Ipc = collection->zskttl +
00255             collection->propdelay + collection->pub_safety;
00256     if (data->keytype == KSM_TYPE_ZSK) {
00257     /*
00258      * A key in the "publish" state moves into the "ready" state when it has
00259      * been published for at least:
00260      *
00261      *      Ipc = TTLkeyc + Dpc +Sp
00262      *
00263      * ... where:
00264      *
00265      *      TTLkeyc  = TTL of the ZSK DNSKEY record
00266      *      Dpc      = Propagation delay
00267      *      Sp       = Publish Safety Margin
00268      *
00269      */
00270 
00271         deltat = Ipc;
00272     }
00273     else if (data->keytype == KSM_TYPE_KSK) {
00274     /*
00275      * A key in the "publish" state moves into the "ready" state when it has
00276      * been published for either:
00277      *
00278      *      Ipc or Ipp, depending on the rollover scheme
00279      *  where
00280      *      Ipp = TTLdsp + Dpp + Dr +Sp
00281      *
00282      * ... where:
00283      *
00284      *      TTLdsp  = TTL of the DS record in the parent
00285      *      Dpp     = Propagation delay
00286      *      Dr      = Registration delay (Currently unused)
00287      *      Sp      = Publish Safety Margin
00288      *
00289      */
00290         if (collection->kskroll == KSM_ROLL_DNSKEY) {
00291             deltat = Ipc;
00292         }
00293         else if (collection->kskroll == KSM_ROLL_DS) {
00294             deltat = collection->kskttl + collection->kskpropdelay + 
00295                 collection->pub_safety; /* Ipp */
00296         }
00297     }
00298     else {
00299         return;
00300     }
00301 
00302     (void) KsmUpdateKeyTime(data, "PUBLISH", "READY", deltat, zone_id);
00303 
00304     return;
00305 }
00306 
00307 void KsmUpdateReadyKeyTime(KSM_KEYDATA* data)
00308 {
00309     /*
00310      * Keys in the ready state don't automatically move into the active state.
00311      * They need to be explicitly activated.
00312      */
00313 
00314     /* check the argument */
00315     if (data == NULL) {
00316         MsgLog(KSM_INVARG, "NULL data");
00317         return;
00318     }
00319     DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'ready' - not updated\n",
00320         (int) data->keypair_id);
00321 
00322     return;
00323 }
00324 
00325 void KsmUpdateActiveKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
00326 {
00327     int deltat;     /* Time interval */
00328 
00329     /* check the argument */
00330     if (data == NULL || collection == NULL) {
00331         MsgLog(KSM_INVARG, "NULL argument");
00332         return;
00333     }
00334     DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'active' - updating\n",
00335         (int) data->keypair_id);
00336 
00337     /*
00338      * A key in the "active" state moves into the "retire" state when it has
00339      * been active for at least:
00340      *
00341      *          Lz
00342      *
00343      * ... where
00344      *
00345      *      Lz = Life time of a ZSK (i.e. how long it is used for)
00346      */
00347 
00348     if (data->keytype == KSM_TYPE_ZSK) {
00349         deltat = collection->zsklife;
00350     }
00351     else if (data->keytype == KSM_TYPE_KSK) {
00352         deltat = collection->ksklife;
00353     }
00354     else {
00355         return;
00356     }
00357 
00358     /* "Infinite" lifetime */
00359     if (deltat == 0) {
00360         deltat = INT_MAX -1;
00361     }
00362 
00363     /* 
00364      * Update the retire time if the key is not marked as fixedDate.
00365      * If we asked for a rollover, but no keys were ready then a compromised key
00366      * may still be active.
00367      */
00368     if (!data->fixedDate) {
00369         (void) KsmUpdateKeyTime(data, "ACTIVE", "RETIRE", deltat, zone_id);
00370     }
00371 
00372     return;
00373 }
00374 
00375 void KsmUpdateRetireKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
00376 {
00377     int deltat = 0;     /* Time interval */
00378 
00379     /* check the argument */
00380     if (data == NULL || collection == NULL) {
00381         MsgLog(KSM_INVARG, "NULL argument");
00382         return;
00383     }
00384     DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'retire' - updating\n",
00385         (int) data->keypair_id);
00386 
00387     /*
00388      * A key in the "retire" state moves into the "dead" state after a period
00389      * of:
00390      *
00391      *          TTLsig + Dp + St
00392      *
00393      * ... where
00394      *
00395      *      TTLsig  = Signature lifetime (how long a signature is valid for)
00396      *      Dp      = Propagation delay
00397      *      St      = Retire safety margin
00398      */
00399 
00400     if (data->keytype == KSM_TYPE_ZSK) {
00401         deltat = collection->zsksiglife + collection->propdelay + collection->ret_safety;
00402     }
00403     else if (data->keytype == KSM_TYPE_KSK) {
00404         /* 
00405          * for a KSK this can be 0 (from the timings draft); are we happy with that? 
00406          * Might revisit this in the future as it might be a surprise for people
00407          *
00408          * Change of heart... make this as large as we can so that keys stay retired
00409          * until some manual process tells us that its DS record has been removed.
00410          * 
00411          * second change of heart:
00412          * Don't do anything here, this time is set when the ksk-roll command is issued.
00413          *
00414          * Third change
00415          */
00416         deltat = collection->dsttl + collection->kskpropdelay + 
00417             collection->ret_safety; /* Ipp */
00418     }
00419     else {
00420         return;
00421     }
00422 
00423     (void) KsmUpdateKeyTime(data, "RETIRE", "DEAD", deltat, zone_id);
00424 
00425     return;
00426 }
00427 
00428 void KsmUpdateDeadKeyTime(KSM_KEYDATA* data)
00429 {
00430     /*
00431      * Keys in the dead state don't automatically change their state - they
00432      * are retained in the database for historical reasons or until they are
00433      * explicitly deleted.
00434      */
00435 
00436     /* check the argument */
00437     if (data == NULL) {
00438         MsgLog(KSM_INVARG, "NULL data");
00439         return;
00440     }
00441     DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'dead' - not updated\n",
00442         (int) data->keypair_id);
00443 
00444     return;
00445 }
00446 
00447 void KsmUpdateDSPublishKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
00448 {
00449     int deltat = 0;  /* Time interval */
00450 
00451     /* check the argument */
00452     if (data == NULL || collection == NULL) {
00453         MsgLog(KSM_INVARG, "NULL argument");
00454         return;
00455     }
00456     DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'publish' - updating\n",
00457         (int) data->keypair_id);
00458 
00459     if (data->keytype == KSM_TYPE_ZSK) {
00460         /*
00461          * This state should only be used by KSKs
00462          */
00463 
00464         return;
00465     }
00466     else if (data->keytype == KSM_TYPE_KSK) {
00467     /*
00468      * A key in the "dspublish" state moves into the "dsready" state when it has
00469      * been published for either:
00470      *
00471      *      Ipp = TTLdsp + Dpp + Dr +Sp
00472      *
00473      * ... where:
00474      *
00475      *      TTLdsp  = TTL of the DS record in the parent
00476      *      Dpp     = Propagation delay
00477      *      Dr      = Registration delay (Currently unused)
00478      *      Sp      = Publish Safety Margin
00479      *
00480      */
00481         deltat = collection->kskttl + collection->kskpropdelay + 
00482             collection->pub_safety;
00483     }
00484     else {
00485         return;
00486     }
00487 
00488     (void) KsmUpdateKeyTime(data, "PUBLISH", "READY", deltat, zone_id);
00489 
00490     return;
00491 }
00492 
00493 void KsmUpdateKEYPublishKeyTime(KSM_KEYDATA* data, KSM_PARCOLL* collection, int zone_id)
00494 {
00495     int deltat = 0;  /* Time interval */
00496 
00497     /* check the argument */
00498     if (data == NULL || collection == NULL) {
00499         MsgLog(KSM_INVARG, "NULL argument");
00500         return;
00501     }
00502     DbgOutput(DBG_M_UPDATE, "Key ID %d in state 'KEYpublish' - updating\n",
00503         (int) data->keypair_id);
00504 
00505     /*
00506      * A key in the "KEYpublish" state moves into the "active" state when it has
00507      * been published for at least:
00508      *
00509      *      Ipc = TTLkeyc + Dpc +Sp
00510      *
00511      * ... where:
00512      *
00513      *      TTLkeyc  = TTL of the ZSK DNSKEY record
00514      *      Dpc      = Propagation delay
00515      *      Sp       = Publish Safety Margin
00516      *
00517      */
00518     deltat = collection->zskttl +
00519             collection->propdelay + collection->pub_safety;
00520 
00521     (void) KsmUpdateKeyTime(data, "PUBLISH", "ACTIVE", deltat, zone_id);
00522 
00523     return;
00524 }
00525 
00526 /*+
00527  * KsmUpdateKeyTime - Update Key Time
00528  *
00529  * Description:
00530  *      Actually performs the update of the database.  The update is
00531  *      
00532  *          destination_time = source_time + interval
00533  *
00534  * Arguments:
00535  *      const KSM_KEYDATA* data
00536  *          Data about the key to be updated.  Note that this is NOT updated
00537  *          by the update.
00538  *
00539  *      const char* source
00540  *          Source field.
00541  *
00542  *      const char* destination
00543  *          Source field.
00544  *
00545  *      int interval
00546  *          Interval (seconds) to update the source field with.
00547  *
00548  *      int zone_id
00549  *          zone we are looking at
00550  *
00551  * Returns:
00552  *      int
00553  *          0       Update successful
00554  *          Other   Error.  A message will have beeen output.
00555 -*/
00556 
00557 int KsmUpdateKeyTime(const KSM_KEYDATA* data, const char* source,
00558     const char* destination, int interval, int zone_id)
00559 {
00560     char            buffer[KSM_SQL_SIZE];    /* Long enough for any statement */
00561     unsigned int    nchar;          /* Number of characters converted */
00562     int             status;         /* Status return */
00563 
00564     /* check the argument */
00565     if (data == NULL || source == NULL || destination == NULL) {
00566         return MsgLog(KSM_INVARG, "NULL argument");
00567     }
00568 
00569 #ifdef USE_MYSQL
00570     nchar = snprintf(buffer, sizeof(buffer),
00571         "UPDATE dnsseckeys SET %s = DATE_ADD(%s, INTERVAL %d SECOND) WHERE KEYPAIR_ID = %lu and zone_id = %d",
00572         destination, source, interval, (unsigned long) data->keypair_id, zone_id);
00573 #else
00574     nchar = snprintf(buffer, sizeof(buffer),
00575         "UPDATE dnsseckeys SET %s = DATETIME(%s, '+%d SECONDS') WHERE KEYPAIR_ID = %lu and zone_id = %d",
00576         destination, source, interval, (unsigned long) data->keypair_id, zone_id);
00577 #endif /* USE_MYSQL */
00578 
00579     if (nchar < sizeof(buffer)) {
00580 
00581         /* All OK, execute the statement */
00582 
00583         status = DbExecuteSqlNoResult(DbHandle(), buffer);
00584     }
00585     else {
00586 
00587         /* Unable to create update statement */
00588 
00589         status = MsgLog(KME_BUFFEROVF, "KsmUpdateKeyTime");
00590     }
00591 
00592     return status;
00593 }