# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <dirent.h>
# include <assert.h>
# include <unistd.h>
# include <ctype.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
# include "config_zkt.h"
#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
# include <getopt.h>
#endif
# include "debug.h"
# include "misc.h"
# include "strlist.h"
# include "zconf.h"
# include "dki.h"
# include "zkt.h"
extern int optopt;
extern int opterr;
extern int optind;
extern char *optarg;
const char *progname;
char *labellist = NULL;
int headerflag = 1;
int ageflag = 0;
int lifetime = 0;
int lifetimeflag = 0;
int timeflag = 1;
int exptimeflag = 0;
int pathflag = 0;
int kskflag = 1;
int zskflag = 1;
int ljustflag = 0;
static int dirflag = 0;
static int recflag = RECURSIVE;
static int trustedkeyflag = 0;
static char *kskdomain = "";
static const char *view = "";
# define short_options ":0:1:2:3:9A:C:D:P:S:R:HKTs:ZV:afF:c:O:dhkLl:prtez"
#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
static struct option long_options[] = {
{"ksk-rollover", no_argument, NULL, '9'},
{"ksk-status", required_argument, NULL, '0'},
{"ksk-roll-status", required_argument, NULL, '0'},
{"ksk-newkey", required_argument, NULL, '1'},
{"ksk-publish", required_argument, NULL, '2'},
{"ksk-delkey", required_argument, NULL, '3'},
{"ksk-roll-phase1", required_argument, NULL, '1'},
{"ksk-roll-phase2", required_argument, NULL, '2'},
{"ksk-roll-phase3", required_argument, NULL, '3'},
{"list-dnskeys", no_argument, NULL, 'K'},
{"list-trustedkeys", no_argument, NULL, 'T'},
{"ksk", no_argument, NULL, 'k'},
{"zsk", no_argument, NULL, 'z'},
{"age", no_argument, NULL, 'a'},
{"lifetime", no_argument, NULL, 'f'},
{"time", no_argument, NULL, 't'},
{"expire", no_argument, NULL, 'e'},
{"recursive", no_argument, NULL, 'r'},
{"zone-config", no_argument, NULL, 'Z'},
{"leftjust", no_argument, NULL, 'L'},
{"path", no_argument, NULL, 'p'},
{"nohead", no_argument, NULL, 'h'},
{"directory", no_argument, NULL, 'd'},
{"config", required_argument, NULL, 'c'},
{"option", required_argument, NULL, 'O'},
{"config-option", required_argument, NULL, 'O'},
{"published", required_argument, NULL, 'P'},
{"standby", required_argument, NULL, 'S'},
{"active", required_argument, NULL, 'A'},
{"depreciated", required_argument, NULL, 'D'},
{"create", required_argument, NULL, 'C'},
{"revoke", required_argument, NULL, 'R'},
{"remove", required_argument, NULL, 19 },
{"destroy", required_argument, NULL, 20 },
{"setlifetime", required_argument, NULL, 'F' },
{"view", required_argument, NULL, 'V' },
{"help", no_argument, NULL, 'H'},
{0, 0, 0, 0}
};
#endif
static int parsedirectory (const char *dir, dki_t **listp);
static void parsefile (const char *file, dki_t **listp);
static void createkey (const char *keyname, const dki_t *list, const zconf_t *conf);
static void ksk_roll (const char *keyname, int phase, const dki_t *list, const zconf_t *conf);
static int create_parent_file (const char *fname, int phase, int ttl, const dki_t *dkp);
static void usage (char *mesg, zconf_t *cp);
static const char *parsetag (const char *str, int *tagp);
static void setglobalflags (zconf_t *config)
{
recflag = config->recursive;
ageflag = config->printage;
timeflag = config->printtime;
ljustflag = config->ljust;
}
int main (int argc, char *argv[])
{
dki_t *data = NULL;
dki_t *dkp;
int c;
int opt_index;
int action;
const char *file;
const char *defconfname = NULL;
char *p;
char str[254+1];
const char *keyname = NULL;
int searchtag;
zconf_t *config;
progname = *argv;
if ( (p = strrchr (progname, '/')) )
progname = ++p;
view = getnameappendix (progname, "dnssec-zkt");
defconfname = getdefconfname (view);
config = loadconfig ("", (zconf_t *)NULL);
if ( fileexist (defconfname) )
config = loadconfig (defconfname, config);
if ( config == NULL )
fatal ("Out of memory\n");
setglobalflags (config);
opterr = 0;
opt_index = 0;
action = 0;
#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
while ( (c = getopt_long (argc, argv, short_options, long_options, &opt_index)) != -1 )
#else
while ( (c = getopt (argc, argv, short_options)) != -1 )
#endif
{
switch ( c )
{
case '9':
ksk_roll ("help", c - '0', NULL, NULL);
exit (1);
case '1':
case '2':
case '3':
case '0':
action = c;
if ( !optarg )
usage ("ksk rollover requires an domain argument", config);
kskdomain = domain_canonicdup (optarg);
break;
case 'T':
trustedkeyflag = 1;
zskflag = pathflag = 0;
case 'H':
case 'K':
case 'Z':
action = c;
break;
case 'C':
pathflag = !pathflag;
case 'P':
case 'S':
case 'A':
case 'D':
case 'R':
case 's':
case 19:
case 20:
if ( (keyname = parsetag (optarg, &searchtag)) != NULL )
keyname = domain_canonicdup (keyname);
action = c;
break;
case 'a':
ageflag = !ageflag;
break;
case 'f':
lifetimeflag = !lifetimeflag;
break;
case 'F':
lifetime = atoi (optarg);
lifetimeflag = 1;
exptimeflag = 1;
timeflag = 1;
action = c;
break;
case 'V':
view = optarg;
defconfname = getdefconfname (view);
if ( fileexist (defconfname) )
config = loadconfig (defconfname, config);
if ( config == NULL )
fatal ("Out of memory\n");
setglobalflags (config);
break;
case 'c':
config = loadconfig (optarg, config);
setglobalflags (config);
checkconfig (config);
break;
case 'O':
config = loadconfig_fromstr (optarg, config);
setglobalflags (config);
checkconfig (config);
break;
case 'd':
dirflag = 1;
break;
case 'h':
headerflag = 0;
break;
case 'k':
zskflag = 0;
break;
case 'L':
ljustflag = !ljustflag;
break;
case 'l':
labellist = prepstrlist (optarg, LISTDELIM);
if ( labellist == NULL )
fatal ("Out of memory\n");
break;
case 'p':
pathflag = 1;
break;
case 'r':
recflag = !recflag;
break;
case 't':
timeflag = !timeflag;
break;
case 'e':
exptimeflag = !exptimeflag;
break;
case 'z':
kskflag = 0;
break;
case ':':
snprintf (str, sizeof(str), "option \"-%c\" requires an argument.\n",
optopt);
usage (str, config);
break;
case '?':
if ( isprint (optopt) )
snprintf (str, sizeof(str), "Unknown option \"-%c\".\n",
optopt);
else
snprintf (str, sizeof (str), "Unknown option char \\x%x.\n",
optopt);
usage (str, config);
break;
default:
abort();
}
}
if ( action == 'Z' )
{
fprintf (stderr, "The use of -Z is deprecated. Please use zkt-conf instead\n");
printconfig ("stdout", config);
return 0;
}
if ( kskflag == 0 && zskflag == 0 )
kskflag = zskflag = 1;
c = optind;
do {
if ( c >= argc )
file = config->zonedir;
else
file = argv[c++];
if ( is_directory (file) )
parsedirectory (file, &data);
else
parsefile (file, &data);
} while ( c < argc );
switch ( action )
{
case 'H':
usage ("", config);
case 'C':
createkey (keyname, data, config);
break;
case 'P':
case 'S':
case 'A':
case 'D':
if ( (dkp = (dki_t*)zkt_search (data, searchtag, keyname)) == NULL )
fatal ("Key with tag %u not found\n", searchtag);
else if ( dkp == (void *) 01 )
fatal ("Key with tag %u found multiple times\n", searchtag);
if ( (c = dki_setstatus_preservetime (dkp, action)) != 0 )
fatal ("Couldn't change status of key %u: %d\n", searchtag, c);
break;
case 19:
if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL )
fatal ("Key with tag %u not found\n", searchtag);
else if ( dkp == (void *) 01 )
fatal ("Key with tag %u found multiple times\n", searchtag);
dki_remove (dkp);
break;
case 20:
if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL )
fatal ("Key with tag %u not found\n", searchtag);
else if ( dkp == (void *) 01 )
fatal ("Key with tag %u found multiple times\n", searchtag);
dki_destroy (dkp);
break;
case 'R':
if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL )
fatal ("Key with tag %u not found\n", searchtag);
else if ( dkp == (void *) 01 )
fatal ("Key with tag %u found multiple times\n", searchtag);
if ( (c = dki_setstatus (dkp, action)) != 0 )
fatal ("Couldn't change status of key %u: %d\n", searchtag, c);
break;
case 's':
if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL )
fatal ("Key with tag %u not found\n", searchtag);
else if ( dkp == (void *) 01 )
fatal ("Key with tag %u found multiple times\n", searchtag);
dki_prt_dnskey (dkp, stdout);
break;
case 'K':
zkt_list_dnskeys (data);
break;
case 'T':
zkt_list_trustedkeys (data);
break;
case '1':
case '2':
case '3':
case '0':
ksk_roll (kskdomain, action - '0', data, config);
break;
case 'F':
zkt_setkeylifetime (data);
default:
zkt_list_keys (data);
}
return 0;
}
# define sopt_usage(mesg, value) fprintf (stderr, mesg, value)
#if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
# define lopt_usage(mesg, value) fprintf (stderr, mesg, value)
# define loptstr(lstr, sstr) lstr
#else
# define lopt_usage(mesg, value)
# define loptstr(lstr, sstr) sstr
#endif
static void usage (char *mesg, zconf_t *cp)
{
fprintf (stderr, "Secure DNS Zone Key Tool %s\n", ZKT_VERSION);
fprintf (stderr, "\n");
fprintf (stderr, "Show zone config parameter as %s file\n", LOCALCONF_FILE);
sopt_usage ("\tusage: %s -Z\n", progname);
lopt_usage ("\tusage: %s --zone-config\n", progname);
fprintf (stderr, "\n");
fprintf (stderr, "List keys in current or given directory (-r for recursive mode)\n");
sopt_usage ("\tusage: %s [-dhatkzpr] [-c config] [file|dir ...]\n", progname);
fprintf (stderr, "\n");
fprintf (stderr, "List public part of keys in DNSKEY RR format\n");
sopt_usage ("\tusage: %s -K [-dhkzr] [-c config] [file|dir ...]\n", progname);
lopt_usage ("\tusage: %s --list-dnskeys [-dhkzr] [-c config] [file|dir ...]\n", progname);
fprintf (stderr, "\n");
fprintf (stderr, "List keys (output is suitable for trusted-keys section)\n");
sopt_usage ("\tusage: %s -T [-dhzr] [-c config] [file|dir ...]\n", progname);
lopt_usage ("\tusage: %s --list-trustedkeys [-dhzr] [-c config] [file|dir ...]\n", progname);
fprintf (stderr, "\n");
fprintf (stderr, "Create a new key \n");
sopt_usage ("\tusage: %s -C <name> [-k] [-dpr] [-c config] [dir ...]\n", progname);
lopt_usage ("\tusage: %s --create=<name> [-k] [-dpr] [-c config] [dir ...]\n", progname);
fprintf (stderr, "\t\tKSK (use -k): %s %d bits\n", dki_algo2str (cp->k_algo), cp->k_bits);
fprintf (stderr, "\t\tZSK (default): %s %d bits\n", dki_algo2str (cp->k_algo), cp->z_bits);
fprintf (stderr, "\n");
fprintf (stderr, "Change key status of specified key to published, active or depreciated\n");
fprintf (stderr, "\t(<keyspec> := tag | tag:name) \n");
sopt_usage ("\tusage: %s -P|-A|-D <keyspec> [-dr] [-c config] [dir ...]\n", progname);
lopt_usage ("\tusage: %s --published=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
lopt_usage ("\tusage: %s --active=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
lopt_usage ("\tusage: %s --depreciated=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
fprintf (stderr, "\n");
fprintf (stderr, "Revoke specified key (<keyspec> := tag | tag:name) \n");
sopt_usage ("\tusage: %s -R <keyspec> [-dr] [-c config] [dir ...]\n", progname);
lopt_usage ("\tusage: %s --revoke=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
fprintf (stderr, "\n");
fprintf (stderr, "Remove (rename) or destroy (delete) specified key (<keyspec> := tag | tag:name) \n");
lopt_usage ("\tusage: %s --remove=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
lopt_usage ("\tusage: %s --destroy=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
fprintf (stderr, "\n");
fprintf (stderr, "Initiate a semi-automated KSK rollover");
fprintf (stderr, "('%s -9%s' prints out a short description)\n", progname, loptstr ("|--ksk-rollover", ""));
sopt_usage ("\tusage: %s {-1} do.ma.in.\n", progname);
lopt_usage ("\tusage: %s {--ksk-roll-phase1|--ksk-newkey} do.ma.in.\n", progname);
sopt_usage ("\tusage: %s {-2} do.ma.in.\n", progname);
lopt_usage ("\tusage: %s {--ksk-roll-phase2|--ksk-publish} do.ma.in.\n", progname);
sopt_usage ("\tusage: %s {-3} do.ma.in.\n", progname);
lopt_usage ("\tusage: %s {--ksk-roll-phase3|--ksk-delkey} do.ma.in.\n", progname);
sopt_usage ("\tusage: %s {-0} do.ma.in.\n", progname);
lopt_usage ("\tusage: %s {--ksk-roll-status|--ksk-status} do.ma.in.\n", progname);
fprintf (stderr, "\n");
fprintf (stderr, "\n");
fprintf (stderr, "General options \n");
fprintf (stderr, "\t-c file%s", loptstr (", --config=file\n", ""));
fprintf (stderr, "\t\t read config from <file> instead of %s\n", CONFIG_FILE);
fprintf (stderr, "\t-O optstr%s", loptstr (", --config-option=\"optstr\"\n", ""));
fprintf (stderr, "\t\t read config options from commandline\n");
fprintf (stderr, "\t-h%s\t no headline or trusted-key section header/trailer in -T mode\n", loptstr (", --nohead", "\t"));
fprintf (stderr, "\t-d%s\t skip directory arguments\n", loptstr (", --directory", "\t"));
fprintf (stderr, "\t-L%s\t print the domain name left justified (default: %s)\n", loptstr (", --leftjust", "\t"), ljustflag ? "on": "off");
fprintf (stderr, "\t-l list\t\t print out only zone keys out of the given domain list\n");
fprintf (stderr, "\t-p%s\t show path of keyfile / create key in current directory\n", loptstr (", --path", "\t"));
fprintf (stderr, "\t-r%s\t recursive mode on/off (default: %s)\n", loptstr(", --recursive", "\t"), recflag ? "on": "off");
fprintf (stderr, "\t-a%s\t print age of key (default: %s)\n", loptstr (", --age", "\t"), ageflag ? "on": "off");
fprintf (stderr, "\t-t%s\t print key generation time (default: %s)\n", loptstr (", --time", "\t"),
timeflag ? "on": "off");
fprintf (stderr, "\t-e%s\t print key expiration time\n", loptstr (", --expire", "\t"));
fprintf (stderr, "\t-f%s\t print key lifetime\n", loptstr (", --lifetime", "\t"));
fprintf (stderr, "\t-F days%s=days\t set key lifetime\n", loptstr (", --setlifetime", "\t"));
fprintf (stderr, "\t-k%s\t key signing keys only\n", loptstr (", --ksk", "\t"));
fprintf (stderr, "\t-z%s\t zone signing keys only\n", loptstr (", --zsk", "\t"));
if ( mesg && *mesg )
fprintf (stderr, "%s\n", mesg);
exit (1);
}
static void createkey (const char *keyname, const dki_t *list, const zconf_t *conf)
{
const char *dir = "";
dki_t *dkp;
if ( keyname == NULL || *keyname == '\0' )
fatal ("Create key: no keyname!");
dbg_val2 ("createkey: keyname %s, pathflag = %d\n", keyname, pathflag);
if ( pathflag && (dkp = (dki_t *)zkt_search (list, 0, keyname)) != NULL )
{
char path[MAX_PATHSIZE+1];
zconf_t localconf;
dir = dkp->dname;
pathname (path, sizeof (path), dir, LOCALCONF_FILE, NULL);
if ( fileexist (path) )
{
dbg_val ("Load local config file \"%s\"\n", path);
memcpy (&localconf, conf, sizeof (zconf_t));
conf = loadconfig (path, &localconf);
}
}
if ( zskflag )
dkp = dki_new (dir, keyname, DKI_ZSK, conf->k_algo, conf->z_bits, conf->z_random, conf->z_life / DAYSEC);
else
dkp = dki_new (dir, keyname, DKI_KSK, conf->k_algo, conf->k_bits, conf->k_random, conf->k_life / DAYSEC);
if ( dkp == NULL )
fatal ("Can't create key %s: %s!\n", keyname, dki_geterrstr ());
dki_setstatus (dkp, DKI_PUB);
}
static int get_parent_phase (const char *file)
{
FILE *fp;
int phase;
if ( (fp = fopen (file, "r")) == NULL )
return -1;
phase = 0;
if ( fscanf (fp, "; KSK rollover phase%d", &phase) != 1 )
phase = 0;
fclose (fp);
return phase;
}
static void ksk_roll (const char *keyname, int phase, const dki_t *list, const zconf_t *conf)
{
char path[MAX_PATHSIZE+1];
zconf_t localconf;
const char *dir;
dki_t *keylist;
dki_t *dkp;
dki_t *standby;
int parent_exist;
int parent_age;
int parent_phase;
int parent_propagation;
int key_ttl;
int ksk;
if ( phase == 9 )
{
fprintf (stderr, "A KSK rollover requires three consecutive steps:\n");
fprintf (stderr, "\n");
fprintf (stderr, "-1%s", loptstr ("|--ksk-roll-phase1 (--ksk-newkey)\n", ""));
fprintf (stderr, "\t Create a new KSK.\n");
fprintf (stderr, "\t This step also creates a parent-<domain> file which contains only\n");
fprintf (stderr, "\t the _old_ key. This file will be copied in hierarchical mode\n");
fprintf (stderr, "\t by dnssec-signer to the parent directory as keyset-<domain> file.\n");
fprintf (stderr, "\t Wait until the new keyset is propagated, before going to the next step.\n");
fprintf (stderr, "\n");
fprintf (stderr, "-2%s", loptstr ("|--ksk-roll-phase2 (--ksk-publish)\n", ""));
fprintf (stderr, "\t This step creates a parent-<domain> file with the _new_ key only.\n");
fprintf (stderr, "\t Please send this file immediately to the parent (In hierarchical\n");
fprintf (stderr, "\t mode this will be done automatically by the dnssec-signer command).\n");
fprintf (stderr, "\t Then wait until the new DS is generated by the parent and propagated\n");
fprintf (stderr, "\t to all the parent name server, plus the old DS TTL before going to step three.\n");
fprintf (stderr, "\n");
fprintf (stderr, "-3%s", loptstr ("|--ksk-roll-phase3 (--ksk-delkey)\n", ""));
fprintf (stderr, "\t Remove (rename) the old KSK and the parent-<domain> file.\n");
fprintf (stderr, "\t You have to manually delete the old KSK (look at file names beginning\n");
fprintf (stderr, "\t with an lower 'k').\n");
fprintf (stderr, "\n");
fprintf (stderr, "-0%s", loptstr ("|--ksk-roll-stat (--ksk-status)\n", ""));
fprintf (stderr, "\t Show the current KSK rollover state of a domain.\n");
fprintf (stderr, "\n");
return;
}
if ( keyname == NULL || *keyname == '\0' )
fatal ("ksk rollover: no domain!");
dbg_val2 ("ksk_roll: keyname %s, phase = %d\n", keyname, phase);
if ( (keylist = (dki_t *)zkt_search (list, 0, keyname)) == NULL )
fatal ("ksk rollover: domain %s not found!\n", keyname);
dkp = keylist;
dir = dkp->dname;
pathname (path, sizeof (path), dir, LOCALCONF_FILE, NULL);
if ( fileexist (path) )
{
dbg_val ("Load local config file \"%s\"\n", path);
memcpy (&localconf, conf, sizeof (zconf_t));
conf = loadconfig (path, &localconf);
}
key_ttl = conf->key_ttl;
pathname (path, sizeof (path), dir, "parent-", keyname);
parent_phase = parent_age = 0;
if ( (parent_exist = fileexist (path)) != 0 )
{
parent_phase = get_parent_phase (path);
parent_age = file_age (path);
}
parent_propagation = 5 * MINSEC;
ksk = 0;
standby = NULL;
for ( dkp = keylist; dkp; dkp = dkp->next )
if ( dki_isksk (dkp) )
{
if ( dki_status (dkp) == DKI_ACT )
ksk++;
else if ( dki_status (dkp) == DKI_PUB )
standby = dkp;
}
switch ( phase )
{
case 0:
fprintf (stdout, "ksk_rollover:\n");
fprintf (stdout, "\t domain = %s\n", keyname);
fprintf (stdout, "\t phase = %d\n", parent_phase);
fprintf (stdout, "\t parent_file %s %s\n", path, parent_exist ? "exist": "not exist");
if ( parent_exist )
fprintf (stdout, "\t age of parent_file %d %s\n", parent_age, str_delspace (age2str (parent_age)));
fprintf (stdout, "\t # of active key signing keys %d\n", ksk);
fprintf (stdout, "\t parent_propagation %d %s\n", parent_propagation, str_delspace (age2str (parent_propagation)));
fprintf (stdout, "\t keys ttl %d %s\n", key_ttl, age2str (key_ttl));
for ( dkp = keylist; dkp; dkp = dkp->next )
{
dki_prt_dnskey (dkp, stdout);
}
break;
case 1:
if ( parent_exist || ksk > 1 )
fatal ("Can\'t create new ksk because there is already an ksk rollover in progress\n");
fprintf (stdout, "create new ksk \n");
dkp = dki_new (dir, keyname, DKI_KSK, conf->k_algo, conf->k_bits, conf->k_random, conf->k_life / DAYSEC);
if ( dkp == NULL )
fatal ("Can't create key %s: %s!\n", keyname, dki_geterrstr ());
if ( standby )
{
dki_setstatus (standby, DKI_ACT);
dki_setstatus (dkp, DKI_PUB);
}
if ( (dkp = (dki_t *)dki_findalgo (keylist, 1, conf->k_algo, 'a', 1)) == NULL )
fatal ("ksk_rollover phase1: Couldn't find the old active key\n");
if ( !create_parent_file (path, phase, key_ttl, dkp) )
fatal ("Couldn't create parentfile %s\n", path);
break;
case 2:
if ( ksk < 2 )
fatal ("Can\'t publish new key because no one exist\n");
if ( !parent_exist )
fatal ("More than one KSK but no parent file found!\n");
if ( parent_phase != 1 )
fatal ("Parent file exists but is in wrong state (phase = %d)\n", parent_phase);
if ( parent_age < conf->proptime + key_ttl )
fatal ("ksk_rollover (phase2): you have to wait for the propagation of the new KSK (at least %dsec or %s)\n",
conf->proptime + key_ttl - parent_age,
str_delspace (age2str (conf->proptime + key_ttl - parent_age)));
fprintf (stdout, "save new ksk in parent file\n");
dkp = keylist->next;
if ( !create_parent_file (path, phase, key_ttl, dkp) )
fatal ("Couldn't create parentfile %s\n", path);
break;
case 3:
if ( !parent_exist || ksk < 2 )
fatal ("ksk-delkey only allowed after ksk-publish\n");
if ( parent_phase != 2 )
fatal ("Parent file exists but is in wrong state (phase = %d)\n", parent_phase);
if ( parent_age < parent_propagation + key_ttl )
fatal ("ksk_rollover (phase3): you have to wait for DS propagation (at least %dsec or %s)\n",
parent_propagation + key_ttl - parent_age,
str_delspace (age2str (parent_propagation + key_ttl - parent_age)));
fprintf (stdout, "remove parentfile \n");
unlink (path);
fprintf (stdout, "old ksk renamed \n");
dkp = keylist;
dki_remove (dkp);
break;
default: assert (phase == 1 || phase == 2 || phase == 3);
}
}
static int create_parent_file (const char *fname, int phase, int ttl, const dki_t *dkp)
{
FILE *fp;
assert ( fname != NULL );
if ( dkp == NULL || (phase != 1 && phase != 2) )
return 0;
if ( (fp = fopen (fname, "w")) == NULL )
fatal ("can\'t create new parentfile \"%s\"\n", fname);
if ( phase == 1 )
fprintf (fp, "; KSK rollover phase1 (old key)\n");
else
fprintf (fp, "; KSK rollover phase2 (new key)\n");
dki_prt_dnskeyttl (dkp, fp, ttl);
fclose (fp);
return phase;
}
static int parsedirectory (const char *dir, dki_t **listp)
{
dki_t *dkp;
DIR *dirp;
struct dirent *dentp;
char path[MAX_PATHSIZE+1];
if ( dirflag )
return 0;
dbg_val ("directory: opendir(%s)\n", dir);
if ( (dirp = opendir (dir)) == NULL )
return 0;
while ( (dentp = readdir (dirp)) != NULL )
{
if ( is_dotfilename (dentp->d_name) )
continue;
dbg_val ("directory: check %s\n", dentp->d_name);
pathname (path, sizeof (path), dir, dentp->d_name, NULL);
if ( is_directory (path) && recflag )
{
dbg_val ("directory: recursive %s\n", path);
parsedirectory (path, listp);
}
else if ( is_keyfilename (dentp->d_name) )
if ( (dkp = dki_read (dir, dentp->d_name)) )
{
#if defined (USE_TREE) && USE_TREE
dki_tadd (listp, dkp, 1);
#else
dki_add (listp, dkp);
#endif
}
}
closedir (dirp);
return 1;
}
static void parsefile (const char *file, dki_t **listp)
{
char path[MAX_PATHSIZE+1];
dki_t *dkp;
file = splitpath (path, sizeof (path), file);
if ( is_keyfilename (file) )
{
if ( (dkp = dki_read (path, file)) )
#if defined (USE_TREE) && USE_TREE
dki_tadd (listp, dkp, 1);
#else
dki_add (listp, dkp);
#endif
else
error ("error parsing %s: (%s)\n", file, dki_geterrstr());
}
}
static const char *parsetag (const char *str, int *tagp)
{
const char *p;
*tagp = 0;
while ( isspace (*str) )
str++;
p = str;
if ( isdigit (*p) )
{
sscanf (p, "%u", tagp);
do
p++;
while ( isdigit (*p) );
if ( *p == ':' )
return p+1;
if ( *p == '\0' )
return NULL;
}
return str;
}