#!/usr/bin/perl
#
# Copyright 2006-2009 SPARTA, Inc.  All rights reserved.  See the COPYING
# file distributed with this software for details.
#
#
# rollinit
#
#	This script creates a rollrec file.
#

use strict;

use Getopt::Long qw(:config no_ignore_case_always);

use Net::DNS::SEC::Tools::rollrec;
use Net::DNS::SEC::Tools::rollmgr;
use Net::DNS::SEC::Tools::tooloptions;

#
# Version information.
#
my $NAME   = "rollinit";
my $VERS   = "$NAME version: 0.6";
my $DTVERS = "DNSSEC-Tools Version: 1.5";

#######################################################################

#
# Data required for command line options.
#
my %options = ();			# Filled option array.
my @opts =
(
	"zonefile=s",			# Zone file.
	"zone=s",			# Zone file (backwards compat).
	"keyrec=s",			# Keyrec file.
	"admin=s",			# Administrator.
	"directory=s",			# Directory.
	"loglevel=s",			# Logging level.
	"skip",				# Skip record flag.

	"out=s",			# Output file.
	"Version",			# Display the version number.
	"help",				# Give a usage message and exit.
);

#
# Flag values for the various options.  Variable/option connection should
# be obvious.
#
my $zonefileopt;				# Zone name option value.
my $kropt;				# Keyrec file option value.
my $adminopt;				# Administrator option value.
my $diropt;				# Directory option value.
my $logopt;				# Logging level option value.
my $skipopt = 0;			# Roll/skip record flag.

my $outfile;				# Output file option value.
my $version = 0;			# Display the version number.

my $argc;				# Number of command line arguments.
my $noopts = 0;				# No-options flag.

#######################################################################

my $ret;				# Return code from main().

$ret = main();
exit($ret);

#-----------------------------------------------------------------------------
# Routine:	main()
#
# Purpose:	Main controller program.
#
sub main()
{
	#
	# Check our options.
	#
	doopts();

	#
	# Set up the output file.
	#
	setout();

	#
	# Generate a rollrec record for each of the non-option command-line
	# arguments.
	#
	foreach my $zone (@ARGV)
	{
		newrollrec($zone);
	}

	return(0);
}

#-----------------------------------------------------------------------------
# Routine:	doopts()
#
# Purpose:	This routine shakes and bakes our command line options.
#		A bunch of option variables are set according to the specified
#		options.  Then a little massaging is done to make sure that
#		the proper actions are taken.
#
sub doopts
{
	#
	# Parse the options.
	#
	GetOptions(\%options,@opts) || usage();

	#
	# Set our option variables based on the parsed options.
	#
	
	# backwards compat: honor -zone if -zonefile isn't given
	$zonefileopt  = $options{'zonefile'}	  || $options{'zone'} || "";
	$kropt	      = $options{'keyrec'}	  || "";
	$adminopt     = $options{'admin'}	  || "";
	$diropt	      = $options{'directory'}     || "";
	$logopt	      = $options{'loglevel'}      || "";
	$skipopt      = $options{'skip'}	  || 0;

	$outfile      = $options{'out'}	          || "";
	$version      = $options{'Version'};

	#
	# Set a flag if neither -zonefile, -keyrec, -admin, nor -directory
	# were given.
	#
	if(($zonefileopt  eq "") && ($kropt  eq "")	 &&
	   ($adminopt eq "") && ($diropt eq ""))
	{
		$noopts = 1;
	}

	#
	# Ensure the logging level (if given) is valid.
	#
	if($logopt ne "")
	{
		if(rolllog_level($logopt,0) < 0)
		{
			print STDERR "invalid logging level \"$logopt\"\n";
			exit(1);
		}
	}

	#
	# Show the version number if requested.
	#
	version() if(defined($options{'Version'}));

	#
	# Give a usage flag if asked.
	#
	usage() if(defined($options{'help'}));

	#
	# Ensure we were given a zone name.
	#
	$argc = @ARGV;
	usage() if($argc == 0);

}

#-----------------------------------------------------------------------------
# Routine:	setout()
#
# Purpose:	Set up the output file descriptor.  If the -out option wasn't
#		given, then we'll just write to the caller's tty.
#
sub setout
{
	$outfile = "-" if($outfile eq "");

	open(OUT,">> $outfile");
}

#-----------------------------------------------------------------------------
# Routine:	newrollrec()
#
# Purpose:	This generates and prints a rollrec record.  It figures out
#		whether to give a roll or skip record.  It also figures out
#		how to use the command-line options in forming the zonefile
#		and keyrec fields for the rollrec.
#
sub newrollrec
{
	my $zone = shift;				# Zone name.

	my $rectype  = "roll";				# Record's type.
	my $zonefile = "$zone.signed";			# Zone file.
	my $krfile   = "$zone.krf";			# Keyrec file.
	my $admin;					# Administrator.
	my $dir;					# Directory.

	#
	# Make a skip record if -skip was given.
	#
	$rectype = "skip" if($skipopt);

	#
	# Figure out what to do with any options we were given.
	#
	if(!$noopts)
	{
		#
		# If multiple zones were given on the command line, we'll use
		# the options as a template, converting any equals signs to
		# the zone name.
		# If only one zone was given on the command line, we'll use
		# the options as-is.
		#
		if($argc > 1)
		{
			if($zonefileopt)
			{
				$zonefile = $zonefileopt;
				$zonefile =~ s/=/$zone/;
			}

			if($kropt)
			{
				$krfile = $kropt;
				$krfile =~ s/=/$zone/;
			}

			if($adminopt)
			{
				$admin = $adminopt;
				$admin =~ s/=/$zone/;
			}

			if($diropt)
			{
				$dir = $diropt;
				$dir =~ s/=/$zone/;
			}

		}
		else
		{
			$zonefile = $zonefileopt  if($zonefileopt);
			$krfile	  = $kropt    if($kropt);
			$admin	  = $adminopt if($adminopt);
			$dir	  = $diropt   if($diropt);
		}
	}

	print OUT "$rectype	\"$zone\"\n";
	print OUT "	zonefile	\"$zonefile\"\n";
	print OUT "	keyrec		\"$krfile\"\n";
	print OUT "	administrator	\"$admin\"\n"	 if($admin  ne "");
	print OUT "	directory	\"$dir\"\n"	 if($dir    ne "");
	print OUT "	loglevel	\"$logopt\"\n"	 if($logopt ne "");
	print OUT "	kskphase	\"0\"\n";
	print OUT "	zskphase	\"0\"\n";
	print OUT "	ksk_rolldate	\" \"\n";
	print OUT "	ksk_rollsecs	\"0\"\n";
	print OUT "	zsk_rolldate	\" \"\n";
	print OUT "	zsk_rollsecs	\"0\"\n";
	print OUT "	maxttl		\"0\"\n";
	print OUT "	display		\"1\"\n";
	print OUT "	phasestart	\"new\"\n";
        print OUT "	# optional records for RFC5011 rolling:\n";
	print OUT "	istrustanchor           \"no\"\n";
        print OUT "	holddowntime            \"60D\"\n";
	print OUT "\n";
}

#----------------------------------------------------------------------
# Routine:	version()
#
# Purpose:	Print the version number(s) and exit.
#
sub version
{
	print STDERR "$VERS\n";
	print STDERR "$DTVERS\n";

	exit(1);
}


#-----------------------------------------------------------------------------
# Routine:	usage()
#
sub usage
{
	print STDERR "usage:  rollinit [options] <zonename1> ... <zonenameN>\n";
	print STDERR "\t-zonefile	zone file\n";
	print STDERR "\t-keyrec		keyrec file\n";
	print STDERR "\t-admin		administrator\n";
	print STDERR "\t-directory	directory\n";
	print STDERR "\t-loglevel	logging level\n";
	print STDERR "\t-skip		skip records\n";
	print STDERR "\t-out		output file\n";
	print STDERR "\t-Version	display version number\n";
	print STDERR "\t-help		help message \n";
	exit(0);
}

1;

##############################################################################
#

=pod

=head1 NAME

rollinit - Create new I<rollrec> records for a DNSSEC-Tools I<rollrec> file.

=head1 SYNOPSIS

  rollinit [options] <zonename1> ... <zonenameN>

=head1 DESCRIPTION

B<rollinit> creates new I<rollrec> entries for a I<rollrec> file.  This
I<rollrec> file will be used by B<rollerd> to manage key rollover for
the named domains.

A I<rollrec> entry has this format:

    roll "example.com"
	zonefile	"example.com.signed"
	keyrec		"example.com.krf"
	kskphase	"0"
	zskphase	"0"
	administrator	"bob@bobhost.example.com"
	directory	"/var/dns/zones/example.com"
	loglevel	"phase"
	ksk_rolldate	" "
	ksk_rollsecs	"0"
	zsk_rolldate	" "
	zsk_rollsecs	"0"
	maxttl		"604800"
	display		"1"
	phasestart	"Mon Jan 9 16:00:00 2006"
        # optional records for RFC5011 rolling:
	istrustanchor   "no"
        holddowntime    "60D"

The I<zonefile> and I<keyrec> fields are set according to command-line options
and arguments.  The manner of generating the I<rollrec>'s actual values is a
little complex and is described in the ZONEFILE And KEYREC FIELDS section
below.

The I<administrator> field is set to "bob@bobhost.example.com" to indicate
that the email messages to the zone's administrator should be sent to
"bob@bobhost.example.com".

The I<directory> field is set to "/var/dns/zones/example.com" to indicate
that the files for this zone should be found in B</var/dns/zones/example.com>.
This includes the zone file, the signed zone file, and the I<keyrec> file.

The I<loglevel> field is set to "phase" to indicate that B<rollerd> should
only log phase-level (and greater) log messages for this zone.

The I<kskphase> field is set to 0 to indicate that the zone is in
normal operation (non-rollover) for KSK keys.
The I<zskphase> field is set to 0 to indicate that the zone is in
normal operation (non-rollover) for ZSK keys.

The I<ksk_rolldate> and I<ksk_rollsecs> fields are set to indicate that the
zone has not yet undergone KSK rollover.

The I<zsk_rolldate> and I<zsk_rollsecs> fields are set to indicate that the
zone has not yet undergone ZSK rollover.

The I<display> field is set to indicate that B<blinkenlights> should display
the record.  The I<maxttl> and I<phasestart> fields are set to dummy values.

I<rollrec> files also have the I<zsargs> field that holds user-specified
options for B<zonesigner>.  This field is set during B<rollerd> execution
when the administrator determines that some zone fields should be modified.
It is not an initial I<rollrec> field and consequently cannot be specified
by B<rollinit>.

The B<istrustanchor> field specifies whether to roll the KSK keys in a
manner compilant with any remote validating resolver using the KSK as
a trust-anchor.  If set to "yes" then 60 days will be the minimum wait
time during phase 3 of KSK rolling to ensure remote validators can
properly follow the steps needed as specified by RFC5011.  The 60 day
default can be changed via the B<holddowntime> field.

The keywords B<roll> and B<skip> indicate whether B<rollerd> should process
or ignore a particular I<rollrec> entry.  B<roll> records are created by
default; B<skip> entries are created if the B<-skip> option is specified.

The newly generated I<rollrec> entries are written to standard output,
unless the B<-out> option is specified.

=head1 ZONEFILE and KEYREC FIELDS

The I<zonefile> and I<keyrec> fields may be given by using the B<-zonefile>
and B<-keyrec> options, or default values may be used.

The default values use the I<rollrec>'s zone name, taken from the command
line, as a base.  B<.signed> is appended to the domain name for the zone file;
B<.krf> is appended to the domain name for the I<keyrec> file.

If B<-zonefile> or B<-keyrec> are specified, then the options values are
used in one of two ways:

=over 4

=item 1.  A single domain name is given on the command line.

The option values for B<-zonefile> and/or B<-keyrec> are used for the actual
I<rollrec> fields.

=item 2.  Multiple domain names are given on the command line.

The option values for B<-zonefile> and/or B<-keyrec> are used as templates
for the actual I<rollrec> fields.  The option values must contain 
the string B<=>.  This string is replaced by the domain whose I<rollrec>
is being created.

=back

See the EXAMPLES section for examples of how options are used by B<rollinit>.

=head1 OPTIONS

B<rollinit> may be given the following options:

=over 4

=item B<-zonefile zonefile>

This specifies the value of the I<zonefile> field.
See the ZONEFILE And KEYREC FIELDS and EXAMPLES sections for more details.

=item B<-keyrec keyrec-file>

This specifies the value of the I<keyrec> field.
See the ZONEFILE And KEYREC FIELDS and EXAMPLES sections for more details.

=item B<-admin>

This specifies the value of the I<administrator> field.  If it is not given,
an I<administrator> field will not be included for the record.

=item B<-directory>

This specifies the value of the I<directory> field.  If it is not given,
a I<directory> field will not be included for the record.

=item B<-loglevel>

This specifies the value of the I<loglevel> field.  If it is not given, a
I<loglevel> field will not be included for the record.

=item B<-skip>

By default, B<roll> records are generated.  If this option is given, then
B<skip> records will be generated instead.

=item B<-out output-file>

The new I<rollrec> entries will be appended to I<output-file>.
The file will be created if it does not exist.

If this option is not given, the new I<rollrec> entries will be written
to standard output.

=item B<-help>

Display a usage message.

=item B<-Version>

Display version information for B<rollinit> and DNSSEC-Tools.

=back

=head1 EXAMPLES

The following options should make clear how B<rollinit> deals with options and
the new I<rollrec>s.  Example 1 will show the complete new I<rollrec> record.
For the sake of brevity, the remaining examples will only show the newly
created I<zonefile> and I<keyrec> records.

=head2 Example 1.  One domain, no options

This example shows the I<rollrec> generated by giving B<rollinit> a single
domain, without any options.

    $ rollinit example.com
	roll    "example.com"
	    zonefile        "example.com.signed"
	    keyrec          "example.com.krf"
	    kskphase        "0"
	    zskphase        "0"
	    ksk_rolldate    " "
	    ksk_rollsecs    "0"
	    zsk_rolldate    " "
	    zsk_rollsecs    "0"
	    maxttl          "0"
	    display	    "1"
	    phasestart      "new"

=head2 Example 2.  One domain, -zonefile option

This example shows the I<rollrec> generated by giving B<rollinit> a single
domain, with the I<-zonefile> option.

    $ rollinit -zonefile signed-example example.com
	roll    "example.com"
	    zonefile        "signed-example"
	    keyrec          "example.com.krf"

=head2 Example 3.  One domain, -keyrec option

This example shows the I<rollrec> generated by giving B<rollinit> a single
domain, with the B<-keyrec> option.

    $ rollinit -keyrec x-rrf example.com
	roll    "example.com"
	    zonefile        "example.com.signed"
	    keyrec          "x-rrf"

=head2 Example 4.  One domain, -zonefile and -keyrec options

This example shows the I<rollrec> generated by giving B<rollinit> a single
domain, with the B<-zonefile> and B<-keyrec> options.

    $ rollinit -zonefile signed-example -keyrec example.rrf example.com
	roll    "example.com"
	    zonefile        "signed-example"
	    keyrec          "example.rrf"

=head2 Example 5.  One domain, -skip option

This example shows the I<rollrec> generated by giving B<rollinit> a single
domain, with the B<-zonefile> and B<-keyrec> options.

    $ rollinit -skip example.com
	skip    "example.com"
	    zonefile        "example.com.signed"
	    keyrec          "example.com.krf"

=head2 Example 6.  Multiple domains, no options

This example shows the I<rollrec>s generated by giving B<rollinit> several
domains, without any options.

    $ rollinit example1.com example2.com
	roll    "example1.com"
		zonefile        "example1.com.signed"
		keyrec          "example1.com.krf"

	roll    "example2.com"
		zonefile        "example2.com.signed"
		keyrec          "example2.com.krf"

=head2 Example 7.  Multiple domains, -zonefile option

This example shows the I<rollrec>s generated by giving B<rollinit> several
domains, with the B<-zonefile> option.

    $ rollinit -zonefile =-signed example1.com example2.com
	roll    "example1.com"
		zonefile        "example1.com-signed"
		keyrec          "example1.com.krf"

	roll    "example2.com"
		zonefile        "example2.com-signed"
		keyrec          "example2.com.krf"

=head2 Example 8.  Multiple domains, -keyrec option

This example shows the I<rollrec>s generated by giving B<rollinit> several
domains, with the B<-keyrec> option.

    $ rollinit -keyrec zone-=-keyrec example1.com example2.com
	roll    "example1.com"
		zonefile        "example1.com.signed"
		keyrec          "zone-example1.com-keyrec"

	roll    "example2.com"
		zonefile        "example2.com.signed"
		keyrec          "zone-example2.com-keyrec"

=head2 Example 9.  Multiple domains, -zonefile and -keyrec options

This example shows the I<rollrec>s generated by giving B<rollinit> several
domains, with the B<-zonefile> and B<-keyrec> options.

    $ rollinit -zonefile Z-= -keyrec =K example1.com example2.com
	roll    "example1.com"
		zonefile        "Z-example1.com"
		keyrec          "example1.comK"

	roll    "example2.com"
		zonefile        "Z-example2.com"
		keyrec          "example2.comK"

=head2 Example 10.  Single domain, -zonefile and -keyrec options with template

This example shows the I<rollrec> generated by giving B<rollinit> a single
domain, with the B<-zonefile> and B<-keyrec> options.  The options use the
multi-domain B<=> template.

    $ rollinit -zonefile Z-= -keyrec =.K example.com
	roll    "example.com"
		zonefile        "Z-="
		keyrec          "=.K"

This is probably not what is wanted, since it results in the I<zonefile> and
I<keyrec> field values containing the B<=>.

=head2 Example 11.  Multiple domains, -zonefile and -keyrec options without template

This example shows the I<rollrec>s generated by giving B<rollinit>
several domains, with the B<-zonefile> and B<-keyrec> options.  The
options do not use the multi-domain B<=> template.

    $ rollinit -zonefile ex.zone -keyrec ex.krf example1.com example2.com
	roll    "example1.com"
		zonefile        "ex.zone"
		keyrec          "ex.krf"

	roll    "example2.com"
		zonefile        "ex.zone"
		keyrec          "ex.krf"

This may not be what is wanted, since it results in the same I<zonefile>
and I<keyrec> fields values for each I<rollrec>.

=head1 COPYRIGHT

Copyright 2006-2009 SPARTA, Inc.  All rights reserved.
See the COPYING file included with the DNSSEC-Tools package for details.

=head1 AUTHOR

Wayne Morrison, tewok@users.sourceforge.net

=head1 SEE ALSO

B<lsroll(1)>,
B<rollerd(8)>,
B<rollchk(8)>,
B<zonesigner(8)>

B<Net::DNS::SEC::Tools::keyrec.pm(3)>,
B<Net::DNS::SEC::Tools::rollrec.pm(3)>

B<file-keyrec.pm(5)>,
B<file-rollrec.pm(5)>

=cut
