diff --git a/CHANGES b/CHANGES index f4d352a..d7c2d20 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,21 @@ # ! = Changed something significant, or removed a feature # * = Fixed a bug, or made a minor improvement +--- 1.99 (2007-02-10 16:00) + + postfix-policyd-spf-perl: + ! Changed from Mail::SPF::Query to Mail::SPF for RFC 4408 compliance + ! Removed Testing handler (usage was undocumented). + * Simplified logging. Policy server is less chatty. Logs are clearer. + + Miscellaneous: + * Updated README file: + - Updated for new SPF library + - Added more detail on results/responses + - Explained how to get verbose logging + + Debian: + --- 1.08.1 (2007-01-10 21:00) postfix-policyd-spf-perl: diff --git a/INSTALL b/INSTALL index cbdd598..b3efa2a 100644 --- a/INSTALL +++ b/INSTALL @@ -6,7 +6,7 @@ postfix-policyd-spf-perl: Perl 5.6 version - Mail::SPF::Query + Mail::SPF (not Mail::SPF::Query) Installing ---------- @@ -31,5 +31,3 @@ Installing 4. Restart Postfix. -# $Id$ -# vim:tw=79 diff --git a/README b/README index aa11c01..dbf722a 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -postfix-policyd-spf-perl 1.08.1 +postfix-policyd-spf-perl 1.99 A Postfix SMTPd policy server for SPF checking (C) 2007 Scott Kitterman 2003-2004 Meng Weng Wong @@ -7,7 +7,19 @@ Contributions by various members of the SPF project ============================================================================== postfix-policyd-spf-perl is a Postfix SMTPd policy daemon for SPF checking. -It is implemented in pure Perl and uses the Mail::SPF::Query CPAN module. +It is implemented in pure Perl and uses the Mail::SPF CPAN module. Note that +Mail::SPF is a complete re-implementation of SPF based on the final SPF RFC, +RFC 4408. It shares no code with the older Mail::SPF::Query that was the +original SPF development implementation. If you are upgrading from on older +version of this policy server you will need to install Mail::SPF. + +This version of the policy server will reject mail that fails either Mail From +or HELO SPF checks. It always checks HELO (older versions just checked HELO if +Mail From was null). It will defer mail if there is a temporary SPF error and +the message would othersise be permitted (DEFER_IF_PERMIT). Otherwise, it will +PREPEND the appropriate SPF Received header. In the case of multi-recipient +mail, multiple headers will get appended. Error conditions within the policy +server (that don't result in a crash) or from Mail::SPF will return DUNNO. See INSTALL or README.Debian for installation instructions. @@ -57,11 +69,11 @@ followed by a empty line: action=dunno [empty line] +If you want more detail in the system logs change $VERBOSE to 1. + License ------- postfix-policyd-spf-perl is free software. You may use, modify, and distribute it under the GNU GPL (version 2 or later); see the LICENSE file. -# $Id$ -# vim:tw=79 diff --git a/debian/README.Debian b/debian/README.Debian index af1060e..da19cd9 100644 --- a/debian/README.Debian +++ b/debian/README.Debian @@ -4,7 +4,7 @@ Installing 1. Add the following to /etc/postfix/master.cf: policy unix - n n - - spawn - user=nobody argv=/usr/bin/perl /usr/lib/postfix/policyd-spf-perl + user=nobody argv=/usr/bin/perl /usr/sbin/postfix-policyd-spf-perl 2. Configure the Postfix policy service in /etc/postfix/main.cf: @@ -19,5 +19,3 @@ Installing 3. Restart Postfix. -# $Id: README 167 2005-01-17 18:26:45Z julian $ -# vim:tw=79 diff --git a/debian/changelog b/debian/changelog index 364aa3a..768f3ae 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,23 +1,17 @@ -postfix-policyd-spf-perl (1.08.1) unstable; urgency=low +postfix-policyd-spf-perl (1.99-0ubuntu1) feisty; urgency=low - Debian: - * New maintainer: Scott Kitterman - * Priority: extra (was: optional) - * Removed Build-Depends-Indep: perl, as there really is no need for it. - * Depends: libversion-perl - * Updated debian/copyright. + * New upstream release for RFC compliant SPF checking. + * Updated control to use libmail-spf-perl instead of the unmaintained + libmail-spf-query-perl and changed maintainer to Scott Kitterman (was + MOTU). + * Updated man pages for new library and upstream documentation udpates. - postfix-policyd-spf-perl: - * Minor and purely cosmetic code clean-up. + -- Scott Kitterman Sat, 03 Feb 2007 16:33:08 -0500 - Miscellaneous: - * Updated README file with new website URL and copyright. - * Added LICENSE file as an explicit copy of the GPLv2. +postfix-policyd-spf-perl (1.08.1-0ubuntu1) feisty; urgency=low - -- Scott Kitterman Wed, 10 Jan 2007 21:00:00 +0000 + * Initial debianization of the package. + * Removed upstream provided /debian directory + * Modified documentation for Debian specific file locations -postfix-policyd-spf-perl (1.08) unstable; urgency=low - - * Initial release as a Debian package. - - -- Julian Mehnle Sat, 17 Jun 2006 19:32:31 +0000 + -- Scott Kitterman Thu, 11 Jan 2007 04:59:08 -0500 diff --git a/debian/control b/debian/control index 00a6fca..49d0cea 100644 --- a/debian/control +++ b/debian/control @@ -7,8 +7,10 @@ Standards-Version: 3.7.2 Package: postfix-policyd-spf-perl Architecture: all -Depends: libversion-perl, libmail-spf-query-perl +Depends: libversion-perl, libmail-spf-perl, ${perl:Depends} Recommends: postfix Description: pure-Perl Postfix policy daemon for SPF checking postfix-policyd-spf-perl is a Postfix SMTPd policy daemon for SPF checking. - It is implemented in pure Perl and uses the Mail::SPF::Query module. + It is implemented in pure Perl and uses the Mail::SPF module. The SPF web + site is http://www.openspf.org/. The Postfix configuration must be changed to + check SPF. See README.Debian or man 8 postfix-policyd-spf-perl for details. diff --git a/debian/copyright b/debian/copyright index 7b59635..3a5ecdc 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,14 +1,77 @@ -This is the Debian package for postfix-policyd-spf-perl, which is available -from . +This package was debianized by Scott Kitterman on +Thu, 11 Jan 2007 04:29:13 -0500. + +It was downloaded from . + +Upstream authors Meng Weng Wong and Scott Kitterman + + +Copyright: (C) 2007 Scott Kitterman - 2003-2004 Meng Weng Wong -Contributions by various members of the SPF project - -Scott Kitterman is the maintainer of the Debian package. +(C) 2003-2004 Meng Weng Wong This is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2 or later). + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + On Debian systems, the complete text of the GPL v2 can be found here: /usr/share/common-licenses/GPL-2 + diff --git a/debian/rules b/debian/rules index 0c49c0f..9bf0142 100755 --- a/debian/rules +++ b/debian/rules @@ -22,8 +22,7 @@ install-stamp: dh_testroot dh_clean -k - install -D postfix-policyd-spf-perl $(TMP)/usr/lib/postfix/policyd-spf-perl - + install -D postfix-policyd-spf-perl $(TMP)/usr/sbin/postfix-policyd-spf-perl touch install-stamp # Build architecture-independent files here: @@ -31,13 +30,9 @@ binary-indep: build install dh_testdir dh_testroot - dh_install - dh_installdirs - dh_installdocs README + dh_installdocs + dh_installman debian/postfix-policyd-spf-perl.8 dh_installchangelogs CHANGES - #dh_installexamples examples/* - #dh_installman - #dh_link dh_compress dh_fixperms diff --git a/postfix-policyd-spf-perl b/postfix-policyd-spf-perl index e442935..24f739b 100755 --- a/postfix-policyd-spf-perl +++ b/postfix-policyd-spf-perl @@ -2,24 +2,40 @@ # postfix-policyd-spf-perl # http://www.openspf.org/Software -# version 1.08.1 +# version 1.99 # $Id$ +#(C) 2007 Scott Kitterman +#(C) 2003-2004 Meng Weng Wong +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -use version; our $VERSION = qv('1.08.1'); +use version; our $VERSION = qv('1.99'); use strict; use Fcntl; use Sys::Syslog qw(:DEFAULT setlogsock); -use Mail::SPF::Query; +use Mail::SPF; # ---------------------------------------------------------- # configuration # ---------------------------------------------------------- - +my $spf_server = Mail::SPF::Server->new(); my @HANDLERS; -push @HANDLERS, "testing"; -push @HANDLERS, "sender_permitted_from"; +push @HANDLERS, "sender_policy_framework"; +#Leaving this to make it easier to add others later. my $VERBOSE = 0; @@ -88,14 +104,17 @@ while () { foreach my $handler (@HANDLERS) { no strict 'refs'; my $response = $handler->(attr=>\%attr); - syslog(debug => "handler %s: %s", $handler, $response); + if ($VERBOSE) { + syslog(debug => "handler %s: %s", $handler, $response); + } + #Picks whatever response is not dunno if ($response and $response !~ /^dunno/i) { - syslog(info => "handler %s: %s is decisive.", $handler, $response); + syslog(info => "handler %s: is decisive.", $handler); $action = $response; last; } } - syslog(info => "decided action=%s", $action); + syslog(info => "Policy action=%s", $action); print STDOUT "action=$action\n\n"; %attr = (); @@ -104,65 +123,71 @@ while () { # ---------------------------------------------------------- # plugin: SPF # ---------------------------------------------------------- -sub sender_permitted_from { +sub sender_policy_framework { local %_ = @_; my %attr = %{ $_{attr} }; - - my $query = eval { - Mail::SPF::Query->new( - ip => $attr{client_address}, - sender => $attr{sender}, - helo => $attr{helo_name} - ) + + #Always do HELO check first. If no HELO policy it's only one lookup. + #Avoids the need to do any Mail From processing for null sender. + my $helo_request = eval { + Mail::SPF::Request->new( + scope => 'helo', # 'mfrom' or 'helo', 'pra' + identity => $attr{helo_name}, + ip_address => $attr{client_address}, + helo_identity # optional, + => $attr{helo_name} + ); }; + my $helo_result = $spf_server->process($helo_request); + + my $helo_result_code = $helo_result->code; # 'pass', 'fail', etc. + my $helo_local_exp = $helo_result->local_explanation; + my $helo_authority_exp = $helo_result->authority_explanation + if $helo_result->is_code('fail'); + my $helo_spf_header = $helo_result->received_spf_header; + + syslog( + info => "%s: SPF %s: HELO/EHLO: %s, IP Address: %s, Recipient: %s", + $attr{queue_id}, $helo_result, $attr{helo_name}, $attr{client_address}, $attr{recipient} + ); + + # Reject on HELO fail. Defer on HELO temperror if message would otherwis + # be accepted. Use the HELO result and return for null sender. + if ($helo_result_code eq "fail") { return "REJECT $helo_authority_exp"; } + elsif ($helo_result_code eq "temperror") { return "DEFER_IF_PERMIT SPF-Result=$helo_local_exp"; } + elsif ($attr{sender} eq '') { return "PREPEND $helo_spf_header"; } + + #Do mail from is HELO doesn't give a definitive result. + my $mfrom_request = eval { + Mail::SPF::Request->new( + scope => 'mfrom', # 'mfrom' or 'helo', 'pra' + identity => $attr{sender}, + ip_address => $attr{client_address}, + helo_identity # optional, + => $attr{helo_name} # for %{h} macro expansion + ); + }; + my $mfrom_result = $spf_server->process($mfrom_request); + + my $mfrom_result_code = $mfrom_result->code; # 'pass', 'fail', etc. + my $mfrom_local_exp = $mfrom_result->local_explanation; + my $mfrom_authority_exp = $mfrom_result->authority_explanation + if $mfrom_result->is_code('fail'); + my $mfrom_spf_header = $mfrom_result->received_spf_header; if ($@) { syslog( - info => "%s: Mail::SPF::Query->new(%s, %s, %s) failed: %s", + info => "%s: Mail::SPF->new(%s, %s, %s) failed: %s", $attr{queue_id}, $attr{client_address}, $attr{sender}, $attr{helo_name}, $@ ); return "DUNNO"; } - my ($result, $smtp_comment, $header_comment) = $query->result(); - syslog( - info => "%s: SPF %s: smtp_comment=%s, header_comment=%s", - $attr{queue_id}, $result, $smtp_comment, $header_comment + info => "%s: SPF %s: Envelope-from: %s, IP Address: %s, Recipient: %s", + $attr{queue_id}, $mfrom_result, $attr{sender}, $attr{client_address}, $attr{recipient} ); - if ($result eq "fail") { return "REJECT $smtp_comment"; } - elsif ($result eq "error") { return "DEFER_IF_PERMIT $smtp_comment"; } - else { return "PREPEND Received-SPF: $result ($header_comment)"; } -} - -# ---------------------------------------------------------- -# plugin: testing -# ---------------------------------------------------------- -sub testing { - local %_ = @_; - my %attr = %{ $_{attr} }; - - if ( - lc(address_stripped($attr{sender})) eq lc(address_stripped($attr{recipient})) and - $attr{recipient} =~ /policyblock/ - ) { - - syslog(info => "%s: testing: will block as requested", $attr{queue_id}); - return "REJECT smtpd-policy blocking $attr{recipient}"; - } - else { - syslog( - info => "%s: testing: stripped sender=%s, stripped rcpt=%s", - $attr{queue_id}, - address_stripped($attr{sender}), - address_stripped($attr{recipient}), - ); - } - return "DUNNO"; -} - -# my $foo = address_stripped('foo+bar@baz.com'); # returns 'foo@baz.com' -sub address_stripped { - my $string = shift; - $string =~ s/[+-].*\@/\@/; - return $string; + #Same approach as HELO.... + if ($mfrom_result_code eq "fail") { return "REJECT $mfrom_authority_exp"; } + elsif ($mfrom_result_code eq "mfrom_temperror") { return "DEFER_IF_PERMIT SPF-Result=$mfrom_local_exp"; } + else { return "PREPEND $mfrom_spf_header"; } }