changeset 62:f192048f9b7e puppet-3.6

Add CentOS 7 config for postfix to take advantage of Postfix 2.10 and Postscreen Also, move files to the module
author IBBoard <dev@ibboard.co.uk>
date Sat, 12 Sep 2015 21:00:55 +0100
parents c2f66d0f2a43
children e5c999fa15e2
files common/postfix/master.cf common/postfix/postfix-policyd-spf-perl modules/postfix/files/master.CentOS7.cf modules/postfix/files/master.cf modules/postfix/files/postfix-policyd-spf-perl modules/postfix/manifests/init.pp modules/postfix/templates/main.cf.erb
diffstat 7 files changed, 625 insertions(+), 505 deletions(-) [+]
line wrap: on
line diff
--- a/common/postfix/master.cf	Sat Sep 12 16:42:27 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-#
-# Postfix master process configuration file.  For details on the format
-# of the file, see the master(5) manual page (command: "man 5 master").
-#
-# Do not forget to execute "postfix reload" after editing this file.
-#
-# ==========================================================================
-# service type  private unpriv  chroot  wakeup  maxproc command + args
-#               (yes)   (yes)   (yes)   (never) (100)
-# ==========================================================================
-smtp      inet  n       -       n       -       -       smtpd
-#submission inet n       -       n       -       -       smtpd
-#  -o smtpd_tls_security_level=encrypt
-#  -o smtpd_sasl_auth_enable=yes
-#  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
-#  -o milter_macro_daemon_name=ORIGINATING
-smtps     inet  n       -       n       -       -       smtpd
-  -o smtpd_tls_wrappermode=yes
-  -o smtpd_sasl_auth_enable=yes
-  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
-  -o milter_macro_daemon_name=ORIGINATING
-#628      inet  n       -       n       -       -       qmqpd
-pickup    fifo  n       -       n       60      1       pickup
-cleanup   unix  n       -       n       -       0       cleanup
-qmgr      fifo  n       -       n       300     1       qmgr
-#qmgr     fifo  n       -       n       300     1       oqmgr
-tlsmgr    unix  -       -       n       1000?   1       tlsmgr
-rewrite   unix  -       -       n       -       -       trivial-rewrite
-bounce    unix  -       -       n       -       0       bounce
-defer     unix  -       -       n       -       0       bounce
-trace     unix  -       -       n       -       0       bounce
-verify    unix  -       -       n       -       1       verify
-flush     unix  n       -       n       1000?   0       flush
-proxymap  unix  -       -       n       -       -       proxymap
-proxywrite unix -       -       n       -       1       proxymap
-smtp      unix  -       -       n       -       -       smtp
-# When relaying mail as backup MX, disable fallback_relay to avoid MX loops
-relay     unix  -       -       n       -       -       smtp
-	-o smtp_fallback_relay=
-#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
-showq     unix  n       -       n       -       -       showq
-error     unix  -       -       n       -       -       error
-retry     unix  -       -       n       -       -       error
-discard   unix  -       -       n       -       -       discard
-local     unix  -       n       n       -       -       local
-virtual   unix  -       n       n       -       -       virtual
-lmtp      unix  -       -       n       -       -       lmtp
-anvil     unix  -       -       n       -       1       anvil
-scache    unix  -       -       n       -       1       scache
-#
-# ====================================================================
-# Interfaces to non-Postfix software. Be sure to examine the manual
-# pages of the non-Postfix software to find out what options it wants.
-#
-# Many of the following services use the Postfix pipe(8) delivery
-# agent.  See the pipe(8) man page for information about ${recipient}
-# and other message envelope options.
-# ====================================================================
-#
-# maildrop. See the Postfix MAILDROP_README file for details.
-# Also specify in main.cf: maildrop_destination_recipient_limit=1
-#
-#maildrop  unix  -       n       n       -       -       pipe
-#  flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d ${recipient}
-#
-# ====================================================================
-#
-# The Cyrus deliver program has changed incompatibly, multiple times.
-#
-#old-cyrus unix  -       n       n       -       -       pipe
-#  flags=R user=cyrus argv=/usr/lib/cyrus-imapd/deliver -e -m ${extension} ${user}
-#
-# ====================================================================
-#
-# Cyrus 2.1.5 (Amos Gouaux)
-# Also specify in main.cf: cyrus_destination_recipient_limit=1
-#
-#cyrus     unix  -       n       n       -       -       pipe
-#  user=cyrus argv=/usr/lib/cyrus-imapd/deliver -e -r ${sender} -m ${extension} ${user}
-#
-# ====================================================================
-#
-# See the Postfix UUCP_README file for configuration details.
-#
-#uucp      unix  -       n       n       -       -       pipe
-#  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
-#
-# ====================================================================
-#
-# Other external delivery methods.
-#
-#ifmail    unix  -       n       n       -       -       pipe
-#  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
-#
-#bsmtp     unix  -       n       n       -       -       pipe
-#  flags=Fq. user=bsmtp argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient
-#
-#scalemail-backend unix -       n       n       -       2       pipe
-#  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store
-#  ${nexthop} ${user} ${extension}
-#
-#mailman   unix  -       n       n       -       -       pipe
-#  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
-#  ${nexthop} ${user}
-
-policy  unix  -       n       n       -       0       spawn 
-        user=nobody argv=/usr/bin/perl /usr/local/lib/postfix-policyd-spf-perl/postfix-policyd-spf-perl
--- a/common/postfix/postfix-policyd-spf-perl	Sat Sep 12 16:42:27 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,396 +0,0 @@
-#!/usr/bin/perl
-
-# postfix-policyd-spf-perl
-# http://www.openspf.org/Software
-# version 2.010
-#
-# (C) 2007-2008,2012 Scott Kitterman <scott@kitterman.com>
-# (C) 2012           Allison Randal <allison@perl.org>
-# (C) 2007           Julian Mehnle <julian@mehnle.net>
-# (C) 2003-2004      Meng Weng Wong <mengwong@pobox.com>
-#
-#    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('2.010');
-
-use strict;
-
-use IO::Handle;
-use Sys::Syslog qw(:DEFAULT setlogsock);
-use NetAddr::IP;
-use Mail::SPF;
-use Sys::Hostname::Long 'hostname_long';
-
-# ----------------------------------------------------------
-#                      configuration
-# ----------------------------------------------------------
-
-my $resolver = Net::DNS::Resolver->new(
-    retrans         => 5,  # Net::DNS::Resolver default: 5
-    retry           => 2,  # Net::DNS::Resolver default: 4
-    # Makes for a total timeout for UDP queries of 5s * 2 = 10s.
-);
-
-# query_rr_type_all will query both type TXT and type SPF. This upstream
-# default is changed due to there being essentiall no type SPF deployment.
-my $spf_server = Mail::SPF::Server->new(
-    dns_resolver    => $resolver,
-    query_rr_types  => Mail::SPF::Server->query_rr_type_txt,
-    default_authority_explanation  =>
-    'Please see http://www.openspf.net/Why?s=%{_scope};id=%{S};ip=%{C};r=%{R}'
-);
-
-# Adding more handlers is easy:
-my @HANDLERS = (
-    {
-        name => 'exempt_localhost',
-        code => \&exempt_localhost
-    },
-    {
-        name => 'exempt_relay',
-        code => \&exempt_relay
-    },
-    {
-        name => 'sender_policy_framework',
-        code => \&sender_policy_framework
-    }
-);
-
-my $VERBOSE = 0;
-
-my $DEFAULT_RESPONSE = 'DUNNO';
-
-#
-# Syslogging options for verbose mode and for fatal errors.
-# NOTE: comment out the $syslog_socktype line if syslogging does not
-# work on your system.
-#
-
-my $syslog_socktype = 'unix'; # inet, unix, stream, console
-my $syslog_facility = 'mail';
-my $syslog_options  = 'pid';
-my $syslog_ident    = 'postfix/policy-spf';
-
-use constant localhost_addresses => map(
-    NetAddr::IP->new($_),
-    qw(  127.0.0.0/8  ::ffff:127.0.0.0/104  ::1  )
-);  # Does Postfix ever say "client_address=::ffff:<ipv4-address>"?
-
-use constant relay_addresses => map(
-    NetAddr::IP->new($_),
-    qw(  )
-); # add addresses to qw (  ) above separated by spaces using CIDR notation.
-
-# Fully qualified hostname, if available, for use in authentication results
-# headers now provided by the localhost and whitelist checks.
-my  $host = hostname_long;
-
-my %results_cache;  # by message instance
-
-# ----------------------------------------------------------
-#                      initialization
-# ----------------------------------------------------------
-
-#
-# Log an error and abort.
-#
-sub fatal_exit {
-    syslog(err     => "fatal_exit: @_");
-    syslog(warning => "fatal_exit: @_");
-    syslog(info    => "fatal_exit: @_");
-    die("fatal: @_");
-}
-
-#
-# Unbuffer standard output.
-#
-STDOUT->autoflush(1);
-
-#
-# This process runs as a daemon, so it can't log to a terminal. Use
-# syslog so that people can actually see our messages.
-#
-setlogsock($syslog_socktype);
-openlog($syslog_ident, $syslog_options, $syslog_facility);
-
-# ----------------------------------------------------------
-#                           main
-# ----------------------------------------------------------
-
-#
-# Receive a bunch of attributes, evaluate the policy, send the result.
-#
-my %attr;
-while (<STDIN>) {
-    chomp;
-    
-    if (/=/) {
-        my ($key, $value) =split (/=/, $_, 2);
-        $attr{$key} = $value;
-        next;
-    }
-    elsif (length) {
-        syslog(warning => sprintf("warning: ignoring garbage: %.100s", $_));
-        next;
-    }
-    
-    if ($VERBOSE) {
-        for (sort keys %attr) {
-            syslog(debug => "Attribute: %s=%s", $_ || '<UNKNOWN>', $attr{$_} || '<UNKNOWN>');
-        }
-    };
-    
-    my $message_instance = $attr{instance};
-    my $cache = defined($message_instance) ? $results_cache{$message_instance} ||= {} : {};
-    
-    my $action = $DEFAULT_RESPONSE;
-    
-    foreach my $handler (@HANDLERS) {
-        my $handler_name = $handler->{name};
-        my $handler_code = $handler->{code};
-        
-        my $response = $handler_code->(attr => \%attr, cache => $cache);
-        
-        if ($VERBOSE) {
-            syslog(debug => "handler %s: %s", $handler_name || '<UNKNOWN>', $response || '<UNKNOWN>');
-        };
-        
-        # Pick whatever response is not 'DUNNO'
-        if ($response and $response !~ /^DUNNO/i) {
-                if ($VERBOSE) {
-                    syslog(info => "handler %s: is decisive.", $handler_name || '<UNKNOWN>');
-                }
-            $action = $response;
-            last;
-        }
-    }
-    
-    syslog(info => "Policy action=%s", $action || '<UNKNOWN>');
-    
-    STDOUT->print("action=$action\n\n");
-    %attr = ();
-}
-
-# ----------------------------------------------------------
-#                handler: localhost exemption
-# ----------------------------------------------------------
-
-sub exempt_localhost {
-    my %options = @_;
-    my $attr = $options{attr};
-    if ($attr->{client_address} ne '') {
-        my $client_address = NetAddr::IP->new($attr->{client_address});
-        return "PREPEND Authentication-Results: $host; none (SPF not checked for localhost)"
-            if grep($_->contains($client_address), localhost_addresses);
-    };
-    return 'DUNNO';
-}
-
-# ----------------------------------------------------------
-#                handler: relay exemption
-# ----------------------------------------------------------
-
-sub exempt_relay {
-    my %options = @_;
-    my $attr = $options{attr};
-    if ($attr->{client_address} ne '') {
-        my $client_address = NetAddr::IP->new($attr->{client_address});
-        return "PREPEND Authentication-Results: $host; none (SPF not checked for whitelisted relay)"
-            if grep($_->contains($client_address), relay_addresses);
-    };
-    return 'DUNNO';
-}
-
-# ----------------------------------------------------------
-#                        handler: SPF
-# ----------------------------------------------------------
-
-sub sender_policy_framework {
-    my %options = @_;
-    my $attr    = $options{attr};
-    my $cache   = $options{cache};
-    
-    # -------------------------------------------------------------------------
-    # Always do HELO check first.  If no HELO policy, it's only one lookup.
-    # This avoids the need to do any MAIL FROM processing for null sender.
-    # -------------------------------------------------------------------------
-    
-    my $helo_result = $cache->{helo_result};
-    
-    if (not defined($helo_result)) {
-        # No HELO result has been cached from earlier checks on this message.
-        
-        my $helo_request = eval {
-            Mail::SPF::Request->new(
-                scope           => 'helo',
-                identity        => $attr->{helo_name},
-                ip_address      => $attr->{client_address}
-            );
-        };
-        
-        if ($@) {
-            # An unexpected error occurred during request creation,
-            # probably due to invalid input data!
-            my $errmsg = $@;
-            $errmsg = $errmsg->text if UNIVERSAL::isa($@, 'Mail::SPF::Exception');
-                if ($VERBOSE) {
-                    syslog(
-                    info => "HELO check failed - Mail::SPF->new(%s, %s, %s) failed: %s",
-                    $attr->{client_address} || '<UNKNOWN>',
-                    $attr->{sender} || '<UNKNOWN>', $attr->{helo_name} || '<UNKNOWN>',
-                    $errmsg || '<UNKNOWN>'
-                    );
-                };
-            return;
-        }
-        
-        $helo_result = $cache->{helo_result} = $spf_server->process($helo_request);
-    }
-    
-    my $helo_result_code    = $helo_result->code;  # 'pass', 'fail', etc.
-    my $helo_local_exp      = nullchomp($helo_result->local_explanation);
-    my $helo_authority_exp  = nullchomp($helo_result->authority_explanation)
-        if $helo_result->is_code('fail');
-    my $helo_spf_header     = $helo_result->received_spf_header;
-    
-    if ($VERBOSE) {
-        syslog(
-            info => "SPF %s: HELO/EHLO: %s, IP Address: %s, Recipient: %s",
-            $helo_result  || '<UNKNOWN>',
-            $attr->{helo_name} || '<UNKNOWN>', $attr->{client_address} || '<UNKNOWN>',
-            $attr->{recipient} || '<UNKNOWN>'
-        );
-    };
-    
-    # Reject on HELO fail.  Defer on HELO temperror if message would otherwise
-    # be accepted.  Use the HELO result and return for null sender.
-    if ($helo_result->is_code('fail')) {
-        if ($VERBOSE) {
-            syslog(
-                info => "SPF %s: HELO/EHLO: %s",
-                $helo_result || '<UNKNOWN>',
-                $attr->{helo_name} || '<UNKNOWN>'
-            );
-        };
-        return "550 $helo_authority_exp";
-    }
-    elsif ($helo_result->is_code('temperror')) {
-        if ($VERBOSE) {
-            syslog(
-                info => "SPF %s: HELO/EHLO: %s",
-                $helo_result || '<UNKNOWN>',
-                $attr->{helo_name} || '<UNKNOWN>'
-            );
-        };
-        return "DEFER_IF_PERMIT SPF-Result=$helo_local_exp";
-    }
-    elsif ($attr->{sender} eq '') {
-        if ($VERBOSE) {
-            syslog(
-                info => "SPF %s: HELO/EHLO (Null Sender): %s",
-                $helo_result || '<UNKNOWN>',
-                $attr->{helo_name} || '<UNKNOWN>'
-            );
-        };
-        return "PREPEND $helo_spf_header"
-            unless $cache->{added_spf_header}++;
-    }
-    
-    # -------------------------------------------------------------------------
-    # Do MAIL FROM check (as HELO did not give a definitive result)
-    # -------------------------------------------------------------------------
-    
-    my $mfrom_result = $cache->{mfrom_result};
-    
-    if (not defined($mfrom_result)) {
-        # No MAIL FROM result has been cached from earlier checks on this message.
-        
-        my $mfrom_request = eval {
-            Mail::SPF::Request->new(
-                scope           => 'mfrom',
-                identity        => $attr->{sender},
-                ip_address      => $attr->{client_address},
-                helo_identity   => $attr->{helo_name}  # for %{h} macro expansion
-            );
-        };
-        
-        if ($@) {
-            # An unexpected error occurred during request creation,
-            # probably due to invalid input data!
-            my $errmsg = $@;
-            $errmsg = $errmsg->text if UNIVERSAL::isa($@, 'Mail::SPF::Exception');
-            if ($VERBOSE) {
-                syslog(
-                    info => "Mail From (sender) check failed - Mail::SPF->new(%s, %s, %s) failed: %s",
-                    $attr->{client_address} || '<UNKNOWN>',
-                    $attr->{sender} || '<UNKNOWN>', $attr->{helo_name} || '<UNKNOWN>', $errmsg || '<UNKNOWN>'
-                );
-            };
-            return;
-        } 
-        
-        $mfrom_result = $cache->{mfrom_result} = $spf_server->process($mfrom_request);
-    }
-    
-    my $mfrom_result_code   = $mfrom_result->code;  # 'pass', 'fail', etc.
-    my $mfrom_local_exp     = nullchomp($mfrom_result->local_explanation);
-    my $mfrom_authority_exp = nullchomp($mfrom_result->authority_explanation)
-        if $mfrom_result->is_code('fail');
-    my $mfrom_spf_header    = $mfrom_result->received_spf_header;
-    
-    if ($VERBOSE) {
-        syslog(
-            info => "SPF %s: Envelope-from: %s, IP Address: %s, Recipient: %s",
-            $mfrom_result || '<UNKNOWN>',
-            $attr->{sender} || '<UNKNOWN>', $attr->{client_address} || '<UNKNOWN>',
-            $attr->{recipient} || '<UNKNOWN>'
-        );
-    };
-    
-    # Same approach as HELO....
-    if ($VERBOSE) {
-        syslog(
-            info => "SPF %s: Envelope-from: %s",
-            $mfrom_result || '<UNKNOWN>',
-            $attr->{sender} || '<UNKNOWN>'
-        );
-    };
-    if ($mfrom_result->is_code('fail')) {
-        return "550 $mfrom_authority_exp";
-    }
-    elsif ($mfrom_result->is_code('temperror')) {
-        return "DEFER_IF_PERMIT SPF-Result=$mfrom_local_exp";
-    }
-    else {
-        return "PREPEND $mfrom_spf_header"
-            unless $cache->{added_spf_header}++;
-    }
-    
-    return;
-}
-
-# ----------------------------------------------------------
-#                   utility, string cleaning
-# ----------------------------------------------------------
-
-sub nullchomp {
-    my $value = shift;
-
-    # Remove one or more null characters from the
-    # end of the input.
-    $value =~ s/\0+$//;
-    return $value;
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/postfix/files/master.CentOS7.cf	Sat Sep 12 21:00:55 2015 +0100
@@ -0,0 +1,111 @@
+# CentOS 7
+# Postfix master process configuration file.  For details on the format
+# of the file, see the master(5) manual page (command: "man 5 master").
+#
+# Do not forget to execute "postfix reload" after editing this file.
+#
+# ==========================================================================
+# service type  private unpriv  chroot  wakeup  maxproc command + args
+#               (yes)   (yes)   (yes)   (never) (100)
+# ==========================================================================
+#smtp      inet  n       -       n       -       -       smtpd
+smtpd     pass  -       -       n       -       -       smtpd
+smtp      inet  n       -       n       -       1       postscreen
+tlsproxy  unix  -       -       n       -       0       tlsproxy
+dnsblog   unix  -       -       n       -       0       dnsblog
+#submission inet n       -       n       -       -       smtpd
+#  -o smtpd_tls_security_level=encrypt
+#  -o smtpd_sasl_auth_enable=yes
+#  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+#  -o milter_macro_daemon_name=ORIGINATING
+smtps     inet  n       -       n       -       -       smtpd
+  -o smtpd_tls_wrappermode=yes
+  -o smtpd_sasl_auth_enable=yes
+  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+  -o milter_macro_daemon_name=ORIGINATING
+#628      inet  n       -       n       -       -       qmqpd
+pickup    fifo  n       -       n       60      1       pickup
+cleanup   unix  n       -       n       -       0       cleanup
+qmgr      fifo  n       -       n       300     1       qmgr
+#qmgr     fifo  n       -       n       300     1       oqmgr
+tlsmgr    unix  -       -       n       1000?   1       tlsmgr
+rewrite   unix  -       -       n       -       -       trivial-rewrite
+bounce    unix  -       -       n       -       0       bounce
+defer     unix  -       -       n       -       0       bounce
+trace     unix  -       -       n       -       0       bounce
+verify    unix  -       -       n       -       1       verify
+flush     unix  n       -       n       1000?   0       flush
+proxymap  unix  -       -       n       -       -       proxymap
+proxywrite unix -       -       n       -       1       proxymap
+smtp      unix  -       -       n       -       -       smtp
+# When relaying mail as backup MX, disable fallback_relay to avoid MX loops
+relay     unix  -       -       n       -       -       smtp
+	-o smtp_fallback_relay=
+#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
+showq     unix  n       -       n       -       -       showq
+error     unix  -       -       n       -       -       error
+retry     unix  -       -       n       -       -       error
+discard   unix  -       -       n       -       -       discard
+local     unix  -       n       n       -       -       local
+virtual   unix  -       n       n       -       -       virtual
+lmtp      unix  -       -       n       -       -       lmtp
+anvil     unix  -       -       n       -       1       anvil
+scache    unix  -       -       n       -       1       scache
+#
+# ====================================================================
+# Interfaces to non-Postfix software. Be sure to examine the manual
+# pages of the non-Postfix software to find out what options it wants.
+#
+# Many of the following services use the Postfix pipe(8) delivery
+# agent.  See the pipe(8) man page for information about ${recipient}
+# and other message envelope options.
+# ====================================================================
+#
+# maildrop. See the Postfix MAILDROP_README file for details.
+# Also specify in main.cf: maildrop_destination_recipient_limit=1
+#
+#maildrop  unix  -       n       n       -       -       pipe
+#  flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d ${recipient}
+#
+# ====================================================================
+#
+# The Cyrus deliver program has changed incompatibly, multiple times.
+#
+#old-cyrus unix  -       n       n       -       -       pipe
+#  flags=R user=cyrus argv=/usr/lib/cyrus-imapd/deliver -e -m ${extension} ${user}
+#
+# ====================================================================
+#
+# Cyrus 2.1.5 (Amos Gouaux)
+# Also specify in main.cf: cyrus_destination_recipient_limit=1
+#
+#cyrus     unix  -       n       n       -       -       pipe
+#  user=cyrus argv=/usr/lib/cyrus-imapd/deliver -e -r ${sender} -m ${extension} ${user}
+#
+# ====================================================================
+#
+# See the Postfix UUCP_README file for configuration details.
+#
+#uucp      unix  -       n       n       -       -       pipe
+#  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
+#
+# ====================================================================
+#
+# Other external delivery methods.
+#
+#ifmail    unix  -       n       n       -       -       pipe
+#  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
+#
+#bsmtp     unix  -       n       n       -       -       pipe
+#  flags=Fq. user=bsmtp argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient
+#
+#scalemail-backend unix -       n       n       -       2       pipe
+#  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store
+#  ${nexthop} ${user} ${extension}
+#
+#mailman   unix  -       n       n       -       -       pipe
+#  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
+#  ${nexthop} ${user}
+
+policy  unix  -       n       n       -       0       spawn 
+        user=nobody argv=/usr/bin/perl /usr/local/lib/postfix-policyd-spf-perl/postfix-policyd-spf-perl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/postfix/files/master.cf	Sat Sep 12 21:00:55 2015 +0100
@@ -0,0 +1,107 @@
+#
+# Postfix master process configuration file.  For details on the format
+# of the file, see the master(5) manual page (command: "man 5 master").
+#
+# Do not forget to execute "postfix reload" after editing this file.
+#
+# ==========================================================================
+# service type  private unpriv  chroot  wakeup  maxproc command + args
+#               (yes)   (yes)   (yes)   (never) (100)
+# ==========================================================================
+smtp      inet  n       -       n       -       -       smtpd
+#submission inet n       -       n       -       -       smtpd
+#  -o smtpd_tls_security_level=encrypt
+#  -o smtpd_sasl_auth_enable=yes
+#  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+#  -o milter_macro_daemon_name=ORIGINATING
+smtps     inet  n       -       n       -       -       smtpd
+  -o smtpd_tls_wrappermode=yes
+  -o smtpd_sasl_auth_enable=yes
+  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+  -o milter_macro_daemon_name=ORIGINATING
+#628      inet  n       -       n       -       -       qmqpd
+pickup    fifo  n       -       n       60      1       pickup
+cleanup   unix  n       -       n       -       0       cleanup
+qmgr      fifo  n       -       n       300     1       qmgr
+#qmgr     fifo  n       -       n       300     1       oqmgr
+tlsmgr    unix  -       -       n       1000?   1       tlsmgr
+rewrite   unix  -       -       n       -       -       trivial-rewrite
+bounce    unix  -       -       n       -       0       bounce
+defer     unix  -       -       n       -       0       bounce
+trace     unix  -       -       n       -       0       bounce
+verify    unix  -       -       n       -       1       verify
+flush     unix  n       -       n       1000?   0       flush
+proxymap  unix  -       -       n       -       -       proxymap
+proxywrite unix -       -       n       -       1       proxymap
+smtp      unix  -       -       n       -       -       smtp
+# When relaying mail as backup MX, disable fallback_relay to avoid MX loops
+relay     unix  -       -       n       -       -       smtp
+	-o smtp_fallback_relay=
+#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
+showq     unix  n       -       n       -       -       showq
+error     unix  -       -       n       -       -       error
+retry     unix  -       -       n       -       -       error
+discard   unix  -       -       n       -       -       discard
+local     unix  -       n       n       -       -       local
+virtual   unix  -       n       n       -       -       virtual
+lmtp      unix  -       -       n       -       -       lmtp
+anvil     unix  -       -       n       -       1       anvil
+scache    unix  -       -       n       -       1       scache
+#
+# ====================================================================
+# Interfaces to non-Postfix software. Be sure to examine the manual
+# pages of the non-Postfix software to find out what options it wants.
+#
+# Many of the following services use the Postfix pipe(8) delivery
+# agent.  See the pipe(8) man page for information about ${recipient}
+# and other message envelope options.
+# ====================================================================
+#
+# maildrop. See the Postfix MAILDROP_README file for details.
+# Also specify in main.cf: maildrop_destination_recipient_limit=1
+#
+#maildrop  unix  -       n       n       -       -       pipe
+#  flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d ${recipient}
+#
+# ====================================================================
+#
+# The Cyrus deliver program has changed incompatibly, multiple times.
+#
+#old-cyrus unix  -       n       n       -       -       pipe
+#  flags=R user=cyrus argv=/usr/lib/cyrus-imapd/deliver -e -m ${extension} ${user}
+#
+# ====================================================================
+#
+# Cyrus 2.1.5 (Amos Gouaux)
+# Also specify in main.cf: cyrus_destination_recipient_limit=1
+#
+#cyrus     unix  -       n       n       -       -       pipe
+#  user=cyrus argv=/usr/lib/cyrus-imapd/deliver -e -r ${sender} -m ${extension} ${user}
+#
+# ====================================================================
+#
+# See the Postfix UUCP_README file for configuration details.
+#
+#uucp      unix  -       n       n       -       -       pipe
+#  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
+#
+# ====================================================================
+#
+# Other external delivery methods.
+#
+#ifmail    unix  -       n       n       -       -       pipe
+#  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
+#
+#bsmtp     unix  -       n       n       -       -       pipe
+#  flags=Fq. user=bsmtp argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient
+#
+#scalemail-backend unix -       n       n       -       2       pipe
+#  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store
+#  ${nexthop} ${user} ${extension}
+#
+#mailman   unix  -       n       n       -       -       pipe
+#  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
+#  ${nexthop} ${user}
+
+policy  unix  -       n       n       -       0       spawn 
+        user=nobody argv=/usr/bin/perl /usr/local/lib/postfix-policyd-spf-perl/postfix-policyd-spf-perl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/postfix/files/postfix-policyd-spf-perl	Sat Sep 12 21:00:55 2015 +0100
@@ -0,0 +1,396 @@
+#!/usr/bin/perl
+
+# postfix-policyd-spf-perl
+# http://www.openspf.org/Software
+# version 2.010
+#
+# (C) 2007-2008,2012 Scott Kitterman <scott@kitterman.com>
+# (C) 2012           Allison Randal <allison@perl.org>
+# (C) 2007           Julian Mehnle <julian@mehnle.net>
+# (C) 2003-2004      Meng Weng Wong <mengwong@pobox.com>
+#
+#    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('2.010');
+
+use strict;
+
+use IO::Handle;
+use Sys::Syslog qw(:DEFAULT setlogsock);
+use NetAddr::IP;
+use Mail::SPF;
+use Sys::Hostname::Long 'hostname_long';
+
+# ----------------------------------------------------------
+#                      configuration
+# ----------------------------------------------------------
+
+my $resolver = Net::DNS::Resolver->new(
+    retrans         => 5,  # Net::DNS::Resolver default: 5
+    retry           => 2,  # Net::DNS::Resolver default: 4
+    # Makes for a total timeout for UDP queries of 5s * 2 = 10s.
+);
+
+# query_rr_type_all will query both type TXT and type SPF. This upstream
+# default is changed due to there being essentiall no type SPF deployment.
+my $spf_server = Mail::SPF::Server->new(
+    dns_resolver    => $resolver,
+    query_rr_types  => Mail::SPF::Server->query_rr_type_txt,
+    default_authority_explanation  =>
+    'Please see http://www.openspf.net/Why?s=%{_scope};id=%{S};ip=%{C};r=%{R}'
+);
+
+# Adding more handlers is easy:
+my @HANDLERS = (
+    {
+        name => 'exempt_localhost',
+        code => \&exempt_localhost
+    },
+    {
+        name => 'exempt_relay',
+        code => \&exempt_relay
+    },
+    {
+        name => 'sender_policy_framework',
+        code => \&sender_policy_framework
+    }
+);
+
+my $VERBOSE = 0;
+
+my $DEFAULT_RESPONSE = 'DUNNO';
+
+#
+# Syslogging options for verbose mode and for fatal errors.
+# NOTE: comment out the $syslog_socktype line if syslogging does not
+# work on your system.
+#
+
+my $syslog_socktype = 'unix'; # inet, unix, stream, console
+my $syslog_facility = 'mail';
+my $syslog_options  = 'pid';
+my $syslog_ident    = 'postfix/policy-spf';
+
+use constant localhost_addresses => map(
+    NetAddr::IP->new($_),
+    qw(  127.0.0.0/8  ::ffff:127.0.0.0/104  ::1  )
+);  # Does Postfix ever say "client_address=::ffff:<ipv4-address>"?
+
+use constant relay_addresses => map(
+    NetAddr::IP->new($_),
+    qw(  )
+); # add addresses to qw (  ) above separated by spaces using CIDR notation.
+
+# Fully qualified hostname, if available, for use in authentication results
+# headers now provided by the localhost and whitelist checks.
+my  $host = hostname_long;
+
+my %results_cache;  # by message instance
+
+# ----------------------------------------------------------
+#                      initialization
+# ----------------------------------------------------------
+
+#
+# Log an error and abort.
+#
+sub fatal_exit {
+    syslog(err     => "fatal_exit: @_");
+    syslog(warning => "fatal_exit: @_");
+    syslog(info    => "fatal_exit: @_");
+    die("fatal: @_");
+}
+
+#
+# Unbuffer standard output.
+#
+STDOUT->autoflush(1);
+
+#
+# This process runs as a daemon, so it can't log to a terminal. Use
+# syslog so that people can actually see our messages.
+#
+setlogsock($syslog_socktype);
+openlog($syslog_ident, $syslog_options, $syslog_facility);
+
+# ----------------------------------------------------------
+#                           main
+# ----------------------------------------------------------
+
+#
+# Receive a bunch of attributes, evaluate the policy, send the result.
+#
+my %attr;
+while (<STDIN>) {
+    chomp;
+    
+    if (/=/) {
+        my ($key, $value) =split (/=/, $_, 2);
+        $attr{$key} = $value;
+        next;
+    }
+    elsif (length) {
+        syslog(warning => sprintf("warning: ignoring garbage: %.100s", $_));
+        next;
+    }
+    
+    if ($VERBOSE) {
+        for (sort keys %attr) {
+            syslog(debug => "Attribute: %s=%s", $_ || '<UNKNOWN>', $attr{$_} || '<UNKNOWN>');
+        }
+    };
+    
+    my $message_instance = $attr{instance};
+    my $cache = defined($message_instance) ? $results_cache{$message_instance} ||= {} : {};
+    
+    my $action = $DEFAULT_RESPONSE;
+    
+    foreach my $handler (@HANDLERS) {
+        my $handler_name = $handler->{name};
+        my $handler_code = $handler->{code};
+        
+        my $response = $handler_code->(attr => \%attr, cache => $cache);
+        
+        if ($VERBOSE) {
+            syslog(debug => "handler %s: %s", $handler_name || '<UNKNOWN>', $response || '<UNKNOWN>');
+        };
+        
+        # Pick whatever response is not 'DUNNO'
+        if ($response and $response !~ /^DUNNO/i) {
+                if ($VERBOSE) {
+                    syslog(info => "handler %s: is decisive.", $handler_name || '<UNKNOWN>');
+                }
+            $action = $response;
+            last;
+        }
+    }
+    
+    syslog(info => "Policy action=%s", $action || '<UNKNOWN>');
+    
+    STDOUT->print("action=$action\n\n");
+    %attr = ();
+}
+
+# ----------------------------------------------------------
+#                handler: localhost exemption
+# ----------------------------------------------------------
+
+sub exempt_localhost {
+    my %options = @_;
+    my $attr = $options{attr};
+    if ($attr->{client_address} ne '') {
+        my $client_address = NetAddr::IP->new($attr->{client_address});
+        return "PREPEND Authentication-Results: $host; none (SPF not checked for localhost)"
+            if grep($_->contains($client_address), localhost_addresses);
+    };
+    return 'DUNNO';
+}
+
+# ----------------------------------------------------------
+#                handler: relay exemption
+# ----------------------------------------------------------
+
+sub exempt_relay {
+    my %options = @_;
+    my $attr = $options{attr};
+    if ($attr->{client_address} ne '') {
+        my $client_address = NetAddr::IP->new($attr->{client_address});
+        return "PREPEND Authentication-Results: $host; none (SPF not checked for whitelisted relay)"
+            if grep($_->contains($client_address), relay_addresses);
+    };
+    return 'DUNNO';
+}
+
+# ----------------------------------------------------------
+#                        handler: SPF
+# ----------------------------------------------------------
+
+sub sender_policy_framework {
+    my %options = @_;
+    my $attr    = $options{attr};
+    my $cache   = $options{cache};
+    
+    # -------------------------------------------------------------------------
+    # Always do HELO check first.  If no HELO policy, it's only one lookup.
+    # This avoids the need to do any MAIL FROM processing for null sender.
+    # -------------------------------------------------------------------------
+    
+    my $helo_result = $cache->{helo_result};
+    
+    if (not defined($helo_result)) {
+        # No HELO result has been cached from earlier checks on this message.
+        
+        my $helo_request = eval {
+            Mail::SPF::Request->new(
+                scope           => 'helo',
+                identity        => $attr->{helo_name},
+                ip_address      => $attr->{client_address}
+            );
+        };
+        
+        if ($@) {
+            # An unexpected error occurred during request creation,
+            # probably due to invalid input data!
+            my $errmsg = $@;
+            $errmsg = $errmsg->text if UNIVERSAL::isa($@, 'Mail::SPF::Exception');
+                if ($VERBOSE) {
+                    syslog(
+                    info => "HELO check failed - Mail::SPF->new(%s, %s, %s) failed: %s",
+                    $attr->{client_address} || '<UNKNOWN>',
+                    $attr->{sender} || '<UNKNOWN>', $attr->{helo_name} || '<UNKNOWN>',
+                    $errmsg || '<UNKNOWN>'
+                    );
+                };
+            return;
+        }
+        
+        $helo_result = $cache->{helo_result} = $spf_server->process($helo_request);
+    }
+    
+    my $helo_result_code    = $helo_result->code;  # 'pass', 'fail', etc.
+    my $helo_local_exp      = nullchomp($helo_result->local_explanation);
+    my $helo_authority_exp  = nullchomp($helo_result->authority_explanation)
+        if $helo_result->is_code('fail');
+    my $helo_spf_header     = $helo_result->received_spf_header;
+    
+    if ($VERBOSE) {
+        syslog(
+            info => "SPF %s: HELO/EHLO: %s, IP Address: %s, Recipient: %s",
+            $helo_result  || '<UNKNOWN>',
+            $attr->{helo_name} || '<UNKNOWN>', $attr->{client_address} || '<UNKNOWN>',
+            $attr->{recipient} || '<UNKNOWN>'
+        );
+    };
+    
+    # Reject on HELO fail.  Defer on HELO temperror if message would otherwise
+    # be accepted.  Use the HELO result and return for null sender.
+    if ($helo_result->is_code('fail')) {
+        if ($VERBOSE) {
+            syslog(
+                info => "SPF %s: HELO/EHLO: %s",
+                $helo_result || '<UNKNOWN>',
+                $attr->{helo_name} || '<UNKNOWN>'
+            );
+        };
+        return "550 $helo_authority_exp";
+    }
+    elsif ($helo_result->is_code('temperror')) {
+        if ($VERBOSE) {
+            syslog(
+                info => "SPF %s: HELO/EHLO: %s",
+                $helo_result || '<UNKNOWN>',
+                $attr->{helo_name} || '<UNKNOWN>'
+            );
+        };
+        return "DEFER_IF_PERMIT SPF-Result=$helo_local_exp";
+    }
+    elsif ($attr->{sender} eq '') {
+        if ($VERBOSE) {
+            syslog(
+                info => "SPF %s: HELO/EHLO (Null Sender): %s",
+                $helo_result || '<UNKNOWN>',
+                $attr->{helo_name} || '<UNKNOWN>'
+            );
+        };
+        return "PREPEND $helo_spf_header"
+            unless $cache->{added_spf_header}++;
+    }
+    
+    # -------------------------------------------------------------------------
+    # Do MAIL FROM check (as HELO did not give a definitive result)
+    # -------------------------------------------------------------------------
+    
+    my $mfrom_result = $cache->{mfrom_result};
+    
+    if (not defined($mfrom_result)) {
+        # No MAIL FROM result has been cached from earlier checks on this message.
+        
+        my $mfrom_request = eval {
+            Mail::SPF::Request->new(
+                scope           => 'mfrom',
+                identity        => $attr->{sender},
+                ip_address      => $attr->{client_address},
+                helo_identity   => $attr->{helo_name}  # for %{h} macro expansion
+            );
+        };
+        
+        if ($@) {
+            # An unexpected error occurred during request creation,
+            # probably due to invalid input data!
+            my $errmsg = $@;
+            $errmsg = $errmsg->text if UNIVERSAL::isa($@, 'Mail::SPF::Exception');
+            if ($VERBOSE) {
+                syslog(
+                    info => "Mail From (sender) check failed - Mail::SPF->new(%s, %s, %s) failed: %s",
+                    $attr->{client_address} || '<UNKNOWN>',
+                    $attr->{sender} || '<UNKNOWN>', $attr->{helo_name} || '<UNKNOWN>', $errmsg || '<UNKNOWN>'
+                );
+            };
+            return;
+        } 
+        
+        $mfrom_result = $cache->{mfrom_result} = $spf_server->process($mfrom_request);
+    }
+    
+    my $mfrom_result_code   = $mfrom_result->code;  # 'pass', 'fail', etc.
+    my $mfrom_local_exp     = nullchomp($mfrom_result->local_explanation);
+    my $mfrom_authority_exp = nullchomp($mfrom_result->authority_explanation)
+        if $mfrom_result->is_code('fail');
+    my $mfrom_spf_header    = $mfrom_result->received_spf_header;
+    
+    if ($VERBOSE) {
+        syslog(
+            info => "SPF %s: Envelope-from: %s, IP Address: %s, Recipient: %s",
+            $mfrom_result || '<UNKNOWN>',
+            $attr->{sender} || '<UNKNOWN>', $attr->{client_address} || '<UNKNOWN>',
+            $attr->{recipient} || '<UNKNOWN>'
+        );
+    };
+    
+    # Same approach as HELO....
+    if ($VERBOSE) {
+        syslog(
+            info => "SPF %s: Envelope-from: %s",
+            $mfrom_result || '<UNKNOWN>',
+            $attr->{sender} || '<UNKNOWN>'
+        );
+    };
+    if ($mfrom_result->is_code('fail')) {
+        return "550 $mfrom_authority_exp";
+    }
+    elsif ($mfrom_result->is_code('temperror')) {
+        return "DEFER_IF_PERMIT SPF-Result=$mfrom_local_exp";
+    }
+    else {
+        return "PREPEND $mfrom_spf_header"
+            unless $cache->{added_spf_header}++;
+    }
+    
+    return;
+}
+
+# ----------------------------------------------------------
+#                   utility, string cleaning
+# ----------------------------------------------------------
+
+sub nullchomp {
+    my $value = shift;
+
+    # Remove one or more null characters from the
+    # end of the input.
+    $value =~ s/\0+$//;
+    return $value;
+}
+
--- a/modules/postfix/manifests/init.pp	Sat Sep 12 16:42:27 2015 +0100
+++ b/modules/postfix/manifests/init.pp	Sat Sep 12 21:00:55 2015 +0100
@@ -30,7 +30,10 @@
     content => template('postfix/main.cf.erb'),
   }
   file { '/etc/postfix/master.cf':
-    source => 'puppet:///common/postfix/master.cf'
+    source => [
+      "puppet:///modules/postfix/master.${operatingsystem}${operatingsystemmajrelease}.cf",
+      'puppet:///modules/postfix/master.cf'
+    ]
   }
   #Hosted domains
   file { '/etc/postfix/vdomains':
@@ -99,7 +102,7 @@
     ensure => directory
   }
   file { '/usr/local/lib/postfix-policyd-spf-perl/postfix-policyd-spf-perl':
-    source => 'puppet:///common/postfix/postfix-policyd-spf-perl',
+    source => 'puppet:///modules/postfix/postfix-policyd-spf-perl',
   }
   $perl_pkgs = [ 'perl', 'perl-NetAddr-IP', 'perl-Mail-SPF', 'perl-version', 'perl-Sys-Hostname-Long']
   package { $perl_pkgs:
--- a/modules/postfix/templates/main.cf.erb	Sat Sep 12 16:42:27 2015 +0100
+++ b/modules/postfix/templates/main.cf.erb	Sat Sep 12 21:00:55 2015 +0100
@@ -65,3 +65,9 @@
 transport_maps = hash:/etc/postfix/transport
 message_size_limit = 15000000
 header_checks = regexp:/etc/postfix/header_checks
+
+# The following may not be used by all versions of Postfix
+postscreen_dnsbl_threshold = 2
+postscreen_dnsbl_sites = zen.spamhaus.org*2 bl.spamcop.net*1 b.barracudacentral.org*1
+#postscreen_greet_action = enforce
+#postscreen_dnsbl_action = enforce
\ No newline at end of file