update to 9.7.1-P2
[tridge/bind9.git] / contrib / zkt / zconf.c
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 some slightly code changes by Holger Zuleger
9 **
10 **      Copyright (c) Aug 2005, Jeroen Massar, Holger Zuleger.
11 **      All rights reserved.
12 **      
13 **      This software is open source.
14 **      
15 **      Redistribution and use in source and binary forms, with or without
16 **      modification, are permitted provided that the following conditions
17 **      are met:
18 **      
19 **      Redistributions of source code must retain the above copyright notice,
20 **      this list of conditions and the following disclaimer.
21 **      
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.
25 **      
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.
29 **      
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.
41 **
42 ****************************************************************/
43 # include <sys/types.h>
44 # include <stdio.h>
45 # include <errno.h>
46 # include <unistd.h>
47 # include <stdlib.h>
48 # include <stdarg.h>
49 # include <string.h>
50 # include <strings.h>
51 # include <assert.h>
52 # include <ctype.h>
53
54 #ifdef HAVE_CONFIG_H
55 # include "config.h"
56 #endif
57 # include "config_zkt.h"
58 # include "debug.h"
59 # include "misc.h"
60 #define extern
61 # include "zconf.h"
62 #undef extern
63 # include "dki.h"
64
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) == '=' )
70
71
72 typedef enum {
73         CONF_END = 0,
74         CONF_STRING,
75         CONF_INT,
76         CONF_TIMEINT,
77         CONF_BOOL,
78         CONF_ALGO,
79         CONF_SERIAL,
80         CONF_FACILITY,
81         CONF_LEVEL,
82         CONF_COMMENT,
83 } ctype_t;
84
85 /*****************************************************************
86 **      private (static) variables
87 *****************************************************************/
88 static  zconf_t def = {
89         ZONEDIR, RECURSIVE, 
90         PRINTTIME, PRINTAGE, LJUST,
91         SIG_VALIDITY, MAX_TTL, KEY_TTL, PROPTIME, Incremental,
92         RESIGN_INT,
93         KEY_ALGO, ADDITIONAL_KEY_ALGO,
94         KSK_LIFETIME, KSK_BITS, KSK_RANDOM,
95         ZSK_LIFETIME, ZSK_BITS, ZSK_RANDOM,
96         SALTLEN,
97         NULL, /* viewname cmdline parameter */
98         0, /* noexec cmdline parameter */
99         LOGFILE, LOGLEVEL, SYSLOGFACILITY, SYSLOGLEVEL, VERBOSELOG, 0,
100         DNSKEYFILE, ZONEFILE, KEYSETDIR,
101         LOOKASIDEDOMAIN,
102         SIG_RANDOM, SIG_PSEUDO, SIG_GENDS, SIG_PARAM,
103         DIST_CMD,       /* defaults to NULL which means to run "rndc reload" */
104         NAMED_CHROOT
105 };
106
107 typedef struct {
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 */
112 } zconf_para_t;
113
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 },
119
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 },
126
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 },
136 #endif
137         { "Serialformat",       0,      CONF_SERIAL,    &def.serialform },
138
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 },
153
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 },
174
175         { NULL,                 0,      CONF_END,       NULL},
176 };
177
178 /*****************************************************************
179 **      private (static) function deklaration and definition
180 *****************************************************************/
181 static  const char      *bool2str (int val)
182 {
183         return val ? "True" : "False";
184 }
185
186 static  const char      *timeint2str (ulong val)
187 {
188         static  char    str[20+1];
189
190         if ( val == 0 )
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);
202         else
203                 snprintf (str, sizeof (str), "%lus", val);
204
205         return str;
206 }
207
208 static  int set_varptr (char *entry, void *ptr)
209 {
210         zconf_para_t    *c;
211
212         for ( c = confpara; c->label; c++ )
213                 if ( strcasecmp (entry, c->label) == 0 )
214                 {
215                         c->var = ptr;
216                         return 1;
217                 }
218         return 0;
219 }
220
221 static  void set_all_varptr (zconf_t *cp)
222 {
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);
228
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);
236 #endif
237         set_varptr ("serialformat", &cp->serialform);
238
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);
245
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);
252
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);
271 }
272
273 static  void    parseconfigline (char *buf, unsigned int line, zconf_t *z)
274 {
275         char            *end, *val, *p;
276         char            *tag;
277         unsigned int    len, found;
278         zconf_para_t    *c;
279
280         assert (buf[0] != '\0');
281
282         p = &buf[strlen(buf)-1];        /* Chop off white space at eol */
283         while ( p >= buf && isspace (*p) )
284                 *p-- = '\0';
285
286         for (p = buf; isspace (*p); p++ )       /* Ignore leading white space */
287                 ;
288         
289         /* Ignore comments and emtpy lines */
290         if ( *p == '\0' || ISCOMMENT (p) )
291                 return;
292
293         tag = p;
294         /* Get the end of the first argument */
295         end = &buf[strlen(buf)-1];
296         while ( p < end && !ISDELIM (*p) )      /* Skip until delim */
297                 p++;
298         *p++ = '\0';    /* Terminate this argument */
299         dbg_val1 ("Parsing \"%s\"\n", tag);
300
301
302         while ( p < end && ISDELIM (*p) )       /* Skip delim chars */
303                 p++;
304
305         val = p;        /* Start of the value */
306         dbg_val1 ("\tgot value \"%s\"\n", val);
307
308         /* If starting with quote, skip until next quote */
309         if ( *p == '"' || *p == '\'' )
310         {
311                 p++;    /* Find next quote */
312                 while ( p <= end && *p && *p != *val )
313                         p++;
314                 *p = '\0';
315                 val++;          /* Skip the first quote */
316         }
317         else    /* Otherwise check if there is any comment char at the end */
318         {
319                 while ( p < end && *p && !ISCOMMENT(p) )
320                         p++;
321                 if ( ISCOMMENT (p) )
322                 {
323                         do      /* Chop off white space before comment */
324                                 *p-- = '\0';
325                         while ( p >= val && isspace (*p) );
326                 }
327         }
328
329         /* Otherwise it is already terminated above */
330
331         found = 0;
332         c = confpara;
333         while ( !found && c->type != CONF_END )
334         {
335                 len = strlen (c->label);
336                 if ( strcasecmp (tag, c->label) == 0 )
337                 {
338                         char    **str;
339                         char    quantity;
340                         long    lval;
341
342                         found = 1;
343                         switch ( c->type )
344                         {
345                         case CONF_LEVEL:
346                         case CONF_FACILITY:
347                         case CONF_STRING:
348                                 str = (char **)c->var;
349                                 *str = strdup (val);
350                                 str_untaint (*str);     /* remove "bad" characters */
351                                 break;
352                         case CONF_INT:
353                                 sscanf (val, "%d", (int *)c->var);
354                                 break;
355                         case CONF_TIMEINT:
356                                 quantity = 'd';
357                                 sscanf (val, "%ld%c", &lval, &quantity);
358                                 if  ( quantity == 'm' )
359                                         lval *= MINSEC;
360                                 else if  ( quantity == 'h' )
361                                         lval *= HOURSEC;
362                                 else if  ( quantity == 'd' )
363                                         lval *= DAYSEC;
364                                 else if  ( quantity == 'w' )
365                                         lval *= WEEKSEC;
366                                 else if  ( quantity == 'y' )
367                                         lval *= YEARSEC;
368                                 (*(long *)c->var) = lval;
369                                 break;
370                         case CONF_ALGO:
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;
383                                 else
384                                         error ("Illegal algorithm \"%s\" "
385                                                 "in line %d.\n" , val, line);
386                                 break;
387                         case CONF_SERIAL:
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;
392                                 else
393                                         error ("Illegal serial no format \"%s\" "
394                                                 "in line %d.\n" , val, line);
395                                 break;
396                         case CONF_BOOL:
397                                 *((int *)c->var) = ISTRUE (val);
398                                 break;
399                         default:
400                                 fatal ("Illegal configuration type in line %d.\n", line);
401                         }
402                 }
403                 c++;
404         }
405         if ( !found )
406                 error ("Unknown configuration statement: %s \"%s\"\n", tag, val);
407         return;
408 }
409
410 static  void    printconfigline (FILE *fp, zconf_para_t *cp)
411 {
412         int     i;
413         long    lval;
414
415         assert (fp != NULL);
416         assert (cp != NULL);
417
418         switch ( cp->type )
419         {
420         case CONF_COMMENT:
421                 if ( cp->var )
422                         fprintf (fp, "#   %s\n", (char *)cp->var);
423                 else
424                         fprintf (fp, "\n");
425                 break;
426         case CONF_LEVEL:
427         case CONF_FACILITY:
428                 if ( *(char **)cp->var != NULL )
429                 {
430                         if ( **(char **)cp->var != '\0' )
431                         {
432                                 char    *p;
433
434                                 fprintf (fp, "%s:\t", cp->label);
435                                 for ( p = *(char **)cp->var; *p; p++ )
436                                         putc (toupper (*p), fp);
437                                 fprintf (fp, "\n");
438                         }
439                         else
440                                 fprintf (fp, "%s:\tNONE", cp->label);
441                 }
442                 break;
443         case CONF_STRING:
444                 if ( *(char **)cp->var )
445                         fprintf (fp, "%s:\t\"%s\"\n", cp->label, *(char **)cp->var);
446                 break;
447         case CONF_BOOL:
448                 fprintf (fp, "%s:\t%s\n", cp->label, bool2str ( *(int*)cp->var ));
449                 break;
450         case CONF_TIMEINT:
451                 lval = *(ulong*)cp->var;        /* in that case it should be of type ulong */
452                 fprintf (fp, "%s:\t%s", cp->label, timeint2str (lval));
453                 if ( lval )
454                         fprintf (fp, "\t# (%ld seconds)", lval);
455                 putc ('\n', fp);
456                 break;
457         case CONF_ALGO:
458                 i = *(int*)cp->var;
459                 if ( i )
460                 {
461                         fprintf (fp, "%s:\t%s", cp->label, dki_algo2str (i));
462                         fprintf (fp, "\t# (Algorithm ID %d)\n", i);
463                 }
464                 break;
465         case CONF_SERIAL:
466                 fprintf (fp, "%s:\t", cp->label);
467                 if ( *(serial_form_t*)cp->var == Unixtime )
468                         fprintf (fp, "unixtime\n");
469                 else
470                         fprintf (fp, "incremental\n");
471                 break;
472         case CONF_INT:
473                 fprintf (fp, "%s:\t%d\n", cp->label, *(int *)cp->var);
474                 break;
475         case CONF_END:
476                 /* NOTREACHED */
477                 break;
478         }
479 }
480
481 /*****************************************************************
482 **      public function definition
483 *****************************************************************/
484
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
489 **      allocated.
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)
494 {
495         FILE            *fp;
496         char            buf[1023+1];
497         unsigned int    line;
498
499         if ( z == NULL )        /* allocate new memory for zconf_t */
500         {
501                 if ( (z = calloc (1, sizeof (zconf_t))) == NULL )
502                         return NULL;
503
504                 if ( filename && *filename )
505                         memcpy (z, &def, sizeof (zconf_t));     /* init new struct with defaults */
506         }
507
508         if ( filename == NULL || *filename == '\0' )    /* no file name given... */
509         {
510                 dbg_val0("loadconfig (NULL)\n");
511                 memcpy (z, &def, sizeof (zconf_t));             /* ..then init with defaults */
512                 return z;
513         }
514
515         dbg_val1 ("loadconfig (%s)\n", filename);
516         set_all_varptr (z);
517
518         if ( (fp = fopen(filename, "r")) == NULL )
519                 fatal ("Could not open config file \"%s\"\n", filename);
520
521         line = 0;
522         while (fgets(buf, sizeof(buf), fp))
523                 parseconfigline (buf, ++line, z);
524
525         fclose(fp);
526         return z;
527 }
528
529 # define        STRCONFIG_DELIMITER     ";\r\n"
530 zconf_t *loadconfig_fromstr (const char *str, zconf_t *z)
531 {
532         char            *buf;
533         char            *tok,   *toksave;
534         unsigned int    line;
535
536         if ( z == NULL )
537         {
538                 if ( (z = calloc (1, sizeof (zconf_t))) == NULL )
539                         return NULL;
540                 memcpy (z, &def, sizeof (zconf_t));             /* init with defaults */
541         }
542
543         if ( str == NULL || *str == '\0' )
544         {
545                 dbg_val0("loadconfig_fromstr (NULL)\n");
546                 memcpy (z, &def, sizeof (zconf_t));             /* init with defaults */
547                 return z;
548         }
549
550         dbg_val1 ("loadconfig_fromstr (\"%s\")\n", str);
551         set_all_varptr (z);
552
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");
556
557         line = 0;
558         tok = strtok_r (buf, STRCONFIG_DELIMITER, &toksave);
559         while ( tok )
560         {
561                 line++;
562                 parseconfigline (tok, line, z);
563                 tok = strtok_r (NULL, STRCONFIG_DELIMITER, &toksave);
564         }
565         free (buf);
566         return z;
567 }
568
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)
574 {
575         zconf_t *z;
576
577         assert (conf != NULL);
578
579         if ( (z = calloc (1, sizeof (zconf_t))) == NULL )
580                 return NULL;
581
582         memcpy (z, conf, sizeof (zconf_t));
583
584         return z;
585 }
586
587 /*****************************************************************
588 **      setconfigpar (entry, pval)
589 *****************************************************************/
590 int     setconfigpar (zconf_t *config, char *entry, const void *pval)
591 {
592         char    *str;
593         zconf_para_t    *c;
594
595         set_all_varptr (config);
596
597         for ( c = confpara; c->type != CONF_END; c++ )
598                 if ( strcasecmp (entry, c->label) == 0 )
599                 {
600                         switch ( c->type )
601                         {
602                         case CONF_LEVEL:
603                         case CONF_FACILITY:
604                         case CONF_STRING:
605                                 if ( pval )
606                                 {
607                                         str = strdup ((char *)pval);
608                                         str_untaint (str);      /* remove "bad" characters */
609                                 }
610                                 else
611                                         str = NULL;
612                                 *((char **)c->var) = str;
613                                 break;
614                         case CONF_BOOL:
615                                 /* fall through */
616                         case CONF_ALGO:
617                                 /* fall through */
618                         case CONF_INT:
619                                 *((int *)c->var) = *((int *)pval);
620                                 break;
621                         case CONF_TIMEINT:
622                                 *((long *)c->var) = *((long *)pval);
623                                 break;
624                         case CONF_SERIAL:
625                                 *((serial_form_t *)c->var) = *((serial_form_t *)pval);
626                                 break;
627                         case CONF_COMMENT:
628                         case CONF_END:
629                                 /* NOTREACHED */
630                                 break;
631                         }
632                         return 1;
633                 }
634         return 0;
635 }
636
637 /*****************************************************************
638 **      printconfig (fname, config)
639 *****************************************************************/
640 int     printconfig (const char *fname, const zconf_t *z)
641 {
642         zconf_para_t    *cp;
643         FILE    *fp;
644
645         if ( z == NULL )
646                 return 0;
647
648         fp = stdout;
649         if ( fname && *fname )
650         {
651                 if ( strcmp (fname, "stdout") == 0 )
652                         fp = stdout;
653                 else if ( strcmp (fname, "stderr") == 0 )
654                         fp = stderr;
655                 else if ( (fp = fopen(fname, "w")) == NULL )
656                 {
657                         error ("Could not open config file \"%s\" for writing\n", fname);
658                         return -1;
659                 }
660         }
661                 
662         set_all_varptr ((zconf_t *)z);
663
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 */
667
668         if ( fp && fp != stdout && fp != stderr )
669                 fclose (fp);
670
671         return 1;
672 }
673
674 #if 0
675 /*****************************************************************
676 **      printconfigdiff (fname, conf_a, conf_b)
677 *****************************************************************/
678 int     printconfigdiff (const char *fname, const zconf_t *ref, const zconf_t *z)
679 {
680         zconf_para_t    *cp;
681         FILE    *fp;
682
683         if ( ref == NULL || z == NULL )
684                 return 0;
685
686         fp = NULL;
687         if ( fname && *fname )
688         {
689                 if ( strcmp (fname, "stdout") == 0 )
690                         fp = stdout;
691                 else if ( strcmp (fname, "stderr") == 0 )
692                         fp = stderr;
693                 else if ( (fp = fopen(fname, "w")) == NULL )
694                 {
695                         error ("Could not open config file \"%s\" for writing\n", fname);
696                         return -1;
697                 }
698         }
699                 
700         set_all_varptr ((zconf_t *)z);
701
702         for ( cp = confpara; cp->type != CONF_END; cp++ )       /* loop through all parameter */
703         {
704                 if ( cp->cmdline )
705                         continue;
706
707                 
708                         printconfigline (fp, cp);       /* print it out */
709         }
710
711         if ( fp && fp != stdout && fp != stderr )
712                 fclose (fp);
713
714         return 1;
715 }
716 #endif
717
718 /*****************************************************************
719 **      checkconfig (config)
720 *****************************************************************/
721 int     checkconfig (const zconf_t *z)
722 {
723         if ( z == NULL )
724                 return 1;
725
726         if ( z->saltbits < 4 )
727                 fprintf (stderr, "Saltlength must be at least 4 bits\n");
728         if ( z->saltbits > 128 )
729         {
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);
732         }
733
734         if ( z->sigvalidity < (1 * DAYSEC) || z->sigvalidity > (12 * WEEKSEC) )
735         {
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));
738         }
739
740         if ( z->resign > (z->sigvalidity*5/6) - (z->max_ttl + z->proptime) )
741         {
742                 fprintf (stderr, "Re-signing interval (%s) should be less than ", timeint2str (z->resign));
743                 fprintf (stderr, "5/6 of sigvalidity\n");
744         }
745         if ( z->resign < (z->max_ttl + z->proptime) )
746         {
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);
750         }
751
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);
755
756         if ( z->z_life > (12 * WEEKSEC) * (z->z_bits / 512.) )
757         {
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);
761         }
762
763         if ( z->k_life > 0 && z->k_life <= z->z_life )
764         {
765                 fprintf (stderr, "Lifetime of key signing key (%s) ", timeint2str (z->k_life));
766                 fprintf (stderr, "should be greater than lifetime of zsk\n");
767         }
768         if ( z->k_life > 0 && z->k_life > (26 * WEEKSEC) * (z->k_bits / 512.) )
769         {
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);
773         }
774
775         return 1;
776 }
777
778 #ifdef CONF_TEST
779 const char *progname;
780 static  zconf_t *config;
781
782 main (int argc, char *argv[])
783 {
784         char    *optstr;
785         int     val;
786
787         progname = *argv;
788
789         config = loadconfig ("", (zconf_t *) NULL);     /* load built in defaults */
790
791         while ( --argc >= 1 )
792         {
793                 optstr = *++argv;
794                 config = loadconfig_fromstr (optstr, config);
795         }
796
797         val = 1;
798         setconfigpar (config, "-v", &val);
799         val = 2;
800         setconfigpar (config, "verboselog", &val);
801         val = 1;
802         setconfigpar (config, "recursive", &val);
803         val = 1200;
804         setconfigpar (config, "propagation", &val);
805         
806         printconfig ("stdout", config);
807 }
808 #endif