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