Tidying
[exim.git] / src / src / exim_checkaccess.src
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
22 args="$@"
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
27 if [ "CONFIGURE_FILE_USE_NODE" = "yes" ]; then
28 hostsuffix=.`uname -n`
29 fi
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
36 set `awk -F: '{ for (i = 1; i <= NF; i++) print $i }' <<End
37 CONFIGURE_FILE
38 End
39 `
40 while [ "$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
47 done
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
54 exim_path=`perl -ne 'chop;if (/^\s*exim_path\s*=\s*(.*)/){print "$1\n";last;}' $config`
55 if 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
64 PERL_COMMAND - $exim_path $args <<'End'
65
66 BEGIN { pop @INC if $INC[-1] eq '.' };
67 use FileHandle;
68 use IPC::Open2;
69
70 if (scalar(@ARGV) < 3)
71 {
72 print "Usage: exim_checkaccess <IP address> <email address> [exim options]\n";
73 exit(1);
74 }
75
76 $exim_path = $ARGV[0]; # Set up by the calling shell script
77 $host = $ARGV[1]; # Mandatory original first argument
78 $recipient = $ARGV[2]; # Mandatory original second argument
79
80 $c4 = qr/2 (?:[0-4]\d | 5[0-5]) | 1\d\d | \d{1,2}/x; # IPv4 component
81 $a4 = qr/^$c4\.$c4\.$c4\.$c4$/; # IPv4 address
82
83 $c6 = qr/[0-9a-f]{1,4}/i; # IPv6 component
84
85 # Split the various formats of IPv6 addresses into several cases. I don't
86 # think I can graft regex that matches all of them without using alternatives.
87
88 # 1. Starts with :: followed by up to 7 components
89
90 $a6_0 = qr/^::(?:$c6:){0,6}$c6$/x;
91
92 # 2. 8 non-empty components
93
94 $a6_1 = qr/^(?:$c6:){7}$c6$/x;
95
96 # 3. This is the cunning one. Up to 7 components, one (and only one) of which
97 # can be empty. We use 0 to cause a failure when we've already matched
98 # an empty component and may be hitting other. This has to fail, because we
99 # know we've just failed to match a component. We also do a final check to
100 # ensure that there has been an empty component.
101
102 $a6_2 = qr/^(?: (?: $c6 | (?(1)0 | () ) ) : ){1,7}$c6 $ (?(1)|.)/x;
103
104 if ($host !~ /$a4 | $a6_0 | $a6_1 | $a6_2/x)
105 {
106 print "** Invalid IP address \"$host\"\n";
107 print "Usage: exim_checkaccess <IP address> <email address> [exim options]\n";
108 exit(1);
109 }
110
111 # Build any remaining original arguments into a string for passing over
112 # as Exim options.
113
114 $opt = "";
115 for ($i = 3; $i < scalar(@ARGV); $i++) { $opt .= "$ARGV[$i] "; }
116
117 # If the string contains "-f xxxx", extract that as the sender. Otherwise
118 # the sender is <>.
119
120 $sender = "";
121 if ($opt =~ /(?:^|\s)-f\s+(\S+|"[^"]*")/)
122 {
123 $sender = $1;
124 $opt = $` . $';
125 }
126
127 # Run a -bh test in Exim, passing the test data
128
129 $pid = open2(*IN, *OUT, "$exim_path -bh $host $opt 2>/dev/null");
130 print OUT "HELO [$host]\r\n";
131 print OUT "MAIL FROM:<$sender>\r\n";
132 print OUT "RCPT TO:<$recipient>\r\n";
133 print OUT "QUIT\r\n";
134 close OUT;
135
136 # Read the output, ignoring anything but the SMTP response to the RCPT
137 # command.
138
139 $count = 0;
140 $reply = "";
141
142 while (<IN>)
143 {
144 next if !/^\d\d\d/;
145 $reply .= $_;
146 next if /^\d\d\d\-/;
147
148 if (++$count != 4)
149 {
150 $reply = "";
151 next;
152 }
153
154 # We have the response we want. Interpret it.
155
156 if ($reply =~ /^2\d\d/)
157 {
158 print "Accepted\n";
159 }
160 else
161 {
162 print "Rejected:\n";
163 $reply =~ s/\n(.)/\n $1/g;
164 print " $reply";
165 }
166 last;
167 }
168
169 # Reap the child process
170
171 waitpid $pid, 0;
172
173 End