1#! /bin/sh 2 3# Copyright (c) University of Cambridge, 1995 - 2007 4# See the file NOTICE for conditions of use and distribution. 5 6# Except when they appear in comments, the following placeholders in this 7# source are replaced when it is turned into a runnable script: 8# 9# CONFIGURE_FILE_USE_NODE 10# CONFIGURE_FILE 11# BIN_DIRECTORY 12# PERL_COMMAND 13 14# PROCESSED_FLAG 15 16# A shell+perl wrapper script to run an automated -bh test to check out 17# ACLs for incoming addresses. 18 19# Save the shell arguments because we are going to need the shell variables 20# while sorting out the configuration file. 21 22args="$@" 23 24# See if this installation is using the esoteric "USE_NODE" feature of Exim, 25# in which it uses the host's name as a suffix for the configuration file name. 26 27if [ "CONFIGURE_FILE_USE_NODE" = "yes" ]; then 28 hostsuffix=.`uname -n` 29fi 30 31# Now find the configuration file name. This has got complicated because 32# CONFIGURE_FILE may now be a list of files. The one that is used is the first 33# one that exists. Mimic the code in readconf.c by testing first for the 34# suffixed file in each case. 35 36set `awk -F: '{ for (i = 1; i <= NF; i++) print $i }' <<End 37CONFIGURE_FILE 38End 39` 40while [ "$config" = "" -a $# -gt 0 ] ; do 41 if [ -f "$1$hostsuffix" ] ; then 42 config="$1$hostsuffix" 43 elif [ -f "$1" ] ; then 44 config="$1" 45 fi 46 shift 47done 48 49# Search for an exim_path setting in the configure file; otherwise use the bin 50# directory. BEWARE: a tab character is needed in the command below. It has had 51# a nasty tendency to get lost in the past. Use a variable to hold a space and 52# a tab to keep the tab in one place. 53 54exim_path=`perl -ne 'chop;if (/^\s*exim_path\s*=\s*(.*)/){print "$1\n";last;}' $config` 55if test "$exim_path" = ""; then exim_path=BIN_DIRECTORY/exim; fi 56 57 58######################################################################### 59 60 61# Now run the perl script, passing in the Exim path and the arguments given 62# to the overall script. 63 64PERL_COMMAND - $exim_path $args <<'End' 65 66BEGIN { pop @INC if $INC[-1] eq '.' }; 67use FileHandle; 68use File::Basename; 69use IPC::Open2; 70 71if ($ARGV[0] eq '--version') { 72 print basename($0) . ": $0\n", 73 "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n", 74 "perl(runtime): $]\n"; 75 exit 0; 76} 77 78if (scalar(@ARGV) < 3) 79 { 80 print "Usage: exim_checkaccess <IP address> <email address> [exim options]\n"; 81 exit(1); 82 } 83 84$exim_path = $ARGV[0]; # Set up by the calling shell script 85$host = $ARGV[1]; # Mandatory original first argument 86$recipient = $ARGV[2]; # Mandatory original second argument 87 88$c4 = qr/2 (?:[0-4]\d | 5[0-5]) | 1\d\d | \d{1,2}/x; # IPv4 component 89$a4 = qr/^$c4\.$c4\.$c4\.$c4$/; # IPv4 address 90 91$c6 = qr/[0-9a-f]{1,4}/i; # IPv6 component 92 93# Split the various formats of IPv6 addresses into several cases. I don't 94# think I can graft regex that matches all of them without using alternatives. 95 96# 1. Starts with :: followed by up to 7 components 97 98$a6_0 = qr/^::(?:$c6:){0,6}$c6$/x; 99 100# 2. 8 non-empty components 101 102$a6_1 = qr/^(?:$c6:){7}$c6$/x; 103 104# 3. This is the cunning one. Up to 7 components, one (and only one) of which 105# can be empty. We use 0 to cause a failure when we've already matched 106# an empty component and may be hitting other. This has to fail, because we 107# know we've just failed to match a component. We also do a final check to 108# ensure that there has been an empty component. 109 110$a6_2 = qr/^(?: (?: $c6 | (?(1)0 | () ) ) : ){1,7}$c6 $ (?(1)|.)/x; 111 112if ($host !~ /$a4 | $a6_0 | $a6_1 | $a6_2/x) 113 { 114 print "** Invalid IP address \"$host\"\n"; 115 print "Usage: exim_checkaccess <IP address> <email address> [exim options]\n"; 116 exit(1); 117 } 118 119# Build any remaining original arguments into a string for passing over 120# as Exim options. 121 122$opt = ""; 123for ($i = 3; $i < scalar(@ARGV); $i++) { $opt .= "$ARGV[$i] "; } 124 125# If the string contains "-f xxxx", extract that as the sender. Otherwise 126# the sender is <>. 127 128$sender = ""; 129if ($opt =~ /(?:^|\s)-f\s+(\S+|"[^"]*")/) 130 { 131 $sender = $1; 132 $opt = $` . $'; 133 } 134 135# Run a -bh test in Exim, passing the test data 136 137$pid = open2(*IN, *OUT, "$exim_path -bh $host $opt 2>/dev/null"); 138print OUT "HELO [$host]\r\n"; 139print OUT "MAIL FROM:<$sender>\r\n"; 140print OUT "RCPT TO:<$recipient>\r\n"; 141print OUT "QUIT\r\n"; 142close OUT; 143 144# Read the output, ignoring anything but the SMTP response to the RCPT 145# command. 146 147$count = 0; 148$reply = ""; 149 150while (<IN>) 151 { 152 next if !/^\d\d\d/; 153 $reply .= $_; 154 next if /^\d\d\d\-/; 155 156 if (++$count != 4) 157 { 158 $reply = ""; 159 next; 160 } 161 162 # We have the response we want. Interpret it. 163 164 if ($reply =~ /^2\d\d/) 165 { 166 print "Accepted\n"; 167 } 168 else 169 { 170 print "Rejected:\n"; 171 $reply =~ s/\n(.)/\n $1/g; 172 print " $reply"; 173 } 174 last; 175 } 176 177# Reap the child process 178 179waitpid $pid, 0; 180 181End 182