mirror of
				https://git.lapiole.org/dani/ansible-roles.git
				synced 2025-10-27 08:51:27 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			218 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| #!/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 <https://www.gnu.org/licenses/>.
 | |
| # ***** 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 (<STDIN>) {
 | |
|     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", $_;
 | |
|     }
 | |
| }
 | 
