mirror of
https://github.com/zerotier/edge.git
synced 2026-05-22 16:25:05 -07:00
588 lines
12 KiB
Perl
Executable File
588 lines
12 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
#
|
|
# Copyright 2005-2014 SPARTA, Inc. All rights reserved. See the COPYING
|
|
# file distributed with this software for details.
|
|
#
|
|
#
|
|
# cleankrf
|
|
#
|
|
# This script cleans unused key keyrecs from a keyrec.
|
|
#
|
|
|
|
use strict;
|
|
|
|
use Getopt::Long qw(:config no_ignore_case_always);
|
|
|
|
use Net::DNS::SEC::Tools::conf;
|
|
use Net::DNS::SEC::Tools::keyrec;
|
|
use Net::DNS::SEC::Tools::tooloptions;
|
|
|
|
#
|
|
# Version information.
|
|
#
|
|
my $NAME = "cleankrf";
|
|
my $VERS = "$NAME version: 2.1.0";
|
|
my $DTVERS = "DNSSEC-Tools Version: 2.2.3";
|
|
|
|
#######################################################################
|
|
|
|
#
|
|
# Data required for command line options.
|
|
#
|
|
my $count = 0; # Error-count flag.
|
|
my $list = 0; # List-only flag.
|
|
my $quiet = 0; # Quiet flag.
|
|
my $remove = 0; # Remove key file flag.
|
|
my $verbose = 0; # Verbose flag.
|
|
my %options = (); # Filled option array.
|
|
my @opts =
|
|
(
|
|
"count", # Give final error count.
|
|
"list", # Only list orphaned keys, don't delete.
|
|
"quiet", # Don't give any output.
|
|
"rm", # Remove key file.
|
|
"verbose", # Give lotsa output.
|
|
"Version", # Show version number.
|
|
"help", # Give a usage message and exit.
|
|
);
|
|
|
|
my $orphsets = 0; # Total count of orphaned sets.
|
|
my $orphans = 0; # Total count of orphaned keys.
|
|
my $obsoletes = 0; # Total count of obsolete keys.
|
|
|
|
|
|
my @krnames; # List of keyrecs in the file.
|
|
|
|
my %zones = (); # Names of zone keyrecs.
|
|
my %sets = (); # Names of set keyrecs.
|
|
my %keys = (); # Names of key keyrecs.
|
|
|
|
main();
|
|
exit($orphans);
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Routine: main()
|
|
#
|
|
# Purpose: This is the top-level processing routine for the command.
|
|
#
|
|
sub main
|
|
{
|
|
my $argc = @ARGV; # Number of command line arguments.
|
|
|
|
erraction(ERR_EXIT);
|
|
|
|
#
|
|
# Check our options.
|
|
#
|
|
optsandargs();
|
|
|
|
#
|
|
# Search each specified keyrec file individually for orphaned
|
|
# key keyrecs.
|
|
#
|
|
while($argc > 0)
|
|
{
|
|
#
|
|
# Read the keyrec file.
|
|
#
|
|
getkeyrecs($ARGV[0]);
|
|
|
|
#
|
|
# Check for orphaned signing sets.
|
|
#
|
|
setchecks();
|
|
|
|
#
|
|
# Check for orphaned and obsolete keys.
|
|
#
|
|
keychecks();
|
|
|
|
#
|
|
# Move on to the next keyrec file.
|
|
#
|
|
shift @ARGV;
|
|
$argc = @ARGV;
|
|
}
|
|
|
|
#
|
|
# Save the modified keyrec file -- iff we're not just listing.
|
|
#
|
|
keyrec_write() if(!$list);
|
|
|
|
#
|
|
# If -count was given, give the counts of orphaned and obsolete keys.
|
|
#
|
|
if($count)
|
|
{
|
|
#
|
|
# Check for orphaned sets.
|
|
#
|
|
if($orphsets == 1) { print("1 orphaned set\n"); }
|
|
else { print("$orphsets orphaned sets\n"); }
|
|
|
|
#
|
|
# Check for orphaned keys.
|
|
#
|
|
if($orphans == 1) { print("1 orphaned key\n"); }
|
|
else { print("$orphans orphaned keys\n"); }
|
|
|
|
#
|
|
# Check for obsolete keys.
|
|
#
|
|
if($obsoletes == 1) { print("1 obsolete keys\n"); }
|
|
else { print("$obsoletes obsolete keys\n"); }
|
|
}
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Routine: optsandargs()
|
|
#
|
|
# Purpose: This routine processes the command's options and arguments.
|
|
#
|
|
sub optsandargs
|
|
{
|
|
my $argc = @ARGV; # Number of command line arguments.
|
|
|
|
GetOptions(\%options,@opts) || usage();
|
|
$count = $options{'count'};
|
|
$list = $options{'list'};
|
|
$quiet = $options{'quiet'};
|
|
$remove = $options{'rm'};
|
|
$verbose = $options{'verbose'};
|
|
|
|
usage() if(defined($options{'help'}));
|
|
version() if(defined($options{'Version'}));
|
|
|
|
#
|
|
# Can't have verbosity and quietude.
|
|
#
|
|
$verbose = 0 if($quiet);
|
|
|
|
#
|
|
# Ensure we were given a keyrec file to check.
|
|
#
|
|
usage() if($argc == 0);
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Routine: getkeyrecs()
|
|
#
|
|
# Purpose: This routine reads a keyrec file and puts each keyrec into
|
|
# either a zone hash or a key hash.
|
|
#
|
|
sub getkeyrecs
|
|
{
|
|
my $krfile = shift; # Keyrec file.
|
|
|
|
#
|
|
# Read the keyrec file and get a list of the keyrec names.
|
|
#
|
|
keyrec_read($krfile);
|
|
@krnames = keyrec_names();
|
|
|
|
#
|
|
# Go through each keyrec and put it in the appropriate hash table.
|
|
#
|
|
foreach my $krn (sort(@krnames))
|
|
{
|
|
my $kr; # Reference to keyrec.
|
|
my %keyrec; # Keyrec.
|
|
my $type; # Keyrec's type.
|
|
my $styp; # Keyrec's set type.
|
|
|
|
$kr = keyrec_fullrec($krn);
|
|
%keyrec = %$kr;
|
|
|
|
$type = $keyrec{'keyrec_type'};
|
|
$styp = $keyrec{'set_type'};
|
|
|
|
if($type eq 'zone')
|
|
{
|
|
$zones{$krn} = $kr;
|
|
}
|
|
elsif(($type eq 'set') ||
|
|
(($type eq 'kskobs') && ($styp eq 'kskobs')))
|
|
{
|
|
$sets{$krn} = $kr;
|
|
}
|
|
else
|
|
{
|
|
$keys{$krn} = $kr;
|
|
}
|
|
}
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Routine: setchecks()
|
|
#
|
|
# Purpose: This routine searches the list of signing sets in a keyrec
|
|
# file for orphaned sets. If found, the orphans are deleted,
|
|
# unless the -list option was specified.
|
|
#
|
|
sub setchecks
|
|
{
|
|
#
|
|
# If there are no signing sets, we have nothing here to do.
|
|
#
|
|
if(length(%sets) == 0)
|
|
{
|
|
vprint("no signing sets defined\n");
|
|
return;
|
|
}
|
|
|
|
#
|
|
# Check each key to see if it is an orphan. If so, we'll delete it,
|
|
# unless the user just wants a list of orphans.
|
|
#
|
|
foreach my $setname (sort(keys(%sets)))
|
|
{
|
|
my $zone = $sets{$setname}{'zonename'}; # Set's zone.
|
|
|
|
#
|
|
# Handle two error conditions:
|
|
# - the set's zone doesn't exist
|
|
# - the set isn't a current set in its zone
|
|
#
|
|
if(!defined($zones{$zone}))
|
|
{
|
|
qprint("warning: set $setname references $zone, but $zone does not exist\n");
|
|
$orphsets++;
|
|
}
|
|
elsif(($zones{$zone}{'zskcur'} ne $setname) &&
|
|
($zones{$zone}{'zskpub'} ne $setname) &&
|
|
($zones{$zone}{'zsknew'} ne $setname) &&
|
|
($zones{$zone}{'zsknew'} ne $setname) &&
|
|
($zones{$zone}{'kskcur'} ne $setname) &&
|
|
($zones{$zone}{'kskpub'} ne $setname)
|
|
)
|
|
{
|
|
qprint("obsolete set: $setname\n");
|
|
$orphsets++;
|
|
|
|
#
|
|
# Resetting the keyrec_type to ensure that obsolete
|
|
# KSK sets will actually be deleted.
|
|
#
|
|
keyrec_setval('set',$setname,'keyrec_type','set');
|
|
}
|
|
else
|
|
{
|
|
vprint("referenced set: $setname ($zone)\n");
|
|
next;
|
|
}
|
|
|
|
#
|
|
# Go to the next set if we're just listing or if this
|
|
# one is okay.
|
|
#
|
|
next if($list);
|
|
|
|
#
|
|
# Delete the set.
|
|
#
|
|
keyrec_del($setname);
|
|
delete $sets{$setname};
|
|
}
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Routine: keychecks()
|
|
#
|
|
# Purpose: This routine searches the list of keys in a keyrec file for
|
|
# orphaned keys. If found, the orphans are deleted, unless
|
|
# the -list option was specified.
|
|
#
|
|
sub keychecks
|
|
{
|
|
#
|
|
# If there are no keys, we have nothing here to do.
|
|
#
|
|
if(length(%keys) == 0)
|
|
{
|
|
vprint("no keys defined\n");
|
|
return;
|
|
}
|
|
|
|
#
|
|
# Check each key to see if it is obsolete. If so, we'll delete it,
|
|
# unless the user just wants a list of obsolete keys.
|
|
#
|
|
# This should find anything, as obsolete keys should be orphans.
|
|
# However, we'll do this check just to be sure.
|
|
#
|
|
foreach my $keyname (sort(keys(%keys)))
|
|
{
|
|
my $kr; # Keyrec reference.
|
|
my %keyrec; # Keyrec hash.
|
|
|
|
$kr = $keys{$keyname};
|
|
%keyrec = %$kr;
|
|
|
|
if(($keyrec{'keyrec_type'} eq "zskobs") ||
|
|
($keyrec{'keyrec_type'} eq "kskobs") ||
|
|
($keyrec{'keyrec_type'} eq "kskrev"))
|
|
{
|
|
qprint("obsolete key: $keyname\n");
|
|
$obsoletes++;
|
|
|
|
next if($list);
|
|
|
|
rmkey($keyname) if($remove);
|
|
keyrec_del($keyname);
|
|
delete $keys{$keyname};
|
|
}
|
|
}
|
|
|
|
#
|
|
# Check each key to see if it is an orphan. If so, we'll delete it,
|
|
# unless the user just wants a list of orphans.
|
|
#
|
|
foreach my $keyname (sort(keys(%keys)))
|
|
{
|
|
if(orphankey($keyname))
|
|
{
|
|
next if($list);
|
|
|
|
rmkey($keyname) if($remove);
|
|
keyrec_del($keyname);
|
|
delete $keys{$keyname};
|
|
}
|
|
}
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Routine: orphankey()
|
|
#
|
|
# Purpose: This routine checks if a given key is an orphan or if it's
|
|
# referenced by a signing set.
|
|
# The orphan count is incremented when an orphan is found.
|
|
#
|
|
# Return Values:
|
|
# 0 - referenced key
|
|
# 1 - orphaned key
|
|
#
|
|
sub orphankey
|
|
{
|
|
my $keyname = shift; # Keyrec's name.
|
|
my $kr; # Keyrec reference.
|
|
my %keyrec; # Key's keyrec.
|
|
my @keysets = (); # Set list.
|
|
my $found = 0; # Found flag.
|
|
|
|
#
|
|
# Get the key's keyrec and save the its zone name.
|
|
#
|
|
$kr = $keys{$keyname};
|
|
%keyrec = %$kr;
|
|
|
|
#
|
|
# Check the zones to see if one references this key.
|
|
#
|
|
foreach my $setname (sort(keys(%sets)))
|
|
{
|
|
if(keyrec_signset_haskey($setname,$keyname))
|
|
{
|
|
push @keysets, $setname;
|
|
$found = 1;
|
|
}
|
|
}
|
|
|
|
#
|
|
# Give an appropriate message. If the key was found, we'll
|
|
# report all the sets it belongs to.
|
|
#
|
|
if($found)
|
|
{
|
|
my $setlist; # All of key's sets.
|
|
|
|
$setlist = join ' ', @keysets;
|
|
vprint("referenced key: $keyname $setlist\n");
|
|
return(0);
|
|
}
|
|
|
|
#
|
|
# This key isn't referenced by any of our zones, so it's an orphan.
|
|
# Bump our counter and give an error message.
|
|
#
|
|
qprint("orphaned key: $keyname\n");
|
|
$orphans++;
|
|
return(1);
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Routine: rmkey()
|
|
#
|
|
# Purpose: This routine deletes the .key and .private file associated
|
|
# with the key specified by the caller.
|
|
#
|
|
sub rmkey
|
|
{
|
|
my $keyname = shift; # Keyrec's name.
|
|
my $keyrec; # Key's keyrec.
|
|
my $fname; # Name of key to be deleted.
|
|
|
|
#
|
|
# Get the key's keyrec and save its pathname.
|
|
#
|
|
$keyrec = $keys{$keyname};
|
|
$fname = $keyrec->{'keypath'};
|
|
return if($fname eq "");
|
|
|
|
#
|
|
# Delete the public half of the key.
|
|
#
|
|
print "\tunlinking $fname\n" if($verbose);
|
|
unlink($fname);
|
|
|
|
#
|
|
# Delete the private half of the key.
|
|
#
|
|
$fname =~ s/key$/private/;
|
|
print "\tunlinking $fname\n" if($verbose);
|
|
unlink($fname);
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Routine: qprint()
|
|
#
|
|
# Purpose: Print the given output iff -quiet wasn't specified.
|
|
#
|
|
sub qprint
|
|
{
|
|
my $line = shift;
|
|
|
|
print $line if(!$quiet);
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Routine: vprint()
|
|
#
|
|
# Purpose: Print the given output iff -verbose was specified.
|
|
#
|
|
sub vprint
|
|
{
|
|
my $line = shift;
|
|
|
|
print $line if($verbose);
|
|
}
|
|
|
|
#----------------------------------------------------------------------
|
|
# Routine: version()
|
|
#
|
|
# Purpose: Print the version number(s) and exit.
|
|
#
|
|
sub version
|
|
{
|
|
print STDERR "$VERS\n";
|
|
print STDERR "$DTVERS\n";
|
|
|
|
exit(0);
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Routine: usage()
|
|
#
|
|
sub usage
|
|
{
|
|
print STDERR "usage: cleankrf [options] <keyrec files>\n";
|
|
print STDERR "\toptions:\n";
|
|
print STDERR "\t\t-count - give count of orphan keys\n";
|
|
print STDERR "\t\t-list - only list orphaned keys\n";
|
|
print STDERR "\t\t-rm - delete orphaned keys\n";
|
|
print STDERR "\t\t-quiet - don't give any output\n";
|
|
print STDERR "\t\t-verbose - give much output\n";
|
|
print STDERR "\t\t-Version - show the version number\n";
|
|
print STDERR "\t\t-help - give a usage message and exit\n";
|
|
|
|
exit(0);
|
|
}
|
|
|
|
1;
|
|
|
|
##############################################################################
|
|
#
|
|
|
|
=pod
|
|
|
|
=head1 NAME
|
|
|
|
cleankrf - Clean a DNSSEC-Tools I<keyrec> files of old data
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
cleankrf [options] <keyrec-files>
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
B<cleankrf> cleans old data out of a set of DNSSEC-Tools I<keyrec> files.
|
|
The old data are obsolete signing sets, orphaned keys, and obsolete keys.
|
|
|
|
Obsolete signing sets are set I<keyrec>s unreferenced by a zone I<keyrec>.
|
|
Revoked signing sets are considered obsolete by B<cleankrf>.
|
|
|
|
Orphaned keys are KSK and ZSK key I<keyrec>s unreferenced by a set I<keyrec>.
|
|
|
|
Obsolete keys are key I<keyrec>s with a I<keyrec_type> of B<kskobs> or
|
|
B<zskobs>.
|
|
|
|
B<cleankrf>'s exit code is the count of orphaned and obsolete I<keyrec>s
|
|
found.
|
|
|
|
=head1 OPTIONS
|
|
|
|
=over 4
|
|
|
|
=item B<-count>
|
|
|
|
Display a final count of old I<keyrec>s found in the I<keyrec> files. This
|
|
option allows the count to be displayed even if the B<-quiet> option is given.
|
|
|
|
=item B<-list>
|
|
|
|
The key I<keyrec>s are checked for old I<keyrec>s, but they are not removed
|
|
from the I<keyrec> file. The names of the old I<keyrec>s are displayed.
|
|
|
|
=item B<-rm>
|
|
|
|
Delete the key files, both B<.key> and B<.private>, from orphaned and
|
|
expired I<keyrec>s.
|
|
|
|
=item B<-quiet>
|
|
|
|
Display no output.
|
|
|
|
=item B<-verbose>
|
|
|
|
Display output about referenced keys and unreferenced keys.
|
|
|
|
=item B<-Version>
|
|
|
|
Displays the version information for B<cleankrf> and the DNSSEC-Tools package.
|
|
|
|
=item B<-help>
|
|
|
|
Display a usage message.
|
|
|
|
=back
|
|
|
|
=head1 COPYRIGHT
|
|
|
|
Copyright 2004-2014 SPARTA, Inc. All rights reserved.
|
|
See the COPYING file included with the DNSSEC-Tools package for details.
|
|
|
|
=head1 AUTHOR
|
|
|
|
Wayne Morrison, tewok@tislabs.com
|
|
|
|
=head1 SEE ALSO
|
|
|
|
B<fixkrf(8)>,
|
|
B<lskrf(8)>,
|
|
B<zonesigner(8)>
|
|
|
|
B<Net::DNS::SEC::Tools::keyrec.pm(3)>
|
|
|
|
B<file-keyrec.pm(5)>
|
|
|
|
=cut
|