--- dkfilter.out	2006-05-02 17:35:57.000000000 +0200

+++ dkfilter.out	2006-07-02 21:40:47.000000000 +0200

@@ -18,14 +18,16 @@

 #   GNU General Public License for more details.
 #
 # Written by Bennett Todd <bet@rahul.net>
+# Support for multiple keys and configuration file added by

+#         Xavier Perseguers <xavier.perseguers@a3.epfl.ch>

 
 use strict;
-use strict;

 
 use Getopt::Long;
 use Pod::Usage;
 use IO::File;
 use Sys::Syslog;
+use AppConfig::File;

 
 use DKMessage;
 use MySmtpServer;
@@ -35,11 +37,8 @@

 
 my $reject_fail = 0;  # not actually used in this filter
 my $reject_error = 0;
-my $keyfile;

-my $selector;

-my $domain_arg;

-my $method = "simple";

 my $headers = 0;
+my $configfile;

 my $pidfile;
 my $debug;
 my $help;
@@ -47,10 +46,7 @@

 		"reject-fail" => \$reject_fail,
 		"reject-error" => \$reject_error,
 		"hostname=s" => \$hostname,
-		"keyfile=s" => \$keyfile,

-		"selector=s" => \$selector,

-		"domain=s" => \$domain_arg,

-		"method=s" => \$method,

+		"configfile=s" => \$configfile,

 		"headers" => \$headers,
 		"pidfile=s" => \$pidfile,
 		"debug" => \$debug,
@@ -75,32 +71,88 @@

 	pod2usage("Error: source or destination port is missing");
 }
 
-unless (defined $keyfile)

+unless (defined $configfile)

 {
-	pod2usage("Error: no keyfile specified");

+	pod2usage("Error: no configfile specified");

 }
-unless (-r $keyfile)

+unless (-r $configfile)

 {
-	pod2usage("Error: cannot read keyfile $keyfile");

+	pod2usage("Error: cannot read configfile $configfile");

+}

+

+# Parse the configuration file

+

+my $state = AppConfig::State->new();

+

+$state->define(

+	'domain_name', {

+		ARGCOUNT => AppConfig::ARGCOUNT_LIST

+	},

+	'domain_selector', {

+		ARGCOUNT => AppConfig::ARGCOUNT_LIST

+	},

+	'domain_method', {

+		ARGCOUNT => AppConfig::ARGCOUNT_LIST,

+		VALIDATE => \&check_method

+	},

+	'domain_private_key', {

+		ARGCOUNT => AppConfig::ARGCOUNT_LIST,

+		VALIDATE => \&check_private_key

+	}

+);

+

+sub check_method {

+	my $var   = shift;

+	my $val   = shift;

+

+	return ($val eq "simple" || $val eq "nofws") ? 1 : 0;

 }
-unless (defined $selector)

+

+sub check_private_key {

+	my $var   = shift;

+	my $val   = shift;

+

+	return (-r $val) ? 1 : 0;

+}

+

+my $config = AppConfig::File->new($state);

+$config->parse($configfile);

+

+my $domains    = $state->get('domain_name');

+my $_methods   = $state->get('domain_method');

+my $_selectors = $state->get('domain_selector');

+my $_keys      = $state->get('domain_private_key');

+

+unless ( scalar @$domains == scalar @$_methods )

 {
-	pod2usage("Error: selector not specified");

+	pod2usage("Error: number of methods is different than number of domains");

 }
-unless (defined $domain_arg)

+unless ( scalar @$domains == scalar @$_selectors )

 {
-	pod2usage("Error: domain not specified");

+	pod2usage("Error: number of selectors is different than number of domains");

 }
-my @domains = split(/,\s*/, $domain_arg);

-unless (@domains)

+unless ( scalar @$domains == scalar @$_keys )

 {
-	pod2usage("Error: domain not specified");

+	pod2usage("Error: number of private keys is different than number of domains");

 }
-unless ($method eq "simple" || $method eq "nofws")

+

+my %methods;

+my %selectors;

+my %keys;

+

+for ( my $i = 0; $i < scalar @$domains; $i++ )

 {
-	die "Error: invalid method; must be simple or nofws\n";

+	$methods{ @$domains[$i] } = @$_methods[$i];

+	$selectors{ @$domains[$i] } = @$_selectors[$i];

+	$keys{ @$domains[$i] } = @$_keys[$i];

 }
 
+# Compare number of key files and number of domains

+# If there is only one key file, each domain will use

+# the same key (dkfilter original version). Otherwise

+# there should be as many key file as domain definitions.

+# If all goes well, create a hash with a key for each domain.

+

 use base "MySmtpProxyServer";
 main->run(
 		host => $srcaddr,
@@ -112,9 +164,9 @@

 {
 	# create an object for sending the outgoing SMTP commands
 	#  (and the signed message)
-    my $client = MSDW::SMTP::Client->new(

-			interface => $dstaddr,

-			port => $dstport);

+	my $client = MSDW::SMTP::Client->new(

+		interface => $dstaddr,

+		port => $dstport);

 	return $client;
 }
 
@@ -164,7 +216,7 @@

 		{
 			while ($domain)
 			{
-				if (grep { lc($_) eq $domain } @domains)

+				if (grep { lc($_) eq $domain } @$domains)

 				{
 					last;
 				}
@@ -175,14 +227,14 @@

 		unless ($domain)
 		{
 			# message has no senderdomain
-			$domain = $domains[0];

+			$domain = @$domains[0];

 		}
 
 		$result = $mess->sign(
-			Method => $method,

-			Selector => $selector,

+			Method => $methods{ $domain },

+			Selector => $selectors{ $domain },

 			Domain => $domain,
-			KeyFile => $keyfile,

+			KeyFile => $keys{ $domain },

 			Headers => $headers
 			);
 		$result_detail = $mess->result_detail;
@@ -244,15 +296,30 @@

   dkfilter.out [options] listen.addr:port talk.addr:port
     options:
       --reject-error
-      --keyfile=filename

-      --selector=SELECTOR

-      --domain=DOMAIN

-      --method=simple|nofws

+      --configfile=filename

       --headers
 
   dkfilter.out --help
     to see a full description of the various options
 
+  Format of the configuration file:

+

+  # ------------------------------------------

+  # domain 1

+  [domain]

+  name        = domain.tld

+  method      = METHOD

+  selector    = SELECTOR

+  private_key = FILENAME

+

+  # domain 2

+  [domain]

+  name        = otherdomain.tld

+  method      = METHOD

+  selector    = SELECTOR

+  private_key = FILENAME

+  # ------------------------------------------

+

 =head1 OPTIONS
 
 =over
@@ -268,17 +335,18 @@

 
 The most common error is a message parse error.
 
-=item B<--keyfile=FILENAME>

+=item B<--configfile=FILENAME>

 
 This is a required argument. Use it to specify the filename containing
-the private key used in signing outgoing messages.

+the configuration of domains and private keys used in signing outgoing

+messages.

 
-=item B<--selector=SELECTOR>

+=item B<SELECTOR>

 
 This is a required argument. Use it to specify the name of the key
 selector.
 
-=item B<--domain=DOMAIN>

+=item B<DOMAIN>

 
 This is a required argument. Use it to specify what domain(s) emails
 are signed for. If you want to sign for multiple domains, specify the
@@ -287,11 +355,10 @@

 specified in this argument. If it sees a match, it will sign the message
 using the matching domain.
 
-=item B<--method=simple|nofws>

+=item B<METHOD>

 
 This option specifies the canonicalization algorithm to use for signing
-messages. Specify either C<simple> or C<nofws>. If not specified,

-the default is C<simple>.

+messages. Specify either C<simple> or C<nofws>.

 
 =item B<--headers>
 
@@ -311,7 +378,7 @@

 
 =head1 EXAMPLE
 
-  dkfilter.out --keyfile=private.key --selector=sydney \

-          --domain=example.org 127.0.0.1:10027 127.0.0.1:10028

+  dkfilter.out --configfile=/etc/dkfilter.conf \

+          127.0.0.1:10027 127.0.0.1:10028

 
 =cut


syntax highlighted by Code2HTML, v. 0.9.1