--- 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