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