diff --git a/roles/zimbra/files/zmpostfixpolicyd b/roles/zimbra/files/zmpostfixpolicyd new file mode 100755 index 0000000..9db8962 --- /dev/null +++ b/roles/zimbra/files/zmpostfixpolicyd @@ -0,0 +1,217 @@ +#!/usr/bin/perl +# +# ***** BEGIN LICENSE BLOCK ***** +# Zimbra Collaboration Suite Server +# Copyright (C) 2008, 2009, 2010, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. +# +# 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, +# version 2 of the License. +# +# 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, see . +# ***** END LICENSE BLOCK ***** + +use strict; +use lib '/opt/zimbra/common/lib/perl5'; +use Sys::Syslog qw(:DEFAULT setlogsock); +use Net::LDAPapi; +use XML::Simple; + +# +# 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'; +my $syslog_facility="mail"; +my $syslog_options="pid"; +our $syslog_priority="info"; +our ($verbose, %attr, @ldap_url, $ldap_starttls_supported, $postfix_pw, $zimbra_pw, $delim_re); +my ($option, $action, $ldap_url, @val); + +$ENV{'HOME'}='/opt/zimbra'; +setlogsock $syslog_socktype; +openlog $0, $syslog_options, $syslog_facility; + +my $localxml = XMLin("/opt/zimbra/conf/localconfig.xml"); + +$ldap_starttls_supported = $localxml->{key}->{ldap_starttls_supported}->{value}; +chomp ($ldap_starttls_supported); +$postfix_pw = $localxml->{key}->{ldap_postfix_password}->{value}; +chomp($postfix_pw); +$zimbra_pw = $localxml->{key}->{zimbra_ldap_password}->{value}; +chomp($zimbra_pw); +$ldap_url = $localxml->{key}->{ldap_url}->{value}; +chomp($ldap_url); +@ldap_url = split / /, $ldap_url; + +sub smtpd_access_policy { + my($domain, $ldap, $mesg, $user, $canon_user, $daddr, @attrs, $result); + $daddr = lc $attr{recipient}; + ($user, $domain) = split /\@/, lc $attr{recipient}; + $canon_user = (defined $delim_re) ? (split /$delim_re/, $user)[0] : $user; + syslog $syslog_priority, "Recipient Domain: %s", $domain if $verbose; + syslog $syslog_priority, "Recipient userid: %s", $user if $verbose; + foreach my $url (@ldap_url) { + $ldap=Net::LDAPapi->new(-url=>$url); + if ( $ldap_starttls_supported ) { + $mesg = $ldap->start_tls_s(); + if ($mesg != 0) { + next; + } + } + $mesg = $ldap->bind_s("uid=zmpostfix,cn=appaccts,cn=zimbra",$postfix_pw); + if ($mesg != 0) { + next; + } else { + last; + } + } + if ($mesg != 0) { + syslog $syslog_priority, "Error: zmpostfixpolicyd unable to find working LDAP server"; + return "dunno"; + } + @attrs=('zimbraDomainType', 'zimbraMailCatchAllForwardingAddress'); + $mesg = $ldap->search_s( + "", + LDAP_SCOPE_SUBTREE, + "(&(zimbraDomainName=$domain)(objectClass=zimbraDomain))", + \@attrs, + 0, + $result + ); + my $ent = $ldap->first_entry(); + if ($ent != 0) { + if (lc(($ldap->get_values("zimbraDomainType"))[0]) eq "alias") { + my $robject = ($ldap->get_values("zimbraMailCatchAllForwardingAddress"))[0]; + syslog $syslog_priority, "Real Domain: %s", $robject if $verbose; + @attrs=('1.1'); + $mesg = $ldap->search_s( + "", + LDAP_SCOPE_SUBTREE, + "(&(|(zimbraMailDeliveryAddress=$user"."$robject)(zimbraMailDeliveryAddress=$canon_user"."$robject)". + "(zimbraMailDeliveryAddress=$daddr)(zimbraMailAlias=$user"."$robject)(zimbraMailAlias=$canon_user"."$robject)". + "(zimbraMailAlias=$daddr)(zimbraMailCatchAllAddress=$user"."$robject)(zimbraMailCatchAllAddress=$robject)". + "(zimbraMailCatchAllAddress=$daddr))(zimbraMailStatus=enabled))", + \@attrs, + 0, + $result + ); + $ent = $ldap->first_entry(); + $ldap->unbind; + if ($ent != 0) { + return "dunno"; + } else { + return "reject 5.1.1 Mailbox unavailable"; + } + } else { + $ldap->unbind; + return "dunno"; + } + } + $ldap->unbind; + return "dunno"; +} + +# +# Log an error and abort. +# +sub fatal_exit { + my($first) = shift(@_); + syslog "err", "fatal: $first", @_; + exit 1; +} + +# +# We don't need getopt() for now. +# +while ($option = shift(@ARGV)) { + if ($option eq "-v") { + $verbose = 1; + } else { + syslog $syslog_priority, "Invalid option: %s. Usage: %s [-v]", + $option, $0; + exit 1; + } +} + +# +# Unbuffer standard output. +# +select((select(STDOUT), $| = 1)[0]); + +# Try to get recipient delimiter, if defined +# This will allow checking for valid recipient on alias domains +# even for recipient using delimiter. Eg user+foobar@alias.example.org +# will correctly check if user@example.org is valid +my ($ldap, $mesg, @attrs, $result); +foreach my $url (@ldap_url) { + $ldap=Net::LDAPapi->new(-url=>$url); + if ( $ldap_starttls_supported ) { + $mesg = $ldap->start_tls_s(); + if ($mesg != 0) { + next; + } + } + $mesg = $ldap->bind_s("uid=zimbra,cn=admins,cn=zimbra",$zimbra_pw); + if ($mesg != 0) { + next; + } else { + last; + } +} +if ($mesg == 0){ + @attrs=('zimbraMtaRecipientDelimiter'); + $mesg = $ldap->search_s( + "", + LDAP_SCOPE_SUBTREE, + "(&(cn=config)(objectClass=zimbraGlobalConfig))", + \@attrs, + 0, + $result + ); + my $ent = $ldap->first_entry(); + if ($ent != 0){ + my $delim = ($ldap->get_values('zimbraMtaRecipientDelimiter'))[0]; + if ($delim ne ''){ + $delim_re = qr{[$delim]}; + syslog $syslog_priority, "Recipient delimiter regex is $delim_re" if $verbose; + } else { + syslog $syslog_priority, "Recipient delimiter is an empty string so it won't be used" if $verbose; + } + } else { + syslog $syslog_priority, "Recipient delimiter not found" if $verbose; + } + # Unbind, everything else will bind with the postfix LDAP user + $ldap->unbind; +} else { + syslog $syslog_priority, "Couldn't bind with zimbra account, recipient delimiter won't be used" if $verbose; +} + +# +# Receive a bunch of attributes, evaluate the policy, send the result. +# +while () { + if (/([^=]+)=(.*)\n/) { + $attr{substr($1, 0, 512)} = substr($2, 0, 512); + } elsif ($_ eq "\n") { + if ($verbose) { + for (keys %attr) { + syslog $syslog_priority, "Attribute: %s=%s", $_, $attr{$_}; + } + } + fatal_exit "unrecognized request type: '%s'", $attr{"request"} + unless $attr{"request"} eq "smtpd_access_policy"; + $action = smtpd_access_policy(); + syslog $syslog_priority, "Action: %s", $action if $verbose; + print STDOUT "action=$action\n\n"; + %attr = (); + } else { + chop; + syslog $syslog_priority, "warning: ignoring garbage: %.100s", $_; + } +} diff --git a/roles/zimbra/files/zmpostfixpolicyd_recipient_delim.patch b/roles/zimbra/files/zmpostfixpolicyd_recipient_delim.patch index 5f28d7f..4daa128 100644 --- a/roles/zimbra/files/zmpostfixpolicyd_recipient_delim.patch +++ b/roles/zimbra/files/zmpostfixpolicyd_recipient_delim.patch @@ -1,5 +1,5 @@ --- /opt/zimbra/libexec/zmpostfixpolicyd.bak 2019-07-18 21:24:39.000000000 +0200 -+++ /opt/zimbra/libexec/zmpostfixpolicyd 2020-11-22 17:07:32.387815282 +0100 ++++ /opt/zimbra/libexec/zmpostfixpolicyd 2020-11-23 10:02:37.956775250 +0100 @@ -30,7 +30,7 @@ my $syslog_facility="mail"; my $syslog_options="pid"; @@ -35,8 +35,8 @@ - "(&(|(zimbraMailDeliveryAddress=$user"."$robject)(zimbraMailDeliveryAddress=$daddr)(zimbraMailAlias=$user". - "$robject)(zimbraMailAlias=$daddr)(zimbraMailCatchAllAddress=$user"."$robject)(zimbraMailCatchAllAddress=$robject)". + "(&(|(zimbraMailDeliveryAddress=$user"."$robject)(zimbraMailDeliveryAddress=$canon_user"."$robject)". -+ "(zimbraMailDeliveryAddress=$daddr)(zimbraMailAlias=$user"."$robject)(zimbraMailAlias=$daddr)". -+ "(zimbraMailCatchAllAddress=$user"."$robject)(zimbraMailCatchAllAddress=$robject)". ++ "(zimbraMailDeliveryAddress=$daddr)(zimbraMailAlias=$user"."$robject)(zimbraMailAlias=$canon_user"."$robject)". ++ "(zimbraMailAlias=$daddr)(zimbraMailCatchAllAddress=$user"."$robject)(zimbraMailCatchAllAddress=$robject)". "(zimbraMailCatchAllAddress=$daddr))(zimbraMailStatus=enabled))", \@attrs, 0, diff --git a/roles/zimbra/tasks/mta.yml b/roles/zimbra/tasks/mta.yml index 221954f..4c31bd2 100644 --- a/roles/zimbra/tasks/mta.yml +++ b/roles/zimbra/tasks/mta.yml @@ -13,10 +13,8 @@ changed_when: False tags: zcs -- name: Patch zmpostfixpolicyd to support recipient delimiter - patch: - src: zmpostfixpolicyd_recipient_delim.patch - dest: /opt/zimbra/libexec/zmpostfixpolicyd +- name: Override zmpostfixpolicyd to support recipient delimiter + copy: src=zmpostfixpolicyd dest=/opt/zimbra/libexec/zmpostfixpolicyd notify: restart zimbra tags: zcs