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

1259 lines
34 KiB
C

/* $NetBSD: dki.c,v 1.1.1.1 2015/07/08 15:37:48 christos Exp $ */
/*****************************************************************
**
** @(#) dki.c (c) Jan 2005 Holger Zuleger hznet.de
**
** A library for managing BIND dnssec key files.
**
** Copyright (c) Jan 2005, Holger Zuleger HZnet. 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 Holger Zuleger HZnet 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 <stdio.h>
# include <string.h>
# include <ctype.h> /* tolower(), ... */
# include <unistd.h> /* link(), unlink(), ... */
# include <stdlib.h>
# include <sys/types.h>
# include <sys/time.h>
# include <sys/stat.h>
# include <dirent.h>
# include <assert.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
# include "config_zkt.h"
# include "debug.h"
# include "domaincmp.h"
# include "misc.h"
# include "zconf.h"
#define extern
# include "dki.h"
#undef extern
/*****************************************************************
** private (static) function declaration and definition
*****************************************************************/
static char dki_estr[255+1];
static dki_t *dki_alloc ()
{
dki_estr[0] = '\0';
dki_t *dkp = malloc (sizeof (dki_t));
if ( (dkp = malloc (sizeof (dki_t))) )
{
memset (dkp, 0, sizeof (dki_t));
return dkp;
}
snprintf (dki_estr, sizeof (dki_estr),
"dki_alloc: Out of memory");
return NULL;
}
static int dki_readfile (FILE *fp, dki_t *dkp)
{
int algo, flags, type;
int c;
char *p;
char buf[4095+1];
char tag[25+1];
char val[14+1]; /* e.g. "YYYYMMDDhhmmss" | "60d" */
assert (dkp != NULL);
assert (fp != NULL);
while ( (c = getc (fp)) == ';' ) /* line start with comment ? */
{
tag[0] = val[0] = '\0';
if ( (c = getc (fp)) == '%' ) /* special comment? */
{
while ( (c = getc (fp)) == ' ' || c == '\t' )
;
ungetc (c, fp);
/* then try to read in the creation, expire and lifetime */
if ( fscanf (fp, "%25[a-zA-Z]=%14s", tag, val) == 2 )
{
dbg_val2 ("dki_readfile: tag=%s val=%s \n", tag, val);
switch ( tolower (tag[0]) )
{
case 'g': dkp->gentime = timestr2time (val); break;
case 'e': dkp->exptime = timestr2time (val); break;
case 'l': dkp->lifetime = atoi (val) * DAYSEC; break;
}
}
}
else
ungetc (c, fp);
while ( (c = getc (fp)) != EOF && c != '\n' ) /* eat up rest of the line */
;
}
ungetc (c, fp); /* push back last char */
if ( fscanf (fp, "%4095s", buf) != 1 ) /* read label */
return -1;
if ( strcmp (buf, dkp->name) != 0 )
return -2;
#if defined(TTL_IN_KEYFILE_ALLOWED) && TTL_IN_KEYFILE_ALLOWED
/* skip optional TTL value */
while ( (c = getc (fp)) != EOF && isspace (c) ) /* skip spaces */
;
if ( isdigit (c) ) /* skip ttl */
fscanf (fp, "%*d");
else
ungetc (c, fp); /* oops, no ttl */
#endif
if ( (c = fscanf (fp, " IN DNSKEY %d %d %d", &flags, &type, &algo)) != 3 &&
(c = fscanf (fp, "KEY %d %d %d", &flags, &type, &algo)) != 3 )
return -3;
if ( type != 3 || algo != dkp->algo )
return -4; /* no DNSKEY or algorithm mismatch */
if ( ((flags >> 8) & 0xFF) != 01 )
return -5; /* no ZONE key */
dkp->flags = flags;
if ( fgets (buf, sizeof buf, fp) == NULL || buf[0] == '\0' )
return -6;
p = buf + strlen (buf);
*--p = '\0'; /* delete trailing \n */
/* delete leading ws */
for ( p = buf; *p && isspace (*p); p++ )
;
dkp->pubkey = strdup (p);
return 0;
}
static int dki_writeinfo (const dki_t *dkp, const char *path)
{
FILE *fp;
assert (dkp != NULL);
assert (path != NULL && path[0] != '\0');
if ( (fp = fopen (path, "w")) == NULL )
return 0;
dbg_val1 ("dki_writeinfo %s\n", path);
if ( dki_prt_dnskey_raw (dkp, fp) == 0 )
return 0;
fclose (fp);
touch (path, dkp->time); /* restore time of key file */
return 1;
}
static int dki_setstat (dki_t *dkp, int status, int preserve_time);
/*****************************************************************
** public function definition
*****************************************************************/
/*****************************************************************
** dki_free ()
*****************************************************************/
void dki_free (dki_t *dkp)
{
assert (dkp != NULL);
if ( dkp->pubkey )
free (dkp->pubkey);
free (dkp);
}
/*****************************************************************
** dki_freelist ()
*****************************************************************/
void dki_freelist (dki_t **listp)
{
dki_t *curr;
dki_t *next;
assert (listp != NULL);
curr = *listp;
while ( curr )
{
next = curr->next;
dki_free (curr);
curr = next;
}
if ( *listp )
*listp = NULL;
}
#if defined(USE_TREE) && USE_TREE
/*****************************************************************
** dki_tfree ()
*****************************************************************/
void dki_tfree (dki_t **tree)
{
assert (tree != NULL);
// TODO: tdestroy is a GNU extension
// tdestroy (*tree, dki_free);
}
#endif
# define KEYGEN_COMPMODE "-C -q " /* this is the compability mode needed since BIND 9.7 */
/*****************************************************************
** dki_new ()
** create new keyfile
** allocate memory for new dki key and init with keyfile
*****************************************************************/
dki_t *dki_new (const char *dir, const char *name, int ksk, int algo, int bitsize, const char *rfile, int lf_days)
{
char cmdline[511+1];
char fname[254+1];
char randfile[254+1];
FILE *fp;
int len;
char *flag = "";
char *expflag = "";
dki_t *new;
if ( ksk )
flag = "-f KSK";
randfile[0] = '\0';
if ( rfile && *rfile )
snprintf (randfile, sizeof (randfile), "-r %.250s ", rfile);
#if defined(BIND_VERSION) && BIND_VERSION < 90902
if ( algo == DK_ALGO_RSA || algo == DK_ALGO_RSASHA1 || algo == DK_ALGO_RSASHA256 || algo == DK_ALGO_RSASHA512 )
expflag = "-e ";
#endif
if ( dir && *dir )
snprintf (cmdline, sizeof (cmdline), "cd %s ; %s %s%s%s-n ZONE -a %s -b %d %s %s",
dir, KEYGENCMD, KEYGEN_COMPMODE, randfile, expflag, dki_algo2str(algo), bitsize, flag, name);
else
snprintf (cmdline, sizeof (cmdline), "%s %s%s%s-n ZONE -a %s -b %d %s %s",
KEYGENCMD, KEYGEN_COMPMODE, randfile, expflag, dki_algo2str(algo), bitsize, flag, name);
dbg_msg (cmdline);
if ( (fp = popen (cmdline, "r")) == NULL || fgets (fname, sizeof fname, fp) == NULL )
return NULL;
pclose (fp);
len = strlen (fname) - 1;
if ( len >= 0 && fname[len] == '\n' )
fname[len] = '\0';
new = dki_read (dir, fname);
if ( new )
dki_setlifetime (new, lf_days); /* sets gentime + proposed lifetime */
return new;
}
/*****************************************************************
** dki_read ()
** read key from file 'filename' (independed of the extension)
*****************************************************************/
dki_t *dki_read (const char *dirname, const char *filename)
{
dki_t *dkp;
FILE *fp;
struct stat st;
int len;
int err;
char fname[MAX_FNAMESIZE+1];
char path[MAX_PATHSIZE+1];
dki_estr[0] = '\0';
if ( (dkp = dki_alloc ()) == NULL )
return (NULL);
len = sizeof (fname) - 1;
fname[len] = '\0';
strncpy (fname, filename, len);
len = strlen (fname); /* delete extension */
if ( len > 4 && strcmp (&fname[len - 4], DKI_KEY_FILEEXT) == 0 )
fname[len - 4] = '\0';
else if ( len > 10 && strcmp (&fname[len - 10], DKI_PUB_FILEEXT) == 0 )
fname[len - 10] = '\0';
else if ( len > 8 && strcmp (&fname[len - 8], DKI_ACT_FILEEXT) == 0 )
fname[len - 8] = '\0';
else if ( len > 12 && strcmp (&fname[len - 12], DKI_DEP_FILEEXT) == 0 )
fname[len - 12] = '\0';
dbg_line ();
assert (strlen (dirname)+1 < sizeof (dkp->dname));
strcpy (dkp->dname, dirname);
assert (strlen (fname)+1 < sizeof (dkp->fname));
strcpy (dkp->fname, fname);
dbg_line ();
if ( sscanf (fname, "K%254[^+]+%hd+%d", dkp->name, &dkp->algo, &dkp->tag) != 3 )
{
snprintf (dki_estr, sizeof (dki_estr),
"dki_read: Filename don't match expected format (%s)", fname);
return (NULL);
}
pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_KEY_FILEEXT);
dbg_val ("dki_read: path \"%s\"\n", path);
if ( (fp = fopen (path, "r")) == NULL )
{
snprintf (dki_estr, sizeof (dki_estr),
"dki_read: Can\'t open file \"%s\" for reading", path);
return (NULL);
}
dbg_line ();
if ( (err = dki_readfile (fp, dkp)) != 0 )
{
dbg_line ();
snprintf (dki_estr, sizeof (dki_estr),
"dki_read: Can\'t read key from file %s (errno %d)", path, err);
fclose (fp);
return (NULL);
}
dbg_line ();
if ( fstat (fileno(fp), &st) )
{
snprintf (dki_estr, sizeof (dki_estr),
"dki_read: Can\'t stat file %s", fname);
return (NULL);
}
dkp->time = st.st_mtime;
dbg_line ();
pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_ACT_FILEEXT);
if ( fileexist (path) )
{
if ( dki_isrevoked (dkp) )
dkp->status = DKI_REV;
else
dkp->status = DKI_ACT;
}
else
{
pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_PUB_FILEEXT);
if ( fileexist (path) )
dkp->status = DKI_PUB;
else
{
pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_DEP_FILEEXT);
if ( fileexist (path) )
dkp->status = DKI_DEP;
else
dkp->status = DKI_SEP;
}
}
dbg_line ();
fclose (fp);
dbg_line ();
return dkp;
}
/*****************************************************************
** dki_readdir ()
** read key files from directory 'dir' and, if recursive is
** true, from all directorys below that.
*****************************************************************/
int dki_readdir (const char *dir, dki_t **listp, int recursive)
{
dki_t *dkp;
DIR *dirp;
struct dirent *dentp;
char path[MAX_PATHSIZE+1];
dbg_val ("directory: opendir(%s)\n", dir);
if ( (dirp = opendir (dir)) == NULL )
return 0;
while ( (dentp = readdir (dirp)) != NULL )
{
if ( is_dotfilename (dentp->d_name) )
continue;
dbg_val ("directory: check %s\n", dentp->d_name);
pathname (path, sizeof (path), dir, dentp->d_name, NULL);
if ( is_directory (path) && recursive )
{
dbg_val ("directory: recursive %s\n", path);
dki_readdir (path, listp, recursive);
}
else if ( is_keyfilename (dentp->d_name) )
if ( (dkp = dki_read (dir, dentp->d_name)) )
dki_add (listp, dkp);
}
closedir (dirp);
return 1;
}
/*****************************************************************
** dki_setstatus_preservetime ()
** set status of key and change extension to
** ".published", ".private" or ".depreciated"
*****************************************************************/
int dki_setstatus_preservetime (dki_t *dkp, int status)
{
return dki_setstat (dkp, status, 1);
}
/*****************************************************************
** dki_setstatus ()
** set status of key and change extension to
** ".published", ".private" or ".depreciated"
*****************************************************************/
int dki_setstatus (dki_t *dkp, int status)
{
return dki_setstat (dkp, status, 0);
}
/*****************************************************************
** dki_setstat ()
** low level function of dki_setstatus and dki_setstatus_preservetime
*****************************************************************/
static int dki_setstat (dki_t *dkp, int status, int preserve_time)
{
char frompath[MAX_PATHSIZE+1];
char topath[MAX_PATHSIZE+1];
time_t totime;
if ( dkp == NULL )
return 0;
status = tolower (status);
switch ( dkp->status ) /* look at old status */
{
case 'r':
if ( status == 'r' )
return 1;
break;
case 'a':
if ( status == 'a' )
return 1;
pathname (frompath, sizeof (frompath), dkp->dname, dkp->fname, DKI_ACT_FILEEXT);
break;
case 'd':
if ( status == 'd' )
return 1;
pathname (frompath, sizeof (frompath), dkp->dname, dkp->fname, DKI_DEP_FILEEXT);
break;
case 'p': /* or 's' */
if ( status == 'p' || status == 's' )
return 1;
pathname (frompath, sizeof (frompath), dkp->dname, dkp->fname, DKI_PUB_FILEEXT);
break;
default:
/* TODO: set error code */
return 0;
}
dbg_val ("dki_setstat: \"%s\"\n", frompath);
dbg_val ("dki_setstat: to status \"%c\"\n", status);
/* a state change could result in different things: */
/* 1) write a new keyfile when the REVOKE bit is set or unset */
if ( status == 'r' || (status == 'a' && dki_isrevoked (dkp)) )
{
pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_KEY_FILEEXT);
if ( status == 'r' )
dki_setflag (dkp, DK_FLAG_REVOKE); /* set REVOKE bit */
else
dki_unsetflag (dkp, DK_FLAG_REVOKE); /* clear REVOKE bit */
dki_writeinfo (dkp, topath); /* ..and write it to the key file */
if ( !preserve_time )
touch (topath, time (NULL));
return 0;
}
/* 2) change the filename of the private key in all other cases */
totime = 0L;
if ( preserve_time )
totime = file_mtime (frompath); /* get original timestamp */
topath[0] = '\0';
switch ( status )
{
case 'a':
pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_ACT_FILEEXT);
break;
case 'd':
pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_DEP_FILEEXT);
break;
case 's': /* standby means a "published KSK" */
if ( !dki_isksk (dkp) )
return 2;
status = 'p';
/* fall through */
case 'p':
pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_PUB_FILEEXT);
break;
}
if ( topath[0] )
{
dbg_val ("dki_setstat: to \"%s\"\n", topath);
if ( link (frompath, topath) == 0 )
unlink (frompath);
dkp->status = status;
if ( !totime )
totime = time (NULL); /* set .key file to current time */
pathname (topath, sizeof (topath), dkp->dname, dkp->fname, DKI_KEY_FILEEXT);
touch (topath, totime); /* store/restore time of status change */
}
return 0;
}
/*****************************************************************
** dki_remove ()
** rename files associated with key, so that the keys are not
** recognized by the zkt tools e.g.
** Kdo.ma.in.+001+12345.key ==> kdo.ma.in.+001+12345.key
** (second one starts with a lower case 'k')
*****************************************************************/
dki_t *dki_remove (dki_t *dkp)
{
char path[MAX_PATHSIZE+1];
char newpath[MAX_PATHSIZE+1];
char newfile[MAX_FNAMESIZE+1];
dki_t *next;
const char **pext;
static const char *ext[] = {
DKI_KEY_FILEEXT, DKI_PUB_FILEEXT,
DKI_ACT_FILEEXT, DKI_DEP_FILEEXT,
NULL
};
if ( dkp == NULL )
return NULL;
strncpy (newfile, dkp->fname, sizeof (newfile));
*newfile = tolower (*newfile);
for ( pext = ext; *pext; pext++ )
{
pathname (path, sizeof (path), dkp->dname, dkp->fname, *pext);
if ( fileexist (path) )
{
pathname (newpath, sizeof (newpath), dkp->dname, newfile, *pext);
dbg_val2 ("dki_remove: %s ==> %s \n", path, newpath);
rename (path, newpath);
}
}
next = dkp->next;
dki_free (dkp);
return next;
}
/*****************************************************************
** dki_destroy ()
** delete files associated with key and free allocated memory
*****************************************************************/
dki_t *dki_destroy (dki_t *dkp)
{
char path[MAX_PATHSIZE+1];
dki_t *next;
const char **pext;
static const char *ext[] = {
DKI_KEY_FILEEXT, DKI_PUB_FILEEXT,
DKI_ACT_FILEEXT, DKI_DEP_FILEEXT,
NULL
};
if ( dkp == NULL )
return NULL;
for ( pext = ext; *pext; pext++ )
{
pathname (path, sizeof (path), dkp->dname, dkp->fname, *pext);
if ( fileexist (path) )
{
dbg_val ("dki_remove: %s \n", path);
unlink (path);
}
}
next = dkp->next;
dki_free (dkp);
return next;
}
/*****************************************************************
** dki_algo2str ()
** return a string describing the key algorithm
*****************************************************************/
char *dki_algo2str (int algo)
{
switch ( algo )
{
case DK_ALGO_RSA: return ("RSAMD5");
case DK_ALGO_DH: return ("DH");
case DK_ALGO_DSA: return ("DSA");
case DK_ALGO_EC: return ("EC");
case DK_ALGO_RSASHA1: return ("RSASHA1");
case DK_ALGO_NSEC3DSA: return ("NSEC3DSA");
case DK_ALGO_NSEC3RSASHA1: return ("NSEC3RSASHA1");
case DK_ALGO_RSASHA256: return ("RSASHA256");
case DK_ALGO_RSASHA512: return ("RSASHA512");
}
return ("unknown");
}
/*****************************************************************
** dki_algo2sstr ()
** return a short string describing the key algorithm
*****************************************************************/
char *dki_algo2sstr (int algo)
{
switch ( algo )
{
case DK_ALGO_RSA: return ("RSAMD5");
case DK_ALGO_DH: return ("DH");
case DK_ALGO_DSA: return ("DSA");
case DK_ALGO_EC: return ("EC");
case DK_ALGO_RSASHA1: return ("RSASHA1");
case DK_ALGO_NSEC3DSA: return ("N3DSA");
case DK_ALGO_NSEC3RSASHA1: return ("N3RSA1");
case DK_ALGO_RSASHA256: return ("RSASHA2");
case DK_ALGO_RSASHA512: return ("RSASHA5");
}
return ("unknown");
}
/*****************************************************************
** dki_geterrstr ()
** return error string
*****************************************************************/
const char *dki_geterrstr ()
{
return dki_estr;
}
/*****************************************************************
** dki_prt_dnskey ()
*****************************************************************/
int dki_prt_dnskey (const dki_t *dkp, FILE *fp)
{
return dki_prt_dnskeyttl (dkp, fp, 0);
}
/*****************************************************************
** dki_prt_dnskeyttl ()
*****************************************************************/
int dki_prt_dnskeyttl (const dki_t *dkp, FILE *fp, int ttl)
{
char *p;
if ( dkp == NULL )
return 0;
fprintf (fp, "%s ", dkp->name);
if ( ttl > 0 )
fprintf (fp, "%d ", ttl);
fprintf (fp, "IN DNSKEY ");
fprintf (fp, "%d 3 %d (", dkp->flags, dkp->algo);
fprintf (fp, "\n\t\t\t");
for ( p = dkp->pubkey; *p ; p++ )
if ( *p == ' ' )
fprintf (fp, "\n\t\t\t");
else
putc (*p, fp);
fprintf (fp, "\n\t\t");
if ( dki_isrevoked (dkp) )
fprintf (fp, ") ; key id = %u (original key id = %u)", (dkp->tag + 128) % 65535, dkp->tag);
else
fprintf (fp, ") ; key id = %u", dkp->tag);
fprintf (fp, "\n");
return 1;
}
/*****************************************************************
** dki_prt_dnskey_raw ()
*****************************************************************/
int dki_prt_dnskey_raw (const dki_t *dkp, FILE *fp)
{
int days;
if ( dkp == NULL )
return 0;
if ( dkp->gentime )
fprintf (fp, ";%%\tgenerationtime=%s\n", time2isostr (dkp->gentime, 's'));
if ( (days = dki_lifetimedays (dkp)) )
fprintf (fp, ";%%\tlifetime=%dd\n", days);
if ( dkp->exptime )
fprintf (fp, ";%%\texpirationtime=%s\n", time2isostr (dkp->exptime, 's'));
fprintf (fp, "%s ", dkp->name);
#if 0
if ( ttl > 0 )
fprintf (fp, "%d ", ttl);
#endif
fprintf (fp, "IN DNSKEY ");
fprintf (fp, "%d 3 %d ", dkp->flags, dkp->algo);
fprintf (fp, "%s\n", dkp->pubkey);
return 1;
}
/*****************************************************************
** dki_prt_comment ()
*****************************************************************/
int dki_prt_comment (const dki_t *dkp, FILE *fp)
{
int len = 0;
if ( dkp == NULL )
return len;
len += fprintf (fp, "; %s ", dkp->name);
len += fprintf (fp, "tag=%u ", dkp->tag);
len += fprintf (fp, "algo=%s ", dki_algo2str(dkp->algo));
len += fprintf (fp, "generated %s\n", time2str (dkp->time, 's'));
return len;
}
/*****************************************************************
** dki_prt_trustedkey ()
*****************************************************************/
int dki_prt_trustedkey (const dki_t *dkp, FILE *fp)
{
char *p;
int spaces;
int len = 0;
if ( dkp == NULL )
return len;
len += fprintf (fp, "\"%s\" ", dkp->name);
spaces = 22 - (strlen (dkp->name) + 3);
len += fprintf (fp, "%*s", spaces > 0 ? spaces : 0 , " ");
len += fprintf (fp, "%d 3 %d ", dkp->flags, dkp->algo);
if ( spaces < 0 )
len += fprintf (fp, "\n\t\t\t%7s", " ");
len += fprintf (fp, "\"");
for ( p = dkp->pubkey; *p ; p++ )
if ( *p == ' ' )
len += fprintf (fp, "\n\t\t\t\t");
else
putc (*p, fp), len += 1;
if ( dki_isrevoked (dkp) )
len += fprintf (fp, "\" ; # key id = %u (original key id = %u)\n\n", (dkp->tag + 128) % 65535, dkp->tag);
else
len += fprintf (fp, "\" ; # key id = %u\n\n", dkp->tag);
return len;
}
/*****************************************************************
** dki_prt_managedkey ()
*****************************************************************/
int dki_prt_managedkey (const dki_t *dkp, FILE *fp)
{
char *p;
int spaces;
int len = 0;
if ( dkp == NULL )
return len;
len += fprintf (fp, "\"%s\" ", dkp->name);
spaces = 22 - (strlen (dkp->name) + 3);
len += fprintf (fp, "initial-key ");
spaces -= 13;
len += fprintf (fp, "%*s", spaces > 0 ? spaces : 0 , " ");
len += fprintf (fp, "%d 3 %d ", dkp->flags, dkp->algo);
if ( spaces < 0 )
len += fprintf (fp, "\n\t\t\t%7s", " ");
len += fprintf (fp, "\"");
for ( p = dkp->pubkey; *p ; p++ )
if ( *p == ' ' )
len += fprintf (fp, "\n\t\t\t\t");
else
putc (*p, fp), len += 1;
if ( dki_isrevoked (dkp) )
len += fprintf (fp, "\" ; # key id = %u (original key id = %u)\n\n", (dkp->tag + 128) % 65535, dkp->tag);
else
len += fprintf (fp, "\" ; # key id = %u\n\n", dkp->tag);
return len;
}
/*****************************************************************
** dki_cmp () return <0 | 0 | >0
*****************************************************************/
int dki_cmp (const dki_t *a, const dki_t *b)
{
int res;
if ( a == NULL ) return -1;
if ( b == NULL ) return 1;
/* sort by domain name, */
if ( (res = domaincmp (a->name, b->name)) != 0 )
return res;
/* then by key type, */
if ( (res = dki_isksk (b) - dki_isksk (a)) != 0 )
return res;
/* and last by creation time, */
return (ulong)a->time - (ulong)b->time;
}
#if defined(USE_TREE) && USE_TREE
/*****************************************************************
** dki_allcmp () return <0 | 0 | >0
*****************************************************************/
int dki_allcmp (const dki_t *a, const dki_t *b)
{
int res;
if ( a == NULL ) return -1;
if ( b == NULL ) return 1;
// fprintf (stderr, "dki_allcmp %s, %s)\n", a->name, b->name);
/* sort by domain name, */
if ( (res = domaincmp (a->name, b->name)) != 0 )
return res;
/* then by key type, */
if ( (res = dki_isksk (b) - dki_isksk (a)) != 0 )
return res;
/* creation time, */
if ( (res = (ulong)a->time - (ulong)b->time) != 0 )
return res;
/* and last by tag */
return a->tag - b->tag;
}
/*****************************************************************
** dki_namecmp () return <0 | 0 | >0
*****************************************************************/
int dki_namecmp (const dki_t *a, const dki_t *b)
{
if ( a == NULL ) return -1;
if ( b == NULL ) return 1;
return domaincmp (a->name, b->name);
}
/*****************************************************************
** dki_revnamecmp () return <0 | 0 | >0
*****************************************************************/
int dki_revnamecmp (const dki_t *a, const dki_t *b)
{
if ( a == NULL ) return -1;
if ( b == NULL ) return 1;
return domaincmp_dir (a->name, b->name, 0);
}
/*****************************************************************
** dki_tagcmp () return <0 | 0 | >0
*****************************************************************/
int dki_tagcmp (const dki_t *a, const dki_t *b)
{
if ( a == NULL ) return -1;
if ( b == NULL ) return 1;
return a->tag - b->tag;
}
#endif
/*****************************************************************
** dki_timecmp ()
*****************************************************************/
int dki_timecmp (const dki_t *a, const dki_t *b)
{
if ( a == NULL ) return -1;
if ( b == NULL ) return 1;
return ((ulong)a->time - (ulong)b->time);
}
/*****************************************************************
** dki_algo () return the algorithm of the key
*****************************************************************/
time_t dki_algo (const dki_t *dkp)
{
assert (dkp != NULL);
return (dkp->algo);
}
/*****************************************************************
** dki_time () return the timestamp of the key
*****************************************************************/
time_t dki_time (const dki_t *dkp)
{
assert (dkp != NULL);
return (dkp->time);
}
/*****************************************************************
** dki_exptime () return the expiration timestamp of the key
*****************************************************************/
time_t dki_exptime (const dki_t *dkp)
{
assert (dkp != NULL);
return (dkp->exptime);
}
/*****************************************************************
** dki_lifetime (dkp) return the lifetime of the key in sec!
*****************************************************************/
time_t dki_lifetime (const dki_t *dkp)
{
assert (dkp != NULL);
return (dkp->lifetime);
}
/*****************************************************************
** dki_lifetimedays (dkp) return the lifetime of the key in days!
*****************************************************************/
ushort dki_lifetimedays (const dki_t *dkp)
{
assert (dkp != NULL);
return (dkp->lifetime / DAYSEC);
}
/*****************************************************************
** dki_gentime (dkp) return the generation timestamp of the key
*****************************************************************/
time_t dki_gentime (const dki_t *dkp)
{
assert (dkp != NULL);
return (dkp->gentime > 0L ? dkp->gentime: dkp->time);
}
/*****************************************************************
** dki_setlifetime (dkp, int days)
** set the lifetime in days (and also the gentime if not set)
** return the old lifetime of the key in days!
*****************************************************************/
ushort dki_setlifetime (dki_t *dkp, int days)
{
ulong lifetsec;
char path[MAX_PATHSIZE+1];
assert (dkp != NULL);
lifetsec = dkp->lifetime; /* old lifetime */
dkp->lifetime = days * DAYSEC; /* set new lifetime */
dbg_val1 ("dki_setlifetime (%d)\n", days);
if ( lifetsec == 0 ) /* initial setup (old lifetime was zero)? */
dkp->gentime = dkp->time;
pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_KEY_FILEEXT);
dki_writeinfo (dkp, path);
return (lifetsec / DAYSEC);
}
/*****************************************************************
** dki_setexptime (dkp, time_t sec)
** set the expiration time of the key in seconds since the epoch
** return the old exptime
*****************************************************************/
time_t dki_setexptime (dki_t *dkp, time_t sec)
{
char path[MAX_PATHSIZE+1];
time_t oldexptime;
assert (dkp != NULL);
dbg_val1 ("dki_setexptime (%ld)\n", sec);
oldexptime = dkp->exptime;
dkp->exptime = sec;
pathname (path, sizeof (path), dkp->dname, dkp->fname, DKI_KEY_FILEEXT);
dki_writeinfo (dkp, path);
#if 0 /* not necessary ? */
touch (path, time (NULL));
#endif
return (oldexptime);
}
/*****************************************************************
** dki_age () return age of key in seconds since 'curr'
*****************************************************************/
int dki_age (const dki_t *dkp, time_t curr)
{
assert (dkp != NULL);
return ((ulong)curr - (ulong)dkp->time);
}
/*****************************************************************
** dki_getflag () return the flags field of a key
*****************************************************************/
dk_flag_t dki_getflag (const dki_t *dkp, time_t curr)
{
return dkp->flags;
}
/*****************************************************************
** dki_setflag () set a flag of a key
*****************************************************************/
dk_flag_t dki_setflag (dki_t *dkp, dk_flag_t flag)
{
return dkp->flags |= (ushort)flag;
}
/*****************************************************************
** dki_unsetflag () unset a flag of a key
*****************************************************************/
dk_flag_t dki_unsetflag (dki_t *dkp, dk_flag_t flag)
{
return dkp->flags &= ~((ushort)flag);
}
/*****************************************************************
** dki_isksk ()
*****************************************************************/
int dki_isksk (const dki_t *dkp)
{
assert (dkp != NULL);
return (dkp->flags & DK_FLAG_KSK) == DK_FLAG_KSK;
}
/*****************************************************************
** dki_isrevoked ()
*****************************************************************/
int dki_isrevoked (const dki_t *dkp)
{
assert (dkp != NULL);
return (dkp->flags & DK_FLAG_REVOKE) == DK_FLAG_REVOKE;
}
/*****************************************************************
** dki_isdepreciated ()
*****************************************************************/
int dki_isdepreciated (const dki_t *dkp)
{
return dki_status (dkp) == DKI_DEPRECIATED;
}
/*****************************************************************
** dki_isactive ()
*****************************************************************/
int dki_isactive (const dki_t *dkp)
{
return dki_status (dkp) == DKI_ACTIVE;
}
/*****************************************************************
** dki_ispublished ()
*****************************************************************/
int dki_ispublished (const dki_t *dkp)
{
return dki_status (dkp) == DKI_PUBLISHED;
}
/*****************************************************************
** dki_status () return key status
*****************************************************************/
dk_status_t dki_status (const dki_t *dkp)
{
assert (dkp != NULL);
return (dkp->status);
}
/*****************************************************************
** dki_statusstr () return key status as string
*****************************************************************/
const char *dki_statusstr (const dki_t *dkp)
{
assert (dkp != NULL);
switch ( dkp->status )
{
case DKI_ACT: return "active";
case DKI_PUB: if ( dki_isksk (dkp) )
return "standby";
else
return "published";
case DKI_DEP: return "depreciated";
case DKI_REV: return "revoked";
case DKI_SEP: return "sep";
}
return "unknown";
}
/*****************************************************************
** dki_add () add a key to the given list
*****************************************************************/
dki_t *dki_add (dki_t **list, dki_t *new)
{
dki_t *curr;
dki_t *last;
if ( list == NULL )
return NULL;
if ( new == NULL )
return *list;
last = curr = *list;
while ( curr && dki_cmp (curr, new) < 0 )
{
last = curr;
curr = curr->next;
}
if ( curr == *list ) /* add node at start of list */
*list = new;
else /* add node at end or between two nodes */
last->next = new;
new->next = curr;
return *list;
}
/*****************************************************************
** dki_search () search a key with the given tag, or the first
** occurence of a key with the given name
*****************************************************************/
const dki_t *dki_search (const dki_t *list, int tag, const char *name)
{
const dki_t *curr;
curr = list;
if ( tag )
while ( curr && (tag != curr->tag ||
(name && *name && strcmp (name, curr->name) != 0)) )
curr = curr->next;
else if ( name && *name )
while ( curr && strcmp (name, curr->name) != 0 )
curr = curr->next;
else
curr = NULL;
return curr;
}
#if defined(USE_TREE) && USE_TREE
/*****************************************************************
** dki_tadd () add a key to the given tree
*****************************************************************/
dki_t *dki_tadd (dki_t **tree, dki_t *new, int sub_before)
{
dki_t **p;
if ( sub_before )
p = tsearch (new, tree, dki_namecmp);
else
p = tsearch (new, tree, dki_revnamecmp);
if ( *p == new )
dbg_val ("dki_tadd: New entry %s added\n", new->name);
else
{
dbg_val ("dki_tadd: New key added to %s\n", new->name);
dki_add (p, new);
}
return *p;
}
/*****************************************************************
** dki_tsearch () search a key with the given tag, or the first
** occurence of a key with the given name
*****************************************************************/
const dki_t *dki_tsearch (const dki_t *tree, int tag, const char *name)
{
dki_t search;
dki_t **p;
search.tag = tag;
snprintf (search.name, sizeof (search.name), "%s", name);
p = tfind (&search, &tree, dki_namecmp);
if ( p == NULL )
return NULL;
return dki_search (*p, tag, name);
}
#endif
/*****************************************************************
** dki_find () find the n'th ksk or zsk key with given status
*****************************************************************/
const dki_t *dki_find (const dki_t *list, int ksk, int status, int no)
{
const dki_t *dkp;
const dki_t *last;
last = NULL;
for ( dkp = list; no > 0 && dkp; dkp = dkp->next )
if ( dki_isksk (dkp) == ksk && dki_status (dkp) == status )
{
no--;
last = dkp;
}
return last;
}
/*****************************************************************
** dki_findalgo () find the n'th ksk or zsk key with given
** algorithm and status
*****************************************************************/
const dki_t *dki_findalgo (const dki_t *list, int ksk, int alg, int status, int no)
{
const dki_t *dkp;
const dki_t *last;
last = NULL;
for ( dkp = list; no > 0 && dkp; dkp = dkp->next )
if ( dki_isksk (dkp) == ksk && dki_algo (dkp) == alg &&
dki_status (dkp) == status )
{
no--;
last = dkp;
}
return last;
}