
$feature_depends{'ssl'} = [ 'web', 'virt', 'dir' ];
$default_web_sslport = $config{'web_sslport'} || 443;

# setup_ssl(&domain)
# Creates a website with SSL enabled, and a private key and cert it to use.
sub setup_ssl
{
local $tmpl = &get_template($_[0]->{'template'});
local $web_sslport = $tmpl->{'web_sslport'} || 443;
&require_apache();
local $conf = &apache::get_config();
if ($apache::config{'virt_file'}) {
	$f = -d $apache::config{'virt_file'} ?
		"$apache::config{'virt_file'}/www.$_[0]->{'dom'}.conf" :
		$apache::config{'virt_file'};
	}
else {
	$vconf = &apache::get_virtual_config();
	$f = $vconf->[0]->{'file'};
	}
&lock_file($f);

# Create a self-signed cert and key, if needed
$_[0]->{'ssl_cert'} ||= "$_[0]->{'home'}/ssl.cert";
$_[0]->{'ssl_key'} ||= "$_[0]->{'home'}/ssl.key";
if (!-r $_[0]->{'ssl_cert'} && !-r $_[0]->{'ssl_key'}) {
	# Need to do it
	local $temp = &tempname();
	&$first_print($text{'setup_openssl'});
	&lock_file($_[0]->{'ssl_cert'});
	&lock_file($_[0]->{'ssl_key'});
	open(CA, "| openssl req -newkey rsa:512 -x509 -nodes -out $_[0]->{'ssl_cert'} -keyout $_[0]->{'ssl_key'} -days 1825 >$temp 2>&1");
	print CA ".\n";
	print CA ".\n";
	print CA ".\n";
	print CA "$_[0]->{'owner'}\n";
	print CA ".\n";
	print CA "*.$_[0]->{'dom'}\n";
	print CA ($_[0]->{'email'} || "."),"\n";
	close(CA);
	local $rv = $?;
	local $out = `cat $temp`;
	unlink($temp);
	if (!-r $_[0]->{'ssl_cert'} || !-r $_[0]->{'ssl_key'} || $?) {
		&$second_print(&text('setup_eopenssl', "<pre>$out</pre>"));
		}
	else {
		chown($_[0]->{'uid'}, $_[0]->{'ugid'}, $_[0]->{'ssl_cert'}, $_[0]->{'ssl_key'});
		chmod(0755, $_[0]->{'ssl_cert'}, $_[0]->{'ssl_key'});
		&$second_print($text{'setup_done'});
		}
	&unlock_file($_[0]->{'ssl_cert'});
	&unlock_file($_[0]->{'ssl_key'});
	}

# Add the actual <VirtualHost>
&$first_print($text{'setup_ssl'});
local @dirs = &apache_template($tmpl->{'web'}, $_[0], $tmpl->{'web_suexec'});
open(FILE, ">>$f");
print FILE "<VirtualHost $_[0]->{'ip'}:$web_sslport>\n";
foreach (@dirs) {
	print FILE $_,"\n";
	}
print FILE "SSLEngine on\n";
print FILE "SSLCertificateFile $_[0]->{'ssl_cert'}\n";
print FILE "SSLCertificateKeyFile $_[0]->{'ssl_key'}\n";
print FILE "</VirtualHost>\n";
close(FILE);

# Update the non-SSL virtualhost to include the port number, to fix old
# hosts that were missing the :80
local ($virt, $vconf) = &get_apache_virtual($_[0]->{'dom'},
					    $_[0]->{'web_port'});
&lock_file($virt->{'file'});
local $lref = &read_file_lines($virt->{'file'});
if (!$_[0]->{'name'} && $lref->[$virt->{'line'}] !~ /:\d+/) {
	$lref->[$virt->{'line'}] =
		"<VirtualHost $_[0]->{'ip'}:$_[0]->{'web_port'}>";
	&flush_file_lines();
	}
&unlock_file($virt->{'file'});

&unlock_file($f);
undef(@apache::get_config_cache);
&$second_print($text{'setup_done'});
&register_post_action(\&restart_apache, 1);
$_[0]->{'web_sslport'} = $web_sslport;
}

# modify_ssl(&domain, &olddomain)
sub modify_ssl
{
local $rv = 0;
&require_apache();
local $conf = &apache::get_config();
local ($virt, $vconf) = &get_apache_virtual($_[1]->{'dom'},
                                            $_[1]->{'web_sslport'});
&lock_file($virt->{'file'});
if ($_[0]->{'home'} ne $_[1]->{'home'}) {
	# Home directory has changed .. update any directives that referred
	# to the old directory
	&$first_print($text{'save_ssl3'});
	local $lref = &read_file_lines($virt->{'file'});
	for($i=$virt->{'line'}; $i<=$virt->{'eline'}; $i++) {
		$lref->[$i] =~ s/$_[1]->{'home'}/$_[0]->{'home'}/g;
		}
	&flush_file_lines();
	$rv++;
	&$second_print($text{'setup_done'});
	}
if ($_[0]->{'dom'} ne $_[1]->{'dom'}) {
        # Domain name has changed
        &$first_print($text{'save_ssl2'});
        &apache::save_directive("ServerName", [ $_[0]->{'dom'} ], $vconf,$conf);
        local @sa = map { s/$_[1]->{'dom'}/$_[0]->{'dom'}/g; $_ }
                        &apache::find_directive("ServerAlias", $vconf);
        &apache::save_directive("ServerAlias", \@sa, $vconf, $conf);
        &flush_file_lines();
        $rv++;
        &$second_print($text{'setup_done'});
        }
&unlock_file($virt->{'file'});
&register_post_action(\&restart_apache, 1) if ($rv);
return $rv;
}

# delete_ssl(&domain)
# Deletes the SSL virtual server from the Apache config
sub delete_ssl
{
&require_apache();
local $conf = &apache::get_config();
&$first_print($text{'delete_ssl'});
local ($virt, $vconf) = &get_apache_virtual($_[0]->{'dom'},
					    $_[0]->{'web_sslport'});
if ($virt) {
	&delete_virtual_server($virt);
	&$second_print($text{'setup_done'});
	&register_post_action(\&restart_apache, 1);
	}
else {
	&$second_print($text{'delete_noapache'});
	}
undef(@apache::get_config_cache);
}

# check_web_clash(&domain, [field])
# Returns 1 if an SSL Apache webserver already exists for some domain
sub check_ssl_clash
{
if (!$_[1] || $_[1] eq 'dom') {
	local $tmpl = &get_template($_[0]->{'template'});
	local $web_port = $tmpl->{'web_sslport'} || 443;
	local ($cvirt, $cconf) = &get_apache_virtual($_[0]->{'dom'}, $web_sslport);
	return $cvirt ? 1 : 0;
	}
return 0;
}

# disable_ssl(&domain)
# Adds a directive to force all requests to show an error page
sub disable_ssl
{
&$first_print($text{'disable_ssl'});
&require_apache();
local ($virt, $vconf) = &get_apache_virtual($_[0]->{'dom'},
					    $_[0]->{'web_sslport'});
if ($virt) {
        &create_disable_directives($virt, $vconf);
        &$second_print($text{'setup_done'});
	&register_post_action(\&restart_apache);
        }
else {
        &$second_print($text{'delete_noapache'});
        }
}

# enable_ssl(&domain)
sub enable_ssl
{
&$first_print($text{'enable_ssl'});
&require_apache();
local ($virt, $vconf) = &get_apache_virtual($_[0]->{'dom'},
					    $_[0]->{'web_sslport'});
if ($virt) {
        &remove_disable_directives($virt, $vconf);
        &$second_print($text{'setup_done'});
	&register_post_action(\&restart_apache);
        }
else {
        &$second_print($text{'delete_noapache'});
        }
}

# backup_ssl(&domain, file)
# Save the SSL virtual server's Apache config as a separate file
sub backup_ssl
{
&$first_print($text{'backup_sslcp'});

# Save the apache directives
local ($virt, $vconf) = &get_apache_virtual($_[0]->{'dom'},
					    $_[0]->{'web_sslport'});
local $lref = &read_file_lines($virt->{'file'});
local $l;
open(FILE, ">$_[1]");
foreach $l (@$lref[$virt->{'line'} .. $virt->{'eline'}]) {
	print FILE "$l\n";
	}
close(FILE);

# Save the cert and key, if any
local $cert = &apache::find_directive("SSLCertificateFile", $vconf, 1);
if ($cert) {
	system("cp ".quotemeta($cert)." ".quotemeta("$_[1]_cert"));
	}
local $key = &apache::find_directive("SSLCertificateKeyFile", $vconf, 1);
if ($key && $key ne $cert) {
	system("cp ".quotemeta($key)." ".quotemeta("$_[1]_key"));
	}

&$second_print($text{'setup_done'});
return 1;
}

# restore_ssl(&domain, file, &options)
# Update the SSL virtual server's Apache configuration from a file. Does not
# change the actual <Virtualhost> lines!
sub restore_ssl
{
&$first_print($text{'restore_sslcp'});

# Restore the Apache directives
local ($virt, $vconf) = &get_apache_virtual($_[0]->{'dom'},
					    $_[0]->{'web_sslport'});
local $srclref = &read_file_lines($_[1]);
local $dstlref = &read_file_lines($virt->{'file'});
&lock_file($virt->{'file'});
splice(@$dstlref, $virt->{'line'}+1, $virt->{'eline'}-$virt->{'line'}-1,
       @$srclref[1 .. @$srclref-2]);
if ($_[2]->{'fixip'}) {
	# Fix ip address in <Virtualhost> section (if needed)
	if ($dstlref->[$virt->{'line'}] =~
	    /^(.*<Virtualhost\s+)([0-9\.]+)(.*)$/i) {
		$dstlref->[$virt->{'line'}] = $1.$_[0]->{'ip'}.$3;
		}
	}
&flush_file_lines();
&unlock_file($virt->{'file'});

# Restore the cert and key, if any and if saved
undef(@apache::get_config_cache);
($virt, $vconf) = &get_apache_virtual($_[0]->{'dom'},
				      $_[0]->{'web_sslport'});
local $cert = &apache::find_directive("SSLCertificateFile", $vconf, 1);
if ($cert && -r "$_[1]_cert") {
	&lock_file($cert);
	system("cp ".quotemeta("$_[1]_cert")." ".quotemeta($cert));
	&unlock_file($cert);
	}
local $key = &apache::find_directive("SSLCertificateKeyFile", $vconf, 1);
if ($key && -r "$_[1]_key" && $key ne $cert) {
	&lock_file($key);
	system("cp ".quotemeta("$_[1]_key")." ".quotemeta($key));
	&unlock_file($key);
	}

&$second_print($text{'setup_done'});

&register_post_action(\&restart_apache);
return 1;
}

# cert_info(&domain)
# Returns a hash of details of a domain's cert
sub cert_info
{
local %rv;
open(OUT, "openssl x509 -in $_[0]->{'ssl_cert'} -issuer -subject -enddate |");
while(<OUT>) {
	s/\r|\n//g;
	if (/subject=.*CN=([^\/]+)/) {
		$rv{'cn'} = $1;
		}
	if (/subject=.*O=([^\/]+)/) {
		$rv{'o'} = $1;
		}
	if (/issuer=.*CN=([^\/]+)/) {
		$rv{'issuer_cn'} = $1;
		}
	if (/issuer=.*O=([^\/]+)/) {
		$rv{'issuer_o'} = $1;
		}
	if (/notAfter=(.*)/) {
		$rv{'notafter'} = $1;
		}
	}
close(OUT);
$rv{'type'} = $rv{'o'} eq $rv{'issuer_o'} ? $text{'cert_typeself'}
					  : $text{'cert_typereal'};
return \%rv;
}

# show_restore_ssl(&options)
# Returns HTML for website restore option inputs
sub show_restore_ssl
{
# Offer to update IP
return sprintf
	"(<input type=checkbox name=ssl_fixip value=1 %s> %s)",
	$opts{'fixip'} ? "checked" : "", $text{'restore_webfixip'};
}

# parse_restore_ssl(&in)
# Parses the inputs for website restore options
sub parse_restore_ssl
{
local %in = %{$_[0]};
return { 'fixip' => $in{'ssl_fixip'} };
}

1;

