1/****************************************************************
2**
3**	@(#) zconf.c -- configuration file parser for dnssec.conf
4**
5**	Most of the code is from the SixXS Heartbeat Client
6**	written by Jeroen Massar <jeroen@sixxs.net>
7**
8**	New config types and many code changes by Holger Zuleger
9**
10**	Copyright (c) Aug 2005, Jeroen Massar.
11**	Copyright (c) Aug 2005 - Apr 2010, Holger Zuleger.
12**	All rights reserved.
13**
14**	This software is open source.
15**
16**	Redistribution and use in source and binary forms, with or without
17**	modification, are permitted provided that the following conditions
18**	are met:
19**
20**	Redistributions of source code must retain the above copyright notice,
21**	this list of conditions and the following disclaimer.
22**
23**	Redistributions in binary form must reproduce the above copyright notice,
24**	this list of conditions and the following disclaimer in the documentation
25**	and/or other materials provided with the distribution.
26**
27**	Neither the name of Jeroen Masar or Holger Zuleger nor the
28**	names of its contributors may be used to endorse or promote products
29**	derived from this software without specific prior written permission.
30**
31**	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32**	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
33**	TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34**	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
35**	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36**	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37**	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38**	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39**	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40**	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41**	POSSIBILITY OF SUCH DAMAGE.
42**
43****************************************************************/
44# include <sys/types.h>
45# include <stdio.h>
46# include <errno.h>
47# include <unistd.h>
48# include <stdlib.h>
49# include <stdarg.h>
50# include <string.h>
51# include <strings.h>
52# include <assert.h>
53# include <ctype.h>
54
55#ifdef HAVE_CONFIG_H
56# include "config.h"
57#endif
58# include "config_zkt.h"
59# include "debug.h"
60# include "misc.h"
61#define extern
62# include "zconf.h"
63#undef extern
64# include "dki.h"
65
66# define	ISTRUE(val)	(strcasecmp (val, "yes") == 0 || \
67				strcasecmp (val, "true") == 0    )
68# define	ISCOMMENT(cp)	(*(cp) == '#' || *(cp) == ';' || \
69				(*(cp) == '/' && *((cp)+1) == '/') )
70# define	ISDELIM(c)	(isspace (c) || (c) == ':' || (c) == '=')
71
72
73# define	cmdln	(0)
74# define	first	(1)
75# define	last	(0x7FFF)
76
77# define	iscmdline(x)	((x)->used_since == cmdln)
78# define	iscompatible(x)	((x)->used_since != cmdln && compversion >= (x)->used_since && \
79				((x)->used_till == 1 || (compversion <= (x)->used_till)))
80
81typedef enum {
82	CONF_END = 0,
83	CONF_STRING,
84	CONF_INT,
85	CONF_TIMEINT,
86	CONF_BOOL,
87	CONF_ALGO,
88	CONF_SERIAL,
89	CONF_FACILITY,
90	CONF_LEVEL,
91	CONF_NSEC3,
92	CONF_COMMENT,
93	CONF_VERSION,
94} ctype_t;
95
96/*****************************************************************
97**	private (static) variables
98*****************************************************************/
99static	int	compversion;
100
101static	zconf_t	def = {
102	ZONEDIR, RECURSIVE,
103	PRINTTIME, PRINTAGE, LJUST, LSCOLORTERM,
104	SIG_VALIDITY, MAX_TTL, KEY_TTL, PROPTIME, Unixtime,
105	RESIGN_INT,
106	KEY_ALGO, ADDITIONAL_KEY_ALGO,
107	KSK_LIFETIME, KSK_BITS, KSK_RANDOM,
108	ZSK_LIFETIME, ZSK_BITS, ZSK_RANDOM,
109	NSEC3_OFF, SALTLEN,
110	NULL, /* viewname cmdline parameter */
111	0, /* noexec cmdline parameter */
112	LOGFILE, LOGLEVEL, LOGDOMAINDIR, SYSLOGFACILITY, SYSLOGLEVEL, VERBOSELOG, 0,
113	DNSKEYFILE, ZONEFILE, KEYSETDIR,
114	LOOKASIDEDOMAIN,
115	SIG_RANDOM, SIG_PSEUDO, SIG_GENDS, SIG_DNSKEY_KSK, SIG_PARAM,
116	DIST_CMD,	/* defaults to NULL which means to run "rndc reload" */
117	NAMED_CHROOT
118};
119
120typedef	struct {
121	char	*label;		/* the name of the paramter */
122	short	used_since;	/* compability (from version; 0 == command line) */
123	short	used_till;	/* compability (to version) */
124	ctype_t	type;		/* the parameter type */
125	void	*var;		/* pointer to the parameter variable */
126	const void	*var2;	/* pointer to a second parameter variable */
127				/* this is a ugly hack needed by cmpconfig () */
128} zconf_para_t;
129
130static	zconf_para_t	confpara[] = {
131	{ "",			first,	last,	CONF_COMMENT,	""},
132	{ "",			first,	last,	CONF_COMMENT,	"\t@(#) dnssec.conf "},
133	{ "",			first,	last,	CONF_VERSION,	"" },
134	{ "",			first,	last,	CONF_COMMENT,	""},
135	{ "",			first,	last,	CONF_COMMENT,	NULL },
136
137	{ "",			first,	99,	CONF_COMMENT,	"dnssec-zkt options" },
138	{ "",			100,	last,	CONF_COMMENT,	"zkt-ls options" },
139	{ "ZoneDir",		first,	last,	CONF_STRING,	&def.zonedir },
140	{ "Recursive",		first,	last,	CONF_BOOL,	&def.recursive },
141	{ "PrintTime",		first,	last,	CONF_BOOL,	&def.printtime },
142	{ "PrintAge",		first,	last,	CONF_BOOL,	&def.printage },
143	{ "LeftJustify",	first,	last,	CONF_BOOL,	&def.ljust },
144	{ "lsColor",		100,	last,	CONF_STRING,	&def.colorterm },
145
146	{ "",			first,	last,	CONF_COMMENT,	NULL },
147	{ "",			first,	last,	CONF_COMMENT,	"zone specific values" },
148	{ "ResignInterval",	first,	last,	CONF_TIMEINT,	&def.resign },
149	{ "SigValidity",	first,	last,	CONF_TIMEINT,	&def.sigvalidity },
150	{ "Max_TTL",		first,	100,	CONF_TIMEINT,	&def.max_ttl },
151	{ "MaximumTTL",		101,	last,	CONF_TIMEINT,	&def.max_ttl },
152	{ "Propagation",	first,	last,	CONF_TIMEINT,	&def.proptime },
153	{ "Key_TTL",		90,	100,	CONF_TIMEINT,	&def.key_ttl },
154	{ "DnsKeyTTL",		101,	last,	CONF_TIMEINT,	&def.key_ttl },
155#if defined (DEF_TTL)
156	{ "def_ttl",		first,	last,	CONF_TIMEINT,	&def.def_ttl },
157#endif
158	{ "SerialFormat",	92,	last,	CONF_SERIAL,	&def.serialform },
159
160	{ "",			first,	last,	CONF_COMMENT,	NULL },
161	{ "",			first,	last,	CONF_COMMENT,	"signing key parameters"},
162	{ "Key_Algo",		99,	100,	CONF_ALGO,	&def.k_algo },	/* now used as general KEY algoritjm (KSK & ZSK) */
163	{ "KeyAlgo",		101,	last,	CONF_ALGO,	&def.k_algo },	/* now used as general KEY algoritjm (KSK & ZSK) */
164	{ "AddKey_Algo",	99,	100,	CONF_ALGO,	&def.k2_algo },		/* second key algorithm added (v0.99) */
165	{ "AddKeyAlgo",		101,	last,	CONF_ALGO,	&def.k2_algo },		/* second key algorithm added (v0.99) */
166	{ "KSK_lifetime",	first,	100,	CONF_TIMEINT,	&def.k_life },
167	{ "KSKlifetime",	101,	last,	CONF_TIMEINT,	&def.k_life },
168	{ "KSK_algo",		first,	98,	CONF_ALGO,	&def.k_algo },	/* old KSK value changed to key algorithm */
169	{ "KSK_bits",		first,	100,	CONF_INT,	&def.k_bits },
170	{ "KSKbits",		101,	last,	CONF_INT,	&def.k_bits },
171	{ "KSK_randfile",	first,	100,	CONF_STRING,	&def.k_random },
172	{ "KSKrandfile",	101,	last,	CONF_STRING,	&def.k_random },
173	{ "ZSK_lifetime",	first,	100,	CONF_TIMEINT,	&def.z_life },
174	{ "ZSKlifetime",	101,	last,	CONF_TIMEINT,	&def.z_life },
175	/* { "ZSK_algo",			1,	CONF_ALGO,	&def.z_algo },		ZSK algo removed (set to same as ksk) */
176	{ "ZSK_algo",		first,	98,	CONF_ALGO,	&def.k2_algo },		/* if someone using it already, map the algo to the additional key algorithm */
177	{ "ZSK_bits",		first,	100,	CONF_INT,	&def.z_bits },
178	{ "ZSKbits",		101,	last,	CONF_INT,	&def.z_bits },
179	{ "ZSK_randfile",	first,	100,	CONF_STRING,	&def.z_random },
180	{ "ZSKrandfile",	101,	last,	CONF_STRING,	&def.z_random },
181	{ "NSEC3",		100,	last,	CONF_NSEC3,	&def.nsec3 },
182	{ "SaltBits",		98,	last,	CONF_INT,	&def.saltbits },
183
184	{ "",			first,	last,	CONF_COMMENT,	NULL },
185	{ "",			first,	99,	CONF_COMMENT,	"dnssec-signer options"},
186	{ "",			100,	last,	CONF_COMMENT,	"zkt-signer options"},
187	{ "--view",		cmdln,	last,	CONF_STRING,	&def.view },
188	{ "--noexec",		cmdln,	last,	CONF_BOOL,	&def.noexec },
189	{ "LogFile",		96,	last,	CONF_STRING,	&def.logfile },
190	{ "LogLevel",		96,	last,	CONF_LEVEL,	&def.loglevel },
191	{ "LogDomainDir",	96,	last,	CONF_STRING,	&def.logdomaindir },
192	{ "SyslogFacility",	96,	last,	CONF_FACILITY,	&def.syslogfacility },
193	{ "SyslogLevel",	96,	last,	CONF_LEVEL,	&def.sysloglevel },
194	{ "VerboseLog",		96,	last,	CONF_INT,	&def.verboselog },
195	{ "-v",			cmdln,	last,	CONF_INT,	&def.verbosity },
196	{ "KeyFile",		first,	last,	CONF_STRING,	&def.keyfile },
197	{ "ZoneFile",		first,	last,	CONF_STRING,	&def.zonefile },
198	{ "KeySetDir",		first,	last,	CONF_STRING,	&def.keysetdir },
199	{ "DLV_Domain",		first,	100,	CONF_STRING,	&def.lookaside },
200	{ "DLVdomain",		101,	last,	CONF_STRING,	&def.lookaside },
201	{ "Sig_Randfile",	first,	100,	CONF_STRING,	&def.sig_random },
202	{ "SigRandfile",	101,	last,	CONF_STRING,	&def.sig_random },
203	{ "Sig_Pseudorand",	first,	100,	CONF_BOOL,	&def.sig_pseudo },
204	{ "SigPseudorand",	101,	last,	CONF_BOOL,	&def.sig_pseudo },
205	{ "Sig_GenerateDS",	first,	100,	CONF_BOOL,	&def.sig_gends },
206	{ "SigGenerateDS",	101,	last,	CONF_BOOL,	&def.sig_gends },
207	{ "Sig_DnsKeyKSK",	99,	100,	CONF_BOOL,	&def.sig_dnskeyksk },
208	{ "SigDnsKeyKSK",	101,	last,	CONF_BOOL,	&def.sig_dnskeyksk },
209	{ "Sig_Parameter",	first,	100,	CONF_STRING,	&def.sig_param },
210	{ "SigParameter",	101,	last,	CONF_STRING,	&def.sig_param },
211	{ "Distribute_Cmd",	97,	100,	CONF_STRING,	&def.dist_cmd },
212	{ "DistributeCmd",	101,	last,	CONF_STRING,	&def.dist_cmd },
213	{ "NamedChrootDir",	99,	last,	CONF_STRING,	&def.chroot_dir },
214
215	{ NULL,			0,	0,	CONF_END,	NULL},
216};
217
218/*****************************************************************
219**	private (static) function deklaration and definition
220*****************************************************************/
221static	const char	*bool2str (int val)
222{
223	return val ? "True" : "False";
224}
225
226static	int set_varptr (char *entry, void *ptr, const void *ptr2)
227{
228	zconf_para_t	*c;
229
230	for ( c = confpara; c->label; c++ )
231		if ( strcasecmp (entry, c->label) == 0 )
232		{
233			c->var = ptr;
234			c->var2 = ptr2;
235			return 1;
236		}
237	return 0;
238}
239
240static	void set_all_varptr (zconf_t *cp, const zconf_t *cp2)
241{
242	set_varptr ("zonedir", &cp->zonedir, cp2 ? &cp2->zonedir: NULL);
243	set_varptr ("recursive", &cp->recursive, cp2 ? &cp2->recursive: NULL);
244	set_varptr ("printage", &cp->printage, cp2 ? &cp2->printage: NULL);
245	set_varptr ("printtime", &cp->printtime, cp2 ? &cp2->printtime: NULL);
246	set_varptr ("leftjustify", &cp->ljust, cp2 ? &cp2->ljust: NULL);
247	set_varptr ("lscolor", &cp->colorterm, cp2 ? &cp2->colorterm: NULL);
248
249	set_varptr ("resigninterval", &cp->resign, cp2 ? &cp2->resign: NULL);
250	set_varptr ("sigvalidity", &cp->sigvalidity, cp2 ? &cp2->sigvalidity: NULL);
251	set_varptr ("max_ttl", &cp->max_ttl, cp2 ? &cp2->max_ttl: NULL);
252	set_varptr ("key_ttl", &cp->key_ttl, cp2 ? &cp2->key_ttl: NULL);
253	set_varptr ("propagation", &cp->proptime, cp2 ? &cp2->proptime: NULL);
254#if defined (DEF_TTL)
255	set_varptr ("def_ttl", &cp->def_ttl, cp2 ? &cp2->def_ttl: NULLl);
256#endif
257	set_varptr ("serialformat", &cp->serialform, cp2 ? &cp2->serialform: NULL);
258
259	set_varptr ("key_algo", &cp->k_algo, cp2 ? &cp2->k_algo: NULL);
260	set_varptr ("addkey_algo", &cp->k2_algo, cp2 ? &cp2->k2_algo: NULL);
261	set_varptr ("ksk_lifetime", &cp->k_life, cp2 ? &cp2->k_life: NULL);
262	set_varptr ("ksk_algo", &cp->k_algo, cp2 ? &cp2->k_algo: NULL);		/* used only in compability mode */
263	set_varptr ("ksk_bits", &cp->k_bits, cp2 ? &cp2->k_bits: NULL);
264	set_varptr ("ksk_randfile", &cp->k_random, cp2 ? &cp2->k_random: NULL);
265
266	set_varptr ("zsk_lifetime", &cp->z_life, cp2 ? &cp2->z_life: NULL);
267	// set_varptr ("zsk_algo", &cp->z_algo, cp2 ? &cp2->z_algo: NULL);
268	set_varptr ("zsk_algo", &cp->k2_algo, cp2 ? &cp2->k2_algo: NULL);
269	set_varptr ("zsk_bits", &cp->z_bits, cp2 ? &cp2->z_bits: NULL);
270	set_varptr ("zsk_randfile", &cp->z_random, cp2 ? &cp2->z_random: NULL);
271	set_varptr ("nsec3", &cp->nsec3, cp2 ? &cp2->nsec3: NULL);
272	set_varptr ("saltbits", &cp->saltbits, cp2 ? &cp2->saltbits: NULL);
273
274	set_varptr ("--view", &cp->view, cp2 ? &cp2->view: NULL);
275	set_varptr ("--noexec", &cp->noexec, cp2 ? &cp2->noexec: NULL);
276	set_varptr ("logfile", &cp->logfile, cp2 ? &cp2->logfile: NULL);
277	set_varptr ("loglevel", &cp->loglevel, cp2 ? &cp2->loglevel: NULL);
278	set_varptr ("logdomaindir", &cp->logdomaindir, cp2 ? &cp2->logdomaindir: NULL);
279	set_varptr ("syslogfacility", &cp->syslogfacility, cp2 ? &cp2->syslogfacility: NULL);
280	set_varptr ("sysloglevel", &cp->sysloglevel, cp2 ? &cp2->sysloglevel: NULL);
281	set_varptr ("verboselog", &cp->verboselog, cp2 ? &cp2->verboselog: NULL);
282	set_varptr ("-v", &cp->verbosity, cp2 ? &cp2->verbosity: NULL);
283	set_varptr ("keyfile", &cp->keyfile, cp2 ? &cp2->keyfile: NULL);
284	set_varptr ("zonefile", &cp->zonefile, cp2 ? &cp2->zonefile: NULL);
285	set_varptr ("keysetdir", &cp->keysetdir, cp2 ? &cp2->keysetdir: NULL);
286	set_varptr ("dlv_domain", &cp->lookaside, cp2 ? &cp2->lookaside: NULL);
287	set_varptr ("sig_randfile", &cp->sig_random, cp2 ? &cp2->sig_random: NULL);
288	set_varptr ("sig_pseudorand", &cp->sig_pseudo, cp2 ? &cp2->sig_pseudo: NULL);
289	set_varptr ("sig_generateds", &cp->sig_gends, cp2 ? &cp2->sig_gends: NULL);
290	set_varptr ("sig_dnskeyksk", &cp->sig_dnskeyksk, cp2 ? &cp2->sig_dnskeyksk: NULL);
291	set_varptr ("sig_parameter", &cp->sig_param, cp2 ? &cp2->sig_param: NULL);
292	set_varptr ("distribute_cmd", &cp->dist_cmd, cp2 ? &cp2->dist_cmd: NULL);
293	set_varptr ("namedchrootdir", &cp->chroot_dir, cp2 ? &cp2->chroot_dir: NULL);
294}
295
296static	void	parseconfigline (char *buf, unsigned int line, zconf_t *z)
297{
298	char		*end, *val, *p;
299	char		*tag;
300	unsigned int	len, found;
301	zconf_para_t	*c;
302
303	assert (buf[0] != '\0');
304
305	p = &buf[strlen(buf)-1];        /* Chop off white space at eol */
306	while ( p >= buf && isspace (*p) )
307		*p-- = '\0';
308
309	for (p = buf; isspace (*p); p++ )	/* Ignore leading white space */
310		;
311
312	/* Ignore comments and emtpy lines */
313	if ( *p == '\0' || ISCOMMENT (p) )
314		return;
315
316	tag = p;
317	/* Get the end of the first argument */
318	end = &buf[strlen(buf)-1];
319	while ( p < end && !ISDELIM (*p) )      /* Skip until delim */
320		p++;
321	*p++ = '\0';    /* Terminate this argument */
322	dbg_val1 ("Parsing \"%s\"\n", tag);
323
324	while ( p < end && ISDELIM (*p) )	/* Skip delim chars */
325		p++;
326
327	val = p;	/* Start of the value */
328	dbg_val1 ("\tgot value \"%s\"\n", val);
329
330	/* If starting with quote, skip until next quote */
331	if ( *p == '"' || *p == '\'' )
332	{
333		p++;    /* Find next quote */
334		while ( p <= end && *p && *p != *val )
335			p++;
336		*p = '\0';
337		val++;          /* Skip the first quote */
338	}
339	else    /* Otherwise check if there is any comment char at the end */
340	{
341		while ( p < end && *p && !ISCOMMENT(p) )
342			p++;
343		if ( ISCOMMENT (p) )
344		{
345			do      /* Chop off white space before comment */
346				*p-- = '\0';
347			while ( p >= val && isspace (*p) );
348		}
349	}
350
351	/* Otherwise it is already terminated above */
352	found = 0;
353	c = confpara;
354	while ( !found && c->type != CONF_END )
355	{
356		len = strlen (c->label);
357		if ( strcasecmp (tag, c->label) == 0 )
358		{
359			char	**str;
360			char	quantity;
361			long	lval;
362
363			found = 1;
364			switch ( c->type )
365			{
366			case CONF_VERSION:
367				break;
368			case CONF_LEVEL:
369			case CONF_FACILITY:
370			case CONF_STRING:
371				str = (char **)c->var;
372				*str = strdup (val);
373				str_untaint (*str);	/* remove "bad" characters */
374				break;
375			case CONF_INT:
376				sscanf (val, "%d", (int *)c->var);
377				break;
378			case CONF_TIMEINT:
379				quantity = 'd';
380				if ( *val == 'u' || *val == 'U' )
381					lval = 0L;
382				else
383					sscanf (val, "%ld%c", &lval, &quantity);
384				if  ( quantity == 'm' )
385					lval *= MINSEC;
386				else if  ( quantity == 'h' )
387					lval *= HOURSEC;
388				else if  ( quantity == 'd' )
389					lval *= DAYSEC;
390				else if  ( quantity == 'w' )
391					lval *= WEEKSEC;
392				else if  ( quantity == 'y' )
393					lval *= YEARSEC;
394				(*(long *)c->var) = lval;
395				break;
396			case CONF_ALGO:
397				if ( strcmp (val, "1") == 0 || strcasecmp (val, "rsa") == 0 ||
398								strcasecmp (val, "rsamd5") == 0 )
399					*((int *)c->var) = DK_ALGO_RSA;
400				else if ( strcmp (val, "3") == 0 ||
401					  strcasecmp (val, "dsa") == 0 )
402					*((int *)c->var) = DK_ALGO_DSA;
403				else if ( strcmp (val, "5") == 0 ||
404					  strcasecmp (val, "rsasha1") == 0 )
405					*((int *)c->var) = DK_ALGO_RSASHA1;
406				else if ( strcmp (val, "6") == 0 ||
407					  strcasecmp (val, "nsec3dsa") == 0 ||
408				          strcasecmp (val, "n3dsa") == 0 )
409					*((int *)c->var) = DK_ALGO_NSEC3DSA;
410				else if ( strcmp (val, "7") == 0 ||
411					  strcasecmp (val, "nsec3rsasha1") == 0 ||
412					  strcasecmp (val, "n3rsasha1") == 0 )
413					*((int *)c->var) = DK_ALGO_NSEC3RSASHA1;
414#if defined(BIND_VERSION) && BIND_VERSION >= 970
415				else if ( strcmp (val, "8") == 0 ||
416					  strcasecmp (val, "rsasha2") == 0 ||
417				          strcasecmp (val, "rsasha256") == 0 ||
418					  strcasecmp (val, "nsec3rsasha2") == 0 ||
419					  strcasecmp (val, "n3rsasha2") == 0 ||
420					  strcasecmp (val, "nsec3rsasha256") == 0 ||
421					  strcasecmp (val, "n3rsasha256") == 0 )
422					*((int *)c->var) = DK_ALGO_RSASHA256;
423				else if ( strcmp (val, "10") == 0 ||
424					  strcasecmp (val, "rsasha5") == 0 ||
425				          strcasecmp (val, "rsasha212") == 0 ||
426					  strcasecmp (val, "nsec3rsasha5") == 0 ||
427					  strcasecmp (val, "n3rsasha5") == 0 ||
428					  strcasecmp (val, "nsec3rsasha512") == 0 ||
429					  strcasecmp (val, "n3rsasha512") == 0 )
430					*((int *)c->var) = DK_ALGO_RSASHA512;
431#endif
432				else
433					error ("Illegal algorithm \"%s\" "
434						"in line %d.\n" , val, line);
435				break;
436			case CONF_SERIAL:
437				if ( strcasecmp (val, "unixtime") == 0 )
438					*((serial_form_t *)c->var) = Unixtime;
439				else if ( strcasecmp (val, "incremental") == 0 || strcasecmp (val, "inc") == 0 )
440					*((serial_form_t *)c->var) = Incremental;
441				else
442					error ("Illegal serial no format \"%s\" "
443						"in line %d.\n" , val, line);
444				break;
445			case CONF_NSEC3:
446				if ( strcasecmp (val, "off") == 0 )
447					*((nsec3_t *)c->var) = NSEC3_OFF;
448				else if ( strcasecmp (val, "on") == 0 )
449					*((nsec3_t *)c->var) = NSEC3_ON;
450				else if ( strcasecmp (val, "optout") == 0 )
451					*((nsec3_t *)c->var) = NSEC3_OPTOUT;
452				else
453					error ("Illegal NSEC3 format \"%s\" "
454						"in line %d.\n" , val, line);
455				break;
456			case CONF_BOOL:
457				*((int *)c->var) = ISTRUE (val);
458				break;
459			default:
460				fatal ("Illegal configuration type in line %d.\n", line);
461			}
462		}
463		c++;
464	}
465	if ( !found )
466		error ("Unknown configuration statement: %s \"%s\"\n", tag, val);
467	return;
468}
469
470static	void	printconfigline (FILE *fp, zconf_para_t *cp)
471{
472	int	i;
473	long	lval;
474
475	assert (fp != NULL);
476	assert (cp != NULL);
477
478	switch ( cp->type )
479	{
480	case CONF_VERSION:
481			fprintf (fp, "#\tZKT config file for version %d.%02d\n",
482						compversion / 100, compversion % 100);
483		break;
484	case CONF_COMMENT:
485		if ( cp->var )
486			fprintf (fp, "#   %s\n", (char *)cp->var);
487		else
488			fprintf (fp, "\n");
489		break;
490	case CONF_LEVEL:
491	case CONF_FACILITY:
492		if ( *(char **)cp->var != NULL )
493		{
494			if ( **(char **)cp->var != '\0' )
495			{
496				char	*p;
497
498				fprintf (fp, "%s:\t", cp->label);
499				for ( p = *(char **)cp->var; *p; p++ )
500					putc (toupper (*p), fp);
501				fprintf (fp, "\n");
502			}
503			else
504				fprintf (fp, "%s:\tNONE", cp->label);
505		}
506		break;
507	case CONF_STRING:
508		if ( *(char **)cp->var )
509			fprintf (fp, "%s:\t\"%s\"\n", cp->label, *(char **)cp->var);
510		break;
511	case CONF_BOOL:
512		fprintf (fp, "%s:\t%s\n", cp->label, bool2str ( *(int*)cp->var ));
513		break;
514	case CONF_TIMEINT:
515		lval = *(ulong*)cp->var;	/* in that case it should be of type ulong */
516		fprintf (fp, "%s:\t%s", cp->label, timeint2str (lval));
517		if ( lval )
518			fprintf (fp, "\t\t# (%ld seconds)", lval);
519		putc ('\n', fp);
520		break;
521	case CONF_ALGO:
522		i = *(int*)cp->var;
523		if ( i )
524		{
525			fprintf (fp, "%s:\t%s ", cp->label, dki_algo2str (i));
526			fprintf (fp, "\t# (Algorithm ID %d)\n", i);
527		}
528		break;
529	case CONF_SERIAL:
530		fprintf (fp, "%s:\t", cp->label);
531		if ( *(serial_form_t*)cp->var == Unixtime )
532			fprintf (fp, "UnixTime");
533		else
534			fprintf (fp, "Incremental");
535		fprintf (fp, "\t# (UnixTime|Incremental)\n");
536		break;
537	case CONF_NSEC3:
538		fprintf (fp, "%s:\t\t", cp->label);
539		if ( *(nsec3_t*)cp->var == NSEC3_OFF )
540			fprintf (fp, "Off");
541		else if ( *(nsec3_t*)cp->var == NSEC3_ON )
542			fprintf (fp, "On");
543		else if ( *(nsec3_t*)cp->var == NSEC3_OPTOUT )
544			fprintf (fp, "OptOut");
545		fprintf (fp, "\t\t# (On|Off|OptOut)\n");
546		break;
547	case CONF_INT:
548		fprintf (fp, "%s:\t%d\n", cp->label, *(int *)cp->var);
549		break;
550	case CONF_END:
551		/* NOTREACHED */
552		break;
553	}
554}
555
556/*****************************************************************
557**	public function definition
558*****************************************************************/
559
560void	setconfigversion (int version)
561{
562	compversion = version;
563}
564
565const char	*timeint2str (unsigned long val)
566{
567	static	char	str[20+1];
568
569	if ( val == 0 )
570		snprintf (str, sizeof (str), "Unset");
571	else if ( val % YEARSEC == 0 )
572		snprintf (str, sizeof (str), "%luy", val / YEARSEC);
573	else if ( val % WEEKSEC == 0 )
574		snprintf (str, sizeof (str), "%luw", val / WEEKSEC);
575	else if ( val % DAYSEC == 0 )
576		snprintf (str, sizeof (str), "%lud", val / DAYSEC);
577	else if ( val % HOURSEC == 0 )
578		snprintf (str, sizeof (str), "%luh", val / HOURSEC);
579	else if ( val % MINSEC == 0 )
580		snprintf (str, sizeof (str), "%lum", val / MINSEC);
581	else
582		snprintf (str, sizeof (str), "%lus", val);
583
584	return str;
585}
586
587
588/*****************************************************************
589**	loadconfig (file, conf)
590**	Loads a config file into the "conf" structure pointed to by "z".
591**	If "z" is NULL then a new conf struct will be dynamically
592**	allocated.
593**	If no filename is given the conf struct will be initialized
594**	with the builtin default config
595*****************************************************************/
596zconf_t	*loadconfig (const char *filename, zconf_t *z)
597{
598	FILE		*fp;
599	char		buf[1023+1];
600	unsigned int	line;
601
602	if ( z == NULL )	/* allocate new memory for zconf_t */
603	{
604		if ( (z = calloc (1, sizeof (zconf_t))) == NULL )
605			return NULL;
606
607		if ( filename && *filename )
608			memcpy (z, &def, sizeof (zconf_t));	/* init new struct with defaults */
609	}
610
611	if ( filename == NULL || *filename == '\0' )	/* no file name given... */
612	{
613		dbg_val0("loadconfig (NULL)\n");
614		memcpy (z, &def, sizeof (zconf_t));		/* ..then init with defaults */
615		return z;
616	}
617
618	dbg_val1 ("loadconfig (%s)\n", filename);
619	set_all_varptr (z, NULL);
620
621	if ( (fp = fopen(filename, "r")) == NULL )
622		fatal ("Could not open config file \"%s\"\n", filename);
623
624	line = 0;
625	while (fgets(buf, sizeof(buf), fp))
626		parseconfigline (buf, ++line, z);
627
628	fclose(fp);
629	return z;
630}
631
632# define	STRCONFIG_DELIMITER	";\r\n"
633zconf_t	*loadconfig_fromstr (const char *str, zconf_t *z)
634{
635	char		*buf;
636	char		*tok,	*toksave;
637	unsigned int	line;
638
639	if ( z == NULL )
640	{
641		if ( (z = calloc (1, sizeof (zconf_t))) == NULL )
642			return NULL;
643		memcpy (z, &def, sizeof (zconf_t));		/* init with defaults */
644	}
645
646	if ( str == NULL || *str == '\0' )
647	{
648		dbg_val0("loadconfig_fromstr (NULL)\n");
649		memcpy (z, &def, sizeof (zconf_t));		/* init with defaults */
650		return z;
651	}
652
653	dbg_val1 ("loadconfig_fromstr (\"%s\")\n", str);
654	set_all_varptr (z, NULL);
655
656	/* str is const, so we have to copy it into a new buffer */
657	if ( (buf = strdup (str)) == NULL )
658		fatal ("loadconfig_fromstr: Out of memory");
659
660	line = 0;
661	tok = strtok_r (buf, STRCONFIG_DELIMITER, &toksave);
662	while ( tok )
663	{
664		line++;
665		parseconfigline (tok, line, z);
666		tok = strtok_r (NULL, STRCONFIG_DELIMITER, &toksave);
667	}
668	free (buf);
669	return z;
670}
671
672/*****************************************************************
673**	dupconfig (config)
674**	duplicate config struct and return a ptr to the new struct
675*****************************************************************/
676zconf_t	*dupconfig (const zconf_t *conf)
677{
678	zconf_t	*z;
679
680	assert (conf != NULL);
681
682	if ( (z = calloc (1, sizeof (zconf_t))) == NULL )
683		return NULL;
684
685	memcpy (z, conf, sizeof (zconf_t));
686
687	return z;
688}
689
690/*****************************************************************
691**	freeconfig (config)
692**	free memory for config struct and return a NULL ptr
693*****************************************************************/
694zconf_t	*freeconfig (zconf_t *conf)
695{
696	if (conf != NULL);
697		free (conf);
698
699	return (zconf_t *)NULL;
700}
701
702/*****************************************************************
703**	setconfigpar (entry, pval)
704*****************************************************************/
705int	setconfigpar (zconf_t *config, char *entry, const void *pval)
706{
707	char	*str;
708	zconf_para_t	*c;
709
710	set_all_varptr (config, NULL);
711
712	for ( c = confpara; c->type != CONF_END; c++ )
713		if ( strcasecmp (entry, c->label) == 0 )
714		{
715			switch ( c->type )
716			{
717			case CONF_VERSION:
718				break;
719			case CONF_LEVEL:
720			case CONF_FACILITY:
721			case CONF_STRING:
722				if ( pval )
723				{
724					str = strdup ((char *)pval);
725					str_untaint (str);	/* remove "bad" characters */
726				}
727				else
728					str = NULL;
729				*((char **)c->var) = str;
730				break;
731			case CONF_BOOL:
732				/* fall through */
733			case CONF_ALGO:
734				/* fall through */
735			case CONF_INT:
736				*((int *)c->var) = *((int *)pval);
737				break;
738			case CONF_TIMEINT:
739				*((long *)c->var) = *((long *)pval);
740				break;
741			case CONF_NSEC3:
742				*((nsec3_t *)c->var) = *((nsec3_t *)pval);
743				break;
744			case CONF_SERIAL:
745				*((serial_form_t *)c->var) = *((serial_form_t *)pval);
746				break;
747			case CONF_COMMENT:
748			case CONF_END:
749				/* NOTREACHED */
750				break;
751			}
752			return 1;
753		}
754	return 0;
755}
756
757/*****************************************************************
758**	printconfig (fname, config)
759*****************************************************************/
760int	printconfig (const char *fname, const zconf_t *z)
761{
762	zconf_para_t	*cp;
763	FILE	*fp;
764
765	if ( z == NULL )
766		return 0;
767
768	fp = stdout;
769	if ( fname && *fname )
770	{
771		if ( strcmp (fname, "stdout") == 0 )
772			fp = stdout;
773		else if ( strcmp (fname, "stderr") == 0 )
774			fp = stderr;
775		else if ( (fp = fopen(fname, "w")) == NULL )
776		{
777			error ("Could not open config file \"%s\" for writing\n", fname);
778			return -1;
779		}
780	}
781
782	set_all_varptr ((zconf_t *)z, NULL);
783
784	for ( cp = confpara; cp->type != CONF_END; cp++ )	/* loop through all parameter */
785		if ( iscompatible (cp) )	/* is parameter compatible to current version? */
786			printconfigline (fp, cp);	/* print it out */
787
788	if ( fp && fp != stdout && fp != stderr )
789		fclose (fp);
790
791	return 1;
792}
793
794/*****************************************************************
795**	printconfigdiff (fname, conf_a, conf_b)
796*****************************************************************/
797int	printconfigdiff (const char *fname, const zconf_t *ref, const zconf_t *z)
798{
799	zconf_para_t	*cp;
800	int	eq;
801	char	*p1,	*p2;
802	FILE	*fp;
803
804	if ( ref == NULL || z == NULL )
805		return 0;
806
807	fp = NULL;
808	if ( fname && *fname )
809	{
810		if ( strcmp (fname, "stdout") == 0 )
811			fp = stdout;
812		else if ( strcmp (fname, "stderr") == 0 )
813			fp = stderr;
814		else if ( (fp = fopen(fname, "w")) == NULL )
815		{
816			error ("Could not open config file \"%s\" for writing\n", fname);
817			return -1;
818		}
819	}
820
821	set_all_varptr ((zconf_t *)z, ref);
822
823	for ( cp = confpara; cp->type != CONF_END; cp++ )	/* loop through all parameter */
824	{
825		eq = 0;
826		if ( iscmdline (cp) )	/* skip command line parameter */
827			continue;
828
829		switch ( cp->type )
830		{
831		case CONF_VERSION:
832		case CONF_END:
833		case CONF_COMMENT:
834			continue;
835		case CONF_NSEC3:
836			eq = ( *(nsec3_t *)cp->var == *(nsec3_t *)cp->var2 );
837			break;
838		case CONF_SERIAL:
839			eq = ( *(serial_form_t *)cp->var == *(serial_form_t *)cp->var2 );
840			break;
841		case CONF_BOOL:
842		case CONF_ALGO:
843		case CONF_INT:
844			eq = ( *(int *)cp->var == *(int *)cp->var2 );
845			break;
846		case CONF_TIMEINT:
847			eq = ( *(long *)cp->var == *(long *)cp->var2 );
848			break;
849		case CONF_LEVEL:
850		case CONF_FACILITY:
851		case CONF_STRING:
852			p1 = *(char **)cp->var;
853			p2 = *(char **)cp->var2;
854			if ( p1 && p2 )
855				eq = strcmp (p1, p2) == 0;
856			else if ( p1 == NULL || p2 == NULL )
857				eq = 0;
858			else
859				eq = 1;
860		}
861		if ( !eq )
862			printconfigline (fp, cp);	/* print it out */
863	}
864
865	if ( fp && fp != stdout && fp != stderr )
866		fclose (fp);
867
868	return 1;
869}
870
871/*****************************************************************
872**	checkconfig (config)
873*****************************************************************/
874int	checkconfig (const zconf_t *z)
875{
876	int	ret;
877	long	max_ttl;
878
879	if ( z == NULL )
880		return 1;
881
882	max_ttl = z->max_ttl;
883	if ( max_ttl <= 0 )
884		max_ttl = z->sigvalidity;
885
886	ret = 0;
887	if ( strcmp (z->k_random, "/dev/urandom") == 0 )
888		ret = fprintf (stderr, "random device without enough entropie used for KSK generation \n");
889	if ( strcmp (z->z_random, "/dev/urandom") == 0 )
890		ret = fprintf (stderr, "random device without enough entropie used for ZSK generation\n");
891
892	if ( z->saltbits < 4 )
893		ret = fprintf (stderr, "Saltlength must be at least 4 bits\n");
894	if ( z->saltbits > 128 )
895	{
896		fprintf (stderr, "While the maximum is 520 bits of salt, it's not recommended to use more than 128 bits.\n");
897		ret = fprintf (stderr, "The current value is %d bits\n", z->saltbits);
898	}
899
900	if ( z->sigvalidity < (1 * DAYSEC) || z->sigvalidity > (12 * WEEKSEC) )
901	{
902		fprintf (stderr, "Signature should be valid for at least 1 day and no longer than 3 month (12 weeks)\n");
903		ret = fprintf (stderr, "The current value is %s\n", timeint2str (z->sigvalidity));
904	}
905
906	if ( z->max_ttl <= 0 )
907	{
908		ret = fprintf (stderr, "The max TTL is unknown which results in suboptimal key rollover.\n");
909		fprintf (stderr, "Please set max_ttl to the maximum ttl used in the zone (run zkt-conf -w zone.db)\n");
910	}
911	else
912		if ( max_ttl > z->sigvalidity/2 )
913			ret = fprintf (stderr, "Max TTL (%ld) should be less or equal signature validity (%ld)\n",
914								max_ttl, z->sigvalidity);
915
916	// if ( z->resign > (z->sigvalidity*5/6) - (max_ttl + z->proptime) )
917	if ( z->resign > (z->sigvalidity*5/6) )
918	{
919		fprintf (stderr, "Re-signing interval (%s) should be less than ", timeint2str (z->resign));
920		ret = fprintf (stderr, "5/6 of sigvalidity (%s)\n", timeint2str (z->sigvalidity));
921	}
922
923	if ( z->max_ttl > 0 && z->resign > (z->sigvalidity - max_ttl) )
924	{
925		fprintf (stderr, "Re-signing interval (%s) should be ", timeint2str (z->resign));
926		fprintf (stderr, "end at least one max_ttl (%ld) before the end of ", max_ttl);
927		ret = fprintf (stderr, "signature lifetime (%ld) (%s)\n", z->sigvalidity, timeint2str(z->sigvalidity - max_ttl));
928	}
929
930	if ( z->z_life > (12 * WEEKSEC) * (z->z_bits / 512.) )
931	{
932		fprintf (stderr, "Lifetime of zone signing key (%s) ", timeint2str (z->z_life));
933		fprintf (stderr, "seems a little bit high ");
934		ret = fprintf (stderr, "(In respect of key size (%d))\n", z->z_bits);
935	}
936
937	if ( z->k_life > 0 && z->k_life <= z->z_life )
938	{
939		fprintf (stderr, "Lifetime of key signing key (%s) ", timeint2str (z->k_life));
940		ret = fprintf (stderr, "should be greater than lifetime of zsk\n");
941	}
942	if ( z->k_life > 0 && z->k_life > (26 * WEEKSEC) * (z->k_bits / 512.) )
943	{
944		fprintf (stderr, "Lifetime of key signing key (%s) ", timeint2str (z->k_life));
945		fprintf (stderr, "seems a little bit high ");
946		ret = fprintf (stderr, "(In respect of key size (%d))\n", z->k_bits);
947	}
948
949	return !ret;
950}
951
952#ifdef CONF_TEST
953const char *progname;
954static	zconf_t	*config;
955
956main (int argc, char *argv[])
957{
958	char	*optstr;
959	int	val;
960
961	progname = *argv;
962
963	config = loadconfig ("", (zconf_t *) NULL);	/* load built in defaults */
964
965	while ( --argc >= 1 )
966	{
967		optstr = *++argv;
968		config = loadconfig_fromstr (optstr, config);
969	}
970
971	val = 1;
972	setconfigpar (config, "-v", &val);
973	val = 2;
974	setconfigpar (config, "verboselog", &val);
975	val = 1;
976	setconfigpar (config, "recursive", &val);
977	val = 1200;
978	setconfigpar (config, "propagation", &val);
979
980	printconfig ("stdout", config);
981}
982#endif
983