#!/usr/bin/perl -w
#################################################################
#
#	@(#) create-trusted-key-section (hoz) 26. Jun 2002
#
#	Read all files matching the pattern "K*+00*.key" and create
#	a trusted-key section for a BIND 9.3 Nameserver.
#
#	Added comment line on output, explaining the flags section
#
#	Aug 2004	KSK-flag check added
#			Option -c and -a added
#
#################################################################
use integer;

#################################################################
#	usage
#################################################################
sub usage
{
	my ($mesg) = shift @_;

	print STDERR "usage: $progname [-a] [-c] [-d directory]\n";
	print STDERR "illegal option $mesg \n" if defined $mesg;

	exit (1);
}

#################################################################
#	parseopts
#################################################################
sub parseopts
{
	my (@args) = @_;
	my ($option);

	while ( $option = shift @args )
	{
		if ( $option eq "-d" ) {
			$directory = shift @args;
		} elsif ( $option eq "-c" ) {
			$printcomment = 1;
		} elsif ( $option eq "-a" ) {
			$allkeys = 1;
		} elsif ( $option eq "--" ) {
			last;
		} elsif ( $option =~ /^-.*/ ) {
			usage $option;
		} else {
			unshift @args, $option;
		}
	}
	return @args;
}

#################################################################
#	error ($format, ....)
#################################################################
sub error
{
	my ($frmt) = shift @_;
	my (@pars) = @_;

	printf (STDERR "$progname: $frmt\n", @pars);
}

#################################################################
#	fatal ($format, ....)
#################################################################
sub fatal
{
	error (@_);
	exit (1);
}

#################################################################
#	getfilelist ($dir, @patternmatchlist)
#################################################################
sub getfilelist
{
	my ($dir) = shift @_;
	my (@patternlist) = @_;

	my (@files);
	local *DIR;

	# create regular expression 
	my ($pattern) = shift @patternlist;
	foreach my $pat (@patternlist)
	{
		$pattern = "$pattern|$pat";
	}
	opendir (DIR, $dir) or
		fatal ("getfilelist: Can't open directory $dir\" for reading");
	@files = grep /$pattern/, readdir (DIR);
	closedir (DIR);

	return @files;
}

#################################################################
#	printentry 
#################################################################
sub printentry
{
	my ($name, $flags, $proto, $algo, $pubkey, $keytag) = @_;

	my $tabs = "\t" x 4;
	my @ktype = (	"", "+NOCONF", "+NOAUTH", "+NOKEY" );
	my @ntype = (	"USER", "ZONE", "HOST" );
	my %pmap =  (	0=>"reserved", 1=>"TLS", 2=>"EMAIL", 3=>"DNSSEC",
			4=>"IPSEC", 255=>"ALL" );
	my %amap =  (	0=>"reserved", 1=>"RSAMD5", 2=>"DH", 3=>"DSA", 4=>"ECC",
			5=>"RSASHA1", 252=>"INDIRECT", 253=>"PRIVATEDNS",
			254=>"PRIVATEOID" );

	my $nt = ($flags >> 8) & 03;
	my $kt = ($flags >> 14) & 03;
	my $ksk = $flags & 01;

	# do some sanity checks:
	return if $nt != 1;	# skip any none ZONE Keys
	
	if ( $allkeys == 0 && not $ksk )	# skip all non sep keys
	{
		printf STDERR "Skipped non SEP key K%s+%03d+%d!\n", $name, $algo, $keytag;
		return;
	}

	if ( $printcomment )	# print description as a comment
	{
		print ";\t";
		printf "\"%s\"  ", $name;
		printf "%d (0%03o ", $flags, $flags;
		printf "%s", defined ($ntype[$nt]) ? $ntype[$nt] : "unknown";
		printf "+KSK" if $ksk;
		printf "%s) ", defined $ktype[$kt] ? $ktype[$kt] : "+$kt";
		printf "%d(%s) ", $proto,
			defined $pmap{$proto} ? $pmap{$proto} : "unknown";
		printf "%d(%s) ", $algo,
			defined $amap{$algo} ? $amap{$algo} : "unknown";
		printf "\"public key ...\" # keyid = %s\n", $keytag;
	}

	# print the record in "trusted-keys" section syntax
	print "\t";
	printf "\"%s\"  ", $name;
	printf "%d %d %d\n", $flags, $proto, $algo;
	$pubkey =~ s/ /\n$tabs/g;
	printf "\t\t\t       \"%s\" ", $pubkey;
	printf "; # keyid = %s\n", $keytag;
}

#################################################################
#	main
#################################################################
local *IN;

local ($progname) = $0;
$progname =~ s|.*/||;

local ($allkeys) = 0;
local ($printcomment) = 0;
local ($directory) = ".";

parseopts @ARGV;

print "trusted-keys {\n";

my ($entrys) = 0;
my (@files) = getfilelist ($directory, "K.*\\+00[135]\\+[0-9]+\\.key");
foreach $file (@files)
{
	my ($name, $class, $type, $a, $b, $c, $d);

	open (IN, "< $directory/$file") or
		fatal "Can't open $file for reading";
	while ( <IN> )
	{
		chomp;
		next if /^;/;		# skip comment lines
		next if /^\s*$/;	# skip empty lines

		($name, $class, $type, $flags, $proto, $algo, $pubkey) = split (" ", $_, 7);
		last if $type eq "DNSKEY";
	}
	close (IN);
	$file =~ /K.*\+(\d+)\.key/;
	my ($keytag) = $1;

	if ( $proto != 3 ) {
		error ("$file: $name is not a key for dnssec\n");
		last;
	}

	printentry ($name, $flags, $proto, $algo, $pubkey, $keytag);
	$entrys++;
}

print "};\n\n";

print STDERR "$progname: no keyfiles found in directory \"$directory\"\n" if $entrys == 0;
