--- opendnssec-1.1.1-policy_prune/enforcer/ksm/include/ksm/ksm.h 2010-07-14 14:58:08.000000000 +0200 +++ opendnssec-1.1.1-policy_prune-keybackup_2phase/enforcer/ksm/include/ksm/ksm.h 2010-07-15 16:45:33.000000000 +0200 @@ -380,6 +380,8 @@ #define KSM_STATE_DSREADY_STRING "dsready" #define KSM_STATE_KEYPUBLISH 10 #define KSM_STATE_KEYPUBLISH_STRING "keypublish" +#define KSM_STATE_BACKUPPREP 11 +#define KSM_STATE_BACKUPPREP_STRING "backupprep" #define KSM_SERIAL_UNIX_STRING "unixtime" #define KSM_SERIAL_UNIX 1 @@ -617,6 +619,9 @@ int KsmSerialIdFromName(const char* name, int *id); int KsmPolicyIdFromName(const char* name, int *id); int KsmMarkBackup(int repo_id, const char* datetime); +int KsmPrepareBackup(int repo_id, const char* datetime); +int KsmCommitBackup(int repo_id, const char* datetime); +int KsmRollbackBackup(int repo_id, const char* datetime); int KsmCheckHSMkeyID(int repo_id, const char* cka_id, int *exists); /* KsmList */ diff -Nur opendnssec-1.1.1-policy_prune/enforcer/ksm/ksm_import.c opendnssec-1.1.1-policy_prune-keybackup_2phase/enforcer/ksm/ksm_import.c --- opendnssec-1.1.1-policy_prune/enforcer/ksm/ksm_import.c 2010-07-14 14:58:08.000000000 +0200 +++ opendnssec-1.1.1-policy_prune-keybackup_2phase/enforcer/ksm/ksm_import.c 2010-07-15 16:54:44.000000000 +0200 @@ -478,6 +478,124 @@ } /*+ + * KsmPrepareBackup - Prepare a backup for two-phase backup + * + * + * Arguments: + * + * int repo_id + * ID of the repository (-1 for all) + * + * const char* datetime + * When the backup was done + * + * Returns: + * int + * Status return. 0 on success. + * other on fail + */ + +int KsmPrepareBackup(int repo_id, const char* datetime) +{ + char* sql = NULL; /* SQL query */ + int status = 0; /* Status return */ + + /* Update rows */ + sql = DusInit("keypairs"); + DusSetInt(&sql, "STATE", KSM_STATE_BACKUPPREP, 0); + DusConditionInt(&sql, "state", DQS_COMPARE_EQ, KSM_STATE_GENERATE, 0); + if (repo_id != -1) { + DusConditionInt(&sql, "securitymodule_id", DQS_COMPARE_EQ, repo_id, 1); + } + StrAppend(&sql, " and backup is null"); + DusEnd(&sql); + + status = DbExecuteSqlNoResult(DbHandle(), sql); + DusFree(sql); + + return status; +} + +/*+ + * KsmCommitBackup - Finish a 2-phase backup successfuly + * + * + * Arguments: + * + * int repo_id + * ID of the repository (-1 for all) + * + * const char* datetime + * When the backup was done + * + * Returns: + * int + * Status return. 0 on success. + * other on fail + */ + +int KsmCommitBackup(int repo_id, const char* datetime) +{ + char* sql = NULL; /* SQL query */ + int status = 0; /* Status return */ + + /* Update rows */ + sql = DusInit("keypairs"); + DusSetInt(&sql, "STATE", KSM_STATE_GENERATE, 0); + DusSetString(&sql, "BACKUP", datetime, 1); + DusConditionInt(&sql, "state", DQS_COMPARE_EQ, KSM_STATE_BACKUPPREP, 0); + if (repo_id != -1) { + DusConditionInt(&sql, "securitymodule_id", DQS_COMPARE_EQ, repo_id, 1); + } + StrAppend(&sql, " and backup is null"); + DusEnd(&sql); + + status = DbExecuteSqlNoResult(DbHandle(), sql); + DusFree(sql); + + return status; +} + +/*+ + * KsmRollbackBackup - Terminate a 2-phase backup by undoing it + * + * + * Arguments: + * + * int repo_id + * ID of the repository (-1 for all) + * + * const char* datetime + * When the backup was done + * + * Returns: + * int + * Status return. 0 on success. + * other on fail + */ + +int KsmRollbackBackup(int repo_id, const char* datetime) +{ + char* sql = NULL; /* SQL query */ + int status = 0; /* Status return */ + + /* Update rows */ + sql = DusInit("keypairs"); + DusSetInt(&sql, "STATE", KSM_STATE_GENERATE, 0); + DusConditionInt(&sql, "state", DQS_COMPARE_EQ, KSM_STATE_BACKUPPREP, 0); + if (repo_id != -1) { + DusConditionInt(&sql, "securitymodule_id", DQS_COMPARE_EQ, repo_id, 1); + } + StrAppend(&sql, " and backup is null"); + DusEnd(&sql); + + status = DbExecuteSqlNoResult(DbHandle(), sql); + DusFree(sql); + + return status; +} + +/*+ * KsmMarkBackup - Mark a backup as having been done * * diff -Nur opendnssec-1.1.1-policy_prune/enforcer/utils/ksmutil.c opendnssec-1.1.1-policy_prune-keybackup_2phase/enforcer/utils/ksmutil.c --- opendnssec-1.1.1-policy_prune/enforcer/utils/ksmutil.c 2010-07-15 13:34:31.000000000 +0200 +++ opendnssec-1.1.1-policy_prune-keybackup_2phase/enforcer/utils/ksmutil.c 2010-07-19 13:03:42.000000000 +0200 @@ -317,9 +317,15 @@ usage_backup () { fprintf(stderr, - " backup done\n" + " backup prepare\n" + "\t--repository aka -r\n" + " backup commit\n" + "\t--repository aka -r\n" + " backup rollback\n" "\t--repository aka -r\n" " backup list\n" + "\t--repository aka -r\n" + " backup done\n" "\t--repository aka -r\n"); } @@ -1758,62 +1764,49 @@ } /* - * note that fact that a backup has been performed + * List rollovers */ int -cmd_backup () +cmd_listrolls () { int status = 0; - int repo_id = -1; + int qualifier_id = -1; /* ID of qualifer (if given) */ /* Database connection details */ DB_HANDLE dbhandle; FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ - char* datetime = DtParseDateTimeString("now"); - - /* Check datetime in case it came back NULL */ - if (datetime == NULL) { - printf("Couldn't turn \"now\" into a date, quitting...\n"); - exit(1); - } - /* try to connect to the database */ status = db_connect(&dbhandle, &lock_fd, 1); if (status != 0) { printf("Failed to connect to database\n"); db_disconnect(lock_fd); - StrFree(datetime); return(1); } - /* Turn repo name into an id (if provided) */ - if (o_repository != NULL) { - status = KsmSmIdFromName(o_repository, &repo_id); + /* Turn zone name into an id (if provided) */ + if (o_zone != NULL) { + status = KsmZoneIdFromName(o_zone, &qualifier_id); if (status != 0) { - printf("Error: unable to find a repository named \"%s\" in database\n", o_repository); + printf("Error: unable to find a zone named \"%s\" in database\n", o_zone); db_disconnect(lock_fd); - StrFree(datetime); return status; } } - status = KsmMarkBackup(repo_id, datetime); + printf("Rollovers:\n"); + + status = KsmListRollovers(qualifier_id); + if (status != 0) { - printf("Error: failed to mark backup as done\n"); + printf("Error: failed to list rollovers\n"); db_disconnect(lock_fd); - StrFree(datetime); return status; } - if (o_repository != NULL) { - printf("Marked repository %s as backed up at %s\n", o_repository, datetime); - } else { - printf("Marked all repositories as backed up at %s\n", datetime); - } + printf("\n"); - StrFree(datetime); /* Release sqlite lock file (if we have it) */ db_disconnect(lock_fd); @@ -1822,10 +1815,10 @@ } /* - * List rollovers + * List backups */ int -cmd_listrolls () +cmd_listbackups () { int status = 0; @@ -1836,33 +1829,31 @@ FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ /* try to connect to the database */ - status = db_connect(&dbhandle, &lock_fd, 1); + status = db_connect(&dbhandle, &lock_fd, 0); if (status != 0) { printf("Failed to connect to database\n"); db_disconnect(lock_fd); return(1); } - /* Turn zone name into an id (if provided) */ - if (o_zone != NULL) { - status = KsmZoneIdFromName(o_zone, &qualifier_id); + /* Turn repo name into an id (if provided) */ + if (o_repository != NULL) { + status = KsmSmIdFromName(o_repository, &qualifier_id); if (status != 0) { - printf("Error: unable to find a zone named \"%s\" in database\n", o_zone); + printf("Error: unable to find a repository named \"%s\" in database\n", o_repository); db_disconnect(lock_fd); return status; } } - printf("Rollovers:\n"); - - status = KsmListRollovers(qualifier_id); + printf("Backups:\n"); + status = KsmListBackups(qualifier_id); if (status != 0) { - printf("Error: failed to list rollovers\n"); + printf("Error: failed to list backups\n"); db_disconnect(lock_fd); return status; } - printf("\n"); /* Release sqlite lock file (if we have it) */ @@ -1873,47 +1864,91 @@ } /* - * List backups + * note that fact that a backup has been performed */ int -cmd_listbackups () +cmd_backup (char *case_verb) { int status = 0; - int qualifier_id = -1; /* ID of qualifer (if given) */ + int repo_id = -1; /* Database connection details */ DB_HANDLE dbhandle; FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */ + char* datetime = DtParseDateTimeString("now"); + + /* Check datetime in case it came back NULL */ + if (datetime == NULL) { + printf("Couldn't turn \"now\" into a date, quitting...\n"); + exit(1); + } + /* try to connect to the database */ - status = db_connect(&dbhandle, &lock_fd, 0); + status = db_connect(&dbhandle, &lock_fd, 1); if (status != 0) { printf("Failed to connect to database\n"); db_disconnect(lock_fd); + StrFree(datetime); return(1); } /* Turn repo name into an id (if provided) */ if (o_repository != NULL) { - status = KsmSmIdFromName(o_repository, &qualifier_id); + status = KsmSmIdFromName(o_repository, &repo_id); if (status != 0) { printf("Error: unable to find a repository named \"%s\" in database\n", o_repository); db_disconnect(lock_fd); + StrFree(datetime); return status; } } - printf("Backups:\n"); - status = KsmListBackups(qualifier_id); + if (!strncmp(case_verb, "DONE", 4)) { + status = KsmMarkBackup(repo_id, datetime); + if (o_repository != NULL) { + printf("Marked repository %s as backed up at %s\n", o_repository, datetime); + } else { + printf("Marked all repositories as backed up at %s\n", datetime); + } + } else if (!strncmp(case_verb, "PREPARE", 7)) { + status = KsmPrepareBackup(repo_id, datetime); + if (o_repository != NULL) { + printf("Prepared new keys in repository %s for backup at %s\n", o_repository, datetime); + } else { + printf("Prepared new keys in all repositories for backup at %s\n", datetime); + } + } else if (!strncmp(case_verb, "COMMIT", 6)) { + status = KsmCommitBackup(repo_id, datetime); + if (o_repository != NULL) { + printf("Marked all prepared keys in repository %s as backed up at %s\n", o_repository, datetime); + } else { + printf("Marked all prepared keys in all repositories as backed up at %s\n", datetime); + } + } else if (!strncmp(case_verb, "ROLLBACK", 8)) { + status = KsmRollbackBackup(repo_id, datetime); + if (o_repository != NULL) { + printf("Rolled back preparation of keys for backup in repository %s at %s\n", o_repository, datetime); + } else { + printf("Rolled back preparation of keys for backup in all repositories at %s\n", datetime); + } + } else if (!strncmp(case_verb, "LIST", 4)) { + status = cmd_listbackups(); + } else { + printf("Unknown command: backup %s\n", case_verb); + usage_backup(); + status = -1; + } if (status != 0) { - printf("Error: failed to list backups\n"); + printf("Error: failed to execute backup subcommand\n"); db_disconnect(lock_fd); + StrFree(datetime); return status; } - printf("\n"); + StrFree(datetime); /* Release sqlite lock file (if we have it) */ db_disconnect(lock_fd); @@ -3082,17 +3117,8 @@ } else if (!strncmp(case_command, "BACKUP", 6)) { argc --; argc --; argv ++; argv ++; - /* verb should be done or list */ - if (!strncmp(case_verb, "DONE", 4)) { - result = cmd_backup(); - } - else if (!strncmp(case_verb, "LIST", 4)) { - result = cmd_listbackups(); - } else { - printf("Unknown command: backup %s\n", case_verb); - usage_backup(); - result = -1; - } + /* verb is further split in cmd_backup() */ + result = cmd_backup(case_verb); } else if (!strncmp(case_command, "ROLLOVER", 8)) { argc --; argc --; argv ++; argv ++; diff -Nur opendnssec-1.1.1-policy_prune/enforcer/utils/ods-ksmutil.1 opendnssec-1.1.1-policy_prune-keybackup_2phase/enforcer/utils/ods-ksmutil.1 --- opendnssec-1.1.1-policy_prune/enforcer/utils/ods-ksmutil.1 2010-07-15 15:22:12.000000000 +0200 +++ opendnssec-1.1.1-policy_prune-keybackup_2phase/enforcer/utils/ods-ksmutil.1 2010-07-19 13:24:57.000000000 +0200 @@ -25,7 +25,7 @@ .B ods-ksmutil repository list .RB ... .br -.B ods-ksmutil backup list|done +.B ods-ksmutil backup list|prepare|commit|rollback|done .br .B ods-ksmutil database backup .RB ... @@ -253,19 +253,42 @@ List the backups that have been made on the given repository. The \-\-repository option specifies what repository to list. .TP +.B backup prepare \-\-repository|\-r name +Start a two-phase key backup procedure. +Prepare the keys generated up to here for backup. Any keys generated +automatically by OpenDNSSEC after this command are not guaranteed to be +backed up, and will therefore not be taken into account when committing +the prepared keys for use by OpenDNSSEC. The next command is usually +either \fBbackup commit\fR or, in case of failure of the key backup +itself, \fBbackup rollback\fR. This sequence works reliably if the +KASP Enforcer is running. If it is not, the single-phase backup of +\fBbackup done\fR provides a one-phase backup alternative. +.TP +.B backup commit \-\-repository|\-r name +Successfully end a two-phase key backup procedure. +After a key backup has succeeded, release all previously prepared keys +for service by OpenDNSSEC. Any keys that were generated since the last +issued preparation will not be released as it is uncertain whether these +are actually backed up. +.TP +.B backup rollback \-\-repository|\-r name +Safely end a failed two-phase key backup procedure. +After a key backup has failed, rollback all previously prepapared keys +to the state where they are generated, but not yet available for service +by OpenDNSSEC. After fixing this problem, a new attempt to backup the +keys can be made. +.TP .B backup done \-\-repository|\-r name Indicate that a backup of the given repository has been done, all non-backed up keys will now be marked as backed up. The \-\-repository option specifies what repository to list. This is a necessary step for repositories that have the RequireBackup flag set. Note that the KASP Enforcer may take the initiative to generate keys after -the backup has started and before the backup is done. In the current version -of OpenDNSSEC, it is therefore needed to stop the KASP Enforcer to be assured -that all keys are backed up. The sequence would therefore be -.LI Issue \fBods-control ksm stop\fR -.LI Make a backup of the repository -.LI Issue \fBods-ksmutil backup done\fR -.LI Issue \fBods-control ksm start\fR +the backup has started and before the backup is done. This single-phase +backup command waives that, which is safe when the KASP Enforcer is not +running. If you intend to keep the Enforcer running, you will instead +want to use the two-phase \fBbackup prepare\fR followed by either +\fBbackup commit\fR or \fBbackup rollback\fR. .TP .B database backup [\-\-output|\-o output] Make a copy of the database of the KASP Enforcer (if using sqlite).