--- assp.pl.orig 2009-01-26 17:49:10.000000000 -0500 +++ assp.pl 2009-01-26 22:10:17.000000000 -0500 @@ -97,6 +97,13 @@ ['smtpDestination','SMTP Destination',40,\&textinput,'125','(\S*)',undef, 'The IP number! and port number of your primary SMTP. If multiple servers are listed and the first listed MTA does not respond, each additional MTA will be tried. If only a port number is entered, or the dynamic keyword INBOUND is used with a port number, then the connection will be established to the local IP address on which the connection was received. This is useful when you have several IP addresses with different domains or profiles in your MTA. If INBOUND:PORT is used, ReportingReplies (Analyze,Help,etc and CopyMail will go to 127.0.0.1:PORT. If your needs are different, use smtpReportServer (SMTP Reporting Destination) and sendAllDestination (Copy Spam SMTP Destination)Examples: 125, 127.0.0.1:125, 127.0.0.1:125|127.0.0.5:125, INBOUND:125','Basic'], +['listenPortSSL','SMTP Secure Listen Port',20,\&textinput,'465','(\S+)','ConfigChangeMailPort', + 'The port number on which ASSP will listen for incoming secure SMTP connections (normally 465). You can specify both an IP address and port number to limit connections to a specific interface.

Examples: 465, 127.0.0.1:465, 127.0.0.1:465|127.0.0.2:465


','Basic'], +['SSLCertFile','SSL Certificate File (PEM format)',48,\&textinput,'','(\S+)',undef, + "Path to the file containing the server's SSL certificate",'Basic'], +['SSLKeyFile','SSL Key File (PEM format)',48,\&textinput,'','(\S+)',undef, + "Path to the file containing the server's SSL key",'Basic'], + ['listenPort2','Second SMTP Listen Port',20,\&textinput,'','(\S*)','ConfigChangeMailPort2', 'A secondary port number on which ASSP can accept SMTP connections. This is useful as a dedicated port for VPN clients or for those who cannot directly send mail to a mail server outside of their ISP\'s network because the ISP is blocking port 25. You may also specify an IP address to limit connections to a specific interface.

Examples: 2525, 127.0.0.1:2525, 192.168.0.100:25000

'], ['smtpAuthServer','Second SMTP Destination',20,\&textinput,'','(\S*)',undef, @@ -1639,6 +1646,8 @@ our $CanUseSysMemInfo = $AvailSysMemInfo; our $AvailNetSMTP = eval('use Net::SMTP; 1'); # Net::SMTP module installed our $CanUseNetSMTP = $AvailNetSMTP; +our $AvailIOSocketSSL = eval('use IO::Socket::SSL; 1'); # IO::Socket::SSL module installed +our $CanUseIOSocketSSL = $AvailIOSocketSSL; #use URI::_foreign; @@ -1747,6 +1756,7 @@ our $VerEMM; our $VerNetSMTP; our $VerFileReadBackwards; +our $VerIOSocketSSL; our $VerLWP; our $VerMailSPF2; our $VerMailSPF; @@ -1770,6 +1780,7 @@ our $CommentEMM; our $CommentNetSMTP; our $CommentFileReadBackwards; +our $CommentIOSocketSSL; our $CommentLWP; our $CommentMailSPF2; our $CommentMailSPF; @@ -1831,6 +1842,7 @@ our $lookup_return; our $lsn2; our $lsn; +our $lsnSSL; our $maillogEnd; our $maillogJump; our $minusIcon; @@ -3095,6 +3107,14 @@ $CommentNetSMTP="Verify Recipients not available"; mlog(0,"Net::SMTP module not installed - Verify Recipients not available"); } + if ($CanUseIOSocketSSL) { + $ver=eval('IO::Socket::SSL->VERSION'); $VerIOSocketSSL=$ver; $ver=" version $ver" if $ver; + mlog(0,"IO::Socket::SSL module$ver installed - secure SSL sockets available"); + $CommentIOSocketSSL="Secure SSL sockets available"; + } elsif (!$AvailIOSocketSSL) { + $CommentIOSocketSSL="Secure SSL sockets not available"; + mlog(0,"IO::Socket::SSL module not installed - secure SSL sockets not available"); + } @@ -3111,6 +3131,11 @@ mlog( 0, "NOT listening for SMTP connections on $listenPort" ) if !$lsn; mlog( 0, "NOT listening for ADMIN http connections on $webAdminPort" ) if !$WebSocket; mlog( 0, "NOT listening for STATISTICS http connections on $webStatPort" ) if !$StatSocket; + if ($CanUseIOSocketSSL && $listenPortSSL) { + $lsnSSL = newListen( $listenPortSSL, \&NewSMTPConnection ); + mlog( 0, "listening for additional SMTP connections on $listenPortSSL" ) if $lsnSSL; + mlog( 0, "NOT listening for additional SMTP connections on $listenPortSSL" ) if !$lsnSSL; + } if ($listenPort2) { $lsn2 = newListen( $listenPort2, \&NewSMTPConnection ); mlog( 0, "listening for additional SMTP connections on $listenPort2" ) if $lsn2; @@ -4119,6 +4144,11 @@ d(106); return; } + if ($CanUseIOSocketSSL && $fh == $lsnSSL && $SSLKeyFile ne '' && $SSLCertFile ne '') { + # connection on the secure SSL port + d(107); + IO::Socket::SSL->start_SSL($client, SSL_key_file => $SSLKeyFile, SSL_cert_file => $SSLCertFile, SSL_use_cert => 1, SSL_server => 1); + } $Con{$client}->{relayok} = $relayok; my $ip = $client->peerhost(); my $port = $client->peerport(); @@ -4259,6 +4289,7 @@ d("limiting sessions: $fh"); $readable->remove($lsn) if $lsn; $readable->remove($lsn2) if $lsn2; + $readable->remove($lsnSSL) if $lsnSSL; $readable->remove($Relay) if $Relay; if ($SessionLog) { mlog( 0, "connected: $ip:$port" ) @@ -4847,6 +4878,7 @@ $smtpConcurrentSessions = 0 if $smtpConcurrentSessions < 0; $readable->add($lsn) if $lsn && ( !$readable->exists($lsn) ); $readable->add($lsn2) if $lsn2 && ( !$readable->exists($lsn2) ); + $readable->add($lsnSSL) if $lsnSSL && ( !$readable->exists($lsnSSL) ); $readable->add($Relay) if $Relay && ( !$readable->exists($Relay) ); $SMTPSession{Total}-- if $maxSMTPSessions; $SMTPSession{$ip}-- if $maxSMTPipSessions; @@ -5454,6 +5486,27 @@ $this->{rcvd} =~ s/=host/$helo2/; $this->{rcvd} =~ s/=\)/=$helo2\)/; $this->{rcvd} = &headerWrap( $this->{rcvd} ); # wrap long lines + } elsif ($CanUseIOSocketSSL && $l =~ /starttls/io) { + # write directly to $fh, bypassing buffering + $fh->write( "220 2.0.0 Ready to start TLS\r\n" ); + # the value of $fh changes when converted to SSL + my $oldfh = $fh; + my $oldConfh = $Con{$fh}; + # convert to SSL + IO::Socket::SSL->start_SSL($fh, SSL_key_file => $SSLKeyFile, SSL_cert_file => $SSLCertFile, SSL_use_cert => 1, SSL_server => 1); + # copy data from old $fh + $Con{$fh} = $oldConfh; + $Con{$fh}->{client} = $fh; + $SMTPSession{$fh} = $SMTPSession{$oldfh}; + # clean up old $fh + delete $SocketCalls{$oldfh}; + $readable->remove($oldfh); + $writable->remove($oldfh); + # set up new $fh + $SocketCalls{$fh} = \&SMTPTraffic; + $readable->add($fh); + d("SSL: $fh $Con{$fh}"); + return; } elsif ( $l =~ /mail from:\s*?/io ) { my $fr = $1; my $RO_e = $1; @@ -11007,15 +11060,22 @@ return unless $cli; $Con{$cli}->{inerror} = $l =~ /^5[05][0-9]/; - if ( $l =~ /250-.*(CHUNKING|PIPELINING|XEXCH50|STARTTLS)/i ) { + if ( $l =~ /250-.*(CHUNKING|PIPELINING|XEXCH50)/i ) { return; - } elsif ( $l =~ /250 .*(CHUNKING|PIPELINING|XEXCH50|STARTTLS)/i ) { + } elsif ( $l =~ /250-.*STARTTLS/i && ($cli =~ /IO::Socket::SSL/ || !$CanUseIOSocketSSL) ) { + # suppress STARTTLS if SSL already enabled or unavailable + return; + } elsif ( $l =~ /250 .*STARTTLS/i && ($cli =~ /IO::Socket::SSL/ || !$CanUseIOSocketSSL) ) { + # change STARTTLS to NOOP if SSL already enabled or unavailable + sendque( $cli, "250 NOOP\r\n" ); + return; + } elsif ( $l =~ /250 .*(CHUNKING|PIPELINING|XEXCH50)/i ) { sendque( $cli, "250 NOOP\r\n" ); return; - # we'll filter off the chunking directive to avoid BDAT problems. + # we'll filter off the CHUNKING directive to avoid BDAT problems. + # we'll filter off the PIPELINING directive to avoid ... problems. # we'll filter off the XEXCH50 service, as it only causes troubles - # we'll filter off the STARTTLS directive to avoid TLS problems. d("$l"); } elsif ( $l =~ /^220/ ) {