xref: /illumos-gate/usr/src/cmd/sendmail/util/etrn.pl (revision 955eb5e1)
17c478bd9Sstevel@tonic-gate#!/usr/perl5/bin/perl -w
27c478bd9Sstevel@tonic-gate#
37c478bd9Sstevel@tonic-gate# CDDL HEADER START
47c478bd9Sstevel@tonic-gate#
57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
6df0345f7SJohn Sonnenschein# Common Development and Distribution License (the "License").
7df0345f7SJohn Sonnenschein# You may not use this file except in compliance with the License.
87c478bd9Sstevel@tonic-gate#
97c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate# and limitations under the License.
137c478bd9Sstevel@tonic-gate#
147c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate#
207c478bd9Sstevel@tonic-gate# CDDL HEADER END
217c478bd9Sstevel@tonic-gate#
227c478bd9Sstevel@tonic-gate#
237c478bd9Sstevel@tonic-gate# Copyright (c) 1996-2000 by John T. Beck <john@beck.org>
247c478bd9Sstevel@tonic-gate# All rights reserved.
257c478bd9Sstevel@tonic-gate#
26df0345f7SJohn Sonnenschein# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
277c478bd9Sstevel@tonic-gate# Use is subject to license terms.
287c478bd9Sstevel@tonic-gate#
297c478bd9Sstevel@tonic-gate
30df0345f7SJohn Sonnenscheinrequire 5.8.4;				# minimal Perl version required
317c478bd9Sstevel@tonic-gateuse strict;
327c478bd9Sstevel@tonic-gateuse warnings;
337c478bd9Sstevel@tonic-gateuse English;
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gateuse Socket;
367c478bd9Sstevel@tonic-gateuse Getopt::Std;
377c478bd9Sstevel@tonic-gateour ($opt_v, $opt_b);
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate# system requirements:
407c478bd9Sstevel@tonic-gate# 	must have 'hostname' program.
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gatemy $port = 'smtp';
437c478bd9Sstevel@tonic-gateselect(STDERR);
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gatechop(my $name = `hostname || uname -n`);
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gatemy ($hostname) = (gethostbyname($name))[0];
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gatemy $usage = "Usage: $PROGRAM_NAME [-bv] host [args]";
507c478bd9Sstevel@tonic-gategetopts('bv');
517c478bd9Sstevel@tonic-gatemy $verbose = $opt_v;
527c478bd9Sstevel@tonic-gatemy $boot_check = $opt_b;
537c478bd9Sstevel@tonic-gatemy $server = shift(@ARGV);
547c478bd9Sstevel@tonic-gatemy @hosts = @ARGV;
557c478bd9Sstevel@tonic-gatedie $usage unless $server;
567c478bd9Sstevel@tonic-gatemy @cwfiles = ();
577c478bd9Sstevel@tonic-gatemy $alarm_action = "";
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gateif (!@hosts) {
607c478bd9Sstevel@tonic-gate	push(@hosts, $hostname);
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate	open(CF, "</etc/mail/sendmail.cf") ||
637c478bd9Sstevel@tonic-gate	    die "open /etc/mail/sendmail.cf: $ERRNO";
647c478bd9Sstevel@tonic-gate	while (<CF>){
657c478bd9Sstevel@tonic-gate		# look for a line starting with "Fw"
667c478bd9Sstevel@tonic-gate		if (/^Fw.*$/) {
677c478bd9Sstevel@tonic-gate			my $cwfile = $ARG;
687c478bd9Sstevel@tonic-gate			chop($cwfile);
697c478bd9Sstevel@tonic-gate			my $optional = /^Fw-o/;
707c478bd9Sstevel@tonic-gate			# extract the file name
717c478bd9Sstevel@tonic-gate			$cwfile =~ s,^Fw[^/]*,,;
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate			# strip the options after the filename
747c478bd9Sstevel@tonic-gate			$cwfile =~ s/ [^ ]+$//;
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate			if (-r $cwfile) {
777c478bd9Sstevel@tonic-gate				push (@cwfiles, $cwfile);
787c478bd9Sstevel@tonic-gate			} else {
797c478bd9Sstevel@tonic-gate				die "$cwfile is not readable" unless $optional;
807c478bd9Sstevel@tonic-gate			}
817c478bd9Sstevel@tonic-gate		}
827c478bd9Sstevel@tonic-gate		# look for a line starting with "Cw"
837c478bd9Sstevel@tonic-gate		if (/^Cw(.*)$/) {
847c478bd9Sstevel@tonic-gate			my @cws = split (' ', $1);
857c478bd9Sstevel@tonic-gate			while (@cws) {
867c478bd9Sstevel@tonic-gate				my $thishost = shift(@cws);
877c478bd9Sstevel@tonic-gate				push(@hosts, $thishost)
887c478bd9Sstevel@tonic-gate				    unless $thishost =~ "$hostname|localhost";
897c478bd9Sstevel@tonic-gate			}
907c478bd9Sstevel@tonic-gate		}
917c478bd9Sstevel@tonic-gate	}
927c478bd9Sstevel@tonic-gate	close(CF);
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate	for my $cwfile (@cwfiles) {
957c478bd9Sstevel@tonic-gate		if (open(CW, "<$cwfile")) {
967c478bd9Sstevel@tonic-gate			while (<CW>) {
977c478bd9Sstevel@tonic-gate			        next if /^\#/;
987c478bd9Sstevel@tonic-gate				my $thishost = $ARG;
997c478bd9Sstevel@tonic-gate				chop($thishost);
1007c478bd9Sstevel@tonic-gate				push(@hosts, $thishost)
1017c478bd9Sstevel@tonic-gate				    unless $thishost =~ $hostname;
1027c478bd9Sstevel@tonic-gate			}
1037c478bd9Sstevel@tonic-gate			close(CW);
1047c478bd9Sstevel@tonic-gate		} else {
1057c478bd9Sstevel@tonic-gate			die "open $cwfile: $ERRNO";
1067c478bd9Sstevel@tonic-gate		}
1077c478bd9Sstevel@tonic-gate	}
1087c478bd9Sstevel@tonic-gate	# Do this automatically if no client hosts are specified.
1097c478bd9Sstevel@tonic-gate	$boot_check = "yes";
1107c478bd9Sstevel@tonic-gate}
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gatemy ($proto) = (getprotobyname('tcp'))[2];
1137c478bd9Sstevel@tonic-gate($port) = (getservbyname($port, 'tcp'))[2]
1147c478bd9Sstevel@tonic-gate	unless $port =~ /^\d+/;
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gateif ($boot_check) {
1177c478bd9Sstevel@tonic-gate	# first connect to localhost to verify that we can accept connections
1187c478bd9Sstevel@tonic-gate	print "verifying that localhost is accepting SMTP connections\n"
1197c478bd9Sstevel@tonic-gate		if ($verbose);
1207c478bd9Sstevel@tonic-gate	my $localhost_ok = 0;
1217c478bd9Sstevel@tonic-gate	($name, my $laddr) = (gethostbyname('localhost'))[0, 4];
1227c478bd9Sstevel@tonic-gate	(!defined($name)) && die "gethostbyname failed, unknown host $server";
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate	# get a connection
1257c478bd9Sstevel@tonic-gate	my $sinl = sockaddr_in($port, $laddr);
1267c478bd9Sstevel@tonic-gate	my $save_errno = 0;
1277c478bd9Sstevel@tonic-gate	for (my $num_tries = 1; $num_tries < 5; $num_tries++) {
1287c478bd9Sstevel@tonic-gate		socket(S, &PF_INET, &SOCK_STREAM, $proto)
1297c478bd9Sstevel@tonic-gate			|| die "socket: $ERRNO";
1307c478bd9Sstevel@tonic-gate		if (connect(S, $sinl)) {
1317c478bd9Sstevel@tonic-gate			&alarm("sending 'quit' to $server");
1327c478bd9Sstevel@tonic-gate			print S "quit\n";
1337c478bd9Sstevel@tonic-gate			alarm(0);
1347c478bd9Sstevel@tonic-gate			$localhost_ok = 1;
1357c478bd9Sstevel@tonic-gate			close(S);
1367c478bd9Sstevel@tonic-gate			alarm(0);
1377c478bd9Sstevel@tonic-gate			last;
1387c478bd9Sstevel@tonic-gate		}
1397c478bd9Sstevel@tonic-gate		print STDERR "localhost connect failed ($num_tries)\n";
1407c478bd9Sstevel@tonic-gate		$save_errno = $ERRNO;
1417c478bd9Sstevel@tonic-gate		sleep(1 << $num_tries);
1427c478bd9Sstevel@tonic-gate		close(S);
1437c478bd9Sstevel@tonic-gate		alarm(0);
1447c478bd9Sstevel@tonic-gate	}
1457c478bd9Sstevel@tonic-gate	if (! $localhost_ok) {
1467c478bd9Sstevel@tonic-gate		die "could not connect to localhost: $save_errno\n";
1477c478bd9Sstevel@tonic-gate	}
1487c478bd9Sstevel@tonic-gate}
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate# look it up
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate($name, my $thataddr) = (gethostbyname($server))[0, 4];
1537c478bd9Sstevel@tonic-gate(!defined($name)) && die "gethostbyname failed, unknown host $server";
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate# get a connection
1567c478bd9Sstevel@tonic-gatemy $sinr = sockaddr_in($port, $thataddr);
1577c478bd9Sstevel@tonic-gatesocket(S, &PF_INET, &SOCK_STREAM, $proto)
1587c478bd9Sstevel@tonic-gate	|| die "socket: $ERRNO";
1597c478bd9Sstevel@tonic-gateprint "server = $server\n" if (defined($verbose));
1607c478bd9Sstevel@tonic-gate&alarm("connect to $server");
1617c478bd9Sstevel@tonic-gateif (! connect(S, $sinr)) {
1627c478bd9Sstevel@tonic-gate	die "cannot connect to $server: $ERRNO\n";
1637c478bd9Sstevel@tonic-gate}
1647c478bd9Sstevel@tonic-gatealarm(0);
1657c478bd9Sstevel@tonic-gateselect((select(S), $OUTPUT_AUTOFLUSH = 1)[0]);	# don't buffer output to S
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate# read the greeting
1687c478bd9Sstevel@tonic-gate&alarm("greeting with $server");
1697c478bd9Sstevel@tonic-gatewhile (<S>) {
1707c478bd9Sstevel@tonic-gate	alarm(0);
1717c478bd9Sstevel@tonic-gate	print if $verbose;
1727c478bd9Sstevel@tonic-gate	if (/^(\d+)([- ])/) {
1737c478bd9Sstevel@tonic-gate		# SMTP's initial greeting response code is 220.
1747c478bd9Sstevel@tonic-gate		if ($1 != 220) {
1757c478bd9Sstevel@tonic-gate			&alarm("giving up after bad response from $server");
1767c478bd9Sstevel@tonic-gate			&read_response($2, $verbose);
1777c478bd9Sstevel@tonic-gate			alarm(0);
1787c478bd9Sstevel@tonic-gate			print STDERR "$server: NOT 220 greeting: $ARG"
1797c478bd9Sstevel@tonic-gate				if ($verbose);
1807c478bd9Sstevel@tonic-gate		}
1817c478bd9Sstevel@tonic-gate		last if ($2 eq " ");
1827c478bd9Sstevel@tonic-gate	} else {
1837c478bd9Sstevel@tonic-gate		print STDERR "$server: NOT 220 greeting: $ARG"
1847c478bd9Sstevel@tonic-gate			if ($verbose);
1857c478bd9Sstevel@tonic-gate		close(S);
1867c478bd9Sstevel@tonic-gate	}
1877c478bd9Sstevel@tonic-gate	&alarm("greeting with $server");
1887c478bd9Sstevel@tonic-gate}
1897c478bd9Sstevel@tonic-gatealarm(0);
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate&alarm("sending ehlo to $server");
1927c478bd9Sstevel@tonic-gate&ps("ehlo $hostname");
1937c478bd9Sstevel@tonic-gatemy $etrn_support = 0;
1947c478bd9Sstevel@tonic-gatewhile (<S>) {
1957c478bd9Sstevel@tonic-gate	if (/^250([- ])ETRN(.+)$/) {
1967c478bd9Sstevel@tonic-gate		$etrn_support = 1;
1977c478bd9Sstevel@tonic-gate	}
1987c478bd9Sstevel@tonic-gate	print if $verbose;
1997c478bd9Sstevel@tonic-gate	last if /^\d+ /;
2007c478bd9Sstevel@tonic-gate}
2017c478bd9Sstevel@tonic-gatealarm(0);
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gateif ($etrn_support) {
2047c478bd9Sstevel@tonic-gate	print "ETRN supported\n" if ($verbose);
2057c478bd9Sstevel@tonic-gate	&alarm("sending etrn to $server");
2067c478bd9Sstevel@tonic-gate	while (@hosts) {
2077c478bd9Sstevel@tonic-gate		$server = shift(@hosts);
2087c478bd9Sstevel@tonic-gate		&ps("etrn $server");
2097c478bd9Sstevel@tonic-gate		while (<S>) {
2107c478bd9Sstevel@tonic-gate			print if $verbose;
2117c478bd9Sstevel@tonic-gate			last if /^\d+ /;
2127c478bd9Sstevel@tonic-gate		}
2137c478bd9Sstevel@tonic-gate		sleep(1);
2147c478bd9Sstevel@tonic-gate	}
2157c478bd9Sstevel@tonic-gate} else {
2167c478bd9Sstevel@tonic-gate	print "\nETRN not supported\n\n"
2177c478bd9Sstevel@tonic-gate}
2187c478bd9Sstevel@tonic-gate
2197c478bd9Sstevel@tonic-gate&alarm("sending 'quit' to $server");
2207c478bd9Sstevel@tonic-gate&ps("quit");
2217c478bd9Sstevel@tonic-gatewhile (<S>) {
2227c478bd9Sstevel@tonic-gate	print if $verbose;
2237c478bd9Sstevel@tonic-gate	last if /^\d+ /;
2247c478bd9Sstevel@tonic-gate}
2257c478bd9Sstevel@tonic-gateclose(S);
2267c478bd9Sstevel@tonic-gatealarm(0);
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gateselect(STDOUT);
2297c478bd9Sstevel@tonic-gateexit(0);
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate# print to the server (also to stdout, if -v)
2327c478bd9Sstevel@tonic-gatesub ps
2337c478bd9Sstevel@tonic-gate{
2347c478bd9Sstevel@tonic-gate	my ($p) = @_;
2357c478bd9Sstevel@tonic-gate	print ">>> $p\n" if $verbose;
2367c478bd9Sstevel@tonic-gate	print S "$p\n";
2377c478bd9Sstevel@tonic-gate}
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gatesub alarm
2407c478bd9Sstevel@tonic-gate{
2417c478bd9Sstevel@tonic-gate	($alarm_action) = @_;
2427c478bd9Sstevel@tonic-gate	alarm(10);
2437c478bd9Sstevel@tonic-gate	$SIG{ALRM} = 'handle_alarm';
2447c478bd9Sstevel@tonic-gate}
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gatesub handle_alarm
2477c478bd9Sstevel@tonic-gate{
2487c478bd9Sstevel@tonic-gate	&giveup($alarm_action);
2497c478bd9Sstevel@tonic-gate}
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gatesub giveup
2527c478bd9Sstevel@tonic-gate{
2537c478bd9Sstevel@tonic-gate	my $reason = @_;
2547c478bd9Sstevel@tonic-gate	(my $pk, my $file, my $line);
2557c478bd9Sstevel@tonic-gate	($pk, $file, $line) = caller;
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate	print "Timed out during $reason\n" if $verbose;
2587c478bd9Sstevel@tonic-gate	exit(1);
2597c478bd9Sstevel@tonic-gate}
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate# read the rest of the current smtp daemon's response (and toss it away)
2627c478bd9Sstevel@tonic-gatesub read_response
2637c478bd9Sstevel@tonic-gate{
2647c478bd9Sstevel@tonic-gate	(my $done, $verbose) = @_;
2657c478bd9Sstevel@tonic-gate	(my @resp);
2667c478bd9Sstevel@tonic-gate	print my $s if $verbose;
2677c478bd9Sstevel@tonic-gate	while (($done eq "-") && ($s = <S>) && ($s =~ /^\d+([- ])/)) {
2687c478bd9Sstevel@tonic-gate		print $s if $verbose;
2697c478bd9Sstevel@tonic-gate		$done = $1;
2707c478bd9Sstevel@tonic-gate		push(@resp, $s);
2717c478bd9Sstevel@tonic-gate	}
2727c478bd9Sstevel@tonic-gate	return @resp;
2737c478bd9Sstevel@tonic-gate}
274