#!/usr/local/bin/perl # # read a message from sympa and sign it and send it # args are -f fromaddress -- recipients # -d domain turn on debug and pretend domain set dmarc policy use strict; use vars qw{$i $pid $u $signset $debug}; use IO::Socket; use Getopt::Std; use Mail::DKIM::Signer; use Mail::DKIM::ARC::Signer; my $queue = "/var/qmail-lists/bin/qmail-queue"; my $chain = "none"; # for ARC our($opt_x, $opt_f, $opt_d); getopts('dxf:'); my $debug = $opt_d; # just pass through if there's an arg open(DEBUG, ">>/tmp/sympa-debug"); # errors even if not debugging if(!$opt_f) { print "no envelope from\n"; exit(1); } my $envfrom = $opt_f; # sign all lists with list domain my $signdom = "lists.iecc.com"; my $srvid = "iecc.com"; # use the usual selector open(SEL, "/var/qmail/control/selector") or die "no selector"; my $signsel = ; chomp($signsel); close SEL; if($debug) { open(MSGWR, ">&STDOUT"); open(ENVWR, ">&STDOUT"); } else { unless(pipe MSGRD,MSGWR) { print DEBUG "msg pipe $!\n:"; exit 111; } unless(pipe ENVRD,ENVWR) { print DEBUG "env pipe $!\n:"; exit 111; } # start up real qmail-queue $pid = fork(); if(!defined $pid) { print DEBUG "fork failed $!\n"; exit 111; } if($pid == 0) { # child close STDIN; close STDOUT; open DMSGRD, "<&MSGRD" or die "msgrd dup"; close MSGRD; close MSGWR; open DENVRD, "<&ENVRD" or die "msgrd dup"; close ENVRD; close ENVWR; # avoid taint complaints $ENV{PATH} = "/bin:/usr/bin:/usr/local/bin"; exec $queue or print DEBUG "qmail-queue failed $!\n"; exit 111; } close MSGRD; close ENVRD; } my @msg = ; my $oar = undef; antidmarc: for $_ (@msg) { last if m{$^}; if($hdrcont and m{^\S}) { $hdrcont = 0; #print "done stripping\n"; } if($hdrcont and m{^\s}) { $_ = ""; next; } if(m{^Authentication-Results: *$srvid}i) { # for OAR header $oar = $_; $chain = $1 if m{\barc=(pass|fail|none)}; # chain arc result next; } } sub signer_policy; my ($dkim, $arc); # create a signer object $dkim = Mail::DKIM::Signer->new( Domain => $signdom, Algorithm => "rsa-sha256", Method => "simple", Selector => $signsel, KeyFile => "/var/qmail/control/key.$signsel.$signdom", Policy => \&signer_policy, ); if($oar) { # only do ARC if there was an A-R header $arc = Mail::DKIM::ARC::Signer->new( Algorithm => "rsa-sha256", # Chain => $chain, Domain => $signdom, SrvId => "iecc.com", # A-R headers Selector => $signsel, KeyFile => "/var/qmail/control/key.$signsel.$signdom", ); } my $inheader = 1; foreach $i (@msg) { next if $i eq ""; # remove local line terminators $_ = $i; chomp; # use SMTP line terminators $dkim->PRINT("$_\015\012"); $arc->PRINT("$_\015\012") if $oar; if($inheader) { $inheader = 0 if m{ ^$ }x; } } $dkim->CLOSE; $arc->CLOSE if $oar; my @signatures = $dkim->signatures; my $sigstr = ""; foreach $i (@signatures) { $sigstr .= $i->as_string() . "\n"; } $sigstr =~ s/\015\012/\n/g; print MSGWR $sigstr; if($oar) { my $arcsig = $arc->as_string() || ""; # in case it failed $arcsig =~ s/\015\012/\012/g; # sigh print MSGWR $arcsig; } map { print MSGWR $_ if $_ gt ""; } @msg; close MSGWR; # create an envelope print ENVWR "F$envfrom\0"; foreach my $to (@ARGV) { print ENVWR "T$to\0"; } print ENVWR "\0"; close ENVWR; print DEBUG time()," from ",$envfrom," to ",join(",",@ARGV),"\n"; exit 0; sub signer_policy { my ($dkim) = @_; my ($u, $identity, $listidentity, $fromdom); use Mail::DKIM::DkSignature; my $sig = Mail::DKIM::Signature->new( Algorithm => $dkim->algorithm, Method => $dkim->method, Headers => $dkim->headers, Domain => $signdom, Selector => $dkim->selector, ); # always sympa $identity = "sympa\@$signdom"; $sig->identity($identity) if $identity; $dkim->add_signature($sig); # if using default domain, add a signature for the # mailing list domain or From: domain if($listidentity = lc $envfrom) { $listidentity =~ s/-owner\@/@/; # remove owner and seq $listidentity =~ s/^bounce.*-=//; # remove VERPy stuff ($fromdom) = $listidentity =~ m{.*\@(.*)}; } else { my $email = lc $dkim->message_originator->address; ($fromdom) = $email =~ m{.*\@(.*)}; } my $fromkey = "/var/qmail/control/key.$signsel.$fromdom"; if($fromdom ne $signdom and -s $fromkey) { my $fromsig = Mail::DKIM::Signature->new( Algorithm => $dkim->algorithm, Method => $dkim->method, Headers => $dkim->headers, Domain => $fromdom, Selector => $dkim->selector, ); $fromsig->key(Mail::DKIM::PrivateKey->load(File => $fromkey)); $dkim->add_signature($fromsig); } return; }