xref: /titanic_54/usr/src/cmd/sendmail/aux/etrn.pl (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate#!/usr/perl5/bin/perl -w
2*7c478bd9Sstevel@tonic-gate#
3*7c478bd9Sstevel@tonic-gate# CDDL HEADER START
4*7c478bd9Sstevel@tonic-gate#
5*7c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
6*7c478bd9Sstevel@tonic-gate# Common Development and Distribution License, Version 1.0 only
7*7c478bd9Sstevel@tonic-gate# (the "License").  You may not use this file except in compliance
8*7c478bd9Sstevel@tonic-gate# with the License.
9*7c478bd9Sstevel@tonic-gate#
10*7c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11*7c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
12*7c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
13*7c478bd9Sstevel@tonic-gate# and limitations under the License.
14*7c478bd9Sstevel@tonic-gate#
15*7c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
16*7c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17*7c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
18*7c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
19*7c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
20*7c478bd9Sstevel@tonic-gate#
21*7c478bd9Sstevel@tonic-gate# CDDL HEADER END
22*7c478bd9Sstevel@tonic-gate#
23*7c478bd9Sstevel@tonic-gate#
24*7c478bd9Sstevel@tonic-gate# Copyright (c) 1996-2000 by John T. Beck <john@beck.org>
25*7c478bd9Sstevel@tonic-gate# All rights reserved.
26*7c478bd9Sstevel@tonic-gate#
27*7c478bd9Sstevel@tonic-gate# Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
28*7c478bd9Sstevel@tonic-gate# Use is subject to license terms.
29*7c478bd9Sstevel@tonic-gate#
30*7c478bd9Sstevel@tonic-gate#ident	"%Z%%M%	%I%	%E% SMI"
31*7c478bd9Sstevel@tonic-gate
32*7c478bd9Sstevel@tonic-gaterequire 5.6.1;				# minimal Perl version required
33*7c478bd9Sstevel@tonic-gateuse strict;
34*7c478bd9Sstevel@tonic-gateuse warnings;
35*7c478bd9Sstevel@tonic-gateuse English;
36*7c478bd9Sstevel@tonic-gate
37*7c478bd9Sstevel@tonic-gateuse Socket;
38*7c478bd9Sstevel@tonic-gateuse Getopt::Std;
39*7c478bd9Sstevel@tonic-gateour ($opt_v, $opt_b);
40*7c478bd9Sstevel@tonic-gate
41*7c478bd9Sstevel@tonic-gate# system requirements:
42*7c478bd9Sstevel@tonic-gate# 	must have 'hostname' program.
43*7c478bd9Sstevel@tonic-gate
44*7c478bd9Sstevel@tonic-gatemy $port = 'smtp';
45*7c478bd9Sstevel@tonic-gateselect(STDERR);
46*7c478bd9Sstevel@tonic-gate
47*7c478bd9Sstevel@tonic-gatechop(my $name = `hostname || uname -n`);
48*7c478bd9Sstevel@tonic-gate
49*7c478bd9Sstevel@tonic-gatemy ($hostname) = (gethostbyname($name))[0];
50*7c478bd9Sstevel@tonic-gate
51*7c478bd9Sstevel@tonic-gatemy $usage = "Usage: $PROGRAM_NAME [-bv] host [args]";
52*7c478bd9Sstevel@tonic-gategetopts('bv');
53*7c478bd9Sstevel@tonic-gatemy $verbose = $opt_v;
54*7c478bd9Sstevel@tonic-gatemy $boot_check = $opt_b;
55*7c478bd9Sstevel@tonic-gatemy $server = shift(@ARGV);
56*7c478bd9Sstevel@tonic-gatemy @hosts = @ARGV;
57*7c478bd9Sstevel@tonic-gatedie $usage unless $server;
58*7c478bd9Sstevel@tonic-gatemy @cwfiles = ();
59*7c478bd9Sstevel@tonic-gatemy $alarm_action = "";
60*7c478bd9Sstevel@tonic-gate
61*7c478bd9Sstevel@tonic-gateif (!@hosts) {
62*7c478bd9Sstevel@tonic-gate	push(@hosts, $hostname);
63*7c478bd9Sstevel@tonic-gate
64*7c478bd9Sstevel@tonic-gate	open(CF, "</etc/mail/sendmail.cf") ||
65*7c478bd9Sstevel@tonic-gate	    die "open /etc/mail/sendmail.cf: $ERRNO";
66*7c478bd9Sstevel@tonic-gate	while (<CF>){
67*7c478bd9Sstevel@tonic-gate		# look for a line starting with "Fw"
68*7c478bd9Sstevel@tonic-gate		if (/^Fw.*$/) {
69*7c478bd9Sstevel@tonic-gate			my $cwfile = $ARG;
70*7c478bd9Sstevel@tonic-gate			chop($cwfile);
71*7c478bd9Sstevel@tonic-gate			my $optional = /^Fw-o/;
72*7c478bd9Sstevel@tonic-gate			# extract the file name
73*7c478bd9Sstevel@tonic-gate			$cwfile =~ s,^Fw[^/]*,,;
74*7c478bd9Sstevel@tonic-gate
75*7c478bd9Sstevel@tonic-gate			# strip the options after the filename
76*7c478bd9Sstevel@tonic-gate			$cwfile =~ s/ [^ ]+$//;
77*7c478bd9Sstevel@tonic-gate
78*7c478bd9Sstevel@tonic-gate			if (-r $cwfile) {
79*7c478bd9Sstevel@tonic-gate				push (@cwfiles, $cwfile);
80*7c478bd9Sstevel@tonic-gate			} else {
81*7c478bd9Sstevel@tonic-gate				die "$cwfile is not readable" unless $optional;
82*7c478bd9Sstevel@tonic-gate			}
83*7c478bd9Sstevel@tonic-gate		}
84*7c478bd9Sstevel@tonic-gate		# look for a line starting with "Cw"
85*7c478bd9Sstevel@tonic-gate		if (/^Cw(.*)$/) {
86*7c478bd9Sstevel@tonic-gate			my @cws = split (' ', $1);
87*7c478bd9Sstevel@tonic-gate			while (@cws) {
88*7c478bd9Sstevel@tonic-gate				my $thishost = shift(@cws);
89*7c478bd9Sstevel@tonic-gate				push(@hosts, $thishost)
90*7c478bd9Sstevel@tonic-gate				    unless $thishost =~ "$hostname|localhost";
91*7c478bd9Sstevel@tonic-gate			}
92*7c478bd9Sstevel@tonic-gate		}
93*7c478bd9Sstevel@tonic-gate	}
94*7c478bd9Sstevel@tonic-gate	close(CF);
95*7c478bd9Sstevel@tonic-gate
96*7c478bd9Sstevel@tonic-gate	for my $cwfile (@cwfiles) {
97*7c478bd9Sstevel@tonic-gate		if (open(CW, "<$cwfile")) {
98*7c478bd9Sstevel@tonic-gate			while (<CW>) {
99*7c478bd9Sstevel@tonic-gate			        next if /^\#/;
100*7c478bd9Sstevel@tonic-gate				my $thishost = $ARG;
101*7c478bd9Sstevel@tonic-gate				chop($thishost);
102*7c478bd9Sstevel@tonic-gate				push(@hosts, $thishost)
103*7c478bd9Sstevel@tonic-gate				    unless $thishost =~ $hostname;
104*7c478bd9Sstevel@tonic-gate			}
105*7c478bd9Sstevel@tonic-gate			close(CW);
106*7c478bd9Sstevel@tonic-gate		} else {
107*7c478bd9Sstevel@tonic-gate			die "open $cwfile: $ERRNO";
108*7c478bd9Sstevel@tonic-gate		}
109*7c478bd9Sstevel@tonic-gate	}
110*7c478bd9Sstevel@tonic-gate	# Do this automatically if no client hosts are specified.
111*7c478bd9Sstevel@tonic-gate	$boot_check = "yes";
112*7c478bd9Sstevel@tonic-gate}
113*7c478bd9Sstevel@tonic-gate
114*7c478bd9Sstevel@tonic-gatemy ($proto) = (getprotobyname('tcp'))[2];
115*7c478bd9Sstevel@tonic-gate($port) = (getservbyname($port, 'tcp'))[2]
116*7c478bd9Sstevel@tonic-gate	unless $port =~ /^\d+/;
117*7c478bd9Sstevel@tonic-gate
118*7c478bd9Sstevel@tonic-gateif ($boot_check) {
119*7c478bd9Sstevel@tonic-gate	# first connect to localhost to verify that we can accept connections
120*7c478bd9Sstevel@tonic-gate	print "verifying that localhost is accepting SMTP connections\n"
121*7c478bd9Sstevel@tonic-gate		if ($verbose);
122*7c478bd9Sstevel@tonic-gate	my $localhost_ok = 0;
123*7c478bd9Sstevel@tonic-gate	($name, my $laddr) = (gethostbyname('localhost'))[0, 4];
124*7c478bd9Sstevel@tonic-gate	(!defined($name)) && die "gethostbyname failed, unknown host $server";
125*7c478bd9Sstevel@tonic-gate
126*7c478bd9Sstevel@tonic-gate	# get a connection
127*7c478bd9Sstevel@tonic-gate	my $sinl = sockaddr_in($port, $laddr);
128*7c478bd9Sstevel@tonic-gate	my $save_errno = 0;
129*7c478bd9Sstevel@tonic-gate	for (my $num_tries = 1; $num_tries < 5; $num_tries++) {
130*7c478bd9Sstevel@tonic-gate		socket(S, &PF_INET, &SOCK_STREAM, $proto)
131*7c478bd9Sstevel@tonic-gate			|| die "socket: $ERRNO";
132*7c478bd9Sstevel@tonic-gate		if (connect(S, $sinl)) {
133*7c478bd9Sstevel@tonic-gate			&alarm("sending 'quit' to $server");
134*7c478bd9Sstevel@tonic-gate			print S "quit\n";
135*7c478bd9Sstevel@tonic-gate			alarm(0);
136*7c478bd9Sstevel@tonic-gate			$localhost_ok = 1;
137*7c478bd9Sstevel@tonic-gate			close(S);
138*7c478bd9Sstevel@tonic-gate			alarm(0);
139*7c478bd9Sstevel@tonic-gate			last;
140*7c478bd9Sstevel@tonic-gate		}
141*7c478bd9Sstevel@tonic-gate		print STDERR "localhost connect failed ($num_tries)\n";
142*7c478bd9Sstevel@tonic-gate		$save_errno = $ERRNO;
143*7c478bd9Sstevel@tonic-gate		sleep(1 << $num_tries);
144*7c478bd9Sstevel@tonic-gate		close(S);
145*7c478bd9Sstevel@tonic-gate		alarm(0);
146*7c478bd9Sstevel@tonic-gate	}
147*7c478bd9Sstevel@tonic-gate	if (! $localhost_ok) {
148*7c478bd9Sstevel@tonic-gate		die "could not connect to localhost: $save_errno\n";
149*7c478bd9Sstevel@tonic-gate	}
150*7c478bd9Sstevel@tonic-gate}
151*7c478bd9Sstevel@tonic-gate
152*7c478bd9Sstevel@tonic-gate# look it up
153*7c478bd9Sstevel@tonic-gate
154*7c478bd9Sstevel@tonic-gate($name, my $thataddr) = (gethostbyname($server))[0, 4];
155*7c478bd9Sstevel@tonic-gate(!defined($name)) && die "gethostbyname failed, unknown host $server";
156*7c478bd9Sstevel@tonic-gate
157*7c478bd9Sstevel@tonic-gate# get a connection
158*7c478bd9Sstevel@tonic-gatemy $sinr = sockaddr_in($port, $thataddr);
159*7c478bd9Sstevel@tonic-gatesocket(S, &PF_INET, &SOCK_STREAM, $proto)
160*7c478bd9Sstevel@tonic-gate	|| die "socket: $ERRNO";
161*7c478bd9Sstevel@tonic-gateprint "server = $server\n" if (defined($verbose));
162*7c478bd9Sstevel@tonic-gate&alarm("connect to $server");
163*7c478bd9Sstevel@tonic-gateif (! connect(S, $sinr)) {
164*7c478bd9Sstevel@tonic-gate	die "cannot connect to $server: $ERRNO\n";
165*7c478bd9Sstevel@tonic-gate}
166*7c478bd9Sstevel@tonic-gatealarm(0);
167*7c478bd9Sstevel@tonic-gateselect((select(S), $OUTPUT_AUTOFLUSH = 1)[0]);	# don't buffer output to S
168*7c478bd9Sstevel@tonic-gate
169*7c478bd9Sstevel@tonic-gate# read the greeting
170*7c478bd9Sstevel@tonic-gate&alarm("greeting with $server");
171*7c478bd9Sstevel@tonic-gatewhile (<S>) {
172*7c478bd9Sstevel@tonic-gate	alarm(0);
173*7c478bd9Sstevel@tonic-gate	print if $verbose;
174*7c478bd9Sstevel@tonic-gate	if (/^(\d+)([- ])/) {
175*7c478bd9Sstevel@tonic-gate		# SMTP's initial greeting response code is 220.
176*7c478bd9Sstevel@tonic-gate		if ($1 != 220) {
177*7c478bd9Sstevel@tonic-gate			&alarm("giving up after bad response from $server");
178*7c478bd9Sstevel@tonic-gate			&read_response($2, $verbose);
179*7c478bd9Sstevel@tonic-gate			alarm(0);
180*7c478bd9Sstevel@tonic-gate			print STDERR "$server: NOT 220 greeting: $ARG"
181*7c478bd9Sstevel@tonic-gate				if ($verbose);
182*7c478bd9Sstevel@tonic-gate		}
183*7c478bd9Sstevel@tonic-gate		last if ($2 eq " ");
184*7c478bd9Sstevel@tonic-gate	} else {
185*7c478bd9Sstevel@tonic-gate		print STDERR "$server: NOT 220 greeting: $ARG"
186*7c478bd9Sstevel@tonic-gate			if ($verbose);
187*7c478bd9Sstevel@tonic-gate		close(S);
188*7c478bd9Sstevel@tonic-gate	}
189*7c478bd9Sstevel@tonic-gate	&alarm("greeting with $server");
190*7c478bd9Sstevel@tonic-gate}
191*7c478bd9Sstevel@tonic-gatealarm(0);
192*7c478bd9Sstevel@tonic-gate
193*7c478bd9Sstevel@tonic-gate&alarm("sending ehlo to $server");
194*7c478bd9Sstevel@tonic-gate&ps("ehlo $hostname");
195*7c478bd9Sstevel@tonic-gatemy $etrn_support = 0;
196*7c478bd9Sstevel@tonic-gatewhile (<S>) {
197*7c478bd9Sstevel@tonic-gate	if (/^250([- ])ETRN(.+)$/) {
198*7c478bd9Sstevel@tonic-gate		$etrn_support = 1;
199*7c478bd9Sstevel@tonic-gate	}
200*7c478bd9Sstevel@tonic-gate	print if $verbose;
201*7c478bd9Sstevel@tonic-gate	last if /^\d+ /;
202*7c478bd9Sstevel@tonic-gate}
203*7c478bd9Sstevel@tonic-gatealarm(0);
204*7c478bd9Sstevel@tonic-gate
205*7c478bd9Sstevel@tonic-gateif ($etrn_support) {
206*7c478bd9Sstevel@tonic-gate	print "ETRN supported\n" if ($verbose);
207*7c478bd9Sstevel@tonic-gate	&alarm("sending etrn to $server");
208*7c478bd9Sstevel@tonic-gate	while (@hosts) {
209*7c478bd9Sstevel@tonic-gate		$server = shift(@hosts);
210*7c478bd9Sstevel@tonic-gate		&ps("etrn $server");
211*7c478bd9Sstevel@tonic-gate		while (<S>) {
212*7c478bd9Sstevel@tonic-gate			print if $verbose;
213*7c478bd9Sstevel@tonic-gate			last if /^\d+ /;
214*7c478bd9Sstevel@tonic-gate		}
215*7c478bd9Sstevel@tonic-gate		sleep(1);
216*7c478bd9Sstevel@tonic-gate	}
217*7c478bd9Sstevel@tonic-gate} else {
218*7c478bd9Sstevel@tonic-gate	print "\nETRN not supported\n\n"
219*7c478bd9Sstevel@tonic-gate}
220*7c478bd9Sstevel@tonic-gate
221*7c478bd9Sstevel@tonic-gate&alarm("sending 'quit' to $server");
222*7c478bd9Sstevel@tonic-gate&ps("quit");
223*7c478bd9Sstevel@tonic-gatewhile (<S>) {
224*7c478bd9Sstevel@tonic-gate	print if $verbose;
225*7c478bd9Sstevel@tonic-gate	last if /^\d+ /;
226*7c478bd9Sstevel@tonic-gate}
227*7c478bd9Sstevel@tonic-gateclose(S);
228*7c478bd9Sstevel@tonic-gatealarm(0);
229*7c478bd9Sstevel@tonic-gate
230*7c478bd9Sstevel@tonic-gateselect(STDOUT);
231*7c478bd9Sstevel@tonic-gateexit(0);
232*7c478bd9Sstevel@tonic-gate
233*7c478bd9Sstevel@tonic-gate# print to the server (also to stdout, if -v)
234*7c478bd9Sstevel@tonic-gatesub ps
235*7c478bd9Sstevel@tonic-gate{
236*7c478bd9Sstevel@tonic-gate	my ($p) = @_;
237*7c478bd9Sstevel@tonic-gate	print ">>> $p\n" if $verbose;
238*7c478bd9Sstevel@tonic-gate	print S "$p\n";
239*7c478bd9Sstevel@tonic-gate}
240*7c478bd9Sstevel@tonic-gate
241*7c478bd9Sstevel@tonic-gatesub alarm
242*7c478bd9Sstevel@tonic-gate{
243*7c478bd9Sstevel@tonic-gate	($alarm_action) = @_;
244*7c478bd9Sstevel@tonic-gate	alarm(10);
245*7c478bd9Sstevel@tonic-gate	$SIG{ALRM} = 'handle_alarm';
246*7c478bd9Sstevel@tonic-gate}
247*7c478bd9Sstevel@tonic-gate
248*7c478bd9Sstevel@tonic-gatesub handle_alarm
249*7c478bd9Sstevel@tonic-gate{
250*7c478bd9Sstevel@tonic-gate	&giveup($alarm_action);
251*7c478bd9Sstevel@tonic-gate}
252*7c478bd9Sstevel@tonic-gate
253*7c478bd9Sstevel@tonic-gatesub giveup
254*7c478bd9Sstevel@tonic-gate{
255*7c478bd9Sstevel@tonic-gate	my $reason = @_;
256*7c478bd9Sstevel@tonic-gate	(my $pk, my $file, my $line);
257*7c478bd9Sstevel@tonic-gate	($pk, $file, $line) = caller;
258*7c478bd9Sstevel@tonic-gate
259*7c478bd9Sstevel@tonic-gate	print "Timed out during $reason\n" if $verbose;
260*7c478bd9Sstevel@tonic-gate	exit(1);
261*7c478bd9Sstevel@tonic-gate}
262*7c478bd9Sstevel@tonic-gate
263*7c478bd9Sstevel@tonic-gate# read the rest of the current smtp daemon's response (and toss it away)
264*7c478bd9Sstevel@tonic-gatesub read_response
265*7c478bd9Sstevel@tonic-gate{
266*7c478bd9Sstevel@tonic-gate	(my $done, $verbose) = @_;
267*7c478bd9Sstevel@tonic-gate	(my @resp);
268*7c478bd9Sstevel@tonic-gate	print my $s if $verbose;
269*7c478bd9Sstevel@tonic-gate	while (($done eq "-") && ($s = <S>) && ($s =~ /^\d+([- ])/)) {
270*7c478bd9Sstevel@tonic-gate		print $s if $verbose;
271*7c478bd9Sstevel@tonic-gate		$done = $1;
272*7c478bd9Sstevel@tonic-gate		push(@resp, $s);
273*7c478bd9Sstevel@tonic-gate	}
274*7c478bd9Sstevel@tonic-gate	return @resp;
275*7c478bd9Sstevel@tonic-gate}
276