Add support for STARTTLS mode

This commit is contained in:
Jamie Cameron
2020-09-13 16:51:44 -07:00
parent 6079a685a1
commit 600b0d7490
3 changed files with 58 additions and 27 deletions

View File

@@ -871,7 +871,7 @@ local $lnum = 0;
$sm ||= $config{'send_mode'};
local $eol = $nocr || !$sm ? "\n" : "\r\n";
$ssl = $config{'smtp_ssl'} if ($ssl eq '');
local $defport = $ssl ? 465 : 25;
local $defport = $ssl == 1 ? 465 : 25;
$port ||= $config{'smtp_port'} || $defport;
my %header;
foreach my $head (@{$mail->{'headers'}}) {
@@ -920,19 +920,9 @@ if ($file) {
elsif ($sm) {
# Connect to SMTP server
&open_socket($sm, $port, $h->{'fh'});
if ($ssl) {
# Switch to SSL mode
eval "use Net::SSLeay";
$@ && &error($text{'link_essl'});
eval "Net::SSLeay::SSLeay_add_ssl_algorithms()";
eval "Net::SSLeay::load_error_strings()";
$h->{'ssl_ctx'} = Net::SSLeay::CTX_new() ||
&error("Failed to create SSL context");
$h->{'ssl_con'} = Net::SSLeay::new($h->{'ssl_ctx'}) ||
&error("Failed to create SSL connection");
Net::SSLeay::set_fd($h->{'ssl_con'}, fileno($h->{'fh'}));
Net::SSLeay::connect($h->{'ssl_con'}) ||
&error("SSL connect() failed");
if ($ssl == 1) {
# Start using SSL mode right away
&switch_smtp_to_ssl($h);
}
&smtp_command($h, undef, 0);
@@ -944,6 +934,17 @@ elsif ($sm) {
&smtp_command($h, "helo $helo\r\n", 0);
}
if ($ssl == 2) {
# Switch to SSL with STARTTLS, if possible
my $rv = &smtp_command($h, "starttls\r\n", 1);
if ($rv =~ /^2\d+/) {
&switch_smtp_to_ssl($h);
}
else {
$ssl = 0;
}
}
# Get username and password from parameters, or from module config
$user ||= $userconfig{'smtp_user'} || $config{'smtp_user'};
$pass ||= $userconfig{'smtp_pass'} || $config{'smtp_pass'};
@@ -963,16 +964,16 @@ elsif ($sm) {
&error("Failed to create Authen::SASL object") if (!$sasl);
local $conn = $sasl->client_new("smtp", &get_system_hostname());
local $arv = &smtp_command($h, "auth $auth\r\n", 1);
if ($arv =~ /^(334)\s+(.*)/) {
if ($arv =~ /^(334)(\-\S+)?\s+(.*)/) {
# Server says to go ahead
$extra = $2;
$extra = $3;
local $initial = $conn->client_start();
local $auth_ok;
if ($initial) {
local $enc = &encode_base64($initial);
$enc =~ s/\r|\n//g;
$arv = &smtp_command($h, "$enc\r\n", 1);
if ($arv =~ /^(\d+)\s+(.*)/) {
if ($arv =~ /^(\d+)(\-\S+)?\s+(.*)/) {
if ($1 == 235) {
$auth_ok = 1;
}
@@ -980,7 +981,7 @@ elsif ($sm) {
&error("Unknown SMTP authentication response : $arv");
}
}
$extra = $2;
$extra = $3;
}
while(!$auth_ok) {
local $message = &decode_base64($extra);
@@ -988,14 +989,14 @@ elsif ($sm) {
local $enc = &encode_base64($return);
$enc =~ s/\r|\n//g;
$arv = &smtp_command($h, "$enc\r\n", 1);
if ($arv =~ /^(\d+)\s+(.*)/) {
if ($arv =~ /^(\d+)(\-\S+)?\s+(.*)/) {
if ($1 == 235) {
$auth_ok = 1;
}
elsif ($1 == 535) {
&error("SMTP authentication failed : $arv");
}
$extra = $2;
$extra = $3;
}
else {
&error("Unknown SMTP authentication response : $arv");
@@ -1175,6 +1176,24 @@ if (!&close_http_connection($h)) {
return $lnum;
}
# switch_smtp_to_ssl(&handle)
# Switch an SMTP connection handle to SSL mode
sub switch_smtp_to_ssl
{
my ($h) = @_;
eval "use Net::SSLeay";
$@ && &error($text{'link_essl'});
eval "Net::SSLeay::SSLeay_add_ssl_algorithms()";
eval "Net::SSLeay::load_error_strings()";
$h->{'ssl_ctx'} = Net::SSLeay::CTX_new() ||
&error("Failed to create SSL context");
$h->{'ssl_con'} = Net::SSLeay::new($h->{'ssl_ctx'}) ||
&error("Failed to create SSL connection");
Net::SSLeay::set_fd($h->{'ssl_con'}, fileno($h->{'fh'}));
Net::SSLeay::connect($h->{'ssl_con'}) ||
&error("SSL connect() failed");
}
# unparse_mail(&attachments, eol, boundary)
# Convert an array of attachments into MIME format, and return them as an
# array of lines.
@@ -1363,6 +1382,7 @@ if ($c) {
}
my $r = &read_http_connection($h);
if ($r !~ /^[23]\d+/ && !$noerr) {
$c =~ s/\r|\n//g;
&error(&text('send_esmtp', "<tt>".&html_escape($c)."</tt>",
"<tt>".&html_escape($r)."</tt>"));
}

View File

@@ -25,13 +25,20 @@ print &ui_table_row($text{'sendmail_smtp'},
&ui_radio("mode", $mode, [ [ 0, $text{'sendmail_smtp0'}."<br>" ],
[ 1, $text{'sendmail_smtp1'}."<br>" ],
[ 2, $text{'sendmail_smtp2'} ] ]).
" ".&ui_textbox("smtp", $mode == 2 ? $smtp : "", 40).
"<br>\n"."&nbsp;&nbsp;".
&ui_checkbox("ssl", 1, $text{'sendmail_ssl'}, $mconfig{'smtp_ssl'}).
"<br>\n"."&nbsp;&nbsp;".
" ".&ui_textbox("smtp", $mode == 2 ? $smtp : "", 40));
# SMTP port
print &ui_table_row($text{'sendmail_port'},
&ui_opt_textbox("port", $port, 6, $text{'sendmail_portdef'},
$text{'sendmail_portsel'}),
undef, [ "valign=top","valign=middle" ]);
$text{'sendmail_portsel'}));
# SMTP encryption
print &ui_table_row($text{'sendmail_ssl'},
&ui_select("ssl", int($mconfig{'smtp_ssl'}),
[ [ 0, $text{'sendmail_ssl0'} ],
[ 1, $text{'sendmail_ssl1'} ],
[ 2, $text{'sendmail_ssl2'} ] ]));
# SMTP login and password
$user = $mconfig{'smtp_user'};

View File

@@ -1011,9 +1011,13 @@ sendmail_desc=This page controls how Webmin sends email, such as from scheduled
sendmail_header=Mail sending options
sendmail_system=Local mail server
sendmail_smtp=Send email using
sendmail_port=SMTP port
sendmail_portdef=Use default port
sendmail_portsel=Use port number
sendmail_ssl=Use SSL encryption?
sendmail_ssl=Use SMTP SSL encryption?
sendmail_ssl0=Never encrypt
sendmail_ssl1=Always use TLS
sendmail_ssl2=Switch with STARTTLS
sendmail_smtp0=Local mail server command
sendmail_smtp1=Via SMTP to local mail server
sendmail_smtp2=Via SMTP to remote mail server