1 /*	$NetBSD: zkt-keyman.c,v 1.1.1.1 2015/07/08 15:37:48 christos Exp $	*/
2 
3 /*****************************************************************
4 **
5 **	@(#) zkt-keyman.c (c) Jan 2005 - Apr 2010  Holger Zuleger  hznet.de
6 **
7 **	ZKT key managing tool (formely knon as dnsses-zkt)
8 **	A wrapper command around the BIND dnssec-keygen utility
9 **
10 **	Copyright (c) 2005 - 2010, Holger Zuleger HZnet. All rights reserved.
11 **
12 **	This software is open source.
13 **
14 **	Redistribution and use in source and binary forms, with or without
15 **	modification, are permitted provided that the following conditions
16 **	are met:
17 **
18 **	Redistributions of source code must retain the above copyright notice,
19 **	this list of conditions and the following disclaimer.
20 **
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.
24 **
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.
28 **
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.
40 **
41 *****************************************************************/
42 
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>
50 
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
58 
59 # include "debug.h"
60 # include "misc.h"
61 # include "strlist.h"
62 # include "zconf.h"
63 # include "dki.h"
64 # include "zkt.h"
65 
66 extern  int	optopt;
67 extern  int	opterr;
68 extern  int	optind;
69 extern  char	*optarg;
70 const	char	*progname;
71 
72 char	*labellist = NULL;
73 
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;
84 
85 static	int	dirflag = 0;
86 static	int	recflag = RECURSIVE;
87 static	char	*kskdomain = "";
88 static	const	char	*view = "";
89 
90 # define	short_options	":0:1:2:3:9A:C:D:P:S:R:h:ZV:F:c:O:krz"
91 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
92 static struct option long_options[] = {
93 	{"ksk-rollover",	no_argument, NULL, '9'},
94 	{"ksk-status",		required_argument, NULL, '0'},
95 	{"ksk-roll-status",	required_argument, NULL, '0'},
96 	{"ksk-newkey",		required_argument, NULL, '1'},
97 	{"ksk-publish",		required_argument, NULL, '2'},
98 	{"ksk-delkey",		required_argument, NULL, '3'},
99 	{"ksk-roll-phase1",	required_argument, NULL, '1'},
100 	{"ksk-roll-phase2",	required_argument, NULL, '2'},
101 	{"ksk-roll-phase3",	required_argument, NULL, '3'},
102 	{"ksk",			no_argument, NULL, 'k'},
103 	{"zsk",			no_argument, NULL, 'z'},
104 	{"recursive",		no_argument, NULL, 'r'},
105 	{"config",		required_argument, NULL, 'c'},
106 	{"option",		required_argument, NULL, 'O'},
107 	{"config-option",	required_argument, NULL, 'O'},
108 	{"published",		required_argument, NULL, 'P'},
109 	{"standby",		required_argument, NULL, 'S'},
110 	{"active",		required_argument, NULL, 'A'},
111 	{"depreciated",		required_argument, NULL, 'D'},
112 	{"create",		required_argument, NULL, 'C'},
113 	{"revoke",		required_argument, NULL, 'R'},
114 	{"remove",		required_argument, NULL, 19 },
115 	{"destroy",		required_argument, NULL, 20 },
116 	{"setlifetime",		required_argument, NULL, 'F' },
117 	{"view",		required_argument, NULL, 'V' },
118 	{"help",		no_argument, NULL, 'h'},
119 	{0, 0, 0, 0}
120 };
121 #endif
122 
123 static	int	parsedirectory (const char *dir, dki_t **listp);
124 static	void	parsefile (const char *file, dki_t **listp);
125 static	void	createkey (const char *keyname, const dki_t *list, const zconf_t *conf);
126 static	void	ksk_roll (const char *keyname, int phase, const dki_t *list, const zconf_t *conf);
127 static	int	create_parent_file (const char *fname, int phase, int ttl, const dki_t *dkp);
128 static	void    usage (char *mesg, zconf_t *cp);
129 static	const char *parsetag (const char *str, int *tagp);
130 
setglobalflags(zconf_t * config)131 static	void	setglobalflags (zconf_t *config)
132 {
133 	recflag = config->recursive;
134 }
135 
main(int argc,char * argv[])136 int	main (int argc, char *argv[])
137 {
138 	dki_t	*data = NULL;
139 	dki_t	*dkp;
140 	int	c;
141 	int	opt_index;
142 	int	action;
143 	const	char	*file;
144 	const	char	*defconfname = NULL;
145 	char	*p;
146 	char	str[254+1];
147 	const char	*keyname = NULL;
148 	int		searchtag;
149 	zconf_t	*config;
150 
151 	progname = *argv;
152 	if ( (p = strrchr (progname, '/')) )
153 		progname = ++p;
154 	view = getnameappendix (progname, "dnssec-zkt");
155 
156 	defconfname = getdefconfname (view);
157 	config = loadconfig ("", (zconf_t *)NULL);	/* load built in config */
158 	if ( fileexist (defconfname) )			/* load default config file */
159 		config = loadconfig (defconfname, config);
160 	if ( config == NULL )
161 		fatal ("Out of memory\n");
162 	setglobalflags (config);
163 
164         opterr = 0;
165 	opt_index = 0;
166 	action = 0;
167 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
168 	while ( (c = getopt_long (argc, argv, short_options, long_options, &opt_index)) != -1 )
169 #else
170 	while ( (c = getopt (argc, argv, short_options)) != -1 )
171 #endif
172 	{
173 		switch ( c )
174 		{
175 		case '9':		/* ksk rollover help */
176 			ksk_roll ("help", c - '0', NULL, NULL);
177 			exit (1);
178 		case '1':		/* ksk rollover: create new key */
179 		case '2':		/* ksk rollover: publish DS */
180 		case '3':		/* ksk rollover: delete old key */
181 		case '0':		/* ksk rollover: show current status */
182 			action = c;
183 			if ( !optarg )
184 				usage ("ksk rollover requires an domain argument", config);
185 			kskdomain = domain_canonicdup (optarg);
186 			break;
187 		case 'h':
188 		case 'K':
189 		case 'Z':
190 			action = c;
191 			break;
192 		case 'C':
193 			pathflag = !pathflag;
194 			/* fall through */
195 		case 'P':
196 		case 'S':
197 		case 'A':
198 		case 'D':
199 		case 'R':
200 		case 's':
201 		case 19:
202 		case 20:
203 			if ( (keyname = parsetag (optarg, &searchtag)) != NULL )
204 				keyname = domain_canonicdup (keyname);
205 			action = c;
206 			break;
207 		case 'F':		/* set key lifetime */
208 			lifetime = atoi (optarg);
209 			action = c;
210 			break;
211 		case 'V':		/* view name */
212 			view = optarg;
213 			defconfname = getdefconfname (view);
214 			if ( fileexist (defconfname) )		/* load default config file */
215 				config = loadconfig (defconfname, config);
216 			if ( config == NULL )
217 				fatal ("Out of memory\n");
218 			setglobalflags (config);
219 			break;
220 		case 'c':
221 			config = loadconfig (optarg, config);
222 			setglobalflags (config);
223 			checkconfig (config);
224 			break;
225 		case 'O':		/* read option from commandline */
226 			config = loadconfig_fromstr (optarg, config);
227 			setglobalflags (config);
228 			checkconfig (config);
229 			break;
230 		case 'd':		/* ignore directory arg */
231 			dirflag = 1;
232 			break;
233 		case 'k':		/* ksk only */
234 			zskflag = 0;
235 			break;
236 		case 'r':		/* switch recursive flag */
237 			recflag = !recflag;
238 			break;
239 		case 'z':		/* zsk only */
240 			kskflag = 0;
241 			break;
242 		case ':':
243 			snprintf (str, sizeof(str), "option \"-%c\" requires an argument.\n",
244 										optopt);
245 			usage (str, config);
246 			break;
247 		case '?':
248 			if ( isprint (optopt) )
249 				snprintf (str, sizeof(str), "Unknown option \"-%c\".\n",
250 										optopt);
251 			else
252 				snprintf (str, sizeof (str), "Unknown option char \\x%x.\n",
253 										optopt);
254 			usage (str, config);
255 			break;
256 		default:
257 			abort();
258 		}
259 	}
260 
261 	if ( kskflag == 0 && zskflag == 0 )
262 		kskflag = zskflag = 1;
263 
264 	c = optind;
265 	do {
266 		if ( c >= argc )		/* no args left */
267 			file = config->zonedir;	/* use default directory */
268 		else
269 			file = argv[c++];
270 
271 		if ( is_directory (file) )
272 			parsedirectory (file, &data);
273 		else
274 			parsefile (file, &data);
275 
276 	}  while ( c < argc );	/* for all arguments */
277 
278 	switch ( action )
279 	{
280 	case 'h':
281 		usage ("", config);
282 	case 'C':
283 		createkey (keyname, data, config);
284 		break;
285 	case 'P':
286 	case 'S':
287 	case 'A':
288 	case 'D':
289 		if ( (dkp = (dki_t*)zkt_search (data, searchtag, keyname)) == NULL )
290 			fatal ("Key with tag %u not found\n", searchtag);
291 		else if ( dkp == (void *) 01 )
292 			fatal ("Key with tag %u found multiple times\n", searchtag);
293 		if ( (c = dki_setstatus_preservetime (dkp, action)) != 0 )
294 			fatal ("Couldn't change status of key %u: %d\n", searchtag, c);
295 		break;
296 	case 19:	/* remove (rename) key file */
297 		if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL )
298 			fatal ("Key with tag %u not found\n", searchtag);
299 		else if ( dkp == (void *) 01 )
300 			fatal ("Key with tag %u found multiple times\n", searchtag);
301 		dki_remove (dkp);
302 		break;
303 	case 20:	/* destroy the key (remove the files!) */
304 		if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL )
305 			fatal ("Key with tag %u not found\n", searchtag);
306 		else if ( dkp == (void *) 01 )
307 			fatal ("Key with tag %u found multiple times\n", searchtag);
308 		dki_destroy (dkp);
309 		break;
310 	case 'R':
311 		if ( (dkp = (dki_t *)zkt_search (data, searchtag, keyname)) == NULL )
312 			fatal ("Key with tag %u not found\n", searchtag);
313 		else if ( dkp == (void *) 01 )
314 			fatal ("Key with tag %u found multiple times\n", searchtag);
315 		if ( (c = dki_setstatus (dkp, action)) != 0 )
316 			fatal ("Couldn't change status of key %u: %d\n", searchtag, c);
317 		break;
318 	case '1':	/* ksk rollover new key */
319 	case '2':	/* ksk rollover publish DS */
320 	case '3':	/* ksk rollover delete old key */
321 	case '0':	/* ksk rollover status */
322 		ksk_roll (kskdomain, action - '0', data, config);
323 		break;
324 	case 'F':
325 		zkt_setkeylifetime (data);
326 		/* fall through */
327 	default:
328 		zkt_list_keys (data);
329 	}
330 
331 	return 0;
332 }
333 
334 # define	sopt_usage(mesg, value)	fprintf (stderr, mesg, value)
335 #if defined(HAVE_GETOPT_LONG) && HAVE_GETOPT_LONG
336 # define	lopt_usage(mesg, value)	fprintf (stderr, mesg, value)
337 # define	loptstr(lstr, sstr)	lstr
338 #else
339 # define	lopt_usage(mesg, value)
340 # define	loptstr(lstr, sstr)	sstr
341 #endif
usage(char * mesg,zconf_t * cp)342 static	void    usage (char *mesg, zconf_t *cp)
343 {
344         fprintf (stderr, "DNS Zone Key Management Tool %s\n", ZKT_VERSION);
345         fprintf (stderr, "\n");
346         fprintf (stderr, "Create a new key \n");
347         sopt_usage ("\tusage: %s -C <name> [-k] [-dpr] [-c config] [dir ...]\n", progname);
348         lopt_usage ("\tusage: %s --create=<name> [-k] [-dpr] [-c config] [dir ...]\n", progname);
349         fprintf (stderr, "\t\tKSK (use -k):  %s %d bits\n", dki_algo2str (cp->k_algo), cp->k_bits);
350         fprintf (stderr, "\t\tZSK (default): %s %d bits\n", dki_algo2str (cp->k_algo), cp->z_bits);
351         fprintf (stderr, "\n");
352         fprintf (stderr, "Change key status of specified key to published, active or depreciated\n");
353         fprintf (stderr, "\t(<keyspec> := tag | tag:name) \n");
354         sopt_usage ("\tusage: %s -P|-A|-D <keyspec> [-dr] [-c config] [dir ...]\n", progname);
355         lopt_usage ("\tusage: %s --published=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
356         lopt_usage ("\tusage: %s --active=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
357         lopt_usage ("\tusage: %s --depreciated=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
358         fprintf (stderr, "\n");
359         fprintf (stderr, "Revoke specified key (<keyspec> := tag | tag:name) \n");
360         sopt_usage ("\tusage: %s -R <keyspec> [-dr] [-c config] [dir ...]\n", progname);
361         lopt_usage ("\tusage: %s --revoke=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
362         fprintf (stderr, "\n");
363         fprintf (stderr, "Remove (rename) or destroy (delete) specified key (<keyspec> := tag | tag:name) \n");
364         lopt_usage ("\tusage: %s --remove=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
365         lopt_usage ("\tusage: %s --destroy=<keyspec> [-dr] [-c config] [dir ...]\n", progname);
366         fprintf (stderr, "\n");
367         fprintf (stderr, "Initiate a semi-automated KSK rollover");
368         fprintf (stderr, "('%s -9%s' prints out a brief description)\n", progname, loptstr ("|--ksk-rollover", ""));
369         sopt_usage ("\tusage: %s {-1} do.ma.in.\n", progname);
370         lopt_usage ("\tusage: %s {--ksk-roll-phase1|--ksk-newkey} do.ma.in.\n", progname);
371         sopt_usage ("\tusage: %s {-2} do.ma.in.\n", progname);
372         lopt_usage ("\tusage: %s {--ksk-roll-phase2|--ksk-publish} do.ma.in.\n", progname);
373         sopt_usage ("\tusage: %s {-3} do.ma.in.\n", progname);
374         lopt_usage ("\tusage: %s {--ksk-roll-phase3|--ksk-delkey} do.ma.in.\n", progname);
375         sopt_usage ("\tusage: %s {-0} do.ma.in.\n", progname);
376         lopt_usage ("\tusage: %s {--ksk-roll-status|--ksk-status} do.ma.in.\n", progname);
377         fprintf (stderr, "\n");
378 
379         fprintf (stderr, "\n");
380         fprintf (stderr, "General options \n");
381         fprintf (stderr, "\t-c file%s", loptstr (", --config=file\n", ""));
382 	fprintf (stderr, "\t\t read config from <file> instead of %s\n", CONFIG_FILE);
383         fprintf (stderr, "\t-O optstr%s", loptstr (", --config-option=\"optstr\"\n", ""));
384 	fprintf (stderr, "\t\t read config options from commandline\n");
385         fprintf (stderr, "\t-d%s\t skip directory arguments\n", loptstr (", --directory", "\t"));
386         fprintf (stderr, "\t-r%s\t recursive mode on/off (default: %s)\n", loptstr(", --recursive", "\t"), recflag ? "on": "off");
387         fprintf (stderr, "\t-F days%s=days\t set key lifetime\n", loptstr (", --setlifetime", "\t"));
388         fprintf (stderr, "\t-k%s\t key signing keys only\n", loptstr (", --ksk", "\t"));
389         fprintf (stderr, "\t-z%s\t zone signing keys only\n", loptstr (", --zsk", "\t"));
390         if ( mesg && *mesg )
391                 fprintf (stderr, "%s\n", mesg);
392         exit (1);
393 }
394 
createkey(const char * keyname,const dki_t * list,const zconf_t * conf)395 static	void	createkey (const char *keyname, const dki_t *list, const zconf_t *conf)
396 {
397 	const char *dir = "";
398 	dki_t	*dkp;
399 
400 	if ( keyname == NULL || *keyname == '\0' )
401 		fatal ("Create key: no keyname!");
402 
403 	dbg_val2 ("createkey: keyname %s, pathflag = %d\n", keyname, pathflag);
404 	/* search for already existent key to get the directory name */
405 	if ( pathflag && (dkp = (dki_t *)zkt_search (list, 0, keyname)) != NULL )
406 	{
407 		char    path[MAX_PATHSIZE+1];
408 		zconf_t localconf;
409 
410 		dir = dkp->dname;
411 		pathname (path, sizeof (path), dir, LOCALCONF_FILE, NULL);
412 		if ( fileexist (path) )                 /* load local config file */
413 		{
414 			dbg_val ("Load local config file \"%s\"\n", path);
415 			memcpy (&localconf, conf, sizeof (zconf_t));
416 			conf = loadconfig (path, &localconf);
417 		}
418 	}
419 
420 	if  ( zskflag )
421 		dkp = dki_new (dir, keyname, DKI_ZSK, conf->k_algo, conf->z_bits, conf->z_random, conf->z_life / DAYSEC);
422 	else
423 		dkp = dki_new (dir, keyname, DKI_KSK, conf->k_algo, conf->k_bits, conf->k_random, conf->k_life / DAYSEC);
424 	if ( dkp == NULL )
425 		fatal ("Can't create key %s: %s!\n", keyname, dki_geterrstr ());
426 
427 	/* create a new key always in state published, which means "standby" for ksk */
428 	dki_setstatus (dkp, DKI_PUB);
429 }
430 
get_parent_phase(const char * file)431 static	int	get_parent_phase (const char *file)
432 {
433 	FILE	*fp;
434 	int	phase;
435 
436 	if ( (fp = fopen (file, "r")) == NULL )
437 		return -1;
438 
439 	phase = 0;
440 	if ( fscanf (fp, "; KSK rollover phase%d", &phase) != 1 )
441 		phase = 0;
442 
443 	fclose (fp);
444 	return phase;
445 }
446 
ksk_roll(const char * keyname,int phase,const dki_t * list,const zconf_t * conf)447 static	void	ksk_roll (const char *keyname, int phase, const dki_t *list, const zconf_t *conf)
448 {
449 	char    path[MAX_PATHSIZE+1];
450 	zconf_t localconf;
451 	const char *dir;
452 	dki_t	*keylist;
453 	dki_t	*dkp;
454 	dki_t	*standby;
455 	int	parent_exist;
456 	int	parent_age;
457 	int	parent_phase;
458 	int	parent_propagation;
459 	int	key_ttl;
460 	int	ksk;
461 
462 	if ( phase == 9 )	/* usage */
463 	{
464 		fprintf (stderr, "A KSK rollover requires three consecutive steps:\n");
465 		fprintf (stderr, "\n");
466 		fprintf (stderr, "-1%s", loptstr ("|--ksk-roll-phase1 (--ksk-newkey)\n", ""));
467 		fprintf (stderr, "\t Create a new KSK.\n");
468 		fprintf (stderr, "\t This step also creates a parent-<domain> file which contains only\n");
469 		fprintf (stderr, "\t the _old_ key.  This file will be copied in hierarchical mode\n");
470 		fprintf (stderr, "\t by dnssec-signer to the parent directory as keyset-<domain> file.\n");
471 		fprintf (stderr, "\t Wait until the new keyset is propagated, before going to the next step.\n");
472 		fprintf (stderr, "\n");
473 		fprintf (stderr, "-2%s", loptstr ("|--ksk-roll-phase2 (--ksk-publish)\n", ""));
474 		fprintf (stderr, "\t This step creates a parent-<domain> file with the _new_ key only.\n");
475 		fprintf (stderr, "\t Please send this file immediately to the parent (In hierarchical\n");
476 		fprintf (stderr, "\t mode this will be done automatically by the dnssec-signer command).\n");
477 		fprintf (stderr, "\t Then wait until the new DS is generated by the parent and propagated\n");
478 		fprintf (stderr, "\t to all the parent name server, plus the old DS TTL before going to step three.\n");
479 		fprintf (stderr, "\n");
480 		fprintf (stderr, "-3%s", loptstr ("|--ksk-roll-phase3 (--ksk-delkey)\n", ""));
481 		fprintf (stderr, "\t Remove (rename) the old KSK and the parent-<domain> file.\n");
482 		fprintf (stderr, "\t You have to manually delete the old KSK (look at file names beginning\n");
483 		fprintf (stderr, "\t with an lower 'k').\n");
484 		fprintf (stderr, "\n");
485 		fprintf (stderr, "-0%s", loptstr ("|--ksk-roll-stat (--ksk-status)\n", ""));
486 		fprintf (stderr, "\t Show the current KSK rollover state of a domain.\n");
487 
488 		fprintf (stderr, "\n");
489 
490 		return;
491 	}
492 
493 	if ( keyname == NULL || *keyname == '\0' )
494 		fatal ("ksk rollover: no domain!");
495 
496 	dbg_val2 ("ksk_roll: keyname %s, phase = %d\n", keyname, phase);
497 
498 	/* search for already existent key to get the directory name */
499 	if ( (keylist = (dki_t *)zkt_search (list, 0, keyname)) == NULL )
500 		fatal ("ksk rollover: domain %s not found!\n", keyname);
501 	dkp = keylist;
502 
503 	/* try to read local config file */
504 	dir = dkp->dname;
505 	pathname (path, sizeof (path), dir, LOCALCONF_FILE, NULL);
506 	if ( fileexist (path) )                 /* load local config file */
507 	{
508 		dbg_val ("Load local config file \"%s\"\n", path);
509 		memcpy (&localconf, conf, sizeof (zconf_t));
510 		conf = loadconfig (path, &localconf);
511 	}
512 	key_ttl = conf->key_ttl;
513 
514 	/* check if parent-file already exist */
515 	pathname (path, sizeof (path), dir, "parent-", keyname);
516 	parent_phase = parent_age = 0;
517 	if ( (parent_exist = fileexist (path)) != 0 )
518 	{
519 		parent_phase = get_parent_phase (path);
520 		parent_age = file_age (path);
521 	}
522 	// parent_propagation = 2 * DAYSEC;
523 	parent_propagation = 5 * MINSEC;
524 
525 	ksk = 0;	/* count active(!) key signing keys */
526 	standby = NULL;	/* find standby key if available */
527 	for ( dkp = keylist; dkp; dkp = dkp->next )
528 		if ( dki_isksk (dkp) )
529 		 {
530 			if ( dki_status (dkp) == DKI_ACT )
531 				ksk++;
532 			else if ( dki_status (dkp) == DKI_PUB )
533 				standby = dkp;
534 		}
535 
536 	switch ( phase )
537 	{
538 	case 0:	/* print status (debug) */
539 		fprintf (stdout, "ksk_rollover:\n");
540 		fprintf (stdout, "\t domain = %s\n", keyname);
541 		fprintf (stdout, "\t phase = %d\n", parent_phase);
542 		fprintf (stdout, "\t parent_file %s %s\n", path, parent_exist ? "exist": "not exist");
543 		if ( parent_exist )
544 			fprintf (stdout, "\t age of parent_file %d %s\n", parent_age, str_delspace (age2str (parent_age)));
545 		fprintf (stdout, "\t # of active key signing keys %d\n", ksk);
546 		fprintf (stdout, "\t parent_propagation %d %s\n", parent_propagation, str_delspace (age2str (parent_propagation)));
547 		fprintf (stdout, "\t keys ttl %d %s\n", key_ttl, age2str (key_ttl));
548 
549 		for ( dkp = keylist; dkp; dkp = dkp->next )
550 		{
551 			/* TODO: Nur zum testen */
552 			dki_prt_dnskey (dkp, stdout);
553 		}
554 		break;
555 	case 1:
556 		if ( parent_exist || ksk > 1 )
557 			fatal ("Can\'t create new ksk because there is already an ksk rollover in progress\n");
558 
559 		fprintf (stdout, "create new ksk \n");
560 		dkp = dki_new (dir, keyname, DKI_KSK, conf->k_algo, conf->k_bits, conf->k_random, conf->k_life / DAYSEC);
561 		if ( dkp == NULL )
562 			fatal ("Can't create key %s: %s!\n", keyname, dki_geterrstr ());
563 		if ( standby )
564 		{
565 			dki_setstatus (standby, DKI_ACT);	/* activate standby key */
566 			dki_setstatus (dkp, DKI_PUB);	/* new key will be the new standby */
567 		}
568 
569 		// dkp = keylist;	/* use old key to create the parent file */
570 		if ( (dkp = (dki_t *)dki_findalgo (keylist, 1, conf->k_algo, 'a', 1)) == NULL )	/* find the oldest active ksk to create the parent file */
571 			fatal ("ksk_rollover phase1: Couldn't find the old active key\n");
572 		if ( !create_parent_file (path, phase, key_ttl, dkp) )
573 			fatal ("Couldn't create parentfile %s\n", path);
574 		break;
575 
576 	case 2:
577 		if ( ksk < 2 )
578 			fatal ("Can\'t publish new key because no one exist\n");
579 		if ( !parent_exist )
580 			fatal ("More than one KSK but no parent file found!\n");
581 		if ( parent_phase != 1 )
582 			fatal ("Parent file exists but is in wrong state (phase = %d)\n", parent_phase);
583 		if ( parent_age < conf->proptime + key_ttl )
584 			fatal ("ksk_rollover (phase2): you have to wait for the propagation of the new KSK (at least %dsec or %s)\n",
585 				conf->proptime + key_ttl - parent_age,
586 				str_delspace (age2str (conf->proptime + key_ttl - parent_age)));
587 
588 		fprintf (stdout, "save new ksk in parent file\n");
589 		dkp = keylist->next;	/* set dkp to new ksk */
590 		if ( !create_parent_file (path, phase, key_ttl, dkp) )
591 			fatal ("Couldn't create parentfile %s\n", path);
592 		break;
593 	case 3:
594 		if ( !parent_exist || ksk < 2 )
595 			fatal ("ksk-delkey only allowed after ksk-publish\n");
596 		if ( parent_phase != 2 )
597 			fatal ("Parent file exists but is in wrong state (phase = %d)\n", parent_phase);
598 		if ( parent_age < parent_propagation + key_ttl )
599 			fatal ("ksk_rollover (phase3): you have to wait for DS propagation (at least %dsec or %s)\n",
600 				parent_propagation + key_ttl - parent_age,
601 				str_delspace (age2str (parent_propagation + key_ttl - parent_age)));
602 		/* remove the parentfile */
603 		fprintf (stdout, "remove parentfile \n");
604 		unlink (path);
605 		/* remove or rename the old key */
606 		fprintf (stdout, "old ksk renamed \n");
607 		dkp = keylist;	/* set dkp to old ksk */
608 		dki_remove (dkp);
609 		break;
610 	default:	assert (phase == 1 || phase == 2 || phase == 3);
611 	}
612 }
613 
614 /*****************************************************************
615 **	create_parent_file ()
616 *****************************************************************/
create_parent_file(const char * fname,int phase,int ttl,const dki_t * dkp)617 static	int	create_parent_file (const char *fname, int phase, int ttl, const dki_t *dkp)
618 {
619 	FILE	*fp;
620 
621 	assert ( fname != NULL );
622 
623 	if ( dkp == NULL || (phase != 1 && phase != 2) )
624 		return 0;
625 
626 	if ( (fp = fopen (fname, "w")) == NULL )
627 		fatal ("can\'t create new parentfile \"%s\"\n", fname);
628 
629 	if ( phase == 1 )
630 		fprintf (fp, "; KSK rollover phase1 (old key)\n");
631 	else
632 		fprintf (fp, "; KSK rollover phase2 (new key)\n");
633 
634 	dki_prt_dnskeyttl (dkp, fp, ttl);
635 	fclose (fp);
636 
637 	return phase;
638 }
639 
parsedirectory(const char * dir,dki_t ** listp)640 static	int	parsedirectory (const char *dir, dki_t **listp)
641 {
642 	dki_t	*dkp;
643 	DIR	*dirp;
644 	struct  dirent  *dentp;
645 	char	path[MAX_PATHSIZE+1];
646 
647 	if ( dirflag )
648 		return 0;
649 
650 	dbg_val ("directory: opendir(%s)\n", dir);
651 	if ( (dirp = opendir (dir)) == NULL )
652 		return 0;
653 
654 	while ( (dentp = readdir (dirp)) != NULL )
655 	{
656 		if ( is_dotfilename (dentp->d_name) )
657 			continue;
658 
659 		dbg_val ("directory: check %s\n", dentp->d_name);
660 		pathname (path, sizeof (path), dir, dentp->d_name, NULL);
661 		if ( is_directory (path) && recflag )
662 		{
663 			dbg_val ("directory: recursive %s\n", path);
664 			parsedirectory (path, listp);
665 		}
666 		else if ( is_keyfilename (dentp->d_name) )
667 			if ( (dkp = dki_read (dir, dentp->d_name)) )
668 			{
669 				// fprintf (stderr, "parsedir: tssearch (%d %s)\n", dkp, dkp->name);
670 #if defined (USE_TREE) && USE_TREE
671 				dki_tadd (listp, dkp, 1);
672 #else
673 				dki_add (listp, dkp);
674 #endif
675 			}
676 	}
677 	closedir (dirp);
678 	return 1;
679 }
680 
parsefile(const char * file,dki_t ** listp)681 static	void	parsefile (const char *file, dki_t **listp)
682 {
683 	char	path[MAX_PATHSIZE+1];
684 	dki_t	*dkp;
685 
686 	/* file arg contains path ? ... */
687 	file = splitpath (path, sizeof (path), file);	/* ... then split of */
688 
689 	if ( is_keyfilename (file) )	/* plain file name looks like DNS key file ? */
690 	{
691 		if ( (dkp = dki_read (path, file)) )	/* read DNS key file ... */
692 #if defined (USE_TREE) && USE_TREE
693 			dki_tadd (listp, dkp, 1);		/* ... and add to tree */
694 #else
695 			dki_add (listp, dkp);		/* ... and add to list */
696 #endif
697 		else
698 			error ("error parsing %s: (%s)\n", file, dki_geterrstr());
699 	}
700 }
701 
parsetag(const char * str,int * tagp)702 static	const char *parsetag (const char *str, int *tagp)
703 {
704 	const	char	*p;
705 
706 	*tagp = 0;
707 	while ( isspace (*str) )	/* skip leading ws */
708 		str++;
709 
710 	p = str;
711 	if ( isdigit (*p) )		/* keytag starts with digit */
712 	{
713 		sscanf (p, "%u", tagp);	/* read keytag as number */
714 		do			/* eat up to the end of the number */
715 			p++;
716 		while ( isdigit (*p) );
717 
718 		if ( *p == ':' )	/* label follows ? */
719 			return p+1;	/* return that */
720 		if ( *p == '\0' )
721 			return NULL;	/* no label */
722 	}
723 	return str;	/* return as label string if not a numeric keytag */
724 }
725