David van Moolenbroek 00b67f09dd Import NetBSD named(8)
Also known as ISC bind.  This import adds utilities such as host(1),
dig(1), and nslookup(1), as well as many other tools and libraries.

Change-Id: I035ca46e64f1965d57019e773f4ff0ef035e4aa3
2017-03-21 22:00:06 +00:00

1046 lines
34 KiB
C

/* $NetBSD: zconf.c,v 1.1.1.1 2015/07/08 15:37:48 christos Exp $ */
/****************************************************************
**
** @(#) zconf.c -- configuration file parser for dnssec.conf
**
** The initial code of this module is from the SixXS Heartbeat Client
** written by Jeroen Massar <jeroen@sixxs.net>
**
** New config types and many code changes by Holger Zuleger
**
** Copyright (c) Aug 2005, Jeroen Massar.
** Copyright (c) Aug 2005 - Nov 2010, Holger Zuleger.
** All rights reserved.
**
** This software is open source.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** Redistributions of source code must retain the above copyright notice,
** this list of conditions and the following disclaimer.
**
** Redistributions in binary form must reproduce the above copyright notice,
** this list of conditions and the following disclaimer in the documentation
** and/or other materials provided with the distribution.
**
** Neither the name of Jeroen Masar or Holger Zuleger nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
**
****************************************************************/
# include <sys/types.h>
# include <stdio.h>
# include <errno.h>
# include <unistd.h>
# include <stdlib.h>
# include <stdarg.h>
# include <string.h>
# include <strings.h>
# include <assert.h>
# include <ctype.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
# include "config_zkt.h"
# include "debug.h"
# include "misc.h"
#define extern
# include "zconf.h"
#undef extern
# include "dki.h"
# define ISTRUE(val) (strcasecmp (val, "yes") == 0 || \
strcasecmp (val, "true") == 0 )
# define ISCOMMENT(cp) (*(cp) == '#' || *(cp) == ';' || \
(*(cp) == '/' && *((cp)+1) == '/') )
# define ISDELIM(c) (isspace (c) || (c) == ':' || (c) == '=')
# define cmdln (0)
# define first (1)
# define last (0x7FFF)
# define iscmdline(x) ((x)->used_since == cmdln)
# define iscompatible(x) ((x)->used_since != cmdln && compversion >= (x)->used_since && \
((x)->used_till == 1 || (compversion <= (x)->used_till)))
typedef enum {
CONF_END = 0,
CONF_STRING,
CONF_INT,
CONF_TIMEINT,
CONF_BOOL,
CONF_ALGO,
CONF_SERIAL,
CONF_FACILITY,
CONF_LEVEL,
CONF_NSEC3,
CONF_COMMENT,
CONF_VERSION,
} ctype_t;
/*****************************************************************
** private (static) variables
*****************************************************************/
static int compversion;
static zconf_t def = {
ZONEDIR, RECURSIVE,
PRINTTIME, PRINTAGE, LJUST, LSCOLORTERM,
SIG_VALIDITY, MAX_TTL, KEY_TTL, PROPTIME, Unixtime,
RESIGN_INT,
KEY_ALGO, ADDITIONAL_KEY_ALGO,
KSK_LIFETIME, KSK_BITS, KSK_RANDOM,
ZSK_LIFETIME, ZSK_BITS, ZSK_ALWAYS, ZSK_RANDOM,
NSEC3_OFF, SALTLEN,
NULL, /* viewname cmdline parameter */
0, /* noexec cmdline parameter */
LOGFILE, LOGLEVEL, LOGDOMAINDIR, SYSLOGFACILITY, SYSLOGLEVEL, VERBOSELOG, 0,
DNSKEYFILE, ZONEFILE, KEYSETDIR,
LOOKASIDEDOMAIN,
SIG_RANDOM, SIG_PSEUDO, SIG_GENDS, SIG_DNSKEY_KSK, SIG_PARAM,
DEPENDFILES,
DIST_CMD, /* defaults to NULL which means to run "rndc reload" */
NAMED_CHROOT
};
typedef struct {
char *label; /* the name of the parameter */
short used_since; /* compability (from version; 0 == command line) */
short used_till; /* compability (to version) */
ctype_t type; /* the parameter type */
void *var; /* pointer to the parameter variable */
const char *desc;
const void *var2; /* pointer to a second parameter variable */
/* this is a ugly hack needed by cmpconfig () */
} zconf_para_t;
static zconf_para_t confpara[] = {
{ "", first, last, CONF_COMMENT, ""},
{ "", first, last, CONF_COMMENT, "\t@(#) dnssec.conf "},
{ "", first, last, CONF_VERSION, "" },
{ "", first, last, CONF_COMMENT, ""},
{ "", first, last, CONF_COMMENT, NULL },
{ "", first, 99, CONF_COMMENT, "dnssec-zkt options" },
{ "", 100, last, CONF_COMMENT, "zkt-ls options" },
{ "ZoneDir", first, last, CONF_STRING, &def.zonedir, "default zone file directory (also used by zkt-signer)"},
{ "Recursive", first, last, CONF_BOOL, &def.recursive, "looking for keys down the directory tree?" },
{ "PrintTime", first, last, CONF_BOOL, &def.printtime, "print absolute key generation time?" },
{ "PrintAge", first, last, CONF_BOOL, &def.printage, "print relative key age?" },
{ "LeftJustify", first, last, CONF_BOOL, &def.ljust, "zone name is printed left justified?" },
{ "lsColor", 100, last, CONF_STRING, &def.colorterm, "terminal name (for coloring)" },
{ "", first, last, CONF_COMMENT, NULL },
{ "", first, last, CONF_COMMENT, "zone specific values" },
{ "ResignInterval", first, last, CONF_TIMEINT, &def.resign },
{ "SigValidity", first, last, CONF_TIMEINT, &def.sigvalidity },
{ "Max_TTL", first, 100, CONF_TIMEINT, &def.max_ttl },
{ "MaximumTTL", 101, last, CONF_TIMEINT, &def.max_ttl },
{ "Propagation", first, last, CONF_TIMEINT, &def.proptime },
{ "Key_TTL", 90, 100, CONF_TIMEINT, &def.key_ttl },
{ "DnsKeyTTL", 101, last, CONF_TIMEINT, &def.key_ttl },
#if defined (DEF_TTL)
{ "def_ttl", first, last, CONF_TIMEINT, &def.def_ttl },
#endif
{ "SerialFormat", 92, last, CONF_SERIAL, &def.serialform },
{ "", first, last, CONF_COMMENT, NULL },
{ "", first, last, CONF_COMMENT, "signing key parameters"},
{ "Key_Algo", 99, 100, CONF_ALGO, &def.k_algo }, /* now used as general KEY algorithm (KSK & ZSK) */
{ "KeyAlgo", 101, last, CONF_ALGO, &def.k_algo }, /* now used as general KEY algorithm (KSK & ZSK) */
{ "AddKey_Algo", 99, 100, CONF_ALGO, &def.k2_algo }, /* second key algorithm added (v0.99) */
{ "AddKeyAlgo", 101, last, CONF_ALGO, &def.k2_algo }, /* second key algorithm added (v0.99) */
{ "KSK_lifetime", first, 100, CONF_TIMEINT, &def.k_life },
{ "KSKlifetime", 101, last, CONF_TIMEINT, &def.k_life },
{ "KSK_algo", first, 98, CONF_ALGO, &def.k_algo }, /* old KSK value changed to key algorithm */
{ "KSK_bits", first, 100, CONF_INT, &def.k_bits },
{ "KSKbits", 101, last, CONF_INT, &def.k_bits },
{ "KSK_randfile", first, 100, CONF_STRING, &def.k_random },
{ "KSKrandfile", 101, last, CONF_STRING, &def.k_random },
{ "ZSK_lifetime", first, 100, CONF_TIMEINT, &def.z_life },
{ "ZSKlifetime", 101, last, CONF_TIMEINT, &def.z_life },
/* { "ZSK_algo", 1, CONF_ALGO, &def.z_algo }, ZSK algo removed (set to same as ksk) */
{ "ZSK_algo", first, 98, CONF_ALGO, &def.k2_algo }, /* if someone using it already, map the algo to the additional key algorithm */
{ "ZSK_bits", first, 100, CONF_INT, &def.z_bits },
{ "ZSKbits", 101, last, CONF_INT, &def.z_bits },
#if defined(ALLOW_ALWAYS_PREPUBLISH_ZSK) && ALLOW_ALWAYS_PREPUBLISH_ZSK
{ "ZSKpermanent", 102, last, CONF_BOOL, &def.z_always, "Always add a pre-publish zone signing key?" },
#endif
{ "ZSK_randfile", first, 100, CONF_STRING, &def.z_random },
{ "ZSKrandfile", 101, last, CONF_STRING, &def.z_random },
{ "NSEC3", 100, last, CONF_NSEC3, &def.nsec3 },
{ "SaltBits", 98, last, CONF_INT, &def.saltbits, },
{ "", first, last, CONF_COMMENT, NULL },
{ "", first, 99, CONF_COMMENT, "dnssec-signer options"},
{ "", 100, last, CONF_COMMENT, "zkt-signer options"},
{ "--view", cmdln, last, CONF_STRING, &def.view },
{ "--noexec", cmdln, last, CONF_BOOL, &def.noexec },
{ "LogFile", 96, last, CONF_STRING, &def.logfile },
{ "LogLevel", 96, last, CONF_LEVEL, &def.loglevel },
{ "LogDomainDir", 96, last, CONF_STRING, &def.logdomaindir },
{ "SyslogFacility", 96, last, CONF_FACILITY, &def.syslogfacility },
{ "SyslogLevel", 96, last, CONF_LEVEL, &def.sysloglevel },
{ "VerboseLog", 96, last, CONF_INT, &def.verboselog },
{ "-v", cmdln, last, CONF_INT, &def.verbosity },
{ "KeyFile", first, last, CONF_STRING, &def.keyfile },
{ "ZoneFile", first, last, CONF_STRING, &def.zonefile },
{ "KeySetDir", first, last, CONF_STRING, &def.keysetdir },
{ "DLV_Domain", first, 100, CONF_STRING, &def.lookaside },
{ "DLVdomain", 101, last, CONF_STRING, &def.lookaside },
{ "Sig_Randfile", first, 100, CONF_STRING, &def.sig_random },
{ "SigRandfile", 101, last, CONF_STRING, &def.sig_random, "a file containing random data" },
{ "Sig_Pseudorand", first, 100, CONF_BOOL, &def.sig_pseudo },
{ "SigPseudorand", 101, last, CONF_BOOL, &def.sig_pseudo, "use pseudorandom data (faster but less secure)?" },
{ "Sig_GenerateDS", first, 100, CONF_BOOL, &def.sig_gends },
{ "SigGenerateDS", 101, last, CONF_BOOL, &def.sig_gends, "update DS records based on child zone\' dsset-* files?" },
{ "Sig_DnsKeyKSK", 99, 100, CONF_BOOL, &def.sig_dnskeyksk },
{ "SigDnsKeyKSK", 101, last, CONF_BOOL, &def.sig_dnskeyksk, "sign dns keyset with ksk only?" },
{ "Sig_Parameter", first, 100, CONF_STRING, &def.sig_param },
{ "SigParameter", 101, last, CONF_STRING, &def.sig_param, "additional dnssec-signzone parameter (if any)" },
{ "DependFiles", 113, last, CONF_STRING, &def.dependfiles, "list of files included in ZoneFile (except KeyFile)" },
{ "Distribute_Cmd", 97, 100, CONF_STRING, &def.dist_cmd },
{ "DistributeCmd", 101, last, CONF_STRING, &def.dist_cmd },
{ "NamedChrootDir", 99, last, CONF_STRING, &def.chroot_dir },
{ NULL, 0, 0, CONF_END, NULL},
};
/*****************************************************************
** private (static) function deklaration and definition
*****************************************************************/
static const char *bool2str (int val)
{
return val ? "True" : "False";
}
static int set_varptr (char *entry, void *ptr, const void *ptr2)
{
zconf_para_t *c;
for ( c = confpara; c->label; c++ )
if ( strcasecmp (entry, c->label) == 0 )
{
c->var = ptr;
c->var2 = ptr2;
return 1;
}
return 0;
}
static void set_all_varptr (zconf_t *cp, const zconf_t *cp2)
{
set_varptr ("zonedir", &cp->zonedir, cp2 ? &cp2->zonedir: NULL);
set_varptr ("recursive", &cp->recursive, cp2 ? &cp2->recursive: NULL);
set_varptr ("printage", &cp->printage, cp2 ? &cp2->printage: NULL);
set_varptr ("printtime", &cp->printtime, cp2 ? &cp2->printtime: NULL);
set_varptr ("leftjustify", &cp->ljust, cp2 ? &cp2->ljust: NULL);
set_varptr ("lscolor", &cp->colorterm, cp2 ? &cp2->colorterm: NULL);
set_varptr ("resigninterval", &cp->resign, cp2 ? &cp2->resign: NULL);
set_varptr ("sigvalidity", &cp->sigvalidity, cp2 ? &cp2->sigvalidity: NULL);
set_varptr ("max_ttl", &cp->max_ttl, cp2 ? &cp2->max_ttl: NULL);
set_varptr ("maximumttl", &cp->max_ttl, cp2 ? &cp2->max_ttl: NULL);
set_varptr ("key_ttl", &cp->key_ttl, cp2 ? &cp2->key_ttl: NULL);
set_varptr ("dnskeyttl", &cp->key_ttl, cp2 ? &cp2->key_ttl: NULL);
set_varptr ("propagation", &cp->proptime, cp2 ? &cp2->proptime: NULL);
#if defined (DEF_TTL)
set_varptr ("def_ttl", &cp->def_ttl, cp2 ? &cp2->def_ttl: NULLl);
#endif
set_varptr ("serialformat", &cp->serialform, cp2 ? &cp2->serialform: NULL);
set_varptr ("key_algo", &cp->k_algo, cp2 ? &cp2->k_algo: NULL);
set_varptr ("keyalgo", &cp->k_algo, cp2 ? &cp2->k_algo: NULL);
set_varptr ("addkey_algo", &cp->k2_algo, cp2 ? &cp2->k2_algo: NULL);
set_varptr ("addkeyalgo", &cp->k2_algo, cp2 ? &cp2->k2_algo: NULL);
set_varptr ("ksk_lifetime", &cp->k_life, cp2 ? &cp2->k_life: NULL);
set_varptr ("ksklifetime", &cp->k_life, cp2 ? &cp2->k_life: NULL);
set_varptr ("ksk_algo", &cp->k_algo, cp2 ? &cp2->k_algo: NULL); /* used only in compability mode */
set_varptr ("ksk_bits", &cp->k_bits, cp2 ? &cp2->k_bits: NULL);
set_varptr ("kskbits", &cp->k_bits, cp2 ? &cp2->k_bits: NULL);
set_varptr ("ksk_randfile", &cp->k_random, cp2 ? &cp2->k_random: NULL);
set_varptr ("kskrandfile", &cp->k_random, cp2 ? &cp2->k_random: NULL);
set_varptr ("zsk_lifetime", &cp->z_life, cp2 ? &cp2->z_life: NULL);
set_varptr ("zsklifetime", &cp->z_life, cp2 ? &cp2->z_life: NULL);
// set_varptr ("zsk_algo", &cp->z_algo, cp2 ? &cp2->z_algo: NULL);
set_varptr ("zsk_algo", &cp->k2_algo, cp2 ? &cp2->k2_algo: NULL);
set_varptr ("zsk_bits", &cp->z_bits, cp2 ? &cp2->z_bits: NULL);
set_varptr ("zskbits", &cp->z_bits, cp2 ? &cp2->z_bits: NULL);
#if defined(ALLOW_ALWAYS_PREPUBLISH_ZSK) && ALLOW_ALWAYS_PREPUBLISH_ZSK
set_varptr ("zskpermanent", &cp->z_always, cp2 ? &cp2->z_always: NULL);
#endif
set_varptr ("zsk_randfile", &cp->z_random, cp2 ? &cp2->z_random: NULL);
set_varptr ("zskrandfile", &cp->z_random, cp2 ? &cp2->z_random: NULL);
set_varptr ("nsec3", &cp->nsec3, cp2 ? &cp2->nsec3: NULL);
set_varptr ("saltbits", &cp->saltbits, cp2 ? &cp2->saltbits: NULL);
set_varptr ("--view", &cp->view, cp2 ? &cp2->view: NULL);
set_varptr ("--noexec", &cp->noexec, cp2 ? &cp2->noexec: NULL);
set_varptr ("logfile", &cp->logfile, cp2 ? &cp2->logfile: NULL);
set_varptr ("loglevel", &cp->loglevel, cp2 ? &cp2->loglevel: NULL);
set_varptr ("logdomaindir", &cp->logdomaindir, cp2 ? &cp2->logdomaindir: NULL);
set_varptr ("syslogfacility", &cp->syslogfacility, cp2 ? &cp2->syslogfacility: NULL);
set_varptr ("sysloglevel", &cp->sysloglevel, cp2 ? &cp2->sysloglevel: NULL);
set_varptr ("verboselog", &cp->verboselog, cp2 ? &cp2->verboselog: NULL);
set_varptr ("-v", &cp->verbosity, cp2 ? &cp2->verbosity: NULL);
set_varptr ("keyfile", &cp->keyfile, cp2 ? &cp2->keyfile: NULL);
set_varptr ("zonefile", &cp->zonefile, cp2 ? &cp2->zonefile: NULL);
set_varptr ("keysetdir", &cp->keysetdir, cp2 ? &cp2->keysetdir: NULL);
set_varptr ("dlv_domain", &cp->lookaside, cp2 ? &cp2->lookaside: NULL);
set_varptr ("dlvdomain", &cp->lookaside, cp2 ? &cp2->lookaside: NULL);
set_varptr ("sig_randfile", &cp->sig_random, cp2 ? &cp2->sig_random: NULL);
set_varptr ("sigrandfile", &cp->sig_random, cp2 ? &cp2->sig_random: NULL);
set_varptr ("sig_pseudorand", &cp->sig_pseudo, cp2 ? &cp2->sig_pseudo: NULL);
set_varptr ("sigpseudorand", &cp->sig_pseudo, cp2 ? &cp2->sig_pseudo: NULL);
set_varptr ("sig_generateds", &cp->sig_gends, cp2 ? &cp2->sig_gends: NULL);
set_varptr ("siggenerateds", &cp->sig_gends, cp2 ? &cp2->sig_gends: NULL);
set_varptr ("sig_dnskeyksk", &cp->sig_dnskeyksk, cp2 ? &cp2->sig_dnskeyksk: NULL);
set_varptr ("sigdnskeyksk", &cp->sig_dnskeyksk, cp2 ? &cp2->sig_dnskeyksk: NULL);
set_varptr ("sig_parameter", &cp->sig_param, cp2 ? &cp2->sig_param: NULL);
set_varptr ("sigparameter", &cp->sig_param, cp2 ? &cp2->sig_param: NULL);
set_varptr ("dependfiles", &cp->dependfiles, cp2 ? &cp2->dependfiles: NULL);
set_varptr ("distribute_cmd", &cp->dist_cmd, cp2 ? &cp2->dist_cmd: NULL);
set_varptr ("distributecmd", &cp->dist_cmd, cp2 ? &cp2->dist_cmd: NULL);
set_varptr ("namedchrootdir", &cp->chroot_dir, cp2 ? &cp2->chroot_dir: NULL);
}
static void parseconfigline (char *buf, unsigned int line, zconf_t *z)
{
char *end, *val, *p;
char *tag;
unsigned int found;
zconf_para_t *c;
assert (buf[0] != '\0');
p = &buf[strlen(buf)-1]; /* Chop off white space at eol */
while ( p >= buf && isspace (*p) )
*p-- = '\0';
for (p = buf; isspace (*p); p++ ) /* Ignore leading white space */
;
/* Ignore comments and emtpy lines */
if ( *p == '\0' || ISCOMMENT (p) )
return;
tag = p;
/* Get the end of the first argument */
end = &buf[strlen(buf)-1];
while ( p < end && !ISDELIM (*p) ) /* Skip until delim */
p++;
*p++ = '\0'; /* Terminate this argument */
dbg_val1 ("Parsing \"%s\"\n", tag);
while ( p < end && ISDELIM (*p) ) /* Skip delim chars */
p++;
val = p; /* Start of the value */
dbg_val1 ("\tgot value \"%s\"\n", val);
/* If starting with quote, skip until next quote */
if ( *p == '"' || *p == '\'' )
{
p++; /* Find next quote */
while ( p <= end && *p && *p != *val )
p++;
*p = '\0';
val++; /* Skip the first quote */
}
else /* Otherwise check if there is any comment char at the end */
{
while ( p < end && *p && !ISCOMMENT(p) )
p++;
if ( ISCOMMENT (p) )
{
do /* Chop off white space before comment */
*p-- = '\0';
while ( p >= val && isspace (*p) );
}
}
/* Otherwise it is already terminated above */
found = 0;
c = confpara;
while ( !found && c->type != CONF_END )
{
if ( strcasecmp (tag, c->label) == 0 )
{
char **str;
char quantity;
long lval;
found = 1;
switch ( c->type )
{
case CONF_VERSION:
break;
case CONF_LEVEL:
case CONF_FACILITY:
case CONF_STRING:
str = (char **)c->var;
*str = strdup (val);
str_untaint (*str); /* remove "bad" characters */
break;
case CONF_INT:
sscanf (val, "%d", (int *)c->var);
break;
case CONF_TIMEINT:
quantity = 'd';
if ( *val == 'u' || *val == 'U' )
lval = 0L;
else
sscanf (val, "%ld%c", &lval, &quantity);
if ( quantity == 'm' )
lval *= MINSEC;
else if ( quantity == 'h' )
lval *= HOURSEC;
else if ( quantity == 'd' )
lval *= DAYSEC;
else if ( quantity == 'w' )
lval *= WEEKSEC;
else if ( quantity == 'y' )
lval *= YEARSEC;
(*(long *)c->var) = lval;
break;
case CONF_ALGO:
if ( strcmp (val, "1") == 0 || strcasecmp (val, "rsa") == 0 ||
strcasecmp (val, "rsamd5") == 0 )
*((int *)c->var) = DK_ALGO_RSA;
else if ( strcmp (val, "3") == 0 ||
strcasecmp (val, "dsa") == 0 )
*((int *)c->var) = DK_ALGO_DSA;
else if ( strcmp (val, "5") == 0 ||
strcasecmp (val, "rsasha1") == 0 )
*((int *)c->var) = DK_ALGO_RSASHA1;
else if ( strcmp (val, "6") == 0 ||
strcasecmp (val, "nsec3dsa") == 0 ||
strcasecmp (val, "n3dsa") == 0 )
*((int *)c->var) = DK_ALGO_NSEC3DSA;
else if ( strcmp (val, "7") == 0 ||
strcasecmp (val, "nsec3rsasha1") == 0 ||
strcasecmp (val, "n3rsasha1") == 0 )
*((int *)c->var) = DK_ALGO_NSEC3RSASHA1;
else if ( strcmp (val, "8") == 0 ||
strcasecmp (val, "rsasha2") == 0 ||
strcasecmp (val, "rsasha256") == 0 ||
strcasecmp (val, "nsec3rsasha2") == 0 ||
strcasecmp (val, "n3rsasha2") == 0 ||
strcasecmp (val, "nsec3rsasha256") == 0 ||
strcasecmp (val, "n3rsasha256") == 0 )
*((int *)c->var) = DK_ALGO_RSASHA256;
else if ( strcmp (val, "10") == 0 ||
strcasecmp (val, "rsasha5") == 0 ||
strcasecmp (val, "rsasha512") == 0 ||
strcasecmp (val, "nsec3rsasha5") == 0 ||
strcasecmp (val, "n3rsasha5") == 0 ||
strcasecmp (val, "nsec3rsasha512") == 0 ||
strcasecmp (val, "n3rsasha512") == 0 )
*((int *)c->var) = DK_ALGO_RSASHA512;
else
error ("Illegal algorithm \"%s\" "
"in line %d.\n" , val, line);
break;
case CONF_SERIAL:
if ( strcasecmp (val, "unixtime") == 0 )
*((serial_form_t *)c->var) = Unixtime;
else if ( strcasecmp (val, "incremental") == 0 || strcasecmp (val, "inc") == 0 )
*((serial_form_t *)c->var) = Incremental;
else
error ("Illegal serial no format \"%s\" "
"in line %d.\n" , val, line);
break;
case CONF_NSEC3:
if ( strcasecmp (val, "off") == 0 )
*((nsec3_t *)c->var) = NSEC3_OFF;
else if ( strcasecmp (val, "on") == 0 )
*((nsec3_t *)c->var) = NSEC3_ON;
else if ( strcasecmp (val, "optout") == 0 )
*((nsec3_t *)c->var) = NSEC3_OPTOUT;
else
error ("Illegal NSEC3 format \"%s\" "
"in line %d.\n" , val, line);
break;
case CONF_BOOL:
*((int *)c->var) = ISTRUE (val);
break;
default:
fatal ("Illegal configuration type in line %d.\n", line);
}
}
c++;
}
if ( !found )
error ("Unknown configuration statement: %s \"%s\"\n", tag, val);
return;
}
static void printconfigline (FILE *fp, zconf_para_t *cp)
{
int i;
long lval;
int printnl;
assert (fp != NULL);
assert (cp != NULL);
printnl = 0;
switch ( cp->type )
{
case CONF_VERSION:
fprintf (fp, "#\tZKT config file for version %d.%d.%d\n",
compversion / 100,
(compversion / 10 ) % 10,
compversion % 10);
break;
case CONF_COMMENT:
if ( cp->var )
fprintf (fp, "# %s", (char *)cp->var);
printnl = 1;
break;
case CONF_LEVEL:
case CONF_FACILITY:
if ( *(char **)cp->var != NULL )
{
if ( **(char **)cp->var != '\0' )
{
char *p;
fprintf (fp, "%s:\t", cp->label);
for ( p = *(char **)cp->var; *p; p++ )
putc (toupper (*p), fp);
// fprintf (fp, "\n");
}
else
fprintf (fp, "%s:\tNONE", cp->label);
}
if ( cp->type == CONF_LEVEL )
fprintf (fp, "\t\t# (NONE|DEBUG|INFO|NOTICE|WARNING|ERROR|FATAL)\n");
else
fprintf (fp, "\t\t# (NONE|USER|DAEMON|LOCAL[0-7])\n");
break;
case CONF_STRING:
if ( *(char **)cp->var )
printnl = fprintf (fp, "%s:\t\"%s\"", cp->label, *(char **)cp->var);
break;
case CONF_BOOL:
fprintf (fp, "%s:\t%s", cp->label, bool2str ( *(int*)cp->var ));
printnl = 1;
break;
case CONF_TIMEINT:
lval = *(ulong*)cp->var; /* in that case it should be of type ulong */
fprintf (fp, "%s:\t%s", cp->label, timeint2str (lval));
if ( lval )
fprintf (fp, "\t\t# (%ld seconds)", lval);
printnl = 1;
break;
case CONF_ALGO:
i = *(int*)cp->var;
if ( i )
{
fprintf (fp, "%s:\t%s ", cp->label, dki_algo2str (i));
fprintf (fp, "\t# (Algorithm ID %d)\n", i);
}
break;
case CONF_SERIAL:
fprintf (fp, "%s:\t", cp->label);
if ( *(serial_form_t*)cp->var == Unixtime )
fprintf (fp, "UnixTime");
else
fprintf (fp, "Incremental");
fprintf (fp, "\t# (UnixTime|Incremental)\n");
break;
case CONF_NSEC3:
fprintf (fp, "%s:\t\t", cp->label);
if ( *(nsec3_t*)cp->var == NSEC3_OFF )
fprintf (fp, "Off");
else if ( *(nsec3_t*)cp->var == NSEC3_ON )
fprintf (fp, "On");
else if ( *(nsec3_t*)cp->var == NSEC3_OPTOUT )
fprintf (fp, "OptOut");
fprintf (fp, "\t\t# (On|Off|OptOut)\n");
break;
case CONF_INT:
fprintf (fp, "%s:\t%d", cp->label, *(int *)cp->var);
printnl = 1;
break;
case CONF_END:
/* NOTREACHED */
break;
}
if ( printnl )
{
if ( cp->desc )
{
if ( printnl < 20 )
putc ('\t', fp);
fprintf (fp, "\t# %s\n", cp->desc);
}
else
putc ('\n', fp);
}
}
/*****************************************************************
** public function definition
*****************************************************************/
void setconfigversion (int version)
{
compversion = version;
}
const char *timeint2str (unsigned long val)
{
static char str[20+1];
if ( val == 0 )
snprintf (str, sizeof (str), "Unset");
else if ( val % YEARSEC == 0 )
snprintf (str, sizeof (str), "%luy", val / YEARSEC);
else if ( val % WEEKSEC == 0 )
snprintf (str, sizeof (str), "%luw", val / WEEKSEC);
else if ( val % DAYSEC == 0 )
snprintf (str, sizeof (str), "%lud", val / DAYSEC);
else if ( val % HOURSEC == 0 )
snprintf (str, sizeof (str), "%luh", val / HOURSEC);
else if ( val % MINSEC == 0 )
snprintf (str, sizeof (str), "%lum", val / MINSEC);
else
snprintf (str, sizeof (str), "%lus", val);
return str;
}
/*****************************************************************
** loadconfig (file, conf)
** Loads a config file into the "conf" structure pointed to by "z".
** If "z" is NULL then a new conf struct will be dynamically
** allocated.
** If no filename is given the conf struct will be initialized
** with the builtin default config
*****************************************************************/
zconf_t *loadconfig (const char *filename, zconf_t *z)
{
FILE *fp;
char buf[1023+1];
unsigned int line;
if ( z == NULL ) /* allocate new memory for zconf_t */
{
if ( (z = calloc (1, sizeof (zconf_t))) == NULL )
return NULL;
if ( filename && *filename )
memcpy (z, &def, sizeof (zconf_t)); /* init new struct with defaults */
}
if ( filename == NULL || *filename == '\0' ) /* no file name given... */
{
dbg_val0("loadconfig (NULL)\n");
memcpy (z, &def, sizeof (zconf_t)); /* ..then init with defaults */
return z;
}
dbg_val1 ("loadconfig (%s)\n", filename);
set_all_varptr (z, NULL);
if ( (fp = fopen(filename, "r")) == NULL )
fatal ("Could not open config file \"%s\"\n", filename);
line = 0;
while (fgets(buf, sizeof(buf), fp))
parseconfigline (buf, ++line, z);
fclose(fp);
return z;
}
# define STRCONFIG_DELIMITER ";\r\n"
zconf_t *loadconfig_fromstr (const char *str, zconf_t *z)
{
char *buf;
char *tok, *toksave;
unsigned int line;
if ( z == NULL )
{
if ( (z = calloc (1, sizeof (zconf_t))) == NULL )
return NULL;
memcpy (z, &def, sizeof (zconf_t)); /* init with defaults */
}
if ( str == NULL || *str == '\0' )
{
dbg_val0("loadconfig_fromstr (NULL)\n");
memcpy (z, &def, sizeof (zconf_t)); /* init with defaults */
return z;
}
dbg_val1 ("loadconfig_fromstr (\"%s\")\n", str);
set_all_varptr (z, NULL);
/* str is const, so we have to copy it into a new buffer */
if ( (buf = strdup (str)) == NULL )
fatal ("loadconfig_fromstr: Out of memory");
line = 0;
tok = strtok_r (buf, STRCONFIG_DELIMITER, &toksave);
while ( tok )
{
line++;
parseconfigline (tok, line, z);
tok = strtok_r (NULL, STRCONFIG_DELIMITER, &toksave);
}
free (buf);
return z;
}
/*****************************************************************
** dupconfig (config)
** duplicate config struct and return a ptr to the new struct
*****************************************************************/
zconf_t *dupconfig (const zconf_t *conf)
{
zconf_t *z;
assert (conf != NULL);
if ( (z = calloc (1, sizeof (zconf_t))) == NULL )
return NULL;
memcpy (z, conf, sizeof (zconf_t));
return z;
}
/*****************************************************************
** freeconfig (config)
** free memory for config struct and return a NULL ptr
*****************************************************************/
zconf_t *freeconfig (zconf_t *conf)
{
if (conf != NULL);
free (conf);
return (zconf_t *)NULL;
}
/*****************************************************************
** setconfigpar (entry, pval)
*****************************************************************/
int setconfigpar (zconf_t *config, char *entry, const void *pval)
{
char *str;
zconf_para_t *c;
set_all_varptr (config, NULL);
for ( c = confpara; c->type != CONF_END; c++ )
if ( strcasecmp (entry, c->label) == 0 )
{
switch ( c->type )
{
case CONF_VERSION:
break;
case CONF_LEVEL:
case CONF_FACILITY:
case CONF_STRING:
if ( pval )
{
str = strdup ((char *)pval);
str_untaint (str); /* remove "bad" characters */
}
else
str = NULL;
*((char **)c->var) = str;
break;
case CONF_BOOL:
/* fall through */
case CONF_ALGO:
/* fall through */
case CONF_INT:
*((int *)c->var) = *((int *)pval);
break;
case CONF_TIMEINT:
*((long *)c->var) = *((long *)pval);
break;
case CONF_NSEC3:
*((nsec3_t *)c->var) = *((nsec3_t *)pval);
break;
case CONF_SERIAL:
*((serial_form_t *)c->var) = *((serial_form_t *)pval);
break;
case CONF_COMMENT:
case CONF_END:
/* NOTREACHED */
break;
}
return 1;
}
return 0;
}
/*****************************************************************
** printconfig (fname, config)
*****************************************************************/
int printconfig (const char *fname, const zconf_t *z)
{
zconf_para_t *cp;
FILE *fp;
if ( z == NULL )
return 0;
fp = stdout;
if ( fname && *fname )
{
if ( strcmp (fname, "stdout") == 0 )
fp = stdout;
else if ( strcmp (fname, "stderr") == 0 )
fp = stderr;
else if ( (fp = fopen(fname, "w")) == NULL )
{
error ("Could not open config file \"%s\" for writing\n", fname);
return -1;
}
}
set_all_varptr ((zconf_t *)z, NULL);
for ( cp = confpara; cp->type != CONF_END; cp++ ) /* loop through all parameter */
if ( iscompatible (cp) ) /* is parameter compatible to current version? */
printconfigline (fp, cp); /* print it out */
if ( fp && fp != stdout && fp != stderr )
fclose (fp);
return 1;
}
/*****************************************************************
** printconfigdiff (fname, conf_a, conf_b)
*****************************************************************/
int printconfigdiff (const char *fname, const zconf_t *ref, const zconf_t *z)
{
zconf_para_t *cp;
int eq;
char *p1, *p2;
FILE *fp;
if ( ref == NULL || z == NULL )
return 0;
fp = NULL;
if ( fname && *fname )
{
if ( strcmp (fname, "stdout") == 0 )
fp = stdout;
else if ( strcmp (fname, "stderr") == 0 )
fp = stderr;
else if ( (fp = fopen(fname, "w")) == NULL )
{
error ("Could not open config file \"%s\" for writing\n", fname);
return -1;
}
}
set_all_varptr ((zconf_t *)z, ref);
for ( cp = confpara; cp->type != CONF_END; cp++ ) /* loop through all parameter */
{
eq = 0;
if ( iscmdline (cp) ) /* skip command line parameter */
continue;
if ( !iscompatible (cp) ) /* is parameter compatible to current version? */
continue;
if ( cp->type == CONF_VERSION || cp->type == CONF_END || cp->type == CONF_COMMENT )
continue;
dbg_val5 ("printconfigdiff: %d: %s %d %d %d\n", cp->type, cp->label,
compversion, cp->used_since, cp->used_till);
assert ( cp->var2 != NULL );
switch ( cp->type )
{
case CONF_VERSION:
case CONF_END:
case CONF_COMMENT:
continue;
case CONF_NSEC3:
eq = ( *(nsec3_t *)cp->var == *(nsec3_t *)cp->var2 );
break;
case CONF_SERIAL:
eq = ( *(serial_form_t *)cp->var == *(serial_form_t *)cp->var2 );
break;
case CONF_BOOL:
case CONF_ALGO:
case CONF_INT:
eq = ( *(int *)cp->var == *(int *)cp->var2 );
break;
case CONF_TIMEINT:
eq = ( *(long *)cp->var == *(long *)cp->var2 );
break;
case CONF_LEVEL:
case CONF_FACILITY:
case CONF_STRING:
p1 = *(char **)cp->var;
p2 = *(char **)cp->var2;
if ( p1 && p2 )
eq = strcmp (p1, p2) == 0;
else if ( p1 == NULL || p2 == NULL )
eq = 0;
else
eq = 1;
}
if ( !eq )
printconfigline (fp, cp); /* print it out */
}
if ( fp && fp != stdout && fp != stderr )
fclose (fp);
return 1;
}
/*****************************************************************
** checkconfig (config)
*****************************************************************/
int checkconfig (const zconf_t *z)
{
int ret;
long max_ttl;
if ( z == NULL )
return 1;
max_ttl = z->max_ttl;
if ( max_ttl <= 0 )
max_ttl = z->sigvalidity;
ret = 0;
if ( z->k_random && strcmp (z->k_random, "/dev/urandom") == 0 )
ret = fprintf (stderr, "random device without enough entropie used for KSK generation \n");
if ( z->z_random && strcmp (z->z_random, "/dev/urandom") == 0 )
ret = fprintf (stderr, "random device without enough entropie used for ZSK generation\n");
if ( z->k_bits < 512 || z->z_bits < 512 )
ret = fprintf (stderr, "Algorithm requires a bit size of at least 512 \n");
if ( z->k_algo == DK_ALGO_RSASHA512 && ( z->k_bits < 1024 || z->z_bits < 1024 ) )
ret = fprintf (stderr, "Algorithm RSASHA 512 requires a bit size of at least 1024 \n");
if ( z->saltbits < 4 )
ret = fprintf (stderr, "Saltlength must be at least 4 bits\n");
if ( z->saltbits > 128 )
{
fprintf (stderr, "While the maximum is 520 bits of salt, it's not recommended to use more than 128 bits.\n");
ret = fprintf (stderr, "The current value is %d bits\n", z->saltbits);
}
if ( z->sigvalidity < (1 * DAYSEC) || z->sigvalidity > (12 * WEEKSEC) )
{
fprintf (stderr, "Signature should be valid for at least 1 day and no longer than 3 month (12 weeks)\n");
ret = fprintf (stderr, "The current value is %s\n", timeint2str (z->sigvalidity));
}
if ( z->max_ttl <= 0 )
{
ret = fprintf (stderr, "The max TTL is unknown which results in suboptimal key rollover.\n");
fprintf (stderr, "Please set max_ttl to the maximum ttl used in the zone (run zkt-conf -w zone.db)\n");
}
else
if ( max_ttl > z->sigvalidity/2 )
ret = fprintf (stderr, "Max TTL (%ld) should be a few times smaller than the signature validity (%ld)\n",
max_ttl, z->sigvalidity);
// if ( z->resign > (z->sigvalidity*5/6) - (max_ttl + z->proptime) )
if ( z->resign > (z->sigvalidity*5/6) )
{
fprintf (stderr, "Re-signing interval (%s) should be less than ", timeint2str (z->resign));
ret = fprintf (stderr, "5/6 of sigvalidity (%s)\n", timeint2str (z->sigvalidity));
}
if ( z->max_ttl > 0 && z->resign > (z->sigvalidity - max_ttl) )
{
fprintf (stderr, "Re-signing interval (%s) should be ", timeint2str (z->resign));
fprintf (stderr, "end at least one max_ttl (%ld) before the end of ", max_ttl);
ret = fprintf (stderr, "signature lifetime (%ld) (%s)\n", z->sigvalidity, timeint2str(z->sigvalidity - max_ttl));
}
if ( z->z_life > (24 * WEEKSEC) * (z->z_bits / 512.) )
{
fprintf (stderr, "Lifetime of zone signing key (%s) ", timeint2str (z->z_life));
fprintf (stderr, "seems a little bit high ");
ret = fprintf (stderr, "(In respect of key size (%d))\n", z->z_bits);
}
if ( z->k_life > 0 && z->k_life <= z->z_life )
{
fprintf (stderr, "Lifetime of key signing key (%s) ", timeint2str (z->k_life));
ret = fprintf (stderr, "should be greater than lifetime of zsk\n");
}
if ( z->k_life > 0 && z->k_life > (52 * WEEKSEC) * (z->k_bits / 512.) )
{
fprintf (stderr, "Lifetime of key signing key (%s) ", timeint2str (z->k_life));
fprintf (stderr, "seems a little bit high ");
ret = fprintf (stderr, "(In respect of key size (%d))\n", z->k_bits);
}
return !ret;
}
#ifdef CONF_TEST
const char *progname;
static zconf_t *config;
main (int argc, char *argv[])
{
char *optstr;
int val;
progname = *argv;
config = loadconfig ("", (zconf_t *) NULL); /* load built in defaults */
while ( --argc >= 1 )
{
optstr = *++argv;
config = loadconfig_fromstr (optstr, config);
}
val = 1;
setconfigpar (config, "-v", &val);
val = 2;
setconfigpar (config, "verboselog", &val);
val = 1;
setconfigpar (config, "recursive", &val);
val = 1200;
setconfigpar (config, "propagation", &val);
printconfig ("stdout", config);
}
#endif