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