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 6*df0345f7SJohn Sonnenschein# Common Development and Distribution License (the "License"). 7*df0345f7SJohn 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# 26*df0345f7SJohn Sonnenschein# Copyright 2008 Sun Microsystems, Inc. All rights reserved. 277c478bd9Sstevel@tonic-gate# Use is subject to license terms. 287c478bd9Sstevel@tonic-gate# 297c478bd9Sstevel@tonic-gate 30*df0345f7SJohn 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