#!/usr/bin/perl # Webserver SSL form use strict; use warnings; no warnings 'redefine'; no warnings 'uninitialized'; require "./webmin-lib.pl"; # Globals our %text; our %miniserv; our %in; our $config_directory; our $module_name; our $strong_ssl_ciphers; our $pfs_ssl_ciphers; our $info; our $root_directory; our %config; our $letsencrypt_cmd; ui_print_header(undef, $text{'ssl_title'}, ""); ReadParse(); get_miniserv_config(\%miniserv); # Check if we even *have* SSL support $@ = undef; eval "use Net::SSLeay"; if ($@) { print text('ssl_essl', "https://webmin.com/ssl.html"),"
\n"; if (foreign_available("cpan")) { print text('ssl_cpan', "../cpan/download.cgi?source=3&cpan=Net::SSLeay&mode=2&return=/$module_name/&returndesc=".urlize($text{'index_return'})),"
\n"; } my $err = $@; $err =~ s/\s+at.*line\s+\d+[\000-\377]*$//; print text('ssl_emessage', "$err"),"
\n"; ui_print_footer("", $text{'index_return'}); exit; } # Show tabs my @tabs = map { [ $_, $text{'ssl_tab'.$_}, "edit_ssl.cgi?mode=$_" ] } ( "ssl", "current", "ips", "create", "csr", "upload", "lets" ); print ui_tabs_start(\@tabs, "mode", $in{'mode'} || $tabs[0]->[0], 1); # Basic SSL settings print ui_tabs_start_tab("mode", "ssl"); print $text{'ssl_desc1'},"
\n";
print ui_form_start("change_ssl.cgi", "post");
print ui_table_start($text{'ssl_header'}, undef, 2);
print ui_table_row($text{'ssl_on'},
ui_yesno_radio("ssl", $miniserv{'ssl'}));
print ui_table_row($text{'ssl_enforce'},
ui_radio("ssl_enforce", $miniserv{'ssl_enforce'} // 1,
[ [ 2, $text{'ssl_hsts'} ],
[ 1, $text{'yes'} ],
[ 0, $text{'no'} ] ]));
print ui_table_row($text{'ssl_key'},
ui_textbox("key", $miniserv{'keyfile'}, 40)." ".
file_chooser_button("key"));
print ui_table_row($text{'ssl_cert'},
ui_opt_textbox("cert", $miniserv{'certfile'}, 40,
$text{'ssl_cert_def'}."
",$text{'ssl_cert_oth'})." ".
file_chooser_button("cert"));
print ui_table_row($text{'ssl_version'},
ui_opt_textbox("version", $miniserv{'ssl_version'}, 4,
$text{'ssl_auto'}));
print ui_table_row($text{'ssl_deny'},
ui_checkbox("no_ssl2", 1, "SSLv2", $miniserv{'no_ssl2'})."\n".
ui_checkbox("no_ssl3", 1, "SSLv3", $miniserv{'no_ssl3'})."\n".
ui_checkbox("no_tls1", 1, "TLSv1.0", $miniserv{'no_tls1'})."\n".
ui_checkbox("no_tls1_1", 1, "TLSv1.1", $miniserv{'no_tls1_1'})."\n".
ui_checkbox("no_tls1_2", 1, "TLSv1.2", $miniserv{'no_tls1_2'})."\n"
);
print ui_table_row($text{'ssl_compression'},
ui_yesno_radio("ssl_compression", !$miniserv{'no_sslcompression'}));
print ui_table_row($text{'ssl_honorcipherorder'},
ui_yesno_radio("ssl_honorcipherorder",
$miniserv{'ssl_honorcipherorder'}));
my $clist = $miniserv{'ssl_cipher_list'};
my $clist_def = $miniserv{'cipher_list_def'};
my $cmode = !$clist ? 1 :
($clist_def && $clist eq $strong_ssl_ciphers) ? 2 :
($clist_def && $clist eq $pfs_ssl_ciphers) ? 3 :
0;
print ui_table_row($text{'ssl_cipher_list'},
ui_radio("cipher_list_def", $cmode,
[ [ 1, $text{'ssl_auto'}."
" ],
[ 2, $text{'ssl_strong'}."
" ],
[ 3, $text{'ssl_pfs'}."
" ],
[ 0, $text{'ssl_clist'}." ".
ui_textbox("cipher_list",
$cmode == 0 ? $clist : "", 50) ] ]));
my $extracas;
if (defined $miniserv{'extracas'}) { $extracas = $miniserv{'extracas'}; }
else { $extracas = ""; }
print ui_table_row($text{'ssl_extracas'},
ui_textarea("extracas", join("\n",split(/\s+/, $extracas)),
3, 60)." ".
"
".file_chooser_button("extracas", 0, undef, undef, 1)."
"); print ui_table_end(); print ui_form_end([ [ "", $text{'save'} ] ]); print ui_tabs_end_tab(); # Page showing current cert print ui_tabs_start_tab("mode", "current"); print "$text{'ssl_current'}
\n"; print ui_table_start($text{'ssl_cheader'}, undef, 4); $info = &cert_info($miniserv{'certfile'} || $miniserv{'keyfile'}); foreach my $i ('cn', 'alt', 'o', 'email', 'issuer_cn', 'issuer_o', 'issuer_email', 'notafter', 'type') { if ($info->{$i}) { print ui_table_row($text{'ca_'.$i}, ref($info->{$i}) ? join(", ", @{$info->{$i}}) : $info->{$i}); } } my @clinks = ( ui_link("download_cert.cgi/cert.pem", $text{'ssl_pem'}), ui_link("download_cert.cgi/cert.p12", $text{'ssl_pkcs12'}) ); print ui_table_row($text{'ssl_download'}, &ui_links_row(\@clinks)); print ui_table_end(); print ui_tabs_end_tab(); # Table listing per-IP / domain SSL certs print ui_tabs_start_tab("mode", "ips"); print "$text{'ssl_ipkeys'}
\n"; my @ipkeys = get_ipkeys(\%miniserv); if (@ipkeys) { print ui_columns_start([ $text{'ssl_ips'}, $text{'ssl_key'}, $text{'ssl_cert'} ]); foreach my $k (@ipkeys) { print ui_columns_row([ ui_link("edit_ipkey.cgi?idx=".$k->{'index'}, join(", ", @{$k->{'ips'}}) ), "$k->{'key'}", $k->{'cert'} ? "$k->{'cert'}" : $text{'ssl_cert_def'}, ]); } print ui_columns_end(); } else { print "$text{'ssl_ipkeynone'}
\n"; } print ui_link("edit_ipkey.cgi?new=1", $text{'ssl_addipkey'}); print "
\n"; print ui_tabs_end_tab(); # SSL key generation form print ui_tabs_start_tab("mode", "create"); print "$text{'ssl_newkey'}
\n"; my $curkey = read_file_contents($miniserv{'keyfile'}); my $origkey = read_file_contents("$root_directory/miniserv.pem"); if ($curkey eq $origkey) { # System is using the original (insecure) Webmin key! print "$text{'ssl_hole'}
\n"; } print ui_form_start("newkey.cgi"); print ui_table_start($text{'ssl_header1'}, undef, 2); my $host = $ENV{'HTTP_HOST'}; $host =~ s/:.*//; print show_ssl_key_form($host, undef, "Webmin Webserver on ".get_system_hostname()); print ui_table_row($text{'ssl_newfile'}, ui_textbox("newfile", "$config_directory/miniserv.pem", 40)); print ui_table_row($text{'ssl_usenew'}, ui_yesno_radio("usenew", 1)); print ui_table_end(); print ui_form_end([ [ "", $text{'ssl_create'} ] ]); print ui_tabs_end_tab(); # SSL CSR generation form my $keydata = read_file_contents("$config_directory/miniserv.newkey"); my $csrdata = read_file_contents("$config_directory/miniserv.csr"); print ui_tabs_start_tab("mode", "csr"); print "$text{'ssl_newcsr'}
\n"; print ui_form_start("newcsr.cgi"); print ui_table_start($text{'ssl_header2'}, undef, 2); print show_ssl_key_form($host, undef, "Webmin Webserver on ".get_system_hostname()); print ui_table_row($text{'ssl_newfile'}, ui_textbox("newfile", "$config_directory/miniserv.newkey", 40)); print ui_table_row($text{'ssl_csrfile'}, ui_textbox("csrfile", "$config_directory/miniserv.csr", 40)); print ui_table_end(); print ui_form_end([ [ "", $text{'ssl_create'} ] ]); if ($keydata) { # Show most recent CSR and key print "
\n"; print ui_hidden_start($text{'ssl_csralready'}, "already", 0); print $text{'ssl_already1'},"
\n"; print "
".html_escape($keydata)."\n"; print $text{'ssl_already2'},"
\n"; print "
".html_escape($csrdata)."\n"; print ui_hidden_end("already"); } print ui_tabs_end_tab(); # SSL key upload form print ui_tabs_start_tab("mode", "upload"); print "$text{'ssl_savekey'}
\n";
print ui_form_start("savekey.cgi", "form-data");
print ui_table_start($text{'ssl_saveheader'}, undef, 2);
print ui_table_row($text{'ssl_privkey'},
ui_textarea("key", $keydata, 7, 70)."
\n".
"$text{'ssl_upload'}\n".
ui_upload("keyfile").
($keydata ? "
".$text{'ssl_fromcsr'} : ""));
print ui_table_row($text{'ssl_privcert'},
ui_radio("cert_def", 1,
[ [ 1, $text{'ssl_same'} ],
[ 0, $text{'ssl_below'} ] ])."
\n".
ui_textarea("cert", undef, 7, 70)."
\n".
"$text{'ssl_upload'}\n".
ui_upload("certfile", undef, undef,
"onChange='form.cert_def.value = 0'"));
print ui_table_row($text{'ssl_privchain'},
ui_radio("chain_def", 1,
[ [ 1, $miniserv{'extracas'} ? $text{'ssl_leavechain'}
: $text{'ssl_nochain'} ],
[ 0, $text{'ssl_below'} ] ])."
\n".
ui_textarea("chain", undef, 7, 70)."
\n".
"$text{'ssl_upload'}\n".
ui_upload("chainfile", undef, undef,
"onChange='form.chain_def.value = 0'"));
print ui_table_end();
print ui_form_end([ [ "save", $text{'save'} ] ]);
print ui_tabs_end_tab();
# Let's Encrypt form
print ui_tabs_start_tab("mode", "lets");
my $err = &check_letsencrypt();
print $text{'ssl_letsdesc'};
if (!$err) {
print &ui_tag('span',
&ui_details({
'class' => 'inline inlined',
'title' => '',
'content' => $text{'ssl_letsdesc2'},
}))."\n".
&ui_tag('style',
".ui--span>details.inline>summary+span {\n".
"margin-top: 0;\n".
"}\n");
}
print "
\n"; if ($err) { print "",&text('ssl_letserr', $err),"
\n"; print &get_letsencrypt_install_message( "/$module_name/edit_ssl.cgi?mode=lets", $text{'ssl_title'}); print "
\n"; print &text('ssl_letserr2', "../config.cgi?$module_name"),"
\n";
}
else {
# Show form to create a cert
print &ui_form_start("letsencrypt.cgi");
print &ui_table_start($text{'ssl_letsheader'}, undef, 2);
# For domain names
my @doms = $config{'letsencrypt_doms'} ?
split(/\s+/, $config{'letsencrypt_doms'}) : ( $host );
print &ui_table_row($text{'ssl_letsdoms'},
&ui_textarea("dom", join("\n", @doms), 5, 40)."
\n".
&ui_checkbox("subset", 1, $text{'ssl_subset'},
$config{'letsencrypt_subset'}));
# Apache vhost or other path
my @opts;
my $certbot_by_webmin = $letsencrypt_cmd
? &is_webmin_listening_on_port(80)
: 0;
my $certbot_warning = $letsencrypt_cmd
? &get_letsencrypt_certbot_port_error()
: undef;
my $webroot = $config{'letsencrypt_webroot'};
my $hasapache = &foreign_installed("apache");
my $saved_mode = $config{'letsencrypt_mode'} || "web";
my $mode = $saved_mode eq 'dns' ? 3 :
$saved_mode eq 'certbot' ? 4 :
$webroot ? 2 :
$hasapache ? 0 :
$letsencrypt_cmd ? 4 : 2;
if ($hasapache) {
&foreign_require("apache");
my $conf = &apache::get_config();
my @snames;
foreach my $virt (&apache::find_directive_struct(
"VirtualHost", $conf)) {
my $sn = &apache::find_directive(
"ServerName", $virt->{'members'});
push(@snames, [ $sn,
$sn || "<".$text{'default'}.">" ]);
}
my %done;
@snames = grep { !$done{$_->[0]}++ } @snames;
if (@snames) {
@snames = sort { $a->[0] cmp $b->[0] } @snames;
push(@opts, [ 0, $text{'ssl_letsmode0'} ]);
push(@opts, [ 1, $text{'ssl_letsmode1'},
&ui_select("vhost", undef, \@snames) ]);
}
else {
$webroot ||= &apache::find_directive("DocumentRoot", $conf);
}
}
push(@opts, [ 2, $text{'ssl_letsmode2'},
&ui_textbox("webroot", $webroot, 40) ]);
if ($letsencrypt_cmd && &foreign_installed("bind8")) {
push(@opts, [ 3, $text{'ssl_letsmode3'} ]);
}
if ($letsencrypt_cmd) {
push(@opts, [ 4, $text{'ssl_letsmode4'} ]);
}
my $mode_html = &ui_radio_table("webroot_mode", $mode, \@opts);
if ($certbot_warning) {
# Keep the warning aligned with the validation options (hacky as
# we have no API for this yet)
$certbot_warning .= " ".$text{'ssl_certbotprehook'}
if (!$certbot_by_webmin && $config{'letsencrypt_before'});
my $warning_note = &ui_note($certbot_warning, 0);
my $warning_html =
"