1 /****************************************************************
3 ** @(#) zconf.c -- configuration file parser for dnssec.conf
5 ** Most of the code is from the SixXS Heartbeat Client
6 ** written by Jeroen Massar <jeroen@sixxs.net>
8 ** New config types and some slightly code changes by Holger Zuleger
10 ** Copyright (c) Aug 2005, Jeroen Massar, Holger Zuleger.
11 ** All rights reserved.
13 ** This software is open source.
15 ** Redistribution and use in source and binary forms, with or without
16 ** modification, are permitted provided that the following conditions
19 ** Redistributions of source code must retain the above copyright notice,
20 ** this list of conditions and the following disclaimer.
22 ** Redistributions in binary form must reproduce the above copyright notice,
23 ** this list of conditions and the following disclaimer in the documentation
24 ** and/or other materials provided with the distribution.
26 ** Neither the name of Jeroen Masar or Holger Zuleger nor the
27 ** names of its contributors may be used to endorse or promote products
28 ** derived from this software without specific prior written permission.
30 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33 ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
34 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40 ** POSSIBILITY OF SUCH DAMAGE.
42 ****************************************************************/
43 # include <sys/types.h>
57 # include "config_zkt.h"
65 # define ISTRUE(val) (strcasecmp (val, "yes") == 0 || \
66 strcasecmp (val, "true") == 0 )
67 # define ISCOMMENT(cp) (*(cp) == '#' || *(cp) == ';' || \
68 (*(cp) == '/' && *((cp)+1) == '/') )
69 # define ISDELIM(c) ( isspace (c) || (c) == ':' || (c) == '=' )
85 /*****************************************************************
86 ** private (static) variables
87 *****************************************************************/
88 static zconf_t def = {
90 PRINTTIME, PRINTAGE, LJUST,
91 SIG_VALIDITY, MAX_TTL, KEY_TTL, PROPTIME, Incremental,
93 KEY_ALGO, ADDITIONAL_KEY_ALGO,
94 KSK_LIFETIME, KSK_BITS, KSK_RANDOM,
95 ZSK_LIFETIME, ZSK_BITS, ZSK_RANDOM,
97 NULL, /* viewname cmdline parameter */
98 0, /* noexec cmdline parameter */
99 LOGFILE, LOGLEVEL, SYSLOGFACILITY, SYSLOGLEVEL, VERBOSELOG, 0,
100 DNSKEYFILE, ZONEFILE, KEYSETDIR,
102 SIG_RANDOM, SIG_PSEUDO, SIG_GENDS, SIG_PARAM,
103 DIST_CMD, /* defaults to NULL which means to run "rndc reload" */
108 char *label; /* the name of the paramter */
109 int cmdline; /* is this a command line parameter ? */
110 ctype_t type; /* the parameter type */
111 void *var; /* pointer to the parameter variable */
114 static zconf_para_t confpara[] = {
115 { "", 0, CONF_COMMENT, ""},
116 { "", 0, CONF_COMMENT, "\t@(#) dnssec.conf " ZKT_VERSION },
117 { "", 0, CONF_COMMENT, ""},
118 { "", 0, CONF_COMMENT, NULL },
120 { "", 0, CONF_COMMENT, "dnssec-zkt options" },
121 { "Zonedir", 0, CONF_STRING, &def.zonedir },
122 { "Recursive", 0, CONF_BOOL, &def.recursive },
123 { "PrintTime", 0, CONF_BOOL, &def.printtime },
124 { "PrintAge", 0, CONF_BOOL, &def.printage },
125 { "LeftJustify", 0, CONF_BOOL, &def.ljust },
127 { "", 0, CONF_COMMENT, NULL },
128 { "", 0, CONF_COMMENT, "zone specific values" },
129 { "ResignInterval", 0, CONF_TIMEINT, &def.resign },
130 { "Sigvalidity", 0, CONF_TIMEINT, &def.sigvalidity },
131 { "Max_TTL", 0, CONF_TIMEINT, &def.max_ttl },
132 { "Propagation", 0, CONF_TIMEINT, &def.proptime },
133 { "KEY_TTL", 0, CONF_TIMEINT, &def.key_ttl },
134 #if defined (DEF_TTL)
135 { "def_ttl", 0, CONF_TIMEINT, &def.def_ttl },
137 { "Serialformat", 0, CONF_SERIAL, &def.serialform },
139 { "", 0, CONF_COMMENT, NULL },
140 { "", 0, CONF_COMMENT, "signing key parameters"},
141 { "Key_algo", 0, CONF_ALGO, &def.k_algo }, /* now used as general KEY algoritjm (KSK & ZSK) */
142 { "AddKey_algo", 0, CONF_ALGO, &def.k2_algo }, /* second key algorithm added (v0.99) */
143 { "KSK_lifetime", 0, CONF_TIMEINT, &def.k_life },
144 { "KSK_algo", 1, CONF_ALGO, &def.k_algo }, /* old KSK value changed to key algorithm */
145 { "KSK_bits", 0, CONF_INT, &def.k_bits },
146 { "KSK_randfile", 0, CONF_STRING, &def.k_random },
147 { "ZSK_lifetime", 0, CONF_TIMEINT, &def.z_life },
148 /* { "ZSK_algo", 1, CONF_ALGO, &def.z_algo }, ZSK algo removed (set to same as ksk) */
149 { "ZSK_algo", 1, CONF_ALGO, &def.k2_algo }, /* if someone using it already, map the algo to the additional key algorithm */
150 { "ZSK_bits", 0, CONF_INT, &def.z_bits },
151 { "ZSK_randfile", 0, CONF_STRING, &def.z_random },
152 { "SaltBits", 0, CONF_INT, &def.saltbits },
154 { "", 0, CONF_COMMENT, NULL },
155 { "", 0, CONF_COMMENT, "dnssec-signer options"},
156 { "--view", 1, CONF_STRING, &def.view },
157 { "--noexec", 1, CONF_BOOL, &def.noexec },
158 { "LogFile", 0, CONF_STRING, &def.logfile },
159 { "LogLevel", 0, CONF_LEVEL, &def.loglevel },
160 { "SyslogFacility", 0, CONF_FACILITY, &def.syslogfacility },
161 { "SyslogLevel", 0, CONF_LEVEL, &def.sysloglevel },
162 { "VerboseLog", 0, CONF_INT, &def.verboselog },
163 { "-v", 1, CONF_INT, &def.verbosity },
164 { "Keyfile", 0, CONF_STRING, &def.keyfile },
165 { "Zonefile", 0, CONF_STRING, &def.zonefile },
166 { "KeySetDir", 0, CONF_STRING, &def.keysetdir },
167 { "DLV_Domain", 0, CONF_STRING, &def.lookaside },
168 { "Sig_Randfile", 0, CONF_STRING, &def.sig_random },
169 { "Sig_Pseudorand", 0, CONF_BOOL, &def.sig_pseudo },
170 { "Sig_GenerateDS", 0, CONF_BOOL, &def.sig_gends },
171 { "Sig_Parameter", 0, CONF_STRING, &def.sig_param },
172 { "Distribute_Cmd", 0, CONF_STRING, &def.dist_cmd },
173 { "NamedChrootDir", 0, CONF_STRING, &def.chroot_dir },
175 { NULL, 0, CONF_END, NULL},
178 /*****************************************************************
179 ** private (static) function deklaration and definition
180 *****************************************************************/
181 static const char *bool2str (int val)
183 return val ? "True" : "False";
186 static const char *timeint2str (ulong val)
188 static char str[20+1];
191 snprintf (str, sizeof (str), "%lu", val / YEARSEC);
192 else if ( val % YEARSEC == 0 )
193 snprintf (str, sizeof (str), "%luy", val / YEARSEC);
194 else if ( val % WEEKSEC == 0 )
195 snprintf (str, sizeof (str), "%luw", val / WEEKSEC);
196 else if ( val % DAYSEC == 0 )
197 snprintf (str, sizeof (str), "%lud", val / DAYSEC);
198 else if ( val % HOURSEC == 0 )
199 snprintf (str, sizeof (str), "%luh", val / HOURSEC);
200 else if ( val % MINSEC == 0 )
201 snprintf (str, sizeof (str), "%lum", val / MINSEC);
203 snprintf (str, sizeof (str), "%lus", val);
208 static int set_varptr (char *entry, void *ptr)
212 for ( c = confpara; c->label; c++ )
213 if ( strcasecmp (entry, c->label) == 0 )
221 static void set_all_varptr (zconf_t *cp)
223 set_varptr ("zonedir", &cp->zonedir);
224 set_varptr ("recursive", &cp->recursive);
225 set_varptr ("printage", &cp->printage);
226 set_varptr ("printtime", &cp->printtime);
227 set_varptr ("leftjustify", &cp->ljust);
229 set_varptr ("resigninterval", &cp->resign);
230 set_varptr ("sigvalidity", &cp->sigvalidity);
231 set_varptr ("max_ttl", &cp->max_ttl);
232 set_varptr ("key_ttl", &cp->key_ttl);
233 set_varptr ("propagation", &cp->proptime);
234 #if defined (DEF_TTL)
235 set_varptr ("def_ttl", &cp->def_ttl);
237 set_varptr ("serialformat", &cp->serialform);
239 set_varptr ("key_algo", &cp->k_algo);
240 set_varptr ("addkey_algo", &cp->k2_algo);
241 set_varptr ("ksk_lifetime", &cp->k_life);
242 set_varptr ("ksk_algo", &cp->k_algo); /* to be removed in next release */
243 set_varptr ("ksk_bits", &cp->k_bits);
244 set_varptr ("ksk_randfile", &cp->k_random);
246 set_varptr ("zsk_lifetime", &cp->z_life);
247 // set_varptr ("zsk_algo", &cp->z_algo);
248 set_varptr ("zsk_algo", &cp->k2_algo);
249 set_varptr ("zsk_bits", &cp->z_bits);
250 set_varptr ("zsk_randfile", &cp->z_random);
251 set_varptr ("saltbits", &cp->saltbits);
253 set_varptr ("--view", &cp->view);
254 set_varptr ("--noexec", &cp->noexec);
255 set_varptr ("logfile", &cp->logfile);
256 set_varptr ("loglevel", &cp->loglevel);
257 set_varptr ("syslogfacility", &cp->syslogfacility);
258 set_varptr ("sysloglevel", &cp->sysloglevel);
259 set_varptr ("verboselog", &cp->verboselog);
260 set_varptr ("-v", &cp->verbosity);
261 set_varptr ("keyfile", &cp->keyfile);
262 set_varptr ("zonefile", &cp->zonefile);
263 set_varptr ("keysetdir", &cp->keysetdir);
264 set_varptr ("dlv_domain", &cp->lookaside);
265 set_varptr ("sig_randfile", &cp->sig_random);
266 set_varptr ("sig_pseudorand", &cp->sig_pseudo);
267 set_varptr ("sig_generateds", &cp->sig_gends);
268 set_varptr ("sig_parameter", &cp->sig_param);
269 set_varptr ("distribute_cmd", &cp->dist_cmd);
270 set_varptr ("namedchrootdir", &cp->chroot_dir);
273 static void parseconfigline (char *buf, unsigned int line, zconf_t *z)
277 unsigned int len, found;
280 assert (buf[0] != '\0');
282 p = &buf[strlen(buf)-1]; /* Chop off white space at eol */
283 while ( p >= buf && isspace (*p) )
286 for (p = buf; isspace (*p); p++ ) /* Ignore leading white space */
289 /* Ignore comments and emtpy lines */
290 if ( *p == '\0' || ISCOMMENT (p) )
294 /* Get the end of the first argument */
295 end = &buf[strlen(buf)-1];
296 while ( p < end && !ISDELIM (*p) ) /* Skip until delim */
298 *p++ = '\0'; /* Terminate this argument */
299 dbg_val1 ("Parsing \"%s\"\n", tag);
302 while ( p < end && ISDELIM (*p) ) /* Skip delim chars */
305 val = p; /* Start of the value */
306 dbg_val1 ("\tgot value \"%s\"\n", val);
308 /* If starting with quote, skip until next quote */
309 if ( *p == '"' || *p == '\'' )
311 p++; /* Find next quote */
312 while ( p <= end && *p && *p != *val )
315 val++; /* Skip the first quote */
317 else /* Otherwise check if there is any comment char at the end */
319 while ( p < end && *p && !ISCOMMENT(p) )
323 do /* Chop off white space before comment */
325 while ( p >= val && isspace (*p) );
329 /* Otherwise it is already terminated above */
333 while ( !found && c->type != CONF_END )
335 len = strlen (c->label);
336 if ( strcasecmp (tag, c->label) == 0 )
348 str = (char **)c->var;
350 str_untaint (*str); /* remove "bad" characters */
353 sscanf (val, "%d", (int *)c->var);
357 sscanf (val, "%ld%c", &lval, &quantity);
358 if ( quantity == 'm' )
360 else if ( quantity == 'h' )
362 else if ( quantity == 'd' )
364 else if ( quantity == 'w' )
366 else if ( quantity == 'y' )
368 (*(long *)c->var) = lval;
371 if ( strcasecmp (val, "rsa") == 0 || strcasecmp (val, "rsamd5") == 0 )
372 *((int *)c->var) = DK_ALGO_RSA;
373 else if ( strcasecmp (val, "dsa") == 0 )
374 *((int *)c->var) = DK_ALGO_DSA;
375 else if ( strcasecmp (val, "rsasha1") == 0 )
376 *((int *)c->var) = DK_ALGO_RSASHA1;
377 else if ( strcasecmp (val, "nsec3dsa") == 0 ||
378 strcasecmp (val, "n3dsa") == 0 )
379 *((int *)c->var) = DK_ALGO_NSEC3DSA;
380 else if ( strcasecmp (val, "nsec3rsasha1") == 0 ||
381 strcasecmp (val, "n3rsasha1") == 0 )
382 *((int *)c->var) = DK_ALGO_NSEC3RSASHA1;
384 error ("Illegal algorithm \"%s\" "
385 "in line %d.\n" , val, line);
388 if ( strcasecmp (val, "unixtime") == 0 )
389 *((serial_form_t *)c->var) = Unixtime;
390 else if ( strcasecmp (val, "incremental") == 0 )
391 *((serial_form_t *)c->var) = Incremental;
393 error ("Illegal serial no format \"%s\" "
394 "in line %d.\n" , val, line);
397 *((int *)c->var) = ISTRUE (val);
400 fatal ("Illegal configuration type in line %d.\n", line);
406 error ("Unknown configuration statement: %s \"%s\"\n", tag, val);
410 static void printconfigline (FILE *fp, zconf_para_t *cp)
422 fprintf (fp, "# %s\n", (char *)cp->var);
428 if ( *(char **)cp->var != NULL )
430 if ( **(char **)cp->var != '\0' )
434 fprintf (fp, "%s:\t", cp->label);
435 for ( p = *(char **)cp->var; *p; p++ )
436 putc (toupper (*p), fp);
440 fprintf (fp, "%s:\tNONE", cp->label);
444 if ( *(char **)cp->var )
445 fprintf (fp, "%s:\t\"%s\"\n", cp->label, *(char **)cp->var);
448 fprintf (fp, "%s:\t%s\n", cp->label, bool2str ( *(int*)cp->var ));
451 lval = *(ulong*)cp->var; /* in that case it should be of type ulong */
452 fprintf (fp, "%s:\t%s", cp->label, timeint2str (lval));
454 fprintf (fp, "\t# (%ld seconds)", lval);
461 fprintf (fp, "%s:\t%s", cp->label, dki_algo2str (i));
462 fprintf (fp, "\t# (Algorithm ID %d)\n", i);
466 fprintf (fp, "%s:\t", cp->label);
467 if ( *(serial_form_t*)cp->var == Unixtime )
468 fprintf (fp, "unixtime\n");
470 fprintf (fp, "incremental\n");
473 fprintf (fp, "%s:\t%d\n", cp->label, *(int *)cp->var);
481 /*****************************************************************
482 ** public function definition
483 *****************************************************************/
485 /*****************************************************************
486 ** loadconfig (file, conf)
487 ** Loads a config file into the "conf" structure pointed to by "z".
488 ** If "z" is NULL then a new conf struct will be dynamically
490 ** If no filename is given the conf struct will be initialized
491 ** by the builtin default config
492 *****************************************************************/
493 zconf_t *loadconfig (const char *filename, zconf_t *z)
499 if ( z == NULL ) /* allocate new memory for zconf_t */
501 if ( (z = calloc (1, sizeof (zconf_t))) == NULL )
504 if ( filename && *filename )
505 memcpy (z, &def, sizeof (zconf_t)); /* init new struct with defaults */
508 if ( filename == NULL || *filename == '\0' ) /* no file name given... */
510 dbg_val0("loadconfig (NULL)\n");
511 memcpy (z, &def, sizeof (zconf_t)); /* ..then init with defaults */
515 dbg_val1 ("loadconfig (%s)\n", filename);
518 if ( (fp = fopen(filename, "r")) == NULL )
519 fatal ("Could not open config file \"%s\"\n", filename);
522 while (fgets(buf, sizeof(buf), fp))
523 parseconfigline (buf, ++line, z);
529 # define STRCONFIG_DELIMITER ";\r\n"
530 zconf_t *loadconfig_fromstr (const char *str, zconf_t *z)
538 if ( (z = calloc (1, sizeof (zconf_t))) == NULL )
540 memcpy (z, &def, sizeof (zconf_t)); /* init with defaults */
543 if ( str == NULL || *str == '\0' )
545 dbg_val0("loadconfig_fromstr (NULL)\n");
546 memcpy (z, &def, sizeof (zconf_t)); /* init with defaults */
550 dbg_val1 ("loadconfig_fromstr (\"%s\")\n", str);
553 /* str is const, so we have to copy it into a new buffer */
554 if ( (buf = strdup (str)) == NULL )
555 fatal ("loadconfig_fromstr: Out of memory");
558 tok = strtok_r (buf, STRCONFIG_DELIMITER, &toksave);
562 parseconfigline (tok, line, z);
563 tok = strtok_r (NULL, STRCONFIG_DELIMITER, &toksave);
569 /*****************************************************************
570 ** dupconfig (config)
571 ** duplicate config struct and return a ptr to the new struct
572 *****************************************************************/
573 zconf_t *dupconfig (const zconf_t *conf)
577 assert (conf != NULL);
579 if ( (z = calloc (1, sizeof (zconf_t))) == NULL )
582 memcpy (z, conf, sizeof (zconf_t));
587 /*****************************************************************
588 ** setconfigpar (entry, pval)
589 *****************************************************************/
590 int setconfigpar (zconf_t *config, char *entry, const void *pval)
595 set_all_varptr (config);
597 for ( c = confpara; c->type != CONF_END; c++ )
598 if ( strcasecmp (entry, c->label) == 0 )
607 str = strdup ((char *)pval);
608 str_untaint (str); /* remove "bad" characters */
612 *((char **)c->var) = str;
619 *((int *)c->var) = *((int *)pval);
622 *((long *)c->var) = *((long *)pval);
625 *((serial_form_t *)c->var) = *((serial_form_t *)pval);
637 /*****************************************************************
638 ** printconfig (fname, config)
639 *****************************************************************/
640 int printconfig (const char *fname, const zconf_t *z)
649 if ( fname && *fname )
651 if ( strcmp (fname, "stdout") == 0 )
653 else if ( strcmp (fname, "stderr") == 0 )
655 else if ( (fp = fopen(fname, "w")) == NULL )
657 error ("Could not open config file \"%s\" for writing\n", fname);
662 set_all_varptr ((zconf_t *)z);
664 for ( cp = confpara; cp->type != CONF_END; cp++ ) /* loop through all parameter */
665 if ( !cp->cmdline ) /* if this is not a command line parameter ? */
666 printconfigline (fp, cp); /* print it out */
668 if ( fp && fp != stdout && fp != stderr )
675 /*****************************************************************
676 ** printconfigdiff (fname, conf_a, conf_b)
677 *****************************************************************/
678 int printconfigdiff (const char *fname, const zconf_t *ref, const zconf_t *z)
683 if ( ref == NULL || z == NULL )
687 if ( fname && *fname )
689 if ( strcmp (fname, "stdout") == 0 )
691 else if ( strcmp (fname, "stderr") == 0 )
693 else if ( (fp = fopen(fname, "w")) == NULL )
695 error ("Could not open config file \"%s\" for writing\n", fname);
700 set_all_varptr ((zconf_t *)z);
702 for ( cp = confpara; cp->type != CONF_END; cp++ ) /* loop through all parameter */
708 printconfigline (fp, cp); /* print it out */
711 if ( fp && fp != stdout && fp != stderr )
718 /*****************************************************************
719 ** checkconfig (config)
720 *****************************************************************/
721 int checkconfig (const zconf_t *z)
726 if ( z->saltbits < 4 )
727 fprintf (stderr, "Saltlength must be at least 4 bits\n");
728 if ( z->saltbits > 128 )
730 fprintf (stderr, "While the maximum is 520 bits of salt, it's not recommended to use more than 128 bits.\n");
731 fprintf (stderr, "The current value is %d bits\n", z->saltbits);
734 if ( z->sigvalidity < (1 * DAYSEC) || z->sigvalidity > (12 * WEEKSEC) )
736 fprintf (stderr, "Signature should be valid for at least 1 day and no longer than 3 month (12 weeks)\n");
737 fprintf (stderr, "The current value is %s\n", timeint2str (z->sigvalidity));
740 if ( z->resign > (z->sigvalidity*5/6) - (z->max_ttl + z->proptime) )
742 fprintf (stderr, "Re-signing interval (%s) should be less than ", timeint2str (z->resign));
743 fprintf (stderr, "5/6 of sigvalidity\n");
745 if ( z->resign < (z->max_ttl + z->proptime) )
747 fprintf (stderr, "Re-signing interval (%s) should be ", timeint2str (z->resign));
748 fprintf (stderr, "greater than max_ttl (%ld) plus ", z->max_ttl);
749 fprintf (stderr, "propagation time (%ld)\n", z->proptime);
752 if ( z->max_ttl >= z->sigvalidity )
753 fprintf (stderr, "Max TTL (%ld) should be less than signature validity (%ld)\n",
754 z->max_ttl, z->sigvalidity);
756 if ( z->z_life > (12 * WEEKSEC) * (z->z_bits / 512.) )
758 fprintf (stderr, "Lifetime of zone signing key (%s) ", timeint2str (z->z_life));
759 fprintf (stderr, "seems a little bit high ");
760 fprintf (stderr, "(In respect of key size (%d))\n", z->z_bits);
763 if ( z->k_life > 0 && z->k_life <= z->z_life )
765 fprintf (stderr, "Lifetime of key signing key (%s) ", timeint2str (z->k_life));
766 fprintf (stderr, "should be greater than lifetime of zsk\n");
768 if ( z->k_life > 0 && z->k_life > (26 * WEEKSEC) * (z->k_bits / 512.) )
770 fprintf (stderr, "Lifetime of key signing key (%s) ", timeint2str (z->k_life));
771 fprintf (stderr, "seems a little bit high ");
772 fprintf (stderr, "(In respect of key size (%d))\n", z->k_bits);
779 const char *progname;
780 static zconf_t *config;
782 main (int argc, char *argv[])
789 config = loadconfig ("", (zconf_t *) NULL); /* load built in defaults */
791 while ( --argc >= 1 )
794 config = loadconfig_fromstr (optstr, config);
798 setconfigpar (config, "-v", &val);
800 setconfigpar (config, "verboselog", &val);
802 setconfigpar (config, "recursive", &val);
804 setconfigpar (config, "propagation", &val);
806 printconfig ("stdout", config);