Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / bind / dist / contrib / zkt / dnssec-zkt.c
blob85945c71eb94b030a55df5acafbc2c726a797e0f
1 /* $NetBSD$ */
3 /*****************************************************************
4 **
5 ** @(#) dnssec-zkt.c (c) Jan 2005 Holger Zuleger hznet.de
6 **
7 ** Secure DNS zone key tool
8 ** A wrapper command around the BIND dnssec-keygen utility
9 **
10 ** Copyright (c) 2005 - 2008, Holger Zuleger HZnet. All rights reserved.
12 ** This software is open source.
14 ** Redistribution and use in source and binary forms, with or without
15 ** modification, are permitted provided that the following conditions
16 ** are met:
18 ** Redistributions of source code must retain the above copyright notice,
19 ** this list of conditions and the following disclaimer.
21 ** Redistributions in binary form must reproduce the above copyright notice,
22 ** this list of conditions and the following disclaimer in the documentation
23 ** and/or other materials provided with the distribution.
25 ** Neither the name of Holger Zuleger HZnet nor the names of its contributors may
26 ** be used to endorse or promote products derived from this software without
27 ** specific prior written permission.
29 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
33 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 ** POSSIBILITY OF SUCH DAMAGE.
41 *****************************************************************/
43 # include <stdio.h>
44 # include <stdlib.h> /* abort(), exit(), ... */
45 # include <string.h>
46 # include <dirent.h>
47 # include <assert.h>
48 # include <unistd.h>
49 # include <ctype.h>
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif
54 # include "config_zkt.h"
55 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
56 # include <getopt.h>
57 #endif
59 # include "debug.h"
60 # include "misc.h"
61 # include "strlist.h"
62 # include "zconf.h"
63 # include "dki.h"
64 # include "zkt.h"
66 extern int optopt;
67 extern int opterr;
68 extern int optind;
69 extern char *optarg;
70 const char *progname;
72 char *labellist = NULL;
74 int headerflag = 1;
75 int ageflag = 0;
76 int lifetime = 0;
77 int lifetimeflag = 0;
78 int timeflag = 1;
79 int exptimeflag = 0;
80 int pathflag = 0;
81 int kskflag = 1;
82 int zskflag = 1;
83 int ljustflag = 0;
85 static int dirflag = 0;
86 static int recflag = RECURSIVE;
87 static int trustedkeyflag = 0;
88 static char *kskdomain = "";
89 static const char *view = "";
91 # define short_options ":0:1:2:3:9A:C:D:P:S:R:HKTs:ZV:afF:c:O:dhkLl:prtez"
92 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
93 static struct option long_options[] = {
94 {"ksk-rollover", no_argument, NULL, '9'},
95 {"ksk-status", required_argument, NULL, '0'},
96 {"ksk-roll-status", required_argument, NULL, '0'},
97 {"ksk-newkey", required_argument, NULL, '1'},
98 {"ksk-publish", required_argument, NULL, '2'},
99 {"ksk-delkey", required_argument, NULL, '3'},
100 {"ksk-roll-phase1", required_argument, NULL, '1'},
101 {"ksk-roll-phase2", required_argument, NULL, '2'},
102 {"ksk-roll-phase3", required_argument, NULL, '3'},
103 {"list-dnskeys", no_argument, NULL, 'K'},
104 {"list-trustedkeys", no_argument, NULL, 'T'},
105 {"ksk", no_argument, NULL, 'k'},
106 {"zsk", no_argument, NULL, 'z'},
107 {"age", no_argument, NULL, 'a'},
108 {"lifetime", no_argument, NULL, 'f'},
109 {"time", no_argument, NULL, 't'},
110 {"expire", no_argument, NULL, 'e'},
111 {"recursive", no_argument, NULL, 'r'},
112 {"zone-config", no_argument, NULL, 'Z'},
113 {"leftjust", no_argument, NULL, 'L'},
114 {"path", no_argument, NULL, 'p'},
115 {"nohead", no_argument, NULL, 'h'},
116 {"directory", no_argument, NULL, 'd'},
117 {"config", required_argument, NULL, 'c'},
118 {"option", required_argument, NULL, 'O'},
119 {"config-option", required_argument, NULL, 'O'},
120 {"published", required_argument, NULL, 'P'},
121 {"standby", required_argument, NULL, 'S'},
122 {"active", required_argument, NULL, 'A'},
123 {"depreciated", required_argument, NULL, 'D'},
124 {"create", required_argument, NULL, 'C'},
125 {"revoke", required_argument, NULL, 'R'},
126 {"remove", required_argument, NULL, 19 },
127 {"destroy", required_argument, NULL, 20 },
128 {"setlifetime", required_argument, NULL, 'F' },
129 {"view", required_argument, NULL, 'V' },
130 {"help", no_argument, NULL, 'H'},
131 {0, 0, 0, 0}
133 #endif
135 static int parsedirectory (const char *dir, dki_t **listp);
136 static void parsefile (const char *file, dki_t **listp);
137 static void createkey (const char *keyname, const dki_t *list, const zconf_t *conf);
138 static void ksk_roll (const char *keyname, int phase, const dki_t *list, const zconf_t *conf);
139 static int create_parent_file (const char *fname, int phase, int ttl, const dki_t *dkp);
140 static void usage (char *mesg, zconf_t *cp);
141 static const char *parsetag (const char *str, int *tagp);
143 static void setglobalflags (zconf_t *config)
145 recflag = config->recursive;
146 ageflag = config->printage;
147 timeflag = config->printtime;
148 ljustflag = config->ljust;
151 int main (int argc, char *argv[])
153 dki_t *data = NULL;
154 dki_t *dkp;
155 int c;
156 int opt_index;
157 int action;
158 const char *file;
159 const char *defconfname = NULL;
160 char *p;
161 char str[254+1];
162 const char *keyname = NULL;
163 int searchtag;
164 zconf_t *config;
166 progname = *argv;
167 if ( (p = strrchr (progname, '/')) )
168 progname = ++p;
169 view = getnameappendix (progname, "dnssec-zkt");
171 defconfname = getdefconfname (view);
172 config = loadconfig ("", (zconf_t *)NULL); /* load built in config */
173 if ( fileexist (defconfname) ) /* load default config file */
174 config = loadconfig (defconfname, config);
175 if ( config == NULL )
176 fatal ("Out of memory\n");
177 setglobalflags (config);
179 opterr = 0;
180 opt_index = 0;
181 action = 0;
182 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
183 while ( (c = getopt_long (argc, argv, short_options, long_options, &opt_index)) != -1 )
184 #else
185 while ( (c = getopt (argc, argv, short_options)) != -1 )
186 #endif
188 switch ( c )
190 case '9': /* ksk rollover help */
191 ksk_roll ("help", c - '0', NULL, NULL);
192 exit (1);
193 case '1': /* ksk rollover: create new key */
194 case '2': /* ksk rollover: publish DS */
195 case '3': /* ksk rollover: delete old key */
196 case '0': /* ksk rollover: show current status */
197 action = c;
198 if ( !optarg )
199 usage ("ksk rollover requires an domain argument", config);
200 kskdomain = domain_canonicdup (optarg);
201 break;
202 case 'T':
203 trustedkeyflag = 1;
204 zskflag = pathflag = 0;
205 /* fall through */
206 case 'H':
207 case 'K':
208 case 'Z':
209 action = c;
210 break;
211 case 'C':
212 pathflag = !pathflag;
213 /* fall through */
214 case 'P':
215 case 'S':
216 case 'A':
217 case 'D':
218 case 'R':
219 case 's':
220 case 19:
221 case 20:
222 if ( (keyname = parsetag (optarg, &searchtag)) != NULL )
223 keyname = domain_canonicdup (keyname);
224 action = c;
225 break;
226 case 'a': /* age */
227 ageflag = !ageflag;
228 break;
229 case 'f': /* key lifetime */
230 lifetimeflag = !lifetimeflag;
231 break;
232 case 'F': /* set key lifetime */
233 lifetime = atoi (optarg);
234 lifetimeflag = 1; /* set some flags for more informative output */
235 exptimeflag = 1;
236 timeflag = 1;
237 action = c;
238 break;
239 case 'V': /* view name */
240 view = optarg;
241 defconfname = getdefconfname (view);
242 if ( fileexist (defconfname) ) /* load default config file */
243 config = loadconfig (defconfname, config);
244 if ( config == NULL )
245 fatal ("Out of memory\n");
246 setglobalflags (config);
247 break;
248 case 'c':
249 config = loadconfig (optarg, config);
250 setglobalflags (config);
251 checkconfig (config);
252 break;
253 case 'O': /* read option from commandline */
254 config = loadconfig_fromstr (optarg, config);
255 setglobalflags (config);
256 checkconfig (config);
257 break;
258 case 'd': /* ignore directory arg */
259 dirflag = 1;
260 break;
261 case 'h': /* print no headline */
262 headerflag = 0;
263 break;
264 case 'k': /* ksk only */
265 zskflag = 0;
266 break;
267 case 'L': /* ljust */
268 ljustflag = !ljustflag;
269 break;
270 case 'l': /* label list */
271 labellist = prepstrlist (optarg, LISTDELIM);
272 if ( labellist == NULL )
273 fatal ("Out of memory\n");
274 break;
275 case 'p': /* print path */
276 pathflag = 1;
277 break;
278 case 'r': /* switch recursive flag */
279 recflag = !recflag;
280 break;
281 case 't': /* time */
282 timeflag = !timeflag;
283 break;
284 case 'e': /* expire time */
285 exptimeflag = !exptimeflag;
286 break;
287 case 'z': /* zsk only */
288 kskflag = 0;
289 break;
290 case ':':
291 snprintf (str, sizeof(str), "option \"-%c\" requires an argument.\n",
292 optopt);
293 usage (str, config);
294 break;
295 case '?':
296 if ( isprint (optopt) )
297 snprintf (str, sizeof(str), "Unknown option \"-%c\".\n",
298 optopt);
299 else
300 snprintf (str, sizeof (str), "Unknown option char \\x%x.\n",
301 optopt);
302 usage (str, config);
303 break;
304 default:
305 abort();
309 /* it's better to do this before we read the whole directory tree */
310 if ( action == 'Z' )
312 printconfig ("stdout", config);
313 return 0;
316 if ( kskflag == 0 && zskflag == 0 )
317 kskflag = zskflag = 1;
319 c = optind;
320 do {
321 if ( c >= argc ) /* no args left */
322 file = config->zonedir; /* use default directory */
323 else
324 file = argv[c++];
326 if ( is_directory (file) )
327 parsedirectory (file, &data);
328 else
329 parsefile (file, &data);
331 } while ( c < argc ); /* for all arguments */
333 switch ( action )
335 case 'H':
336 usage ("", config);
337 case 'C':
338 createkey (keyname, data, config);
339 break;
340 case 'P':
341 case 'S':
342 case 'A':
343 case 'D':
344 if ( (dkp = (dki_t*)zkt_search (data, searchtag, keyname)) == NULL )
345 fatal ("Key with tag %u not found\n", searchtag);
346 else if ( dkp == (void *) 01 )
347 fatal ("Key with tag %u found multiple times\n", searchtag);
348 if ( (c = dki_setstatus_preservetime (dkp, action)) != 0 )
349 fatal ("Couldn't change status of key %u: %d\n", searchtag, c);
350 break;
351 case 19: /* remove (rename) key file */
352 if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL )
353 fatal ("Key with tag %u not found\n", searchtag);
354 else if ( dkp == (void *) 01 )
355 fatal ("Key with tag %u found multiple times\n", searchtag);
356 dki_remove (dkp);
357 break;
358 case 20: /* destroy the key (remove the files!) */
359 if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL )
360 fatal ("Key with tag %u not found\n", searchtag);
361 else if ( dkp == (void *) 01 )
362 fatal ("Key with tag %u found multiple times\n", searchtag);
363 dki_destroy (dkp);
364 break;
365 case 'R':
366 if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL )
367 fatal ("Key with tag %u not found\n", searchtag);
368 else if ( dkp == (void *) 01 )
369 fatal ("Key with tag %u found multiple times\n", searchtag);
370 if ( (c = dki_setstatus (dkp, action)) != 0 )
371 fatal ("Couldn't change status of key %u: %d\n", searchtag, c);
372 break;
373 case 's':
374 if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL )
375 fatal ("Key with tag %u not found\n", searchtag);
376 else if ( dkp == (void *) 01 )
377 fatal ("Key with tag %u found multiple times\n", searchtag);
378 dki_prt_dnskey (dkp, stdout);
379 break;
380 case 'K':
381 zkt_list_dnskeys (data);
382 break;
383 case 'T':
384 zkt_list_trustedkeys (data);
385 break;
386 case '1': /* ksk rollover new key */
387 case '2': /* ksk rollover publish DS */
388 case '3': /* ksk rollover delete old key */
389 case '0': /* ksk rollover status */
390 ksk_roll (kskdomain, action - '0', data, config);
391 break;
392 case 'F':
393 zkt_setkeylifetime (data);
394 /* fall through */
395 default:
396 zkt_list_keys (data);
399 return 0;
402 # define sopt_usage(mesg, value) fprintf (stderr, mesg, value)
403 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
404 # define lopt_usage(mesg, value) fprintf (stderr, mesg, value)
405 # define loptstr(lstr, sstr) lstr
406 #else
407 # define lopt_usage(mesg, value)
408 # define loptstr(lstr, sstr) sstr
409 #endif
410 static void usage (char *mesg, zconf_t *cp)
412 fprintf (stderr, "Secure DNS Zone Key Tool %s\n", ZKT_VERSION);
413 fprintf (stderr, "\n");
414 fprintf (stderr, "Show zone config parameter as %s file\n", LOCALCONF_FILE);
415 sopt_usage ("\tusage: %s -Z\n", progname);
416 lopt_usage ("\tusage: %s --zone-config\n", progname);
417 fprintf (stderr, "\n");
418 fprintf (stderr, "List keys in current or given directory (-r for recursive mode)\n");
419 sopt_usage ("\tusage: %s [-dhatkzpr] [-c config] [file|dir ...]\n", progname);
420 fprintf (stderr, "\n");
421 fprintf (stderr, "List public part of keys in DNSKEY RR format\n");
422 sopt_usage ("\tusage: %s -K [-dhkzr] [-c config] [file|dir ...]\n", progname);
423 lopt_usage ("\tusage: %s --list-dnskeys [-dhkzr] [-c config] [file|dir ...]\n", progname);
424 fprintf (stderr, "\n");
425 fprintf (stderr, "List keys (output is suitable for trusted-keys section)\n");
426 sopt_usage ("\tusage: %s -T [-dhzr] [-c config] [file|dir ...]\n", progname);
427 lopt_usage ("\tusage: %s --list-trustedkeys [-dhzr] [-c config] [file|dir ...]\n", progname);
428 fprintf (stderr, "\n");
429 fprintf (stderr, "Create a new key \n");
430 sopt_usage ("\tusage: %s -C <name> [-k] [-dpr] [-c config] [dir ...]\n", progname);
431 lopt_usage ("\tusage: %s --create=<name> [-k] [-dpr] [-c config] [dir ...]\n", progname);
432 fprintf (stderr, "\t\tKSK (use -k): %s %d bits\n", dki_algo2str (cp->k_algo), cp->k_bits);
433 fprintf (stderr, "\t\tZSK (default): %s %d bits\n", dki_algo2str (cp->k_algo), cp->z_bits);
434 fprintf (stderr, "\n");
435 fprintf (stderr, "Change key status of specified key to published, active or depreciated\n");
436 fprintf (stderr, "\t(<keyspec> := tag | tag:name) \n");
437 sopt_usage ("\tusage: %s -P|-A|-D <keyspec> [-dr] [-c config] [dir ...]\n", progname);
438 lopt_usage ("\tusage: %s --published=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
439 lopt_usage ("\tusage: %s --active=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
440 lopt_usage ("\tusage: %s --depreciated=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
441 fprintf (stderr, "\n");
442 fprintf (stderr, "Revoke specified key (<keyspec> := tag | tag:name) \n");
443 sopt_usage ("\tusage: %s -R <keyspec> [-dr] [-c config] [dir ...]\n", progname);
444 lopt_usage ("\tusage: %s --revoke=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
445 fprintf (stderr, "\n");
446 fprintf (stderr, "Remove (rename) or destroy (delete) specified key (<keyspec> := tag | tag:name) \n");
447 lopt_usage ("\tusage: %s --remove=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
448 lopt_usage ("\tusage: %s --destroy=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
449 fprintf (stderr, "\n");
450 fprintf (stderr, "Initiate a semi-automated KSK rollover");
451 fprintf (stderr, "('%s -9%s' prints out a short description)\n", progname, loptstr ("|--ksk-rollover", ""));
452 sopt_usage ("\tusage: %s {-1} do.ma.in.\n", progname);
453 lopt_usage ("\tusage: %s {--ksk-roll-phase1|--ksk-newkey} do.ma.in.\n", progname);
454 sopt_usage ("\tusage: %s {-2} do.ma.in.\n", progname);
455 lopt_usage ("\tusage: %s {--ksk-roll-phase2|--ksk-publish} do.ma.in.\n", progname);
456 sopt_usage ("\tusage: %s {-3} do.ma.in.\n", progname);
457 lopt_usage ("\tusage: %s {--ksk-roll-phase3|--ksk-delkey} do.ma.in.\n", progname);
458 sopt_usage ("\tusage: %s {-0} do.ma.in.\n", progname);
459 lopt_usage ("\tusage: %s {--ksk-roll-status|--ksk-status} do.ma.in.\n", progname);
460 fprintf (stderr, "\n");
462 fprintf (stderr, "\n");
463 fprintf (stderr, "General options \n");
464 fprintf (stderr, "\t-c file%s", loptstr (", --config=file\n", ""));
465 fprintf (stderr, "\t\t read config from <file> instead of %s\n", CONFIG_FILE);
466 fprintf (stderr, "\t-O optstr%s", loptstr (", --config-option=\"optstr\"\n", ""));
467 fprintf (stderr, "\t\t read config options from commandline\n");
468 fprintf (stderr, "\t-h%s\t no headline or trusted-key section header/trailer in -T mode\n", loptstr (", --nohead", "\t"));
469 fprintf (stderr, "\t-d%s\t skip directory arguments\n", loptstr (", --directory", "\t"));
470 fprintf (stderr, "\t-L%s\t print the domain name left justified (default: %s)\n", loptstr (", --leftjust", "\t"), ljustflag ? "on": "off");
471 fprintf (stderr, "\t-l list\t\t print out only zone keys out of the given domain list\n");
472 fprintf (stderr, "\t-p%s\t show path of keyfile / create key in current directory\n", loptstr (", --path", "\t"));
473 fprintf (stderr, "\t-r%s\t recursive mode on/off (default: %s)\n", loptstr(", --recursive", "\t"), recflag ? "on": "off");
474 fprintf (stderr, "\t-a%s\t print age of key (default: %s)\n", loptstr (", --age", "\t"), ageflag ? "on": "off");
475 fprintf (stderr, "\t-t%s\t print key generation time (default: %s)\n", loptstr (", --time", "\t"),
476 timeflag ? "on": "off");
477 fprintf (stderr, "\t-e%s\t print key expiration time\n", loptstr (", --expire", "\t"));
478 fprintf (stderr, "\t-f%s\t print key lifetime\n", loptstr (", --lifetime", "\t"));
479 fprintf (stderr, "\t-F days%s=days\t set key lifetime\n", loptstr (", --setlifetime", "\t"));
480 fprintf (stderr, "\t-k%s\t key signing keys only\n", loptstr (", --ksk", "\t"));
481 fprintf (stderr, "\t-z%s\t zone signing keys only\n", loptstr (", --zsk", "\t"));
482 if ( mesg && *mesg )
483 fprintf (stderr, "%s\n", mesg);
484 exit (1);
487 static void createkey (const char *keyname, const dki_t *list, const zconf_t *conf)
489 const char *dir = "";
490 dki_t *dkp;
492 if ( keyname == NULL || *keyname == '\0' )
493 fatal ("Create key: no keyname!");
495 dbg_val2 ("createkey: keyname %s, pathflag = %d\n", keyname, pathflag);
496 /* search for already existent key to get the directory name */
497 if ( pathflag && (dkp = (dki_t *)zkt_search (list, 0, keyname)) != NULL )
499 char path[MAX_PATHSIZE+1];
500 zconf_t localconf;
502 dir = dkp->dname;
503 pathname (path, sizeof (path), dir, LOCALCONF_FILE, NULL);
504 if ( fileexist (path) ) /* load local config file */
506 dbg_val ("Load local config file \"%s\"\n", path);
507 memcpy (&localconf, conf, sizeof (zconf_t));
508 conf = loadconfig (path, &localconf);
512 if ( zskflag )
513 dkp = dki_new (dir, keyname, DKI_ZSK, conf->k_algo, conf->z_bits, conf->z_random, conf->z_life / DAYSEC);
514 else
515 dkp = dki_new (dir, keyname, DKI_KSK, conf->k_algo, conf->k_bits, conf->k_random, conf->k_life / DAYSEC);
516 if ( dkp == NULL )
517 fatal ("Can't create key %s: %s!\n", keyname, dki_geterrstr ());
519 /* create a new key always in state published, which means "standby" for ksk */
520 dki_setstatus (dkp, DKI_PUB);
523 static int get_parent_phase (const char *file)
525 FILE *fp;
526 int phase;
528 if ( (fp = fopen (file, "r")) == NULL )
529 return -1;
531 phase = 0;
532 if ( fscanf (fp, "; KSK rollover phase%d", &phase) != 1 )
533 phase = 0;
535 fclose (fp);
536 return phase;
539 static void ksk_roll (const char *keyname, int phase, const dki_t *list, const zconf_t *conf)
541 char path[MAX_PATHSIZE+1];
542 zconf_t localconf;
543 const char *dir;
544 dki_t *keylist;
545 dki_t *dkp;
546 dki_t *standby;
547 int parent_exist;
548 int parent_age;
549 int parent_phase;
550 int parent_propagation;
551 int key_ttl;
552 int ksk;
554 if ( phase == 9 ) /* usage */
556 fprintf (stderr, "A KSK rollover requires three consecutive steps:\n");
557 fprintf (stderr, "\n");
558 fprintf (stderr, "-1%s", loptstr ("|--ksk-roll-phase1 (--ksk-newkey)\n", ""));
559 fprintf (stderr, "\t Create a new KSK.\n");
560 fprintf (stderr, "\t This step also creates a parent-<domain> file which contains only\n");
561 fprintf (stderr, "\t the _old_ key. This file will be copied in hierarchical mode\n");
562 fprintf (stderr, "\t by dnssec-signer to the parent directory as keyset-<domain> file.\n");
563 fprintf (stderr, "\t Wait until the new keyset is propagated, before going to the next step.\n");
564 fprintf (stderr, "\n");
565 fprintf (stderr, "-2%s", loptstr ("|--ksk-roll-phase2 (--ksk-publish)\n", ""));
566 fprintf (stderr, "\t This step creates a parent-<domain> file with the _new_ key only.\n");
567 fprintf (stderr, "\t Please send this file immediately to the parent (In hierarchical\n");
568 fprintf (stderr, "\t mode this will be done automatically by the dnssec-signer command).\n");
569 fprintf (stderr, "\t Then wait until the new DS is generated by the parent and propagated\n");
570 fprintf (stderr, "\t to all the parent name server, plus the old DS TTL before going to step three.\n");
571 fprintf (stderr, "\n");
572 fprintf (stderr, "-3%s", loptstr ("|--ksk-roll-phase3 (--ksk-delkey)\n", ""));
573 fprintf (stderr, "\t Remove (rename) the old KSK and the parent-<domain> file.\n");
574 fprintf (stderr, "\t You have to manually delete the old KSK (look at file names beginning\n");
575 fprintf (stderr, "\t with an lower 'k').\n");
576 fprintf (stderr, "\n");
577 fprintf (stderr, "-0%s", loptstr ("|--ksk-roll-stat (--ksk-status)\n", ""));
578 fprintf (stderr, "\t Show the current KSK rollover state of a domain.\n");
580 fprintf (stderr, "\n");
582 return;
585 if ( keyname == NULL || *keyname == '\0' )
586 fatal ("ksk rollover: no domain!");
588 dbg_val2 ("ksk_roll: keyname %s, phase = %d\n", keyname, phase);
590 /* search for already existent key to get the directory name */
591 if ( (keylist = (dki_t *)zkt_search (list, 0, keyname)) == NULL )
592 fatal ("ksk rollover: domain %s not found!\n", keyname);
593 dkp = keylist;
595 /* try to read local config file */
596 dir = dkp->dname;
597 pathname (path, sizeof (path), dir, LOCALCONF_FILE, NULL);
598 if ( fileexist (path) ) /* load local config file */
600 dbg_val ("Load local config file \"%s\"\n", path);
601 memcpy (&localconf, conf, sizeof (zconf_t));
602 conf = loadconfig (path, &localconf);
604 key_ttl = conf->key_ttl;
606 /* check if parent-file already exist */
607 pathname (path, sizeof (path), dir, "parent-", keyname);
608 parent_phase = parent_age = 0;
609 if ( (parent_exist = fileexist (path)) != 0 )
611 parent_phase = get_parent_phase (path);
612 parent_age = file_age (path);
614 // parent_propagation = 2 * DAYSEC;
615 parent_propagation = 5 * MINSEC;
617 ksk = 0; /* count active(!) key signing keys */
618 standby = NULL; /* find standby key if available */
619 for ( dkp = keylist; dkp; dkp = dkp->next )
620 if ( dki_isksk (dkp) )
622 if ( dki_status (dkp) == DKI_ACT )
623 ksk++;
624 else if ( dki_status (dkp) == DKI_PUB )
625 standby = dkp;
628 switch ( phase )
630 case 0: /* print status (debug) */
631 fprintf (stdout, "ksk_rollover:\n");
632 fprintf (stdout, "\t domain = %s\n", keyname);
633 fprintf (stdout, "\t phase = %d\n", parent_phase);
634 fprintf (stdout, "\t parent_file %s %s\n", path, parent_exist ? "exist": "not exist");
635 if ( parent_exist )
636 fprintf (stdout, "\t age of parent_file %d %s\n", parent_age, str_delspace (age2str (parent_age)));
637 fprintf (stdout, "\t # of active key signing keys %d\n", ksk);
638 fprintf (stdout, "\t parent_propagation %d %s\n", parent_propagation, str_delspace (age2str (parent_propagation)));
639 fprintf (stdout, "\t keys ttl %d %s\n", key_ttl, age2str (key_ttl));
641 for ( dkp = keylist; dkp; dkp = dkp->next )
643 /* TODO: Nur zum testen */
644 dki_prt_dnskey (dkp, stdout);
646 break;
647 case 1:
648 if ( parent_exist || ksk > 1 )
649 fatal ("Can\'t create new ksk because there is already an ksk rollover in progress\n");
651 fprintf (stdout, "create new ksk \n");
652 dkp = dki_new (dir, keyname, DKI_KSK, conf->k_algo, conf->k_bits, conf->k_random, conf->k_life / DAYSEC);
653 if ( dkp == NULL )
654 fatal ("Can't create key %s: %s!\n", keyname, dki_geterrstr ());
655 if ( standby )
657 dki_setstatus (standby, DKI_ACT); /* activate standby key */
658 dki_setstatus (dkp, DKI_PUB); /* new key will be the new standby */
661 // dkp = keylist; /* use old key to create the parent file */
662 if ( (dkp = (dki_t *)dki_findalgo (keylist, 1, conf->k_algo, 'a', 1)) == NULL ) /* find the oldest active ksk to create the parent file */
663 fatal ("ksk_rollover phase1: Couldn't find the old active key\n");
664 if ( !create_parent_file (path, phase, key_ttl, dkp) )
665 fatal ("Couldn't create parentfile %s\n", path);
666 break;
668 case 2:
669 if ( ksk < 2 )
670 fatal ("Can\'t publish new key because no one exist\n");
671 if ( !parent_exist )
672 fatal ("More than one KSK but no parent file found!\n");
673 if ( parent_phase != 1 )
674 fatal ("Parent file exists but is in wrong state (phase = %d)\n", parent_phase);
675 if ( parent_age < conf->proptime + key_ttl )
676 fatal ("ksk_rollover (phase2): you have to wait for the propagation of the new KSK (at least %dsec or %s)\n",
677 conf->proptime + key_ttl - parent_age,
678 str_delspace (age2str (conf->proptime + key_ttl - parent_age)));
680 fprintf (stdout, "save new ksk in parent file\n");
681 dkp = keylist->next; /* set dkp to new ksk */
682 if ( !create_parent_file (path, phase, key_ttl, dkp) )
683 fatal ("Couldn't create parentfile %s\n", path);
684 break;
685 case 3:
686 if ( !parent_exist || ksk < 2 )
687 fatal ("ksk-delkey only allowed after ksk-publish\n");
688 if ( parent_phase != 2 )
689 fatal ("Parent file exists but is in wrong state (phase = %d)\n", parent_phase);
690 if ( parent_age < parent_propagation + key_ttl )
691 fatal ("ksk_rollover (phase3): you have to wait for DS propagation (at least %dsec or %s)\n",
692 parent_propagation + key_ttl - parent_age,
693 str_delspace (age2str (parent_propagation + key_ttl - parent_age)));
694 /* remove the parentfile */
695 fprintf (stdout, "remove parentfile \n");
696 unlink (path);
697 /* remove or rename the old key */
698 fprintf (stdout, "old ksk renamed \n");
699 dkp = keylist; /* set dkp to old ksk */
700 dki_remove (dkp);
701 break;
702 default: assert (phase == 1 || phase == 2 || phase == 3);
706 /*****************************************************************
707 ** create_parent_file ()
708 *****************************************************************/
709 static int create_parent_file (const char *fname, int phase, int ttl, const dki_t *dkp)
711 FILE *fp;
713 assert ( fname != NULL );
715 if ( dkp == NULL || (phase != 1 && phase != 2) )
716 return 0;
718 if ( (fp = fopen (fname, "w")) == NULL )
719 fatal ("can\'t create new parentfile \"%s\"\n", fname);
721 if ( phase == 1 )
722 fprintf (fp, "; KSK rollover phase1 (old key)\n");
723 else
724 fprintf (fp, "; KSK rollover phase2 (new key)\n");
726 dki_prt_dnskeyttl (dkp, fp, ttl);
727 fclose (fp);
729 return phase;
732 static int parsedirectory (const char *dir, dki_t **listp)
734 dki_t *dkp;
735 DIR *dirp;
736 struct dirent *dentp;
737 char path[MAX_PATHSIZE+1];
739 if ( dirflag )
740 return 0;
742 dbg_val ("directory: opendir(%s)\n", dir);
743 if ( (dirp = opendir (dir)) == NULL )
744 return 0;
746 while ( (dentp = readdir (dirp)) != NULL )
748 if ( is_dotfilename (dentp->d_name) )
749 continue;
751 dbg_val ("directory: check %s\n", dentp->d_name);
752 pathname (path, sizeof (path), dir, dentp->d_name, NULL);
753 if ( is_directory (path) && recflag )
755 dbg_val ("directory: recursive %s\n", path);
756 parsedirectory (path, listp);
758 else if ( is_keyfilename (dentp->d_name) )
759 if ( (dkp = dki_read (dir, dentp->d_name)) )
761 // fprintf (stderr, "parsedir: tssearch (%d %s)\n", dkp, dkp->name);
762 #if defined (USE_TREE) && USE_TREE
763 dki_tadd (listp, dkp);
764 #else
765 dki_add (listp, dkp);
766 #endif
769 closedir (dirp);
770 return 1;
773 static void parsefile (const char *file, dki_t **listp)
775 char path[MAX_PATHSIZE+1];
776 dki_t *dkp;
778 /* file arg contains path ? ... */
779 file = splitpath (path, sizeof (path), file); /* ... then split of */
781 if ( is_keyfilename (file) ) /* plain file name looks like DNS key file ? */
783 if ( (dkp = dki_read (path, file)) ) /* read DNS key file ... */
784 #if defined (USE_TREE) && USE_TREE
785 dki_tadd (listp, dkp); /* ... and add to tree */
786 #else
787 dki_add (listp, dkp); /* ... and add to list */
788 #endif
789 else
790 error ("error parsing %s: (%s)\n", file, dki_geterrstr());
794 static const char *parsetag (const char *str, int *tagp)
796 const char *p;
798 *tagp = 0;
799 while ( isspace (*str) ) /* skip leading ws */
800 str++;
802 p = str;
803 if ( isdigit (*p) ) /* keytag starts with digit */
805 sscanf (p, "%u", tagp); /* read keytag as number */
806 do /* eat up to the end of the number */
807 p++;
808 while ( isdigit (*p) );
810 if ( *p == ':' ) /* label follows ? */
811 return p+1; /* return that */
812 if ( *p == '\0' )
813 return NULL; /* no label */
815 return str; /* return as label string if not a numeric keytag */