X-Git-Url: http://git.ipfire.org/?p=people%2Fpmueller%2Fipfire-2.x.git;a=blobdiff_plain;f=html%2Fcgi-bin%2Fvpnmain.cgi;h=49563faab4a12f23a6cc4daf0660f42aed687e4f;hp=1aa7984b65227d1a7afdce2d2f9c5d5afb3e4f14;hb=a84c3a5a8990056854563812b3982ec9e9a40994;hpb=cd1a2927226c734d96478e12bb768256fb64a06a diff --git a/html/cgi-bin/vpnmain.cgi b/html/cgi-bin/vpnmain.cgi index 1aa7984b65..49563faab4 100644 --- a/html/cgi-bin/vpnmain.cgi +++ b/html/cgi-bin/vpnmain.cgi @@ -1,2580 +1,2810 @@ -#!/usr/bin/perl -# -# This file is part of the IPCop Firewall. -# -# IPCop is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# IPCop is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with IPCop; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Copyright (C) 2003-05-25 Mark Wormgoor -# -# $Id: vpnmain.cgi,v 1.10.2.69 2006/01/31 02:07:19 franck78 Exp $ -# - -use Net::DNS; -use File::Copy; -use File::Temp qw/ tempfile tempdir /; -use strict; - -# enable only the following on debugging purpose -#use warnings; -#use CGI::Carp 'fatalsToBrowser'; - -require 'CONFIG_ROOT/general-functions.pl'; -require "${General::swroot}/lang.pl"; -require "${General::swroot}/header.pl"; - -require "${General::swroot}/countries.pl"; - -#workaround to suppress a warning when a variable is used only once -my @dummy = ( ${Header::colourgreen} ); -undef (@dummy); - -### -### Initialize variables -### -my $sleepDelay = '4s'; # after a call to ipsecctrl S or R, wait this delay (seconds) before reading status - # (let the ipsec do its job) -my %netsettings=(); -my %cgiparams=(); -my %vpnsettings=(); -my %checked=(); -my %confighash=(); -my %cahash=(); -my %selected=(); -my $warnmessage = ''; -my $errormessage = ''; -&General::readhash("${General::swroot}/ethernet/settings", \%netsettings); -$cgiparams{'ENABLED'} = 'off'; -$cgiparams{'ENABLED_BLUE'} = 'off'; -$cgiparams{'EDIT_ADVANCED'} = 'off'; -$cgiparams{'NAT'} = 'off'; -$cgiparams{'COMPRESSION'} = 'off'; -$cgiparams{'ONLY_PROPOSED'} = 'off'; -$cgiparams{'ACTION'} = ''; -$cgiparams{'CA_NAME'} = ''; -$cgiparams{'DBG_CRYPT'} = ''; -$cgiparams{'DBG_PARSING'} = ''; -$cgiparams{'DBG_EMITTING'} = ''; -$cgiparams{'DBG_CONTROL'} = ''; -$cgiparams{'DBG_KLIPS'} = ''; -$cgiparams{'DBG_DNS'} = ''; -$cgiparams{'DBG_NAT_T'} = ''; - -&Header::getcgihash(\%cgiparams, {'wantfile' => 1, 'filevar' => 'FH'}); - -### -### Useful functions -### -sub valid_dns_host { - my $hostname = $_[0]; - unless ($hostname) { return "No hostname"}; - my $res = new Net::DNS::Resolver; - my $query = $res->search("$hostname"); - if ($query) { - foreach my $rr ($query->answer) { - ## Potential bug - we are only looking at A records: - return 0 if $rr->type eq "A"; - } - } else { - return $res->errorstring; - } -} - -# -# old version: maintain serial number to one, without explication. -# this : let the counter go, so that each cert is numbered. -# -sub cleanssldatabase -{ - if (open(FILE, ">${General::swroot}/certs/serial")) { - print FILE "01"; - close FILE; - } - if (open(FILE, ">${General::swroot}/certs/index.txt")) { - print FILE ""; - close FILE; - } - unlink ("${General::swroot}/certs/index.txt.old"); - unlink ("${General::swroot}/certs/serial.old"); - unlink ("${General::swroot}/certs/01.pem"); -} -sub newcleanssldatabase -{ - if (! -s "${General::swroot}/certs/serial" ) { - open(FILE, ">${General::swroot}/certs/serial"); - print FILE "01"; - close FILE; - } - if (! -s ">${General::swroot}/certs/index.txt") { - system ("touch ${General::swroot}/certs/index.txt"); - } - unlink ("${General::swroot}/certs/index.txt.old"); - unlink ("${General::swroot}/certs/serial.old"); -# unlink ("${General::swroot}/certs/01.pem"); numbering evolves. Wrong place to delete -} - -sub writeipsecfiles { - my %lconfighash = (); - my %lvpnsettings = (); - &General::readhasharray("${General::swroot}/vpn/config", \%lconfighash); - &General::readhash("${General::swroot}/vpn/settings", \%lvpnsettings); - - open(CONF, ">${General::swroot}/vpn/ipsec.conf") or die "Unable to open ${General::swroot}/vpn/ipsec.conf: $!"; - open(SECRETS, ">${General::swroot}/vpn/ipsec.secrets") or die "Unable to open ${General::swroot}/vpn/ipsec.secrets: $!"; - flock CONF, 2; - flock SECRETS, 2; - print CONF "config setup\n"; - if ($lvpnsettings{'ENABLED_BLUE'} eq 'on') - { - if ($lvpnsettings{'ENABLED'} eq 'on') - { - print CONF "\tinterfaces=\"%defaultroute ipsec1=$netsettings{'BLUE_DEV'}\"\n"; - } else { - print CONF "\tinterfaces=ipsec0=$netsettings{'BLUE_DEV'}\n"; - } - } else { - print CONF "\tinterfaces=%defaultroute\n"; - } - - my $plutodebug = ''; # build debug list - map ($plutodebug .= $lvpnsettings{$_} eq 'on' ? lc (substr($_,4)).' ' : '', - ('DBG_CRYPT','DBG_PARSING','DBG_EMITTING','DBG_CONTROL', - 'DBG_KLIPS','DBG_DNS','DBG_NAT_T')); - $plutodebug = 'none' if $plutodebug eq ''; # if nothing selected, use 'none'. - print CONF "\tklipsdebug=none\n"; - print CONF "\tplutodebug=\"$plutodebug\"\n"; - print CONF "\tplutoload=%search\n"; - print CONF "\tplutostart=%search\n"; - print CONF "\tuniqueids=yes\n"; - print CONF "\tnat_traversal=yes\n"; - print CONF "\toverridemtu=$lvpnsettings{'VPN_OVERRIDE_MTU'}\n" if ($lvpnsettings{'VPN_OVERRIDE_MTU'} ne ''); - print CONF "\tvirtual_private=%v4:10.0.0.0/8,%v4:172.16.0.0/12,%v4:192.168.0.0/16"; - print CONF ",%v4:!$netsettings{'GREEN_NETADDRESS'}/$netsettings{'GREEN_NETMASK'}"; - if (length($netsettings{'ORANGE_DEV'}) > 2) { - print CONF ",%v4:!$netsettings{'ORANGE_NETADDRESS'}/$netsettings{'ORANGE_NETMASK'}"; - } - if (length($netsettings{'BLUE_DEV'}) > 2) { - print CONF ",%v4:!$netsettings{'BLUE_NETADDRESS'}/$netsettings{'BLUE_NETMASK'}"; - } - foreach my $key (keys %lconfighash) { - if ($lconfighash{$key}[3] eq 'net') { - print CONF ",%v4:!$lconfighash{$key}[11]"; - } - } - print CONF "\n\n"; - print CONF "conn %default\n"; - print CONF "\tkeyingtries=0\n"; - print CONF "\tdisablearrivalcheck=no\n"; - print CONF "\n"; - - if (-f "${General::swroot}/certs/hostkey.pem") { - print SECRETS ": RSA ${General::swroot}/certs/hostkey.pem\n" - } - - foreach my $key (keys %lconfighash) { - if ($lconfighash{$key}[0] eq 'on') { - if ($lconfighash{$key}[10] eq '') { $lconfighash{$key}[10] = '%any'; } - - print CONF "conn $lconfighash{$key}[1]\n"; - #always choose LEFT localside for roadwarrior - if ($lconfighash{$key}[3] eq 'host' || $lconfighash{$key}[6] eq 'left') { - if ($lconfighash{$key}[26] eq 'BLUE') - { - print CONF "\tleft=$netsettings{'BLUE_ADDRESS'}\n"; -# print CONF "\tleftnexthop=$netsettings{'BLUE_NETADDRESS'}\n"; - } - elsif ($lconfighash{$key}[26] eq 'ORANGE') - { - print CONF "\tleft=$netsettings{'ORANGE_ADDRESS'}\n"; - } - elsif ($lconfighash{$key}[26] eq 'GREEN') - { - print CONF "\tleft=$netsettings{'GREEN_ADDRESS'}\n"; - } - elsif ($lconfighash{$key}[26] eq 'RED') - { - print CONF "\tleft=$lvpnsettings{'VPN_IP'}\n"; - print CONF "\tleftnexthop=%defaultroute\n" if ($lvpnsettings{'VPN_IP'} ne '%defaultroute'); - } - print CONF "\tleftsubnet=$lconfighash{$key}[8]\n"; - print CONF "\tright=$lconfighash{$key}[10]\n"; - if ($lconfighash{$key}[3] eq 'net') { - print CONF "\trightsubnet=$lconfighash{$key}[11]\n"; - print CONF "\trightnexthop=%defaultroute\n"; - } elsif ($lconfighash{$key}[10] eq '%any' && $lconfighash{$key}[14] eq 'on') { - print CONF "\trightsubnet=vhost:%no,%priv\n"; - } - if ($lconfighash{$key}[4] eq 'cert') { - print CONF "\tleftcert=${General::swroot}/certs/hostcert.pem\n"; - print CONF "\trightcert=${General::swroot}/certs/$lconfighash{$key}[1]cert.pem\n"; - } - } else { - print CONF "\tright=$lvpnsettings{'VPN_IP'}\n"; - print CONF "\trightsubnet=$lconfighash{$key}[8]\n"; - print CONF "\trightnexthop=%defaultroute\n" if ($lvpnsettings{'VPN_IP'} ne '%defaultroute'); - print CONF "\tleft=$lconfighash{$key}[10]\n"; - if ($lconfighash{$key}[3] eq 'net') { - print CONF "\tleftsubnet=$lconfighash{$key}[11]\n"; - print CONF "\tleftnexthop=%defaultroute\n"; - } - if ($lconfighash{$key}[4] eq 'cert') { - print CONF "\trightcert=${General::swroot}/certs/hostcert.pem\n"; - print CONF "\tleftcert=${General::swroot}/certs/$lconfighash{$key}[1]cert.pem\n"; - } - } - print CONF "\tleftid=$lconfighash{$key}[7]\n" if ($lconfighash{$key}[7]); - print CONF "\trightid=$lconfighash{$key}[9]\n" if ($lconfighash{$key}[9]); - - # Algorithms - if ($lconfighash{$key}[18] && $lconfighash{$key}[19] && $lconfighash{$key}[20]) { - print CONF "\tike="; - my @encs = split('\|', $lconfighash{$key}[18]); - my @ints = split('\|', $lconfighash{$key}[19]); - my @groups = split('\|', $lconfighash{$key}[20]); - my $comma = 0; - foreach my $i (@encs) { - foreach my $j (@ints) { - foreach my $k (@groups) { - if ($comma != 0) { print CONF ","; } else { $comma = 1; } - print CONF "$i-$j-modp$k"; - } - } - } - if ($lconfighash{$key}[24] eq 'on') { - print CONF "!\n"; - } else { - print CONF "\n"; - } - } - if ($lconfighash{$key}[21] && $lconfighash{$key}[22]) { - print CONF "\tesp="; - my @encs = split('\|', $lconfighash{$key}[21]); - my @ints = split('\|', $lconfighash{$key}[22]); - my $comma = 0; - foreach my $i (@encs) { - foreach my $j (@ints) { - if ($comma != 0) { print CONF ","; } else { $comma = 1; } - print CONF "$i-$j"; - } - } - if ($lconfighash{$key}[24] eq 'on') { - print CONF "!\n"; - } else { - print CONF "\n"; - } - } - if ($lconfighash{$key}[23]) { - print CONF "\tpfsgroup=$lconfighash{$key}[23]\n"; - } - - # Lifetimes - if ($lconfighash{$key}[16]) { - print CONF "\tikelifetime=$lconfighash{$key}[16]h\n"; - } - if ($lconfighash{$key}[17]) { - print CONF "\tkeylife=$lconfighash{$key}[17]h\n"; - } - - # Compression - if ($lconfighash{$key}[13] eq 'on') { - print CONF "\tcompress=yes\n"; - } - - # Dead Peer Detection - print CONF "\tdpddelay=30\n"; - print CONF "\tdpdtimeout=120\n"; - print CONF "\tdpdaction=$lconfighash{$key}[27]\n"; - - # Disable pfs ? - print CONF "\tpfs=$lconfighash{$key}[28]\n"; - - # Print Authentication details - if ($lconfighash{$key}[4] eq 'psk') { - if ($lconfighash{$key}[6] eq 'left'){ - if ($lconfighash{$key}[26] eq 'BLUE') { - print SECRETS ($lconfighash{$key}[7] ? $lconfighash{$key}[7] : $netsettings{'BLUE_ADDRESS'}) . " "; - print SECRETS $lconfighash{$key}[9] ? $lconfighash{$key}[9] : $lconfighash{$key}[10]; - print SECRETS " : PSK \"$lconfighash{$key}[5]\"\n"; - } else { - print SECRETS ($lconfighash{$key}[7] ? $lconfighash{$key}[7] : $lvpnsettings{'VPN_IP'}) . " "; - print SECRETS $lconfighash{$key}[9] ? $lconfighash{$key}[9] : $lconfighash{$key}[10]; - print SECRETS " : PSK \"$lconfighash{$key}[5]\"\n"; - } - } else { - if ($lconfighash{$key}[26] eq 'BLUE') { - print SECRETS ($lconfighash{$key}[9] ? $lconfighash{$key}[9] : $netsettings{'BLUE_ADDRESS'}) . " "; - print SECRETS $lconfighash{$key}[7] ? $lconfighash{$key}[7] : $lconfighash{$key}[10]; - print SECRETS " : PSK \"$lconfighash{$key}[5]\"\n"; - } else { - print SECRETS ($lconfighash{$key}[9] ? $lconfighash{$key}[9] : $lvpnsettings{'VPN_IP'}) . " "; - print SECRETS $lconfighash{$key}[7] ? $lconfighash{$key}[7] : $lconfighash{$key}[10]; - print SECRETS " : PSK \"$lconfighash{$key}[5]\"\n"; - } - } - - print CONF "\tauthby=secret\n"; - } else { - print CONF "\tauthby=rsasig\n"; - } - - # Automatically start only if a net-to-net connection - if ($lconfighash{$key}[3] eq 'host') { - print CONF "\tauto=add\n"; - } else { - print CONF "\tauto=start\n"; - } - print CONF "\n"; - }#on - }#foreach key - - close(CONF); - close(SECRETS); -} - -### -### Save main settings -### -if ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'TYPE'} eq '' && $cgiparams{'KEY'} eq '') { - &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); - unless (&General::validfqdn($cgiparams{'VPN_IP'}) || &General::validip($cgiparams{'VPN_IP'}) - || $cgiparams{'VPN_IP'} eq '%defaultroute' ) { - $errormessage = $Lang::tr{'invalid input for hostname'}; - goto SAVE_ERROR; - } - - unless ($cgiparams{'VPN_DELAYED_START'} =~ /^[0-9]{1,3}$/ ) { #allow 0-999 seconds ! - $errormessage = $Lang::tr{'invalid time period'}; - goto SAVE_ERROR; - } - - unless ($cgiparams{'VPN_OVERRIDE_MTU'} =~ /^(|[0-9]{1,5})$/ ) { #allow 0-99999 - $errormessage = $Lang::tr{'vpn mtu invalid'}; - goto SAVE_ERROR; - } - - map ($vpnsettings{$_} = $cgiparams{$_}, - ('ENABLED','ENABLED_BLUE','DBG_CRYPT','DBG_PARSING','DBG_EMITTING','DBG_CONTROL', - 'DBG_KLIPS','DBG_DNS','DBG_NAT_T')); - - $vpnsettings{'VPN_IP'} = $cgiparams{'VPN_IP'}; - $vpnsettings{'VPN_DELAYED_START'} = $cgiparams{'VPN_DELAYED_START'}; - $vpnsettings{'VPN_OVERRIDE_MTU'} = $cgiparams{'VPN_OVERRIDE_MTU'}; - &General::writehash("${General::swroot}/vpn/settings", \%vpnsettings); - &writeipsecfiles(); - if ($vpnsettings{'ENABLED'} eq 'on' || - $vpnsettings{'ENABLED_BLUE'} eq 'on') { - system('/usr/local/bin/ipsecctrl', 'S'); - } else { - system('/usr/local/bin/ipsecctrl', 'D'); - } - sleep $sleepDelay; - SAVE_ERROR: -### -### Reset all step 2 -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'reset'} && $cgiparams{'AREUSURE'} eq 'yes') { - my $file = ''; - &General::readhasharray("${General::swroot}/vpn/config", \%confighash); - - foreach my $key (keys %confighash) { - if ($confighash{$key}[4] eq 'cert') { - delete $confighash{$key}; - } - } - while ($file = glob("${General::swroot}/{ca,certs,crls,private}/*")) { - unlink $file - } - &cleanssldatabase(); - if (open(FILE, ">${General::swroot}/vpn/caconfig")) { - print FILE ""; - close FILE; - } - &General::writehasharray("${General::swroot}/vpn/config", \%confighash); - &writeipsecfiles(); - system('/usr/local/bin/ipsecctrl', 'R'); - sleep $sleepDelay; - -### -### Reset all step 1 -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'reset'}) { - &Header::showhttpheaders(); - &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); - &Header::openbigbox('100%', 'LEFT', '', ''); - &Header::openbox('100%', 'LEFT', $Lang::tr{'are you sure'}); - print <
- - $Lang::tr{'capswarning'}: - $Lang::tr{'resetting the vpn configuration will remove the root ca, the host certificate and all certificate based connections'} - - -
-END - ; - &Header::closebox(); - &Header::closebigbox(); - &Header::closepage(); - exit (0); - -### -### Upload CA Certificate -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'upload ca certificate'}) { - &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); - - if ($cgiparams{'CA_NAME'} !~ /^[a-zA-Z0-9]+$/) { - $errormessage = $Lang::tr{'name must only contain characters'}; - goto UPLOADCA_ERROR; - } - - if (length($cgiparams{'CA_NAME'}) >60) { - $errormessage = $Lang::tr{'name too long'}; - goto VPNCONF_ERROR; - } - - if ($cgiparams{'CA_NAME'} eq 'ca') { - $errormessage = $Lang::tr{'name is invalid'}; - goto UPLOAD_CA_ERROR; - } - - # Check if there is no other entry with this name - foreach my $key (keys %cahash) { - if ($cahash{$key}[0] eq $cgiparams{'CA_NAME'}) { - $errormessage = $Lang::tr{'a ca certificate with this name already exists'}; - goto UPLOADCA_ERROR; - } - } - - if (ref ($cgiparams{'FH'}) ne 'Fh') { - $errormessage = $Lang::tr{'there was no file upload'}; - goto UPLOADCA_ERROR; - } - # Move uploaded ca to a temporary file - (my $fh, my $filename) = tempfile( ); - if (copy ($cgiparams{'FH'}, $fh) != 1) { - $errormessage = $!; - goto UPLOADCA_ERROR; - } - my $temp = `/usr/bin/openssl x509 -text -in $filename`; - if ($temp !~ /CA:TRUE/i) { - $errormessage = $Lang::tr{'not a valid ca certificate'}; - unlink ($filename); - goto UPLOADCA_ERROR; - } else { - move($filename, "${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem"); - if ($? ne 0) { - $errormessage = "$Lang::tr{'certificate file move failed'}: $!"; - unlink ($filename); - goto UPLOADCA_ERROR; - } - } - - my $casubject = `/usr/bin/openssl x509 -text -in ${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem`; - $casubject =~ /Subject: (.*)[\n]/; - $casubject = $1; - $casubject =~ s+/Email+, E+; - $casubject =~ s/ ST=/ S=/; - $casubject = &Header::cleanhtml($casubject); - - my $key = &General::findhasharraykey (\%cahash); - $cahash{$key}[0] = $cgiparams{'CA_NAME'}; - $cahash{$key}[1] = $casubject; - &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash); - system('/usr/local/bin/ipsecctrl', 'R'); - sleep $sleepDelay; - - UPLOADCA_ERROR: - -### -### Display ca certificate -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show ca certificate'}) { - &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); - - if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem") { - &Header::showhttpheaders(); - &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); - &Header::openbigbox('100%', 'LEFT', '', ''); - &Header::openbox('100%', 'LEFT', "$Lang::tr{'ca certificate'}:"); - my $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem`; - $output = &Header::cleanhtml($output,"y"); - print "
$output
\n"; - &Header::closebox(); - print "
$Lang::tr{'back'}
"; - &Header::closebigbox(); - &Header::closepage(); - exit(0); - } else { - $errormessage = $Lang::tr{'invalid key'}; - } - -### -### Download ca certificate -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download ca certificate'}) { - &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); - - if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) { - print "Content-Type: application/octet-stream\r\n"; - print "Content-Disposition: filename=$cahash{$cgiparams{'KEY'}}[0]cert.pem\r\n\r\n"; - print `/usr/bin/openssl x509 -in ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem`; - exit(0); - } else { - $errormessage = $Lang::tr{'invalid key'}; - } - -### -### Remove ca certificate (step 2) -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove ca certificate'} && $cgiparams{'AREUSURE'} eq 'yes') { - &General::readhasharray("${General::swroot}/vpn/config", \%confighash); - &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); - - if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) { - foreach my $key (keys %confighash) { - my $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem ${General::swroot}/certs/$confighash{$key}[1]cert.pem`; - if ($test =~ /: OK/) { - # Delete connection - if ($vpnsettings{'ENABLED'} eq 'on' || - $vpnsettings{'ENABLED_BLUE'} eq 'on') { - system('/usr/local/bin/ipsecctrl', 'D', $key); - } - unlink ("${General::swroot}/certs/$confighash{$key}[1]cert.pem"); - unlink ("${General::swroot}/certs/$confighash{$key}[1].p12"); - delete $confighash{$key}; - &General::writehasharray("${General::swroot}/vpn/config", \%confighash); - &writeipsecfiles(); - } - } - unlink ("${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem"); - delete $cahash{$cgiparams{'KEY'}}; - &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash); - system('/usr/local/bin/ipsecctrl', 'R'); - sleep $sleepDelay; - } else { - $errormessage = $Lang::tr{'invalid key'}; - } -### -### Remove ca certificate (step 1) -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove ca certificate'}) { - &General::readhasharray("${General::swroot}/vpn/config", \%confighash); - &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); - - my $assignedcerts = 0; - if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) { - foreach my $key (keys %confighash) { - my $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem ${General::swroot}/certs/$confighash{$key}[1]cert.pem`; - if ($test =~ /: OK/) { - $assignedcerts++; - } - } - if ($assignedcerts) { - &Header::showhttpheaders(); - &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); - &Header::openbigbox('100%', 'LEFT', '', ''); - &Header::openbox('100%', 'LEFT', $Lang::tr{'are you sure'}); - print <
- - - $Lang::tr{'capswarning'}: $assignedcerts - $Lang::tr{'connections are associated with this ca. deleting the ca will delete these connections as well.'} - - -
-END - ; - &Header::closebox(); - &Header::closebigbox(); - &Header::closepage(); - exit (0); - } else { - unlink ("${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem"); - delete $cahash{$cgiparams{'KEY'}}; - &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash); - system('/usr/local/bin/ipsecctrl', 'R'); - sleep $sleepDelay; - } - } else { - $errormessage = $Lang::tr{'invalid key'}; - } - -### -### Display root certificate -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show root certificate'} || - $cgiparams{'ACTION'} eq $Lang::tr{'show host certificate'}) { - my $output; - &Header::showhttpheaders(); - &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); - &Header::openbigbox('100%', 'LEFT', '', ''); - if ($cgiparams{'ACTION'} eq $Lang::tr{'show root certificate'}) { - &Header::openbox('100%', 'LEFT', "$Lang::tr{'root certificate'}:"); - $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/ca/cacert.pem`; - } else { - &Header::openbox('100%', 'LEFT', "$Lang::tr{'host certificate'}:"); - $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/certs/hostcert.pem`; - } - $output = &Header::cleanhtml($output,"y"); - print "
$output
\n"; - &Header::closebox(); - print "
$Lang::tr{'back'}
"; - &Header::closebigbox(); - &Header::closepage(); - exit(0); - -### -### Download root certificate -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download root certificate'}) { - if ( -f "${General::swroot}/ca/cacert.pem" ) { - print "Content-Type: application/octet-stream\r\n"; - print "Content-Disposition: filename=cacert.pem\r\n\r\n"; - print `/usr/bin/openssl x509 -in ${General::swroot}/ca/cacert.pem`; - exit(0); - } -### -### Download host certificate -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download host certificate'}) { - if ( -f "${General::swroot}/certs/hostcert.pem" ) { - print "Content-Type: application/octet-stream\r\n"; - print "Content-Disposition: filename=hostcert.pem\r\n\r\n"; - print `/usr/bin/openssl x509 -in ${General::swroot}/certs/hostcert.pem`; - exit(0); - } -### -### Form for generating a root certificate -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'generate root/host certificates'} || - $cgiparams{'ACTION'} eq $Lang::tr{'upload p12 file'}) { - - &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); - if (-f "${General::swroot}/ca/cacert.pem") { - $errormessage = $Lang::tr{'valid root certificate already exists'}; - $cgiparams{'ACTION'} = ''; - goto ROOTCERT_ERROR; - } - - if (($cgiparams{'ROOTCERT_HOSTNAME'} eq '') && -e "${General::swroot}/red/active") { - if (open(IPADDR, "${General::swroot}/red/local-ipaddress")) { - my $ipaddr = ; - close IPADDR; - chomp ($ipaddr); - $cgiparams{'ROOTCERT_HOSTNAME'} = (gethostbyaddr(pack("C4", split(/\./, $ipaddr)), 2))[0]; - if ($cgiparams{'ROOTCERT_HOSTNAME'} eq '') { - $cgiparams{'ROOTCERT_HOSTNAME'} = $ipaddr; - } - } - } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'upload p12 file'}) { - - if (ref ($cgiparams{'FH'}) ne 'Fh') { - $errormessage = $Lang::tr{'there was no file upload'}; - goto ROOTCERT_ERROR; - } - - # Move uploaded certificate request to a temporary file - (my $fh, my $filename) = tempfile( ); - if (copy ($cgiparams{'FH'}, $fh) != 1) { - $errormessage = $!; - goto ROOTCERT_ERROR; - } - - # Create a temporary dirctory - my $tempdir = tempdir( CLEANUP => 1 ); - - # Extract the CA certificate from the file - my $pid = open(OPENSSL, "|-"); - $SIG{ALRM} = sub { $errormessage = $Lang::tr{'broken pipe'}; goto ROOTCERT_ERROR;}; - if ($pid) { # parent - if ($cgiparams{'P12_PASS'} ne '') { - print OPENSSL "$cgiparams{'P12_PASS'}\n"; - } - close (OPENSSL); - if ($?) { - $errormessage = "$Lang::tr{'openssl produced an error'}: $?"; - unlink ($filename); - goto ROOTCERT_ERROR; - } - } else { # child - unless (exec ('/usr/bin/openssl', 'pkcs12', '-cacerts', '-nokeys', - '-in', $filename, - '-out', "$tempdir/cacert.pem")) { - $errormessage = "$Lang::tr{'cant start openssl'}: $!"; - unlink ($filename); - goto ROOTCERT_ERROR; - } - } - - # Extract the Host certificate from the file - $pid = open(OPENSSL, "|-"); - $SIG{ALRM} = sub { $errormessage = $Lang::tr{'broken pipe'}; goto ROOTCERT_ERROR;}; - if ($pid) { # parent - if ($cgiparams{'P12_PASS'} ne '') { - print OPENSSL "$cgiparams{'P12_PASS'}\n"; - } - close (OPENSSL); - if ($?) { - $errormessage = "$Lang::tr{'openssl produced an error'}: $?"; - unlink ($filename); - goto ROOTCERT_ERROR; - } - } else { # child - unless (exec ('/usr/bin/openssl', 'pkcs12', '-clcerts', '-nokeys', - '-in', $filename, - '-out', "$tempdir/hostcert.pem")) { - $errormessage = "$Lang::tr{'cant start openssl'}: $!"; - unlink ($filename); - goto ROOTCERT_ERROR; - } - } - - # Extract the Host key from the file - $pid = open(OPENSSL, "|-"); - $SIG{ALRM} = sub { $errormessage = $Lang::tr{'broken pipe'}; goto ROOTCERT_ERROR;}; - if ($pid) { # parent - if ($cgiparams{'P12_PASS'} ne '') { - print OPENSSL "$cgiparams{'P12_PASS'}\n"; - } - close (OPENSSL); - if ($?) { - $errormessage = "$Lang::tr{'openssl produced an error'}: $?"; - unlink ($filename); - goto ROOTCERT_ERROR; - } - } else { # child - unless (exec ('/usr/bin/openssl', 'pkcs12', '-nocerts', - '-nodes', - '-in', $filename, - '-out', "$tempdir/hostkey.pem")) { - $errormessage = "$Lang::tr{'cant start openssl'}: $!"; - unlink ($filename); - goto ROOTCERT_ERROR; - } - } - - move("$tempdir/cacert.pem", "${General::swroot}/ca/cacert.pem"); - if ($? ne 0) { - $errormessage = "$Lang::tr{'certificate file move failed'}: $!"; - unlink ($filename); - unlink ("${General::swroot}/ca/cacert.pem"); - unlink ("${General::swroot}/certs/hostcert.pem"); - unlink ("${General::swroot}/certs/hostkey.pem"); - goto ROOTCERT_ERROR; - } - - move("$tempdir/hostcert.pem", "${General::swroot}/certs/hostcert.pem"); - if ($? ne 0) { - $errormessage = "$Lang::tr{'certificate file move failed'}: $!"; - unlink ($filename); - unlink ("${General::swroot}/ca/cacert.pem"); - unlink ("${General::swroot}/certs/hostcert.pem"); - unlink ("${General::swroot}/certs/hostkey.pem"); - goto ROOTCERT_ERROR; - } - - move("$tempdir/hostkey.pem", "${General::swroot}/certs/hostkey.pem"); - if ($? ne 0) { - $errormessage = "$Lang::tr{'certificate file move failed'}: $!"; - unlink ($filename); - unlink ("${General::swroot}/ca/cacert.pem"); - unlink ("${General::swroot}/certs/hostcert.pem"); - unlink ("${General::swroot}/certs/hostkey.pem"); - goto ROOTCERT_ERROR; - } - - # Create an empty CRL - system('/usr/bin/openssl', 'ca', '-gencrl', - '-out', "${General::swroot}/crls/cacrl.pem"); - if ($?) { - $errormessage = "$Lang::tr{'openssl produced an error'}: $?"; - unlink ("${General::swroot}/certs/hostkey.pem"); - unlink ("${General::swroot}/certs/hostcert.pem"); - unlink ("${General::swroot}/ca/cacert.pem"); - unlink ("${General::swroot}/crls/cacrl.pem"); - &cleanssldatabase(); - goto ROOTCERT_ERROR; - } else { - &cleanssldatabase(); - } - - goto ROOTCERT_SUCCESS; - - } elsif ($cgiparams{'ROOTCERT_COUNTRY'} ne '') { - - # Validate input since the form was submitted - if ($cgiparams{'ROOTCERT_ORGANIZATION'} eq ''){ - $errormessage = $Lang::tr{'organization cant be empty'}; - goto ROOTCERT_ERROR; - } - if (length($cgiparams{'ROOTCERT_ORGANIZATION'}) >60) { - $errormessage = $Lang::tr{'organization too long'}; - goto ROOTCERT_ERROR; - } - if ($cgiparams{'ROOTCERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { - $errormessage = $Lang::tr{'invalid input for organization'}; - goto ROOTCERT_ERROR; - } - if ($cgiparams{'ROOTCERT_HOSTNAME'} eq ''){ - $errormessage = $Lang::tr{'hostname cant be empty'}; - goto ROOTCERT_ERROR; - } - unless (&General::validfqdn($cgiparams{'ROOTCERT_HOSTNAME'}) || &General::validip($cgiparams{'ROOTCERT_HOSTNAME'})) { - $errormessage = $Lang::tr{'invalid input for hostname'}; - goto ROOTCERT_ERROR; - } - if ($cgiparams{'ROOTCERT_EMAIL'} ne '' && (! &General::validemail($cgiparams{'ROOTCERT_EMAIL'}))) { - $errormessage = $Lang::tr{'invalid input for e-mail address'}; - goto ROOTCERT_ERROR; - } - if (length($cgiparams{'ROOTCERT_EMAIL'}) > 40) { - $errormessage = $Lang::tr{'e-mail address too long'}; - goto ROOTCERT_ERROR; - } - if ($cgiparams{'ROOTCERT_OU'} ne '' && $cgiparams{'ROOTCERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { - $errormessage = $Lang::tr{'invalid input for department'}; - goto ROOTCERT_ERROR; - } - if ($cgiparams{'ROOTCERT_CITY'} ne '' && $cgiparams{'ROOTCERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { - $errormessage = $Lang::tr{'invalid input for city'}; - goto ROOTCERT_ERROR; - } - if ($cgiparams{'ROOTCERT_STATE'} ne '' && $cgiparams{'ROOTCERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { - $errormessage = $Lang::tr{'invalid input for state or province'}; - goto ROOTCERT_ERROR; - } - if ($cgiparams{'ROOTCERT_COUNTRY'} !~ /^[A-Z]*$/) { - $errormessage = $Lang::tr{'invalid input for country'}; - goto ROOTCERT_ERROR; - } - - # Copy the cgisettings to vpnsettings and save the configfile - $vpnsettings{'ROOTCERT_ORGANIZATION'} = $cgiparams{'ROOTCERT_ORGANIZATION'}; - $vpnsettings{'ROOTCERT_HOSTNAME'} = $cgiparams{'ROOTCERT_HOSTNAME'}; - $vpnsettings{'ROOTCERT_EMAIL'} = $cgiparams{'ROOTCERT_EMAIL'}; - $vpnsettings{'ROOTCERT_OU'} = $cgiparams{'ROOTCERT_OU'}; - $vpnsettings{'ROOTCERT_CITY'} = $cgiparams{'ROOTCERT_CITY'}; - $vpnsettings{'ROOTCERT_STATE'} = $cgiparams{'ROOTCERT_STATE'}; - $vpnsettings{'ROOTCERT_COUNTRY'} = $cgiparams{'ROOTCERT_COUNTRY'}; - &General::writehash("${General::swroot}/vpn/settings", \%vpnsettings); - - # Replace empty strings with a . - (my $ou = $cgiparams{'ROOTCERT_OU'}) =~ s/^\s*$/\./; - (my $city = $cgiparams{'ROOTCERT_CITY'}) =~ s/^\s*$/\./; - (my $state = $cgiparams{'ROOTCERT_STATE'}) =~ s/^\s*$/\./; - - # Create the CA certificate - my $pid = open(OPENSSL, "|-"); - $SIG{ALRM} = sub { $errormessage = $Lang::tr{'broken pipe'}; goto ROOTCERT_ERROR;}; - if ($pid) { # parent - print OPENSSL "$cgiparams{'ROOTCERT_COUNTRY'}\n"; - print OPENSSL "$state\n"; - print OPENSSL "$city\n"; - print OPENSSL "$cgiparams{'ROOTCERT_ORGANIZATION'}\n"; - print OPENSSL "$ou\n"; - print OPENSSL "$cgiparams{'ROOTCERT_ORGANIZATION'} CA\n"; - print OPENSSL "$cgiparams{'ROOTCERT_EMAIL'}\n"; - close (OPENSSL); - if ($?) { - $errormessage = "$Lang::tr{'openssl produced an error'}: $?"; - unlink ("${General::swroot}/private/cakey.pem"); - unlink ("${General::swroot}/ca/cacert.pem"); - goto ROOTCERT_ERROR; - } - } else { # child - unless (exec ('/usr/bin/openssl', 'req', '-x509', '-nodes', '-rand', '/proc/interrupts:/proc/net/rt_cache', - '-days', '999999', '-newkey', 'rsa:2048', - '-keyout', "${General::swroot}/private/cakey.pem", - '-out', "${General::swroot}/ca/cacert.pem")) { - $errormessage = "$Lang::tr{'cant start openssl'}: $!"; - goto ROOTCERT_ERROR; - } - } - - # Create the Host certificate request - $pid = open(OPENSSL, "|-"); - $SIG{ALRM} = sub { $errormessage = $Lang::tr{'broken pipe'}; goto ROOTCERT_ERROR;}; - if ($pid) { # parent - print OPENSSL "$cgiparams{'ROOTCERT_COUNTRY'}\n"; - print OPENSSL "$state\n"; - print OPENSSL "$city\n"; - print OPENSSL "$cgiparams{'ROOTCERT_ORGANIZATION'}\n"; - print OPENSSL "$ou\n"; - print OPENSSL "$cgiparams{'ROOTCERT_HOSTNAME'}\n"; - print OPENSSL "$cgiparams{'ROOTCERT_EMAIL'}\n"; - print OPENSSL ".\n"; - print OPENSSL ".\n"; - close (OPENSSL); - if ($?) { - $errormessage = "$Lang::tr{'openssl produced an error'}: $?"; - unlink ("${General::swroot}/certs/hostkey.pem"); - unlink ("${General::swroot}/certs/hostreq.pem"); - goto ROOTCERT_ERROR; - } - } else { # child - unless (exec ('/usr/bin/openssl', 'req', '-nodes', '-rand', '/proc/interrupts:/proc/net/rt_cache', - '-newkey', 'rsa:1024', - '-keyout', "${General::swroot}/certs/hostkey.pem", - '-out', "${General::swroot}/certs/hostreq.pem")) { - $errormessage = "$Lang::tr{'cant start openssl'}: $!"; - unlink ("${General::swroot}/certs/hostkey.pem"); - unlink ("${General::swroot}/certs/hostreq.pem"); - unlink ("${General::swroot}/private/cakey.pem"); - unlink ("${General::swroot}/ca/cacert.pem"); - goto ROOTCERT_ERROR; - } - } - - # Sign the host certificate request - system('/usr/bin/openssl', 'ca', '-days', '999999', - '-batch', '-notext', - '-in', "${General::swroot}/certs/hostreq.pem", - '-out', "${General::swroot}/certs/hostcert.pem"); - if ($?) { - $errormessage = "$Lang::tr{'openssl produced an error'}: $?"; - unlink ("${General::swroot}/private/cakey.pem"); - unlink ("${General::swroot}/ca/cacert.pem"); - unlink ("${General::swroot}/certs/hostkey.pem"); - unlink ("${General::swroot}/certs/hostreq.pem"); - unlink ("${General::swroot}/certs/hostcert.pem"); - &cleanssldatabase(); - goto ROOTCERT_ERROR; - } else { - unlink ("${General::swroot}/certs/hostreq.pem"); - &cleanssldatabase(); - } - - # Create an empty CRL - system('/usr/bin/openssl', 'ca', '-gencrl', - '-out', "${General::swroot}/crls/cacrl.pem"); - if ($?) { - $errormessage = "$Lang::tr{'openssl produced an error'}: $?"; - unlink ("${General::swroot}/certs/hostkey.pem"); - unlink ("${General::swroot}/certs/hostcert.pem"); - unlink ("${General::swroot}/ca/cacert.pem"); - unlink ("${General::swroot}/crls/cacrl.pem"); - &cleanssldatabase(); - goto ROOTCERT_ERROR; - } else { - &cleanssldatabase(); - } - goto ROOTCERT_SUCCESS; - } - ROOTCERT_ERROR: - if ($cgiparams{'ACTION'} ne '') { - &Header::showhttpheaders(); - &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); - &Header::openbigbox('100%', 'LEFT', '', $errormessage); - if ($errormessage) { - &Header::openbox('100%', 'LEFT', $Lang::tr{'error messages'}); - print "$errormessage"; - print " "; - &Header::closebox(); - } - &Header::openbox('100%', 'LEFT', "$Lang::tr{'generate root/host certificates'}:"); - print < - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
$Lang::tr{'organization name'}: 
$Lang::tr{'ipcops hostname'}: 
$Lang::tr{'your e-mail'}: * 
$Lang::tr{'your department'}: * 
$Lang::tr{'city'}: * 
$Lang::tr{'state or province'}: * 
$Lang::tr{'country'}: 
 


  
- * $Lang::tr{'this field may be blank'} - $Lang::tr{'capswarning'}: - $Lang::tr{'generating the root and host certificates may take a long time. it can take up to several minutes on older hardware. please be patient'} -

$Lang::tr{'upload p12 file'}: 
$Lang::tr{'pkcs12 file password'}: * 
  
- * $Lang::tr{'this field may be blank'}
-END - ; - &Header::closebox(); - - &Header::closebigbox(); - &Header::closepage(); - exit(0) - } - - ROOTCERT_SUCCESS: - if ($vpnsettings{'ENABLED'} eq 'on' || - $vpnsettings{'ENABLE_BLUE'} eq 'on') { - system('/usr/local/bin/ipsecctrl', 'S'); - sleep $sleepDelay; - } -### -### Download PKCS12 file -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download pkcs12 file'}) { - &General::readhasharray("${General::swroot}/vpn/config", \%confighash); - - print "Content-Disposition: filename=" . $confighash{$cgiparams{'KEY'}}[1] . ".p12\r\n"; - print "Content-Type: application/octet-stream\r\n\r\n"; - print `/bin/cat ${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1].p12`; - exit (0); - -### -### Display certificate -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show certificate'}) { - &General::readhasharray("${General::swroot}/vpn/config", \%confighash); - - if ( -f "${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") { - &Header::showhttpheaders(); - &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); - &Header::openbigbox('100%', 'LEFT', '', ''); - &Header::openbox('100%', 'LEFT', "$Lang::tr{'certificate'}:"); - my $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem`; - $output = &Header::cleanhtml($output,"y"); - print "
$output
\n"; - &Header::closebox(); - print ""; - &Header::closebigbox(); - &Header::closepage(); - exit(0); - } - -### -### Download Certificate -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download certificate'}) { - &General::readhasharray("${General::swroot}/vpn/config", \%confighash); - - if ( -f "${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") { - print "Content-Disposition: filename=" . $confighash{$cgiparams{'KEY'}}[1] . "cert.pem\r\n"; - print "Content-Type: application/octet-stream\r\n\r\n"; - print `/bin/cat ${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem`; - exit (0); - } - -### -### Enable/Disable connection -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'toggle enable disable'}) { - - &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); - &General::readhasharray("${General::swroot}/vpn/config", \%confighash); - - if ($confighash{$cgiparams{'KEY'}}) { - if ($confighash{$cgiparams{'KEY'}}[0] eq 'off') { - $confighash{$cgiparams{'KEY'}}[0] = 'on'; - &General::writehasharray("${General::swroot}/vpn/config", \%confighash); - &writeipsecfiles(); - if ($vpnsettings{'ENABLED'} eq 'on' || - $vpnsettings{'ENABLED_BLUE'} eq 'on') { - system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'}); - sleep $sleepDelay; - } - } else { - $confighash{$cgiparams{'KEY'}}[0] = 'off'; - if ($vpnsettings{'ENABLED'} eq 'on' || - $vpnsettings{'ENABLED_BLUE'} eq 'on') { - system('/usr/local/bin/ipsecctrl', 'D', $cgiparams{'KEY'}); - } - &General::writehasharray("${General::swroot}/vpn/config", \%confighash); - &writeipsecfiles(); - } - } else { - $errormessage = $Lang::tr{'invalid key'}; - } - -### -### Restart connection -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'restart'}) { - &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); - &General::readhasharray("${General::swroot}/vpn/config", \%confighash); - - if ($confighash{$cgiparams{'KEY'}}) { - if ($vpnsettings{'ENABLED'} eq 'on' || - $vpnsettings{'ENABLED_BLUE'} eq 'on') { - system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'}); - sleep $sleepDelay; - } - } else { - $errormessage = $Lang::tr{'invalid key'}; - } - -### -### Remove connection -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove'}) { - &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); - &General::readhasharray("${General::swroot}/vpn/config", \%confighash); - - if ($confighash{$cgiparams{'KEY'}}) { - if ($vpnsettings{'ENABLED'} eq 'on' || - $vpnsettings{'ENABLED_BLUE'} eq 'on') { - system('/usr/local/bin/ipsecctrl', 'D', $cgiparams{'KEY'}); - } - unlink ("${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem"); - unlink ("${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1].p12"); - delete $confighash{$cgiparams{'KEY'}}; - &General::writehasharray("${General::swroot}/vpn/config", \%confighash); - &writeipsecfiles(); - } else { - $errormessage = $Lang::tr{'invalid key'}; - } - -### -### Choose between adding a host-net or net-net connection -### -} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'add'} && $cgiparams{'TYPE'} eq '') { - &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); - &Header::showhttpheaders(); - &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); - &Header::openbigbox('100%', 'LEFT', '', ''); - &Header::openbox('100%', 'LEFT', $Lang::tr{'connection type'}); - print <$Lang::tr{'connection type'}:
- - - - - - -
$Lang::tr{'host to net vpn'}
$Lang::tr{'net to net vpn'}
-END - ; - &Header::closebox(); - &Header::closebigbox(); - &Header::closepage(); - exit (0); -### -### Adding a new connection -### -} elsif (($cgiparams{'ACTION'} eq $Lang::tr{'add'}) || - ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}) || - ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'ADVANCED'} eq '')) { - - &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); - &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); - &General::readhasharray("${General::swroot}/vpn/config", \%confighash); - - if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}) { - if (! $confighash{$cgiparams{'KEY'}}[0]) { - $errormessage = $Lang::tr{'invalid key'}; - goto VPNCONF_END; - } - $cgiparams{'ENABLED'} = $confighash{$cgiparams{'KEY'}}[0]; - $cgiparams{'NAME'} = $confighash{$cgiparams{'KEY'}}[1]; - $cgiparams{'TYPE'} = $confighash{$cgiparams{'KEY'}}[3]; - $cgiparams{'AUTH'} = $confighash{$cgiparams{'KEY'}}[4]; - $cgiparams{'PSK'} = $confighash{$cgiparams{'KEY'}}[5]; - $cgiparams{'SIDE'} = $confighash{$cgiparams{'KEY'}}[6]; - $cgiparams{'LOCAL_ID'} = $confighash{$cgiparams{'KEY'}}[7]; - $cgiparams{'LOCAL_SUBNET'} = $confighash{$cgiparams{'KEY'}}[8]; - $cgiparams{'REMOTE_ID'} = $confighash{$cgiparams{'KEY'}}[9]; - $cgiparams{'REMOTE'} = $confighash{$cgiparams{'KEY'}}[10]; - $cgiparams{'REMOTE_SUBNET'} = $confighash{$cgiparams{'KEY'}}[11]; - $cgiparams{'REMARK'} = $confighash{$cgiparams{'KEY'}}[25]; - $cgiparams{'INTERFACE'} = $confighash{$cgiparams{'KEY'}}[26]; - $cgiparams{'DPD_ACTION'}= $confighash{$cgiparams{'KEY'}}[27]; - $cgiparams{'PFS_YES_NO'}= $confighash{$cgiparams{'KEY'}}[28]; - - } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'save'}) { - $cgiparams{'REMARK'} = &Header::cleanhtml($cgiparams{'REMARK'}); - if ($cgiparams{'TYPE'} !~ /^(host|net)$/) { - $errormessage = $Lang::tr{'connection type is invalid'}; - goto VPNCONF_ERROR; - } - - if ($cgiparams{'NAME'} !~ /^[a-zA-Z0-9]+$/) { - $errormessage = $Lang::tr{'name must only contain characters'}; - goto VPNCONF_ERROR; - } - - if ($cgiparams{'NAME'} =~ /^(host|01|block|private|clear|packetdefault)$/) { - $errormessage = $Lang::tr{'name is invalid'}; - goto VPNCONF_ERROR; - } - - if (length($cgiparams{'NAME'}) >60) { - $errormessage = $Lang::tr{'name too long'}; - goto VPNCONF_ERROR; - } - - if (($cgiparams{'TYPE'} eq 'net') && ($cgiparams{'SIDE'} !~ /^(left|right)$/)) { - $errormessage = $Lang::tr{'ipcop side is invalid'}; - goto VPNCONF_ERROR; - } - - # Check if there is no other entry with this name - if (! $cgiparams{'KEY'}) { - foreach my $key (keys %confighash) { - if ($confighash{$key}[1] eq $cgiparams{'NAME'}) { - $errormessage = $Lang::tr{'a connection with this name already exists'}; - goto VPNCONF_ERROR; - } - } - } - - if (($cgiparams{'TYPE'} eq 'net') && (! $cgiparams{'REMOTE'})) { - $errormessage = $Lang::tr{'invalid input for remote host/ip'}; - goto VPNCONF_ERROR; - } - - if ($cgiparams{'REMOTE'}) { - if (! &General::validip($cgiparams{'REMOTE'})) { - if (! &General::validfqdn ($cgiparams{'REMOTE'})) { - $errormessage = $Lang::tr{'invalid input for remote host/ip'}; - goto VPNCONF_ERROR; - } else { - if (&valid_dns_host($cgiparams{'REMOTE'})) { - $warnmessage = "$Lang::tr{'check vpn lr'} $cgiparams{'REMOTE'}. $Lang::tr{'dns check failed'}"; - } - } - } - } - - unless (&General::validipandmask($cgiparams{'LOCAL_SUBNET'})) { - $errormessage = $Lang::tr{'local subnet is invalid'}; - goto VPNCONF_ERROR; - } - - # Check if there is no other entry without IP-address and PSK - if ($cgiparams{'REMOTE'} eq '') { - foreach my $key (keys %confighash) { - if(($cgiparams{'KEY'} ne $key) && - ($confighash{$key}[4] eq 'psk' || $cgiparams{'AUTH'} eq 'psk') && - $confighash{$key}[10] eq '') { - $errormessage = $Lang::tr{'you can only define one roadwarrior connection when using pre-shared key authentication'}; - goto VPNCONF_ERROR; - } - } - } - if (($cgiparams{'TYPE'} eq 'net') && (! &General::validipandmask($cgiparams{'REMOTE_SUBNET'}))) { - $errormessage = $Lang::tr{'remote subnet is invalid'}; - goto VPNCONF_ERROR; - } - - if ($cgiparams{'ENABLED'} !~ /^(on|off)$/) { - $errormessage = $Lang::tr{'invalid input'}; - goto VPNCONF_ERROR; - } - if ($cgiparams{'EDIT_ADVANCED'} !~ /^(on|off)$/) { - $errormessage = $Lang::tr{'invalid input'}; - goto VPNCONF_ERROR; - } - - if (($cgiparams{'LOCAL_ID'} !~ /^(|@[a-zA-Z0-9_.-]*)$/) || - ($cgiparams{'REMOTE_ID'} !~ /^(|@[a-zA-Z0-9_.-]*)$/) || - (($cgiparams{'REMOTE_ID'} eq $cgiparams{'LOCAL_ID'}) && ($cgiparams{'LOCAL_ID'} ne '')) - ) { - $errormessage = $Lang::tr{'invalid local-remote id'}; - goto VPNCONF_ERROR; - } - - if ($cgiparams{'AUTH'} eq 'psk') { - if (! length($cgiparams{'PSK'}) ) { - $errormessage = $Lang::tr{'pre-shared key is too short'}; - goto VPNCONF_ERROR; - } - if ($cgiparams{'PSK'} =~ /['",&]/) { # " ' correct coloring syntax editor ! - $errormessage = $Lang::tr{'invalid characters found in pre-shared key'}; - goto VPNCONF_ERROR; - } - } elsif ($cgiparams{'AUTH'} eq 'certreq') { - if ($cgiparams{'KEY'}) { - $errormessage = $Lang::tr{'cant change certificates'}; - goto VPNCONF_ERROR; - } - if (ref ($cgiparams{'FH'}) ne 'Fh') { - $errormessage = $Lang::tr{'there was no file upload'}; - goto VPNCONF_ERROR; - } - - # Move uploaded certificate request to a temporary file - (my $fh, my $filename) = tempfile( ); - if (copy ($cgiparams{'FH'}, $fh) != 1) { - $errormessage = $!; - goto VPNCONF_ERROR; - } - - # Sign the certificate request and move it - # Sign the host certificate request - system('/usr/bin/openssl', 'ca', '-days', '999999', - '-batch', '-notext', - '-in', $filename, - '-out', "${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); - if ($?) { - $errormessage = "$Lang::tr{'openssl produced an error'}: $?"; - unlink ($filename); - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); - &cleanssldatabase(); - goto VPNCONF_ERROR; - } else { - unlink ($filename); - &cleanssldatabase(); - } - - my $temp = `/usr/bin/openssl x509 -text -in ${General::swroot}/certs/$cgiparams{'NAME'}cert.pem`; - $temp =~ /Subject:.*CN=(.*)[\n]/; - $temp = $1; - $temp =~ s+/Email+, E+; - $temp =~ s/ ST=/ S=/; - $cgiparams{'CERT_NAME'} = $temp; - $cgiparams{'CERT_NAME'} =~ s/,//g; - $cgiparams{'CERT_NAME'} =~ s/\'//g; - if ($cgiparams{'CERT_NAME'} eq '') { - $errormessage = $Lang::tr{'could not retrieve common name from certificate'}; - goto VPNCONF_ERROR; - } - } elsif ($cgiparams{'AUTH'} eq 'certfile') { - if ($cgiparams{'KEY'}) { - $errormessage = $Lang::tr{'cant change certificates'}; - goto VPNCONF_ERROR; - } - if (ref ($cgiparams{'FH'}) ne 'Fh') { - $errormessage = $Lang::tr{'there was no file upload'}; - goto VPNCONF_ERROR; - } - # Move uploaded certificate to a temporary file - (my $fh, my $filename) = tempfile( ); - if (copy ($cgiparams{'FH'}, $fh) != 1) { - $errormessage = $!; - goto VPNCONF_ERROR; - } - - # Verify the certificate has a valid CA and move it - my $validca = 0; - my $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/cacert.pem $filename`; - if ($test =~ /: OK/) { - $validca = 1; - } else { - foreach my $key (keys %cahash) { - $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/$cahash{$key}[0]cert.pem $filename`; - if ($test =~ /: OK/) { - $validca = 1; - } - } - } - if (! $validca) { - $errormessage = $Lang::tr{'certificate does not have a valid ca associated with it'}; - unlink ($filename); - goto VPNCONF_ERROR; - } else { - move($filename, "${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); - if ($? ne 0) { - $errormessage = "$Lang::tr{'certificate file move failed'}: $!"; - unlink ($filename); - goto VPNCONF_ERROR; - } - } - - my $temp = `/usr/bin/openssl x509 -text -in ${General::swroot}/certs/$cgiparams{'NAME'}cert.pem`; - $temp =~ /Subject:.*CN=(.*)[\n]/; - $temp = $1; - $temp =~ s+/Email+, E+; - $temp =~ s/ ST=/ S=/; - $cgiparams{'CERT_NAME'} = $temp; - $cgiparams{'CERT_NAME'} =~ s/,//g; - $cgiparams{'CERT_NAME'} =~ s/\'//g; - if ($cgiparams{'CERT_NAME'} eq '') { - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); - $errormessage = $Lang::tr{'could not retrieve common name from certificate'}; - goto VPNCONF_ERROR; - } - } elsif ($cgiparams{'AUTH'} eq 'certgen') { - if ($cgiparams{'KEY'}) { - $errormessage = $Lang::tr{'cant change certificates'}; - goto VPNCONF_ERROR; - } - # Validate input since the form was submitted - if (length($cgiparams{'CERT_NAME'}) >60) { - $errormessage = $Lang::tr{'name too long'}; - goto VPNCONF_ERROR; - } - if ($cgiparams{'CERT_NAME'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) { - $errormessage = $Lang::tr{'invalid input for name'}; - goto VPNCONF_ERROR; - } - if ($cgiparams{'CERT_EMAIL'} ne '' && (! &General::validemail($cgiparams{'CERT_EMAIL'}))) { - $errormessage = $Lang::tr{'invalid input for e-mail address'}; - goto VPNCONF_ERROR; - } - if (length($cgiparams{'CERT_EMAIL'}) > 40) { - $errormessage = $Lang::tr{'e-mail address too long'}; - goto VPNCONF_ERROR; - } - if ($cgiparams{'CERT_OU'} ne '' && $cgiparams{'CERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { - $errormessage = $Lang::tr{'invalid input for department'}; - goto VPNCONF_ERROR; - } - if (length($cgiparams{'CERT_ORGANIZATION'}) >60) { - $errormessage = $Lang::tr{'organization too long'}; - goto VPNCONF_ERROR; - } - if ($cgiparams{'CERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) { - $errormessage = $Lang::tr{'invalid input for organization'}; - goto VPNCONF_ERROR; - } - if ($cgiparams{'CERT_CITY'} ne '' && $cgiparams{'CERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { - $errormessage = $Lang::tr{'invalid input for city'}; - goto VPNCONF_ERROR; - } - if ($cgiparams{'CERT_STATE'} ne '' && $cgiparams{'CERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { - $errormessage = $Lang::tr{'invalid input for state or province'}; - goto VPNCONF_ERROR; - } - if ($cgiparams{'CERT_COUNTRY'} !~ /^[A-Z]*$/) { - $errormessage = $Lang::tr{'invalid input for country'}; - goto VPNCONF_ERROR; - } - if (length($cgiparams{'CERT_PASS1'}) < 5) { - $errormessage = $Lang::tr{'password too short'}; - goto VPNCONF_ERROR; - } - if ($cgiparams{'CERT_PASS1'} ne $cgiparams{'CERT_PASS2'}) { - $errormessage = $Lang::tr{'passwords do not match'}; - goto VPNCONF_ERROR; - } - - # Replace empty strings with a . - (my $ou = $cgiparams{'CERT_OU'}) =~ s/^\s*$/\./; - (my $city = $cgiparams{'CERT_CITY'}) =~ s/^\s*$/\./; - (my $state = $cgiparams{'CERT_STATE'}) =~ s/^\s*$/\./; - - # Create the Host certificate request - my $pid = open(OPENSSL, "|-"); - $SIG{ALRM} = sub { $errormessage = $Lang::tr{'broken pipe'}; goto VPNCONF_ERROR;}; - if ($pid) { # parent - print OPENSSL "$cgiparams{'CERT_COUNTRY'}\n"; - print OPENSSL "$state\n"; - print OPENSSL "$city\n"; - print OPENSSL "$cgiparams{'CERT_ORGANIZATION'}\n"; - print OPENSSL "$ou\n"; - print OPENSSL "$cgiparams{'CERT_NAME'}\n"; - print OPENSSL "$cgiparams{'CERT_EMAIL'}\n"; - print OPENSSL ".\n"; - print OPENSSL ".\n"; - close (OPENSSL); - if ($?) { - $errormessage = "$Lang::tr{'openssl produced an error'}: $?"; - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}key.pem"); - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}req.pem"); - goto VPNCONF_ERROR; - } - } else { # child - unless (exec ('/usr/bin/openssl', 'req', '-nodes', '-rand', '/proc/interrupts:/proc/net/rt_cache', - '-newkey', 'rsa:1024', - '-keyout', "${General::swroot}/certs/$cgiparams{'NAME'}key.pem", - '-out', "${General::swroot}/certs/$cgiparams{'NAME'}req.pem")) { - $errormessage = "$Lang::tr{'cant start openssl'}: $!"; - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}key.pem"); - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}req.pem"); - goto VPNCONF_ERROR; - } - } - - # Sign the host certificate request - system('/usr/bin/openssl', 'ca', '-days', '999999', - '-batch', '-notext', - '-in', "${General::swroot}/certs/$cgiparams{'NAME'}req.pem", - '-out', "${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); - if ($?) { - $errormessage = "$Lang::tr{'openssl produced an error'}: $?"; - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}key.pem"); - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}req.pem"); - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); - &cleanssldatabase(); - goto VPNCONF_ERROR; - } else { - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}req.pem"); - &cleanssldatabase(); - } - - # Create the pkcs12 file - system('/usr/bin/openssl', 'pkcs12', '-export', - '-inkey', "${General::swroot}/certs/$cgiparams{'NAME'}key.pem", - '-in', "${General::swroot}/certs/$cgiparams{'NAME'}cert.pem", - '-name', $cgiparams{'NAME'}, - '-passout', "pass:$cgiparams{'CERT_PASS1'}", - '-certfile', "${General::swroot}/ca/cacert.pem", - '-caname', "$vpnsettings{'ROOTCERT_ORGANIZATION'} CA", - '-out', "${General::swroot}/certs/$cgiparams{'NAME'}.p12"); - if ($?) { - $errormessage = "$Lang::tr{'openssl produced an error'}: $?"; - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}key.pem"); - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}.p12"); - goto VPNCONF_ERROR; - } else { - unlink ("${General::swroot}/certs/$cgiparams{'NAME'}key.pem"); - } - } elsif ($cgiparams{'AUTH'} eq 'cert') { - ;# Nothing, just editing - } else { - $errormessage = $Lang::tr{'invalid input for authentication method'}; - goto VPNCONF_ERROR; - } - - # Check if there is no other entry with this common name - if ((! $cgiparams{'KEY'}) && ($cgiparams{'AUTH'} ne 'psk')) { - foreach my $key (keys %confighash) { - if ($confighash{$key}[2] eq $cgiparams{'CERT_NAME'}) { - $errormessage = $Lang::tr{'a connection with this common name already exists'}; - goto VPNCONF_ERROR; - } - } - } - - # Save the config - my $key = $cgiparams{'KEY'}; - if (! $key) { - $key = &General::findhasharraykey (\%confighash); - foreach my $i (0 .. 28) { $confighash{$key}[$i] = "";} - } - $confighash{$key}[0] = $cgiparams{'ENABLED'}; - $confighash{$key}[1] = $cgiparams{'NAME'}; - if ((! $cgiparams{'KEY'}) && $cgiparams{'AUTH'} ne 'psk') { - $confighash{$key}[2] = $cgiparams{'CERT_NAME'}; - } - $confighash{$key}[3] = $cgiparams{'TYPE'}; - if ($cgiparams{'AUTH'} eq 'psk') { - $confighash{$key}[4] = 'psk'; - $confighash{$key}[5] = $cgiparams{'PSK'}; - } else { - $confighash{$key}[4] = 'cert'; - } - if ($cgiparams{'TYPE'} eq 'net') { - $confighash{$key}[6] = $cgiparams{'SIDE'}; - $confighash{$key}[11] = $cgiparams{'REMOTE_SUBNET'}; - } - $confighash{$key}[7] = $cgiparams{'LOCAL_ID'}; - $confighash{$key}[8] = $cgiparams{'LOCAL_SUBNET'}; - $confighash{$key}[9] = $cgiparams{'REMOTE_ID'}; - $confighash{$key}[10] = $cgiparams{'REMOTE'}; - $confighash{$key}[25] = $cgiparams{'REMARK'}; - $confighash{$key}[26] = $cgiparams{'INTERFACE'}; - $confighash{$key}[27] = $cgiparams{'DPD_ACTION'}; - $confighash{$key}[28] = $cgiparams{'PFS_YES_NO'}; - - #use default advanced value - $confighash{$key}[14] = 'on'; - $confighash{$key}[13] = 'off'; - $confighash{$key}[18] = 'aes128|3des'; - $confighash{$key}[19] = 'sha|md5'; - $confighash{$key}[20] = '1536|1024'; - $confighash{$key}[16] = '1'; - $confighash{$key}[21] = 'aes128|3des'; - $confighash{$key}[22] = 'sha1|md5'; - $confighash{$key}[23] = ''; - $confighash{$key}[17] = '8'; - $confighash{$key}[24] = 'off'; - - #free unused fields! - #$confighash{$key}[12] = ''; - #$confighash{$key}[15] = ''; - - &General::writehasharray("${General::swroot}/vpn/config", \%confighash); - &writeipsecfiles(); - if ($vpnsettings{'ENABLED'} eq 'on' || - $vpnsettings{'ENABLED_BLUE'} eq 'on') { - system('/usr/local/bin/ipsecctrl', 'S', $key); - sleep $sleepDelay; - } - if ($cgiparams{'EDIT_ADVANCED'} eq 'on') { - $cgiparams{'KEY'} = $key; - $cgiparams{'ACTION'} = $Lang::tr{'advanced'}; - } - goto VPNCONF_END; - } else { # add new connection - $cgiparams{'ENABLED'} = 'on'; - $cgiparams{'SIDE'} = 'left'; - if ( ! -f "${General::swroot}/private/cakey.pem" ) { - $cgiparams{'AUTH'} = 'psk'; - } elsif ( ! -f "${General::swroot}/ca/cacert.pem") { - $cgiparams{'AUTH'} = 'certfile'; - } else { - $cgiparams{'AUTH'} = 'certgen'; - } - $cgiparams{'LOCAL_SUBNET'} ="$netsettings{'GREEN_NETADDRESS'}/$netsettings{'GREEN_NETMASK'}"; - $cgiparams{'CERT_ORGANIZATION'} = $vpnsettings{'ROOTCERT_ORGANIZATION'}; - $cgiparams{'CERT_CITY'} = $vpnsettings{'ROOTCERT_CITY'}; - $cgiparams{'CERT_STATE'} = $vpnsettings{'ROOTCERT_STATE'}; - $cgiparams{'CERT_COUNTRY'} = $vpnsettings{'ROOTCERT_COUNTRY'}; - - # choose appropriate dpd action - if ($cgiparams{'TYPE'} eq 'host') { - $cgiparams{'DPD_ACTION'} = 'clear'; - } else { - $cgiparams{'DPD_ACTION'} = 'hold'; #restart when available! - } - - # Default is yes for 'pfs' - $cgiparams{'PFS_YES_NO'} = 'yes'; - - # ID are empty - $cgiparams{'LOCAL_ID'} = ''; - $cgiparams{'REMOTE_ID'} = ''; - - } - - VPNCONF_ERROR: - $checked{'ENABLED'}{'off'} = ''; - $checked{'ENABLED'}{'on'} = ''; - $checked{'ENABLED'}{$cgiparams{'ENABLED'}} = "checked='checked'"; - $checked{'ENABLED_BLUE'}{'off'} = ''; - $checked{'ENABLED_BLUE'}{'on'} = ''; - $checked{'ENABLED_BLUE'}{$cgiparams{'ENABLED_BLUE'}} = "checked='checked'"; - - $checked{'EDIT_ADVANCED'}{'off'} = ''; - $checked{'EDIT_ADVANCED'}{'on'} = ''; - $checked{'EDIT_ADVANCED'}{$cgiparams{'EDIT_ADVANCED'}} = "checked='checked'"; - - $selected{'SIDE'}{'left'} = ''; - $selected{'SIDE'}{'right'} = ''; - $selected{'SIDE'}{$cgiparams{'SIDE'}} = "selected='selected'"; - - $checked{'AUTH'}{'psk'} = ''; - $checked{'AUTH'}{'certreq'} = ''; - $checked{'AUTH'}{'certgen'} = ''; - $checked{'AUTH'}{'certfile'} = ''; - $checked{'AUTH'}{$cgiparams{'AUTH'}} = "checked='checked'"; - - $selected{'INTERFACE'}{$cgiparams{'INTERFACE'}} = "selected='selected'"; - $selected{'DPD_ACTION'}{$cgiparams{'DPD_ACTION'}} = "selected='selected'"; - $selected{'PFS_YES_NO'}{$cgiparams{'PFS_YES_NO'}} = "selected='selected'"; - - if (1) { - &Header::showhttpheaders(); - &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); - &Header::openbigbox('100%', 'LEFT', '', $errormessage); - if ($errormessage) { - &Header::openbox('100%', 'LEFT', $Lang::tr{'error messages'}); - print "$errormessage"; - print " "; - &Header::closebox(); - } - - if ($warnmessage) { - &Header::openbox('100%', 'LEFT', "$Lang::tr{'warning messages'}:"); - print "$warnmessage"; - print " "; - &Header::closebox(); - } - - print "
"; - print ""; - - if ($cgiparams{'KEY'}) { - print ""; - print ""; - } - - &Header::openbox('100%', 'LEFT', "$Lang::tr{'connection'}:"); - print ""; - print ""; - if ($cgiparams{'KEY'}) { - print ""; - } else { - print ""; - } - print ""; - - if ($cgiparams{'TYPE'} eq 'host') { - - print ""; - print ""; - print < - - - - - -END - ; - } else { - print < - - - - - - - - -END - ; - } - print < - - - - - - - - - - -END - ; - if (!$cgiparams{'KEY'}) { - print ""; - } - print "
$Lang::tr{'name'}:$cgiparams{'NAME'}$Lang::tr{'enabled'}
$Lang::tr{'interface'}
$Lang::tr{'local subnet'} 
$Lang::tr{'remote host/ip'}: * 
$Lang::tr{'ipcop side'}$Lang::tr{'remote host/ip'}:
$Lang::tr{'local subnet'}$Lang::tr{'remote subnet'}
$Lang::tr{'dpd action'}:  ? $Lang::tr{'pfs yes no'}:
$Lang::tr{'options'}
leftid: * -
($Lang::tr{'eg'} @xy.example.com)
rightid: *
$Lang::tr{'remark title'} *
$Lang::tr{'edit advanced settings when done'}
"; - &Header::closebox(); - - if ($cgiparams{'KEY'} && $cgiparams{'AUTH'} eq 'psk') { - &Header::openbox('100%', 'LEFT', $Lang::tr{'authentication'}); - print < - $Lang::tr{'use a pre-shared key'} - - -END - ; - &Header::closebox(); - } elsif (! $cgiparams{'KEY'}) { - my $disabled=''; - my $cakeydisabled=''; - my $cacrtdisabled=''; - if ( ! -f "${General::swroot}/private/cakey.pem" ) { $cakeydisabled = "disabled='disabled'" } else { $cakeydisabled = "" }; - if ( ! -f "${General::swroot}/ca/cacert.pem" ) { $cacrtdisabled = "disabled='disabled'" } else { $cacrtdisabled = "" }; - &Header::openbox('100%', 'LEFT', $Lang::tr{'authentication'}); - print < - - $Lang::tr{'use a pre-shared key'} - - - - $Lang::tr{'upload a certificate request'} - - - $Lang::tr{'upload a certificate'} - - - $Lang::tr{'generate a certificate'}  -   - $Lang::tr{'users fullname or system hostname'}: - -   - $Lang::tr{'users email'}: * - -   - $Lang::tr{'users department'}: * - -   - $Lang::tr{'organization name'}: * - -   - $Lang::tr{'city'}: * - -   - $Lang::tr{'state or province'}: * - -   - $Lang::tr{'country'}: - -  $Lang::tr{'pkcs12 file password'}:
($Lang::tr{'confirmation'}) - - -END - ; - &Header::closebox(); - } - - print "
"; - if ($cgiparams{'KEY'}) { - print ""; - } - print "
"; - &Header::closebigbox(); - &Header::closepage(); - exit (0); - } - VPNCONF_END: -} - -### -### Advanced settings -### -if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) || - ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'ADVANCED'} eq 'yes')) { - &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); - &General::readhasharray("${General::swroot}/vpn/config", \%confighash); - if (! $confighash{$cgiparams{'KEY'}}) { - $errormessage = $Lang::tr{'invalid key'}; - goto ADVANCED_END; - } - - if ($cgiparams{'ACTION'} eq $Lang::tr{'save'}) { - if ($cgiparams{'NAT'} !~ /^(on|off)$/) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - if ($cgiparams{'COMPRESSION'} !~ /^(on|off)$/) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - if ($cgiparams{'NAT'} eq 'on' && $cgiparams{'COMPRESSION'} eq 'on') { - $errormessage = $Lang::tr{'cannot enable both nat traversal and compression'}; - goto ADVANCED_ERROR; - } - my @temp = split('\|', $cgiparams{'IKE_ENCRYPTION'}); - if ($#temp < 0) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - foreach my $val (@temp) { - if ($val !~ /^(aes256|aes128|3des|twofish256|twofish128|serpent256|serpent128|blowfish256|blowfish128|cast128)$/) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - } - @temp = split('\|', $cgiparams{'IKE_INTEGRITY'}); - if ($#temp < 0) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - foreach my $val (@temp) { - if ($val !~ /^(sha2_512|sha2_256|sha|md5)$/) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - } - @temp = split('\|', $cgiparams{'IKE_GROUPTYPE'}); - if ($#temp < 0) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - foreach my $val (@temp) { - if ($val !~ /^(768|1024|1536|2048|3072|4096|6144|8192)$/) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - } - if ($cgiparams{'IKE_LIFETIME'} !~ /^\d+$/) { - $errormessage = $Lang::tr{'invalid input for ike lifetime'}; - goto ADVANCED_ERROR; - } - if ($cgiparams{'IKE_LIFETIME'} < 1 || $cgiparams{'IKE_LIFETIME'} > 8) { - $errormessage = $Lang::tr{'ike lifetime should be between 1 and 8 hours'}; - goto ADVANCED_ERROR; - } - @temp = split('\|', $cgiparams{'ESP_ENCRYPTION'}); - if ($#temp < 0) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - foreach my $val (@temp) { - if ($val !~ /^(aes256|aes128|3des|twofish256|twofish128|serpent256|serpent128|blowfish256|blowfish128)$/) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - } - @temp = split('\|', $cgiparams{'ESP_INTEGRITY'}); - if ($#temp < 0) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - foreach my $val (@temp) { - if ($val !~ /^(sha2_512|sha2_256|sha1|md5)$/) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - } - if ($cgiparams{'ESP_GROUPTYPE'} ne '' && - $cgiparams{'ESP_GROUPTYPE'} !~ /^modp(768|1024|1536|2048|3072|4096)$/) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - - if ($cgiparams{'ESP_KEYLIFE'} !~ /^\d+$/) { - $errormessage = $Lang::tr{'invalid input for esp keylife'}; - goto ADVANCED_ERROR; - } - if ($cgiparams{'ESP_KEYLIFE'} < 1 || $cgiparams{'ESP_KEYLIFE'} > 24) { - $errormessage = $Lang::tr{'esp keylife should be between 1 and 24 hours'}; - goto ADVANCED_ERROR; - } - if ($cgiparams{'ONLY_PROPOSED'} !~ /^(on|off)$/) { - $errormessage = $Lang::tr{'invalid input'}; - goto ADVANCED_ERROR; - } - $confighash{$cgiparams{'KEY'}}[14] = $cgiparams{'NAT'}; - $confighash{$cgiparams{'KEY'}}[13] = $cgiparams{'COMPRESSION'}; - $confighash{$cgiparams{'KEY'}}[18] = $cgiparams{'IKE_ENCRYPTION'}; - $confighash{$cgiparams{'KEY'}}[19] = $cgiparams{'IKE_INTEGRITY'}; - $confighash{$cgiparams{'KEY'}}[20] = $cgiparams{'IKE_GROUPTYPE'}; - $confighash{$cgiparams{'KEY'}}[16] = $cgiparams{'IKE_LIFETIME'}; - $confighash{$cgiparams{'KEY'}}[21] = $cgiparams{'ESP_ENCRYPTION'}; - $confighash{$cgiparams{'KEY'}}[22] = $cgiparams{'ESP_INTEGRITY'}; - $confighash{$cgiparams{'KEY'}}[23] = $cgiparams{'ESP_GROUPTYPE'}; - $confighash{$cgiparams{'KEY'}}[17] = $cgiparams{'ESP_KEYLIFE'}; - $confighash{$cgiparams{'KEY'}}[24] = $cgiparams{'ONLY_PROPOSED'}; - &General::writehasharray("${General::swroot}/vpn/config", \%confighash); - &writeipsecfiles(); - if ($vpnsettings{'ENABLED'} eq 'on' || - $vpnsettings{'ENABLED_BLUE'} eq 'on') { - system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'}); - sleep $sleepDelay; - } - goto ADVANCED_END; - } else { - - $cgiparams{'NAT'} = $confighash{$cgiparams{'KEY'}}[14]; - $cgiparams{'COMPRESSION'} = $confighash{$cgiparams{'KEY'}}[13]; - $cgiparams{'IKE_ENCRYPTION'} = $confighash{$cgiparams{'KEY'}}[18]; - $cgiparams{'IKE_INTEGRITY'} = $confighash{$cgiparams{'KEY'}}[19]; - $cgiparams{'IKE_GROUPTYPE'} = $confighash{$cgiparams{'KEY'}}[20]; - $cgiparams{'IKE_LIFETIME'} = $confighash{$cgiparams{'KEY'}}[16]; - $cgiparams{'ESP_ENCRYPTION'} = $confighash{$cgiparams{'KEY'}}[21]; - $cgiparams{'ESP_INTEGRITY'} = $confighash{$cgiparams{'KEY'}}[22]; - $cgiparams{'ESP_GROUPTYPE'} = $confighash{$cgiparams{'KEY'}}[23]; - $cgiparams{'ESP_KEYLIFE'} = $confighash{$cgiparams{'KEY'}}[17]; - $cgiparams{'ONLY_PROPOSED'} = $confighash{$cgiparams{'KEY'}}[24]; - - if ($confighash{$cgiparams{'KEY'}}[3] eq 'net' || $confighash{$cgiparams{'KEY'}}[10]) { - $cgiparams{'NAT'} = 'off'; - } - } - - ADVANCED_ERROR: - $checked{'NAT'}{'off'} = ''; - $checked{'NAT'}{'on'} = ''; - $checked{'NAT'}{$cgiparams{'NAT'}} = "checked='checked'"; - $checked{'COMPRESSION'}{'off'} = ''; - $checked{'COMPRESSION'}{'on'} = ''; - $checked{'COMPRESSION'}{$cgiparams{'COMPRESSION'}} = "checked='checked'"; - $checked{'IKE_ENCRYPTION'}{'aes256'} = ''; - $checked{'IKE_ENCRYPTION'}{'aes128'} = ''; - $checked{'IKE_ENCRYPTION'}{'3des'} = ''; - $checked{'IKE_ENCRYPTION'}{'twofish256'} = ''; - $checked{'IKE_ENCRYPTION'}{'twofish128'} = ''; - $checked{'IKE_ENCRYPTION'}{'serpent256'} = ''; - $checked{'IKE_ENCRYPTION'}{'serpent128'} = ''; - $checked{'IKE_ENCRYPTION'}{'blowfish256'} = ''; - $checked{'IKE_ENCRYPTION'}{'blowfish128'} = ''; - $checked{'IKE_ENCRYPTION'}{'cast128'} = ''; - my @temp = split('\|', $cgiparams{'IKE_ENCRYPTION'}); - foreach my $key (@temp) {$checked{'IKE_ENCRYPTION'}{$key} = "selected='selected'"; } - $checked{'IKE_INTEGRITY'}{'sha2_512'} = ''; - $checked{'IKE_INTEGRITY'}{'sha2_256'} = ''; - $checked{'IKE_INTEGRITY'}{'sha'} = ''; - $checked{'IKE_INTEGRITY'}{'md5'} = ''; - @temp = split('\|', $cgiparams{'IKE_INTEGRITY'}); - foreach my $key (@temp) {$checked{'IKE_INTEGRITY'}{$key} = "selected='selected'"; } - $checked{'IKE_GROUPTYPE'}{'768'} = ''; - $checked{'IKE_GROUPTYPE'}{'1024'} = ''; - $checked{'IKE_GROUPTYPE'}{'1536'} = ''; - $checked{'IKE_GROUPTYPE'}{'2048'} = ''; - $checked{'IKE_GROUPTYPE'}{'3072'} = ''; - $checked{'IKE_GROUPTYPE'}{'4096'} = ''; - $checked{'IKE_GROUPTYPE'}{'6144'} = ''; - $checked{'IKE_GROUPTYPE'}{'8192'} = ''; - @temp = split('\|', $cgiparams{'IKE_GROUPTYPE'}); - foreach my $key (@temp) {$checked{'IKE_GROUPTYPE'}{$key} = "selected='selected'"; } - $checked{'ESP_ENCRYPTION'}{'aes256'} = ''; - $checked{'ESP_ENCRYPTION'}{'aes128'} = ''; - $checked{'ESP_ENCRYPTION'}{'3des'} = ''; - $checked{'ESP_ENCRYPTION'}{'twofish256'} = ''; - $checked{'ESP_ENCRYPTION'}{'twofish128'} = ''; - $checked{'ESP_ENCRYPTION'}{'serpent256'} = ''; - $checked{'ESP_ENCRYPTION'}{'serpent128'} = ''; - $checked{'ESP_ENCRYPTION'}{'blowfish256'} = ''; - $checked{'ESP_ENCRYPTION'}{'blowfish128'} = ''; - @temp = split('\|', $cgiparams{'ESP_ENCRYPTION'}); - foreach my $key (@temp) {$checked{'ESP_ENCRYPTION'}{$key} = "selected='selected'"; } - $checked{'ESP_INTEGRITY'}{'sha2_512'} = ''; - $checked{'ESP_INTEGRITY'}{'sha2_256'} = ''; - $checked{'ESP_INTEGRITY'}{'sha1'} = ''; - $checked{'ESP_INTEGRITY'}{'md5'} = ''; - @temp = split('\|', $cgiparams{'ESP_INTEGRITY'}); - foreach my $key (@temp) {$checked{'ESP_INTEGRITY'}{$key} = "selected='selected'"; } - $checked{'ESP_GROUPTYPE'}{'modp768'} = ''; - $checked{'ESP_GROUPTYPE'}{'modp1024'} = ''; - $checked{'ESP_GROUPTYPE'}{'modp1536'} = ''; - $checked{'ESP_GROUPTYPE'}{'modp2048'} = ''; - $checked{'ESP_GROUPTYPE'}{'modp3072'} = ''; - $checked{'ESP_GROUPTYPE'}{'modp4096'} = ''; - $checked{'ESP_GROUPTYPE'}{$cgiparams{'ESP_GROUPTYPE'}} = "selected='selected'"; - $checked{'ONLY_PROPOSED'}{'off'} = ''; - $checked{'ONLY_PROPOSED'}{'on'} = ''; - $checked{'ONLY_PROPOSED'}{$cgiparams{'ONLY_PROPOSED'}} = "checked='checked'"; - - &Header::showhttpheaders(); - &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); - &Header::openbigbox('100%', 'LEFT', '', $errormessage); - - if ($errormessage) { - &Header::openbox('100%', 'LEFT', $Lang::tr{'error messages'}); - print "$errormessage"; - print " "; - &Header::closebox(); - } - - if ($warnmessage) { - &Header::openbox('100%', 'LEFT', $Lang::tr{'warning messages'}); - print "$warnmessage"; - print " "; - &Header::closebox(); - } - - print "
\n"; - print "\n"; - print "\n"; - - &Header::openbox('100%', 'LEFT', "$Lang::tr{'advanced'}:"); - print "\n"; - print "\n"; - print "\n"; - if ($confighash{$cgiparams{'KEY'}}[3] eq 'net') { - print "\n"; - } elsif ($confighash{$cgiparams{'KEY'}}[10]) { - print "\n"; - print "\n"; - } else { - print "\n"; - print "\n"; - } - print < - - - - - - - - - - - - - - - - -
$Lang::tr{'compression'} 
$Lang::tr{'nat-traversal'}
$Lang::tr{'nat-traversal'}
$Lang::tr{'ike encryption'}$Lang::tr{'ike integrity'}
$Lang::tr{'ike lifetime'} $Lang::tr{'hours'}$Lang::tr{'ike grouptype'}
$Lang::tr{'esp encryption'}$Lang::tr{'esp integrity'}
$Lang::tr{'esp keylife'} $Lang::tr{'hours'}$Lang::tr{'esp grouptype'}
- $Lang::tr{'use only proposed settings'}
-EOF - ; - &Header::closebox(); - print "
"; - print "
"; - &Header::closebigbox(); - &Header::closepage(); - exit(0); - - ADVANCED_END: -} - -### -### Default status page -### - %cgiparams = (); - %cahash = (); - %confighash = (); - &General::readhash("${General::swroot}/vpn/settings", \%cgiparams); - &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); - &General::readhasharray("${General::swroot}/vpn/config", \%confighash); - - my @status = `/usr/sbin/ipsec auto --status`; - - # suggest a default name for this side - if ($cgiparams{'VPN_IP'} eq '' && -e "${General::swroot}/red/active") { - if (open(IPADDR, "${General::swroot}/red/local-ipaddress")) { - my $ipaddr = ; - close IPADDR; - chomp ($ipaddr); - $cgiparams{'VPN_IP'} = (gethostbyaddr(pack("C4", split(/\./, $ipaddr)), 2))[0]; - if ($cgiparams{'VPN_IP'} eq '') { - $cgiparams{'VPN_IP'} = $ipaddr; - } - } - } - # no IP found, use %defaultroute - $cgiparams{'VPN_IP'} ='%defaultroute' if ($cgiparams{'VPN_IP'} eq ''); - - $cgiparams{'VPN_DELAYED_START'} = 0 if (! defined ($cgiparams{'VPN_DELAYED_START'})); - map ($checked{$_} = $cgiparams{$_} eq 'on' ? "checked='checked'" : '', - ('ENABLED','ENABLED_BLUE','DBG_CRYPT','DBG_PARSING','DBG_EMITTING','DBG_CONTROL', - 'DBG_KLIPS','DBG_DNS','DBG_NAT_T')); - - - &Header::showhttpheaders(); - &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); - &Header::openbigbox('100%', 'LEFT', '', $errormessage); - - if ($errormessage) { - &Header::openbox('100%', 'LEFT', $Lang::tr{'error messages'}); - print "$errormessage\n"; - print " \n"; - &Header::closebox(); - } - - &Header::openbox('100%', 'LEFT', $Lang::tr{'global settings'}); - print < - - - - - - -END - ; - if ($netsettings{'BLUE_DEV'} ne '') { - print < - - - - -END - ; - } -print <$Lang::tr{'vpn delayed start'}: * - - - -
$Lang::tr{'local vpn hostname/ip'}:$Lang::tr{'enabled'}
$Lang::tr{'vpn on blue'}:$Lang::tr{'enabled'}
$Lang::tr{'override mtu'}: *
- - - - - - - - - -
PLUTO DEBUGcrypt:parsing:emitting:control:klips:dns:nat_t:
-
- - - - - - -
*$Lang::tr{'vpn delayed start help'}
-END -; - print ""; - &Header::closebox(); - - &Header::openbox('100%', 'LEFT', $Lang::tr{'connection status and controlc'}); - print < - - $Lang::tr{'name'} - $Lang::tr{'type'} - $Lang::tr{'common name'} - $Lang::tr{'remark'}
L2089 - $Lang::tr{'status'} - $Lang::tr{'action'} - -END - ; - my $id = 0; - my $gif; - foreach my $key (keys %confighash) { - if ($confighash{$key}[0] eq 'on') { $gif = 'on.gif'; } else { $gif = 'off.gif'; } - - if ($id % 2) { - print "\n"; - } else { - print "\n"; - } - print "$confighash{$key}[1]"; - print "" . $Lang::tr{"$confighash{$key}[3]"} . " (" . $Lang::tr{"$confighash{$key}[4]"} . ")"; - if ($confighash{$key}[4] eq 'cert') { - print "$confighash{$key}[2]"; - } else { - print " "; - } - print "$confighash{$key}[25]"; - my $active = "
$Lang::tr{'capsclosed'}
"; - if ($confighash{$key}[0] eq 'off') { - $active = "
$Lang::tr{'capsclosed'}
"; - } else { - foreach my $line (@status) { - if ($line =~ /\"$confighash{$key}[1]\".*IPsec SA established/) { - $active = "
$Lang::tr{'capsopen'}
"; - } - } - } - print <$active -
- - - -
-END - ; - if ($confighash{$key}[4] eq 'cert') { - print < - - - - -END - ; } else { - print " "; - } - if ($confighash{$key}[4] eq 'cert' && -f "${General::swroot}/certs/$confighash{$key}[1].p12") { - print < - - - - -END - ; } elsif ($confighash{$key}[4] eq 'cert') { - print < - - - - -END - ; } else { - print " "; - } - print < - - - - - -
- - - -
-
- - - -
- -END - ; - $id++; - } - ; - - # If the config file contains entries, print Key to action icons - if ( $id ) { - print < - -   $Lang::tr{'legend'}: -   $Lang::tr{ - $Lang::tr{'click to disable'} -     $Lang::tr{ - $Lang::tr{'show certificate'} -     $Lang::tr{ - $Lang::tr{'edit'} -     $Lang::tr{ - $Lang::tr{'remove'} - - -   -   ?OFF - $Lang::tr{'click to enable'} -     ?FLOPPY - $Lang::tr{'download certificate'} -     ?RELOAD - $Lang::tr{'restart'} - - -END - ; - } - - print < -
- -
- -END - ; - &Header::closebox(); - - &Header::openbox('100%', 'LEFT', "$Lang::tr{'certificate authorities'}:"); - print < - - $Lang::tr{'name'} - $Lang::tr{'subject'} - $Lang::tr{'action'} - -EOF - ; - if (-f "${General::swroot}/ca/cacert.pem") { - my $casubject = `/usr/bin/openssl x509 -text -in ${General::swroot}/ca/cacert.pem`; - $casubject =~ /Subject: (.*)[\n]/; - $casubject = $1; - $casubject =~ s+/Email+, E+; - $casubject =~ s/ ST=/ S=/; - - print < - $Lang::tr{'root certificate'} - $casubject -
- - -
-
- - -
-   -END - ; - } else { - # display rootcert generation buttons - print < - $Lang::tr{'root certificate'}: - $Lang::tr{'not present'} -   -END - ; - } - - if (-f "${General::swroot}/certs/hostcert.pem") { - my $hostsubject = `/usr/bin/openssl x509 -text -in ${General::swroot}/certs/hostcert.pem`; - $hostsubject =~ /Subject: (.*)[\n]/; - $hostsubject = $1; - $hostsubject =~ s+/Email+, E+; - $hostsubject =~ s/ ST=/ S=/; - - print < - $Lang::tr{'host certificate'} - $hostsubject -
- - -
-
- - -
-   -END - ; - } else { - # Nothing - print < - $Lang::tr{'host certificate'}: - $Lang::tr{'not present'} -   -END - ; - } - - if (! -f "${General::swroot}/ca/cacert.pem") { - print "
"; - print ""; - print "
\n"; - } - - if (keys %cahash > 0) { - foreach my $key (keys %cahash) { - if (($key + 1) % 2) { - print "\n"; - } else { - print "\n"; - } - print "$cahash{$key}[0]\n"; - print "$cahash{$key}[1]\n"; - print < - - - - -
- - - -
-
- - - -
-END - ; - } - } - - print ""; - - # If the file contains entries, print Key to action icons - if ( -f "${General::swroot}/ca/cacert.pem") { - print < - -   $Lang::tr{'legend'}: -     $Lang::tr{ - $Lang::tr{'show certificate'} -     $Lang::tr{ - $Lang::tr{'download certificate'} - - -END - ; - } - print < - - - - -
$Lang::tr{'ca name'}: -
-END - ; - &Header::closebox(); - - print "
\n"; - print "$Lang::tr{'this feature has been sponsored by'} : "; - print "Seminole Canada Gas Company.\n"; - - &Header::closebigbox(); - &Header::closepage(); +#!/usr/bin/perl +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2007 Michael Tremer & Christian Schmidt # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +use Net::DNS; +use File::Copy; +use File::Temp qw/ tempfile tempdir /; +use strict; + +# enable only the following on debugging purpose +#use warnings; +#use CGI::Carp 'fatalsToBrowser'; + +require '/var/ipfire/general-functions.pl'; +require "${General::swroot}/lang.pl"; +require "${General::swroot}/header.pl"; +require "${General::swroot}/countries.pl"; + +#workaround to suppress a warning when a variable is used only once +my @dummy = ( ${Header::colourgreen}, ${Header::colourblue} ); +undef (@dummy); + +### +### Initialize variables +### +my $sleepDelay = 4; # after a call to ipsecctrl S or R, wait this delay (seconds) before reading status + # (let the ipsec do its job) +my %netsettings=(); +our %cgiparams=(); +our %vpnsettings=(); +my %checked=(); +my %confighash=(); +my %cahash=(); +my %selected=(); +my $warnmessage = ''; +my $errormessage = ''; + +my %color = (); +my %mainsettings = (); +&General::readhash("${General::swroot}/main/settings", \%mainsettings); +&General::readhash("/srv/web/ipfire/html/themes/".$mainsettings{'THEME'}."/include/colors.txt", \%color); + +&General::readhash("${General::swroot}/ethernet/settings", \%netsettings); +$cgiparams{'ENABLED'} = 'off'; +$cgiparams{'EDIT_ADVANCED'} = 'off'; +$cgiparams{'ACTION'} = ''; +$cgiparams{'CA_NAME'} = ''; +$cgiparams{'DBG_CRYPT'} = ''; +$cgiparams{'DBG_PARSING'} = ''; +$cgiparams{'DBG_EMITTING'} = ''; +$cgiparams{'DBG_CONTROL'} = ''; +$cgiparams{'DBG_KLIPS'} = ''; +$cgiparams{'DBG_DNS'} = ''; +$cgiparams{'DBG_NAT_T'} = ''; +$cgiparams{'KEY'} = ''; +$cgiparams{'TYPE'} = ''; +$cgiparams{'ADVANCED'} = ''; +$cgiparams{'INTERFACE'} = ''; +$cgiparams{'NAME'} = ''; +$cgiparams{'LOCAL_SUBNET'} = ''; +$cgiparams{'REMOTE_SUBNET'} = ''; +$cgiparams{'REMOTE'} = ''; +$cgiparams{'LOCAL_ID'} = ''; +$cgiparams{'REMOTE_ID'} = ''; +$cgiparams{'REMARK'} = ''; +$cgiparams{'PSK'} = ''; +$cgiparams{'CERT_NAME'} = ''; +$cgiparams{'CERT_EMAIL'} = ''; +$cgiparams{'CERT_OU'} = ''; +$cgiparams{'CERT_ORGANIZATION'} = ''; +$cgiparams{'CERT_CITY'} = ''; +$cgiparams{'CERT_STATE'} = ''; +$cgiparams{'CERT_COUNTRY'} = ''; +$cgiparams{'SUBJECTALTNAME'} = ''; +$cgiparams{'CERT_PASS1'} = ''; +$cgiparams{'CERT_PASS2'} = ''; +$cgiparams{'ROOTCERT_HOSTNAME'} = ''; +$cgiparams{'ROOTCERT_COUNTRY'} = ''; +$cgiparams{'P12_PASS'} = ''; +$cgiparams{'ROOTCERT_ORGANIZATION'} = ''; +$cgiparams{'ROOTCERT_HOSTNAME'} = ''; +$cgiparams{'ROOTCERT_EMAIL'} = ''; +$cgiparams{'ROOTCERT_OU'} = ''; +$cgiparams{'ROOTCERT_CITY'} = ''; +$cgiparams{'ROOTCERT_STATE'} = ''; + +&Header::getcgihash(\%cgiparams, {'wantfile' => 1, 'filevar' => 'FH'}); + +### +### Useful functions +### +sub valid_dns_host { + my $hostname = $_[0]; + unless ($hostname) { return "No hostname"}; + my $res = new Net::DNS::Resolver; + my $query = $res->search("$hostname"); + if ($query) { + foreach my $rr ($query->answer) { + ## Potential bug - we are only looking at A records: + return 0 if $rr->type eq "A"; + } + } else { + return $res->errorstring; + } +} +### +### Just return true is one interface is vpn enabled +### +sub vpnenabled { + return ($vpnsettings{'ENABLED'} eq 'on'); +} +### +### old version: maintain serial number to one, without explication. +### this : let the counter go, so that each cert is numbered. +### +sub cleanssldatabase +{ + if (open(FILE, ">${General::swroot}/certs/serial")) { + print FILE "01"; + close FILE; + } + if (open(FILE, ">${General::swroot}/certs/index.txt")) { + print FILE ""; + close FILE; + } + unlink ("${General::swroot}/certs/index.txt.old"); + unlink ("${General::swroot}/certs/serial.old"); + unlink ("${General::swroot}/certs/01.pem"); +} +sub newcleanssldatabase +{ + if (! -s "${General::swroot}/certs/serial" ) { + open(FILE, ">${General::swroot}/certs/serial"); + print FILE "01"; + close FILE; + } + if (! -s ">${General::swroot}/certs/index.txt") { + system ("touch ${General::swroot}/certs/index.txt"); + } + unlink ("${General::swroot}/certs/index.txt.old"); + unlink ("${General::swroot}/certs/serial.old"); +# unlink ("${General::swroot}/certs/01.pem"); numbering evolves. Wrong place to delete +} + +### +### Call openssl and return errormessage if any +### +sub callssl ($) { + my $opt = shift; + my $retssl = `/usr/bin/openssl $opt 2>&1`; #redirect stderr + my $ret = ''; + foreach my $line (split (/\n/, $retssl)) { + &General::log("ipsec", "$line") if (0); # 1 for verbose logging + $ret .= '
'.$line if ( $line =~ /error|unknown/ ); + } + if ($ret) { + $ret= &Header::cleanhtml($ret); + } + return $ret ? "$Lang::tr{'openssl produced an error'}: $ret" : '' ; +} +### +### Obtain a CN from given cert +### +sub getCNfromcert ($) { + #&General::log("ipsec", "Extracting name from $_[0]..."); + my $temp = `/usr/bin/openssl x509 -text -in $_[0]`; + $temp =~ /Subject:.*CN=(.*)[\n]/; + $temp = $1; + $temp =~ s+/Email+, E+; + $temp =~ s/ ST=/ S=/; + $temp =~ s/,//g; + $temp =~ s/\'//g; + return $temp; +} +### +### Obtain Subject from given cert +### +sub getsubjectfromcert ($) { + #&General::log("ipsec", "Extracting subject from $_[0]..."); + my $temp = `/usr/bin/openssl x509 -text -in $_[0]`; + $temp =~ /Subject: (.*)[\n]/; + $temp = $1; + $temp =~ s+/Email+, E+; + $temp =~ s/ ST=/ S=/; + return $temp; +} +### +### Combine local subnet and connection name to make a unique name for each connection section +### (this sub is not used now) +### +sub makeconnname ($) { + my $conn = shift; + my $subnet = shift; + + $subnet =~ /^(.*?)\/(.*?)$/; # $1=IP $2=mask + my $ip = unpack('N', &Socket::inet_aton($1)); + if (length ($2) > 2) { + my $mm = unpack('N', &Socket::inet_aton($2)); + while ( ($mm & 1)==0 ) { + $ip >>= 1; + $mm >>= 1; + }; + } else { + $ip >>= (32 - $2); + } + return sprintf ("%s-%X", $conn, $ip); +} +### +### Write a config file. +### +###Type=Host : GUI can choose the interface used (RED,GREEN,BLUE) and +### the side is always defined as 'left'. +### configihash[14]: 'VHOST' is allowed +### + +sub writeipsecfiles { + my %lconfighash = (); + my %lvpnsettings = (); + &General::readhasharray("${General::swroot}/vpn/config", \%lconfighash); + &General::readhash("${General::swroot}/vpn/settings", \%lvpnsettings); + + open(CONF, ">${General::swroot}/vpn/ipsec.conf") or die "Unable to open ${General::swroot}/vpn/ipsec.conf: $!"; + open(SECRETS, ">${General::swroot}/vpn/ipsec.secrets") or die "Unable to open ${General::swroot}/vpn/ipsec.secrets: $!"; + flock CONF, 2; + flock SECRETS, 2; + print CONF "version 2\n\n"; + print CONF "config setup\n"; + #create an ipsec Interface for each 'enabled' ones + #loop trought configuration and add physical interfaces to the list + my $interfaces = "\tinterfaces=\""; + foreach my $key (keys %lconfighash) { + next if ($lconfighash{$key}[0] ne 'on'); + $interfaces .= "%defaultroute " if ($interfaces !~ /defaultroute/ && $lconfighash{$key}[26] eq 'RED'); + $interfaces .= "ipsec1=$netsettings{'GREEN_DEV'} " if ($interfaces !~ /ipsec1/ && $lconfighash{$key}[26] eq 'GREEN'); + $interfaces .= "ipsec2=$netsettings{'BLUE_DEV'} " if ($interfaces !~ /ipsec2/ && $lconfighash{$key}[26] eq 'BLUE'); + $interfaces .= "ipsec3=$netsettings{'ORANGE_DEV'} " if ($interfaces !~ /ipsec3/ && $lconfighash{$key}[26] eq 'ORANGE'); + } + print CONF $interfaces . "\"\n"; + + my $plutodebug = ''; # build debug list + map ($plutodebug .= $lvpnsettings{$_} eq 'on' ? lc (substr($_,4)).' ' : '', + ('DBG_CRYPT','DBG_PARSING','DBG_EMITTING','DBG_CONTROL', + 'DBG_KLIPS','DBG_DNS','DBG_NAT_T')); + $plutodebug = 'none' if $plutodebug eq ''; # if nothing selected, use 'none'. + print CONF "\tklipsdebug=\"none\"\n"; + print CONF "\tplutodebug=\"$plutodebug\"\n"; + # deprecated in ipsec.conf version 2 + #print CONF "\tplutoload=%search\n"; + #print CONF "\tplutostart=%search\n"; + print CONF "\tuniqueids=yes\n"; + print CONF "\tnat_traversal=yes\n"; + print CONF "\toverridemtu=$lvpnsettings{'VPN_OVERRIDE_MTU'}\n" if ($lvpnsettings{'VPN_OVERRIDE_MTU'} ne ''); + print CONF "\tvirtual_private=%v4:10.0.0.0/8,%v4:172.16.0.0/12,%v4:192.168.0.0/16"; + print CONF ",%v4:!$netsettings{'GREEN_NETADDRESS'}/$netsettings{'GREEN_NETMASK'}"; + if (length($netsettings{'ORANGE_DEV'}) > 2) { + print CONF ",%v4:!$netsettings{'ORANGE_NETADDRESS'}/$netsettings{'ORANGE_NETMASK'}"; + } + if (length($netsettings{'BLUE_DEV'}) > 2) { + print CONF ",%v4:!$netsettings{'BLUE_NETADDRESS'}/$netsettings{'BLUE_NETMASK'}"; + } + foreach my $key (keys %lconfighash) { + if ($lconfighash{$key}[3] eq 'net') { + print CONF ",%v4:!$lconfighash{$key}[11]"; + } + } + print CONF "\n\n"; + print CONF "conn %default\n"; + print CONF "\tkeyingtries=0\n"; + print CONF "\tdisablearrivalcheck=no\n"; + print CONF "\n"; + + if (-f "${General::swroot}/certs/hostkey.pem") { + print SECRETS ": RSA ${General::swroot}/certs/hostkey.pem\n" + } + my $last_secrets = ''; # old the less specifics connections + + foreach my $key (keys %lconfighash) { + next if ($lconfighash{$key}[0] ne 'on'); + + #remote peer is not set? => use '%any' + $lconfighash{$key}[10] = '%any' if ($lconfighash{$key}[10] eq ''); + + my $localside; + if ($lconfighash{$key}[26] eq 'BLUE') { + $localside = $netsettings{'BLUE_ADDRESS'}; + } elsif ($lconfighash{$key}[26] eq 'GREEN') { + $localside = $netsettings{'GREEN_ADDRESS'}; + } elsif ($lconfighash{$key}[26] eq 'ORANGE') { + $localside = $netsettings{'ORANGE_ADDRESS'}; + } else { # it is RED + $localside = $lvpnsettings{'VPN_IP'}; + } + + print CONF "conn $lconfighash{$key}[1]\n"; + print CONF "\tleft=$localside\n"; + print CONF "\tleftnexthop=%defaultroute\n" if ($lconfighash{$key}[26] eq 'RED' && $lvpnsettings{'VPN_IP'} ne '%defaultroute'); + print CONF "\tleftsubnet=$lconfighash{$key}[8]\n"; + + print CONF "\tright=$lconfighash{$key}[10]\n"; + if ($lconfighash{$key}[3] eq 'net') { + print CONF "\trightsubnet=$lconfighash{$key}[11]\n"; + print CONF "\trightnexthop=%defaultroute\n"; + } elsif ($lconfighash{$key}[10] eq '%any' && $lconfighash{$key}[14] eq 'on') { #vhost allowed for roadwarriors? + print CONF "\trightsubnet=vhost:%no,%priv\n"; + } + + # Local Cert and Remote Cert (unless auth is DN dn-auth) + if ($lconfighash{$key}[4] eq 'cert') { + print CONF "\tleftcert=${General::swroot}/certs/hostcert.pem\n"; + print CONF "\trightcert=${General::swroot}/certs/$lconfighash{$key}[1]cert.pem\n" if ($lconfighash{$key}[2] ne '%auth-dn'); + } + + # Local and Remote IDs + print CONF "\tleftid=\"$lconfighash{$key}[7]\"\n" if ($lconfighash{$key}[7]); + print CONF "\trightid=\"$lconfighash{$key}[9]\"\n" if ($lconfighash{$key}[9]); + + # Algorithms + if ($lconfighash{$key}[18] && $lconfighash{$key}[19] && $lconfighash{$key}[20]) { + print CONF "\tike="; + my @encs = split('\|', $lconfighash{$key}[18]); + my @ints = split('\|', $lconfighash{$key}[19]); + my @groups = split('\|', $lconfighash{$key}[20]); + my $comma = 0; + foreach my $i (@encs) { + foreach my $j (@ints) { + foreach my $k (@groups) { + if ($comma != 0) { print CONF ","; } else { $comma = 1; } + print CONF "$i-$j-modp$k"; + } + } + } + if ($lconfighash{$key}[24] eq 'on') { #only proposed algorythms? + print CONF "!\n"; + } else { + print CONF "\n"; + } + } + if ($lconfighash{$key}[21] && $lconfighash{$key}[22]) { + print CONF "\tesp="; + my @encs = split('\|', $lconfighash{$key}[21]); + my @ints = split('\|', $lconfighash{$key}[22]); + my $comma = 0; + foreach my $i (@encs) { + foreach my $j (@ints) { + if ($comma != 0) { print CONF ","; } else { $comma = 1; } + print CONF "$i-$j"; + } + } + if ($lconfighash{$key}[24] eq 'on') { #only proposed algorythms? + print CONF "!\n"; + } else { + print CONF "\n"; + } + } + if ($lconfighash{$key}[23]) { + print CONF "\tpfsgroup=$lconfighash{$key}[23]\n"; + } + + # Lifetimes + print CONF "\tikelifetime=$lconfighash{$key}[16]h\n" if ($lconfighash{$key}[16]); + print CONF "\tkeylife=$lconfighash{$key}[17]h\n" if ($lconfighash{$key}[17]); + + # Aggresive mode + print CONF "\taggrmode=yes\n" if ($lconfighash{$key}[12] eq 'on'); + + # Compression + print CONF "\tcompress=yes\n" if ($lconfighash{$key}[13] eq 'on'); + + # Dead Peer Detection + print CONF "\tdpddelay=30\n"; + print CONF "\tdpdtimeout=120\n"; + print CONF "\tdpdaction=$lconfighash{$key}[27]\n"; + + # Disable pfs ? + print CONF "\tpfs=". ($lconfighash{$key}[28] eq 'on' ? "yes\n" : "no\n"); + + # Build Authentication details: LEFTid RIGHTid : PSK psk + my $psk_line; + if ($lconfighash{$key}[4] eq 'psk') { + $psk_line = ($lconfighash{$key}[7] ? $lconfighash{$key}[7] : $localside) . " " ; + $psk_line .= $lconfighash{$key}[9] ? $lconfighash{$key}[9] : $lconfighash{$key}[10]; #remoteid or remote address? + $psk_line .= " : PSK '$lconfighash{$key}[5]'\n"; + # if the line contains %any, it is less specific than two IP or ID, so move it at end of file. + if ($psk_line =~ /%any/) { + $last_secrets .= $psk_line; + } else { + print SECRETS $psk_line; + } + print CONF "\tauthby=secret\n"; + } else { + print CONF "\tauthby=rsasig\n"; + print CONF "\tleftrsasigkey=%cert\n"; + print CONF "\trightrsasigkey=%cert\n"; + } + + # Automatically start only if a net-to-net connection + if ($lconfighash{$key}[3] eq 'host') { + print CONF "\tauto=add\n"; + } else { + print CONF "\tauto=start\n"; + } + print CONF "\n"; + }#foreach key + print SECRETS $last_secrets if ($last_secrets); + close(CONF); + close(SECRETS); +} + +### +### Save main settings +### +if ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'TYPE'} eq '' && $cgiparams{'KEY'} eq '') { + &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); + unless (&General::validfqdn($cgiparams{'VPN_IP'}) || &General::validip($cgiparams{'VPN_IP'}) + || $cgiparams{'VPN_IP'} eq '%defaultroute' ) { + $errormessage = $Lang::tr{'invalid input for hostname'}; + goto SAVE_ERROR; + } + + unless ($cgiparams{'VPN_DELAYED_START'} =~ /^[0-9]{1,3}$/ ) { #allow 0-999 seconds ! + $errormessage = $Lang::tr{'invalid time period'}; + goto SAVE_ERROR; + } + + unless ($cgiparams{'VPN_OVERRIDE_MTU'} =~ /^(|[0-9]{1,5})$/ ) { #allow 0-99999 + $errormessage = $Lang::tr{'vpn mtu invalid'}; + goto SAVE_ERROR; + } + + unless ($cgiparams{'VPN_WATCH'} =~ /^(|off|on)$/ ) { + $errormessage = $Lang::tr{'invalid input'}; + goto SAVE_ERROR; + } + + map ($vpnsettings{$_} = $cgiparams{$_}, + ('ENABLED','DBG_CRYPT','DBG_PARSING','DBG_EMITTING','DBG_CONTROL', + 'DBG_KLIPS','DBG_DNS','DBG_NAT_T')); + + $vpnsettings{'VPN_IP'} = $cgiparams{'VPN_IP'}; + $vpnsettings{'VPN_DELAYED_START'} = $cgiparams{'VPN_DELAYED_START'}; + $vpnsettings{'VPN_OVERRIDE_MTU'} = $cgiparams{'VPN_OVERRIDE_MTU'}; + $vpnsettings{'VPN_WATCH'} = $cgiparams{'VPN_WATCH'}; + &General::writehash("${General::swroot}/vpn/settings", \%vpnsettings); + &writeipsecfiles(); + if (&vpnenabled) { + system('/usr/local/bin/ipsecctrl', 'S'); + } else { + system('/usr/local/bin/ipsecctrl', 'D'); + } + sleep $sleepDelay; + SAVE_ERROR: +### +### Reset all step 2 +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove x509'} && $cgiparams{'AREUSURE'} eq 'yes') { + &General::readhasharray("${General::swroot}/vpn/config", \%confighash); + + foreach my $key (keys %confighash) { + if ($confighash{$key}[4] eq 'cert') { + delete $confighash{$key}; + } + } + while (my $file = glob("${General::swroot}/{ca,certs,crls,private}/*")) { + unlink $file + } + &cleanssldatabase(); + if (open(FILE, ">${General::swroot}/vpn/caconfig")) { + print FILE ""; + close FILE; + } + &General::writehasharray("${General::swroot}/vpn/config", \%confighash); + &writeipsecfiles(); + system('/usr/local/bin/ipsecctrl', 'R'); + sleep $sleepDelay; + +### +### Reset all step 1 +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove x509'}) { + &Header::showhttpheaders(); + &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); + &Header::openbigbox('100%', 'left', '', ''); + &Header::openbox('100%', 'left', $Lang::tr{'are you sure'}); + print < + + + + + + +
+ + $Lang::tr{'capswarning'}: + $Lang::tr{'resetting the vpn configuration will remove the root ca, the host certificate and all certificate based connections'}
+ +
+ +END + ; + &Header::closebox(); + &Header::closebigbox(); + &Header::closepage(); + exit (0); + +### +### Upload CA Certificate +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'upload ca certificate'}) { + &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); + + if ($cgiparams{'CA_NAME'} !~ /^[a-zA-Z0-9]+$/) { + $errormessage = $Lang::tr{'name must only contain characters'}; + goto UPLOADCA_ERROR; + } + + if (length($cgiparams{'CA_NAME'}) >60) { + $errormessage = $Lang::tr{'name too long'}; + goto VPNCONF_ERROR; + } + + if ($cgiparams{'CA_NAME'} eq 'ca') { + $errormessage = $Lang::tr{'name is invalid'}; + goto UPLOAD_CA_ERROR; + } + + # Check if there is no other entry with this name + foreach my $key (keys %cahash) { + if ($cahash{$key}[0] eq $cgiparams{'CA_NAME'}) { + $errormessage = $Lang::tr{'a ca certificate with this name already exists'}; + goto UPLOADCA_ERROR; + } + } + + if (ref ($cgiparams{'FH'}) ne 'Fh') { + $errormessage = $Lang::tr{'there was no file upload'}; + goto UPLOADCA_ERROR; + } + # Move uploaded ca to a temporary file + (my $fh, my $filename) = tempfile( ); + if (copy ($cgiparams{'FH'}, $fh) != 1) { + $errormessage = $!; + goto UPLOADCA_ERROR; + } + my $temp = `/usr/bin/openssl x509 -text -in $filename`; + if ($temp !~ /CA:TRUE/i) { + $errormessage = $Lang::tr{'not a valid ca certificate'}; + unlink ($filename); + goto UPLOADCA_ERROR; + } else { + move($filename, "${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem"); + if ($? ne 0) { + $errormessage = "$Lang::tr{'certificate file move failed'}: $!"; + unlink ($filename); + goto UPLOADCA_ERROR; + } + } + + my $key = &General::findhasharraykey (\%cahash); + $cahash{$key}[0] = $cgiparams{'CA_NAME'}; + $cahash{$key}[1] = &Header::cleanhtml(getsubjectfromcert ("${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem")); + &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash); + system('/usr/local/bin/ipsecctrl', 'R'); + sleep $sleepDelay; + + UPLOADCA_ERROR: + +### +### Display ca certificate +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show ca certificate'}) { + &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); + + if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem") { + &Header::showhttpheaders(); + &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); + &Header::openbigbox('100%', 'left', '', ''); + &Header::openbox('100%', 'left', "$Lang::tr{'ca certificate'}:"); + my $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem`; + $output = &Header::cleanhtml($output,"y"); + print "
$output
\n"; + &Header::closebox(); + print ""; + &Header::closebigbox(); + &Header::closepage(); + exit(0); + } else { + $errormessage = $Lang::tr{'invalid key'}; + } + +### +### Export ca certificate to browser +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download ca certificate'}) { + &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); + + if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) { + print "Content-Type: application/force-download\n"; + print "Content-Type: application/octet-stream\r\n"; + print "Content-Disposition: attachment; filename=$cahash{$cgiparams{'KEY'}}[0]cert.pem\r\n\r\n"; + print `/usr/bin/openssl x509 -in ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem`; + exit(0); + } else { + $errormessage = $Lang::tr{'invalid key'}; + } + +### +### Remove ca certificate (step 2) +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove ca certificate'} && $cgiparams{'AREUSURE'} eq 'yes') { + &General::readhasharray("${General::swroot}/vpn/config", \%confighash); + &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); + + if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) { + foreach my $key (keys %confighash) { + my $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem ${General::swroot}/certs/$confighash{$key}[1]cert.pem`; + if ($test =~ /: OK/) { + # Delete connection + system('/usr/local/bin/ipsecctrl', 'D', $key) if (&vpnenabled); + unlink ("${General::swroot}/certs/$confighash{$key}[1]cert.pem"); + unlink ("${General::swroot}/certs/$confighash{$key}[1].p12"); + delete $confighash{$key}; + &General::writehasharray("${General::swroot}/vpn/config", \%confighash); + &writeipsecfiles(); + } + } + unlink ("${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem"); + delete $cahash{$cgiparams{'KEY'}}; + &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash); + system('/usr/local/bin/ipsecctrl', 'R'); + sleep $sleepDelay; + } else { + $errormessage = $Lang::tr{'invalid key'}; + } +### +### Remove ca certificate (step 1) +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove ca certificate'}) { + &General::readhasharray("${General::swroot}/vpn/config", \%confighash); + &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); + + my $assignedcerts = 0; + if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) { + foreach my $key (keys %confighash) { + my $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem ${General::swroot}/certs/$confighash{$key}[1]cert.pem`; + if ($test =~ /: OK/) { + $assignedcerts++; + } + } + if ($assignedcerts) { + &Header::showhttpheaders(); + &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); + &Header::openbigbox('100%', 'left', '', ''); + &Header::openbox('100%', 'left', $Lang::tr{'are you sure'}); + print < + + + + + + + + +
+ +
+ $Lang::tr{'capswarning'} + $Lang::tr{'connections are associated with this ca. deleting the ca will delete these connections as well.'}
+ +
+ +END + ; + &Header::closebox(); + &Header::closebigbox(); + &Header::closepage(); + exit (0); + } else { + unlink ("${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem"); + delete $cahash{$cgiparams{'KEY'}}; + &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash); + system('/usr/local/bin/ipsecctrl', 'R'); + sleep $sleepDelay; + } + } else { + $errormessage = $Lang::tr{'invalid key'}; + } + +### +### Display root certificate +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show root certificate'} || + $cgiparams{'ACTION'} eq $Lang::tr{'show host certificate'}) { + my $output; + &Header::showhttpheaders(); + &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); + &Header::openbigbox('100%', 'left', '', ''); + if ($cgiparams{'ACTION'} eq $Lang::tr{'show root certificate'}) { + &Header::openbox('100%', 'left', "$Lang::tr{'root certificate'}:"); + $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/ca/cacert.pem`; + } else { + &Header::openbox('100%', 'left', "$Lang::tr{'host certificate'}:"); + $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/certs/hostcert.pem`; + } + $output = &Header::cleanhtml($output,"y"); + print "
$output
\n"; + &Header::closebox(); + print ""; + &Header::closebigbox(); + &Header::closepage(); + exit(0); + +### +### Export root certificate to browser +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download root certificate'}) { + if ( -f "${General::swroot}/ca/cacert.pem" ) { + print "Content-Type: application/force-download\n"; + print "Content-Disposition: attachment; filename=cacert.pem\r\n\r\n"; + print `/usr/bin/openssl x509 -in ${General::swroot}/ca/cacert.pem`; + exit(0); + } +### +### Export host certificate to browser +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download host certificate'}) { + if ( -f "${General::swroot}/certs/hostcert.pem" ) { + print "Content-Type: application/force-download\n"; + print "Content-Disposition: attachment; filename=hostcert.pem\r\n\r\n"; + print `/usr/bin/openssl x509 -in ${General::swroot}/certs/hostcert.pem`; + exit(0); + } +### +### Form for generating/importing the caroot+host certificate +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'generate root/host certificates'} || + $cgiparams{'ACTION'} eq $Lang::tr{'upload p12 file'}) { + + if (-f "${General::swroot}/ca/cacert.pem") { + $errormessage = $Lang::tr{'valid root certificate already exists'}; + goto ROOTCERT_SKIP; + } + + &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); + # fill in initial values + if ($cgiparams{'ROOTCERT_HOSTNAME'} eq '') { + if (-e "${General::swroot}/red/active" && open(IPADDR, "${General::swroot}/red/local-ipaddress")) { + my $ipaddr = ; + close IPADDR; + chomp ($ipaddr); + $cgiparams{'ROOTCERT_HOSTNAME'} = (gethostbyaddr(pack("C4", split(/\./, $ipaddr)), 2))[0]; + if ($cgiparams{'ROOTCERT_HOSTNAME'} eq '') { + $cgiparams{'ROOTCERT_HOSTNAME'} = $ipaddr; + } + } + $cgiparams{'ROOTCERT_COUNTRY'} = $vpnsettings{'ROOTCERT_COUNTRY'} if (!$cgiparams{'ROOTCERT_COUNTRY'}); + } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'upload p12 file'}) { + &General::log("ipsec", "Importing from p12..."); + + if (ref ($cgiparams{'FH'}) ne 'Fh') { + $errormessage = $Lang::tr{'there was no file upload'}; + goto ROOTCERT_ERROR; + } + + # Move uploaded certificate request to a temporary file + (my $fh, my $filename) = tempfile( ); + if (copy ($cgiparams{'FH'}, $fh) != 1) { + $errormessage = $!; + goto ROOTCERT_ERROR; + } + + # Extract the CA certificate from the file + &General::log("ipsec", "Extracting caroot from p12..."); + if (open(STDIN, "-|")) { + my $opt = " pkcs12 -cacerts -nokeys"; + $opt .= " -in $filename"; + $opt .= " -out /tmp/newcacert"; + $errormessage = &callssl ($opt); + } else { #child + print "$cgiparams{'P12_PASS'}\n"; + exit (0); + } + + # Extract the Host certificate from the file + if (!$errormessage) { + &General::log("ipsec", "Extracting host cert from p12..."); + if (open(STDIN, "-|")) { + my $opt = " pkcs12 -clcerts -nokeys"; + $opt .= " -in $filename"; + $opt .= " -out /tmp/newhostcert"; + $errormessage = &callssl ($opt); + } else { #child + print "$cgiparams{'P12_PASS'}\n"; + exit (0); + } + } + + # Extract the Host key from the file + if (!$errormessage) { + &General::log("ipsec", "Extracting private key from p12..."); + if (open(STDIN, "-|")) { + my $opt = " pkcs12 -nocerts -nodes"; + $opt .= " -in $filename"; + $opt .= " -out /tmp/newhostkey"; + $errormessage = &callssl ($opt); + } else { #child + print "$cgiparams{'P12_PASS'}\n"; + exit (0); + } + } + + if (!$errormessage) { + &General::log("ipsec", "Moving cacert..."); + move("/tmp/newcacert", "${General::swroot}/ca/cacert.pem"); + $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0); + } + + if (!$errormessage) { + &General::log("ipsec", "Moving host cert..."); + move("/tmp/newhostcert", "${General::swroot}/certs/hostcert.pem"); + $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0); + } + + if (!$errormessage) { + &General::log("ipsec", "Moving private key..."); + move("/tmp/newhostkey", "${General::swroot}/certs/hostkey.pem"); + $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0); + } + + #cleanup temp files + unlink ($filename); + unlink ('/tmp/newcacert'); + unlink ('/tmp/newhostcert'); + unlink ('/tmp/newhostkey'); + if ($errormessage) { + unlink ("${General::swroot}/ca/cacert.pem"); + unlink ("${General::swroot}/certs/hostcert.pem"); + unlink ("${General::swroot}/certs/hostkey.pem"); + goto ROOTCERT_ERROR; + } + + # Create empty CRL cannot be done because we don't have + # the private key for this CAROOT + # IPFire can only import certificates + + &General::log("ipsec", "p12 import completed!"); + &cleanssldatabase(); + goto ROOTCERT_SUCCESS; + + } elsif ($cgiparams{'ROOTCERT_COUNTRY'} ne '') { + + # Validate input since the form was submitted + if ($cgiparams{'ROOTCERT_ORGANIZATION'} eq ''){ + $errormessage = $Lang::tr{'organization cant be empty'}; + goto ROOTCERT_ERROR; + } + if (length($cgiparams{'ROOTCERT_ORGANIZATION'}) >60) { + $errormessage = $Lang::tr{'organization too long'}; + goto ROOTCERT_ERROR; + } + if ($cgiparams{'ROOTCERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { + $errormessage = $Lang::tr{'invalid input for organization'}; + goto ROOTCERT_ERROR; + } + if ($cgiparams{'ROOTCERT_HOSTNAME'} eq ''){ + $errormessage = $Lang::tr{'hostname cant be empty'}; + goto ROOTCERT_ERROR; + } + unless (&General::validfqdn($cgiparams{'ROOTCERT_HOSTNAME'}) || &General::validip($cgiparams{'ROOTCERT_HOSTNAME'})) { + $errormessage = $Lang::tr{'invalid input for hostname'}; + goto ROOTCERT_ERROR; + } + if ($cgiparams{'ROOTCERT_EMAIL'} ne '' && (! &General::validemail($cgiparams{'ROOTCERT_EMAIL'}))) { + $errormessage = $Lang::tr{'invalid input for e-mail address'}; + goto ROOTCERT_ERROR; + } + if (length($cgiparams{'ROOTCERT_EMAIL'}) > 40) { + $errormessage = $Lang::tr{'e-mail address too long'}; + goto ROOTCERT_ERROR; + } + if ($cgiparams{'ROOTCERT_OU'} ne '' && $cgiparams{'ROOTCERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { + $errormessage = $Lang::tr{'invalid input for department'}; + goto ROOTCERT_ERROR; + } + if ($cgiparams{'ROOTCERT_CITY'} ne '' && $cgiparams{'ROOTCERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { + $errormessage = $Lang::tr{'invalid input for city'}; + goto ROOTCERT_ERROR; + } + if ($cgiparams{'ROOTCERT_STATE'} ne '' && $cgiparams{'ROOTCERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { + $errormessage = $Lang::tr{'invalid input for state or province'}; + goto ROOTCERT_ERROR; + } + if ($cgiparams{'ROOTCERT_COUNTRY'} !~ /^[A-Z]*$/) { + $errormessage = $Lang::tr{'invalid input for country'}; + goto ROOTCERT_ERROR; + } + #the exact syntax is a list comma separated of + # email:any-validemail + # URI: a uniform resource indicator + # DNS: a DNS domain name + # RID: a registered OBJECT IDENTIFIER + # IP: an IP address + # example: email:franck@foo.com,IP:10.0.0.10,DNS:franck.foo.com + + if ($cgiparams{'SUBJECTALTNAME'} ne '' && $cgiparams{'SUBJECTALTNAME'} !~ /^(email|URI|DNS|RID|IP):[a-zA-Z0-9 :\/,\.\-_@]*$/) { + $errormessage = $Lang::tr{'vpn altname syntax'}; + goto VPNCONF_ERROR; + } + + # Copy the cgisettings to vpnsettings and save the configfile + $vpnsettings{'ROOTCERT_ORGANIZATION'} = $cgiparams{'ROOTCERT_ORGANIZATION'}; + $vpnsettings{'ROOTCERT_HOSTNAME'} = $cgiparams{'ROOTCERT_HOSTNAME'}; + $vpnsettings{'ROOTCERT_EMAIL'} = $cgiparams{'ROOTCERT_EMAIL'}; + $vpnsettings{'ROOTCERT_OU'} = $cgiparams{'ROOTCERT_OU'}; + $vpnsettings{'ROOTCERT_CITY'} = $cgiparams{'ROOTCERT_CITY'}; + $vpnsettings{'ROOTCERT_STATE'} = $cgiparams{'ROOTCERT_STATE'}; + $vpnsettings{'ROOTCERT_COUNTRY'} = $cgiparams{'ROOTCERT_COUNTRY'}; + &General::writehash("${General::swroot}/vpn/settings", \%vpnsettings); + + # Replace empty strings with a . + (my $ou = $cgiparams{'ROOTCERT_OU'}) =~ s/^\s*$/\./; + (my $city = $cgiparams{'ROOTCERT_CITY'}) =~ s/^\s*$/\./; + (my $state = $cgiparams{'ROOTCERT_STATE'}) =~ s/^\s*$/\./; + + # Create the CA certificate + if (!$errormessage) { + &General::log("ipsec", "Creating cacert..."); + if (open(STDIN, "-|")) { + my $opt = " req -x509 -nodes -rand /proc/interrupts:/proc/net/rt_cache"; + $opt .= " -days 999999"; + $opt .= " -newkey rsa:2048"; + $opt .= " -keyout ${General::swroot}/private/cakey.pem"; + $opt .= " -out ${General::swroot}/ca/cacert.pem"; + + $errormessage = &callssl ($opt); + } else { #child + print "$cgiparams{'ROOTCERT_COUNTRY'}\n"; + print "$state\n"; + print "$city\n"; + print "$cgiparams{'ROOTCERT_ORGANIZATION'}\n"; + print "$ou\n"; + print "$cgiparams{'ROOTCERT_ORGANIZATION'} CA\n"; + print "$cgiparams{'ROOTCERT_EMAIL'}\n"; + exit (0); + } + } + + # Create the Host certificate request + if (!$errormessage) { + &General::log("ipsec", "Creating host cert..."); + if (open(STDIN, "-|")) { + my $opt = " req -nodes -rand /proc/interrupts:/proc/net/rt_cache"; + $opt .= " -newkey rsa:1024"; + $opt .= " -keyout ${General::swroot}/certs/hostkey.pem"; + $opt .= " -out ${General::swroot}/certs/hostreq.pem"; + $errormessage = &callssl ($opt); + } else { #child + print "$cgiparams{'ROOTCERT_COUNTRY'}\n"; + print "$state\n"; + print "$city\n"; + print "$cgiparams{'ROOTCERT_ORGANIZATION'}\n"; + print "$ou\n"; + print "$cgiparams{'ROOTCERT_HOSTNAME'}\n"; + print "$cgiparams{'ROOTCERT_EMAIL'}\n"; + print ".\n"; + print ".\n"; + exit (0); + } + } + + # Sign the host certificate request + if (!$errormessage) { + &General::log("ipsec", "Self signing host cert..."); + + #No easy way for specifying the contain of subjectAltName without writing a config file... + my ($fh, $v3extname) = tempfile ('/tmp/XXXXXXXX'); + print $fh <$errormessage"; + print " "; + &Header::closebox(); + } + &Header::openbox('100%', 'left', "$Lang::tr{'generate root/host certificates'}:"); + print < + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
$Lang::tr{'organization name'}:
$Lang::tr{'ipfires hostname'}:
$Lang::tr{'your e-mail'}: *
$Lang::tr{'your department'}: *
$Lang::tr{'city'}: *
$Lang::tr{'state or province'}: *
$Lang::tr{'country'}:
$Lang::tr{'vpn subjectaltname'} (subjectAltName=email:*,URI:*,DNS:*,RID:*) *
 


+ $Lang::tr{'capswarning'}: + $Lang::tr{'generating the root and host certificates may take a long time. it can take up to several minutes on older hardware. please be patient'} +

$Lang::tr{'upload p12 file'}:
$Lang::tr{'pkcs12 file password'}: *
 
+ * $Lang::tr{'this field may be blank'}
+END + ; + &Header::closebox(); + &Header::closebigbox(); + &Header::closepage(); + exit(0); + + ROOTCERT_SUCCESS: + if (&vpnenabled) { + system('/usr/local/bin/ipsecctrl', 'S'); + sleep $sleepDelay; + } + ROOTCERT_SKIP: +### +### Export PKCS12 file to browser +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download pkcs12 file'}) { + &General::readhasharray("${General::swroot}/vpn/config", \%confighash); + print "Content-Type: application/force-download\n"; + print "Content-Disposition: attachment; filename=" . $confighash{$cgiparams{'KEY'}}[1] . ".p12\r\n"; + print "Content-Type: application/octet-stream\r\n\r\n"; + print `/bin/cat ${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1].p12`; + exit (0); + +### +### Display certificate +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show certificate'}) { + &General::readhasharray("${General::swroot}/vpn/config", \%confighash); + + if ( -f "${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") { + &Header::showhttpheaders(); + &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); + &Header::openbigbox('100%', 'left', '', ''); + &Header::openbox('100%', 'left', "$Lang::tr{'cert'}:"); + my $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem`; + $output = &Header::cleanhtml($output,"y"); + print "
$output
\n"; + &Header::closebox(); + print ""; + &Header::closebigbox(); + &Header::closepage(); + exit(0); + } + +### +### Export Certificate to browser +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download certificate'}) { + &General::readhasharray("${General::swroot}/vpn/config", \%confighash); + + if ( -f "${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") { + print "Content-Type: application/force-download\n"; + print "Content-Disposition: attachment; filename=" . $confighash{$cgiparams{'KEY'}}[1] . "cert.pem\n\n"; + print `/bin/cat ${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem`; + exit (0); + } + +### +### Enable/Disable connection +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'toggle enable disable'}) { + + &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); + &General::readhasharray("${General::swroot}/vpn/config", \%confighash); + + if ($confighash{$cgiparams{'KEY'}}) { + if ($confighash{$cgiparams{'KEY'}}[0] eq 'off') { + $confighash{$cgiparams{'KEY'}}[0] = 'on'; + &General::writehasharray("${General::swroot}/vpn/config", \%confighash); + &writeipsecfiles(); + system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'}) if (&vpnenabled); + } else { + system('/usr/local/bin/ipsecctrl', 'D', $cgiparams{'KEY'}) if (&vpnenabled); + $confighash{$cgiparams{'KEY'}}[0] = 'off'; + &General::writehasharray("${General::swroot}/vpn/config", \%confighash); + &writeipsecfiles(); + } + sleep $sleepDelay; + } else { + $errormessage = $Lang::tr{'invalid key'}; + } + +### +### Restart connection +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'restart'}) { + &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); + &General::readhasharray("${General::swroot}/vpn/config", \%confighash); + + if ($confighash{$cgiparams{'KEY'}}) { + if (&vpnenabled) { + system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'}); + sleep $sleepDelay; + } + } else { + $errormessage = $Lang::tr{'invalid key'}; + } + +### +### Remove connection +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove'}) { + &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); + &General::readhasharray("${General::swroot}/vpn/config", \%confighash); + + if ($confighash{$cgiparams{'KEY'}}) { + system('/usr/local/bin/ipsecctrl', 'D', $cgiparams{'KEY'}) if (&vpnenabled); + unlink ("${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem"); + unlink ("${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1].p12"); + delete $confighash{$cgiparams{'KEY'}}; + &General::writehasharray("${General::swroot}/vpn/config", \%confighash); + &writeipsecfiles(); + } else { + $errormessage = $Lang::tr{'invalid key'}; + } + +### +### Choose between adding a host-net or net-net connection +### +} elsif ($cgiparams{'ACTION'} eq $Lang::tr{'add'} && $cgiparams{'TYPE'} eq '') { + &Header::showhttpheaders(); + &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); + &Header::openbigbox('100%', 'left', '', ''); + &Header::openbox('100%', 'left', $Lang::tr{'connection type'}); + print < + $Lang::tr{'connection type'}:
+ + + + + + + + + +
$Lang::tr{'host to net vpn'}
$Lang::tr{'net to net vpn'}
+END + ; + &Header::closebox(); + &Header::closebigbox(); + &Header::closepage(); + exit (0); +### +### Adding/Editing/Saving a connection +### +} elsif (($cgiparams{'ACTION'} eq $Lang::tr{'add'}) || + ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}) || + ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'ADVANCED'} eq '')) { + + &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); + &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); + &General::readhasharray("${General::swroot}/vpn/config", \%confighash); + + if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}) { + if (! $confighash{$cgiparams{'KEY'}}[0]) { + $errormessage = $Lang::tr{'invalid key'}; + goto VPNCONF_END; + } + $cgiparams{'ENABLED'} = $confighash{$cgiparams{'KEY'}}[0]; + $cgiparams{'NAME'} = $confighash{$cgiparams{'KEY'}}[1]; + $cgiparams{'TYPE'} = $confighash{$cgiparams{'KEY'}}[3]; + $cgiparams{'AUTH'} = $confighash{$cgiparams{'KEY'}}[4]; + $cgiparams{'PSK'} = $confighash{$cgiparams{'KEY'}}[5]; + #$cgiparams{'free'} = $confighash{$cgiparams{'KEY'}}[6]; + $cgiparams{'LOCAL_ID'} = $confighash{$cgiparams{'KEY'}}[7]; + $cgiparams{'LOCAL_SUBNET'} = $confighash{$cgiparams{'KEY'}}[8]; + $cgiparams{'REMOTE_ID'} = $confighash{$cgiparams{'KEY'}}[9]; + $cgiparams{'REMOTE'} = $confighash{$cgiparams{'KEY'}}[10]; + $cgiparams{'REMOTE_SUBNET'} = $confighash{$cgiparams{'KEY'}}[11]; + $cgiparams{'REMARK'} = $confighash{$cgiparams{'KEY'}}[25]; + $cgiparams{'INTERFACE'} = $confighash{$cgiparams{'KEY'}}[26]; + $cgiparams{'DPD_ACTION'} = $confighash{$cgiparams{'KEY'}}[27]; + $cgiparams{'IKE_ENCRYPTION'} = $confighash{$cgiparams{'KEY'}}[18]; + $cgiparams{'IKE_INTEGRITY'} = $confighash{$cgiparams{'KEY'}}[19]; + $cgiparams{'IKE_GROUPTYPE'} = $confighash{$cgiparams{'KEY'}}[20]; + $cgiparams{'IKE_LIFETIME'} = $confighash{$cgiparams{'KEY'}}[16]; + $cgiparams{'ESP_ENCRYPTION'} = $confighash{$cgiparams{'KEY'}}[21]; + $cgiparams{'ESP_INTEGRITY'} = $confighash{$cgiparams{'KEY'}}[22]; + $cgiparams{'ESP_GROUPTYPE'} = $confighash{$cgiparams{'KEY'}}[23]; + $cgiparams{'ESP_KEYLIFE'} = $confighash{$cgiparams{'KEY'}}[17]; + $cgiparams{'AGGRMODE'} = $confighash{$cgiparams{'KEY'}}[12]; + $cgiparams{'COMPRESSION'} = $confighash{$cgiparams{'KEY'}}[13]; + $cgiparams{'ONLY_PROPOSED'} = $confighash{$cgiparams{'KEY'}}[24]; + $cgiparams{'PFS'} = $confighash{$cgiparams{'KEY'}}[28]; + $cgiparams{'VHOST'} = $confighash{$cgiparams{'KEY'}}[14]; + + } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'save'}) { + $cgiparams{'REMARK'} = &Header::cleanhtml($cgiparams{'REMARK'}); + if ($cgiparams{'TYPE'} !~ /^(host|net)$/) { + $errormessage = $Lang::tr{'connection type is invalid'}; + goto VPNCONF_ERROR; + } + + if ($cgiparams{'NAME'} !~ /^[a-zA-Z0-9]+$/) { + $errormessage = $Lang::tr{'name must only contain characters'}; + goto VPNCONF_ERROR; + } + + if ($cgiparams{'NAME'} =~ /^(host|01|block|private|clear|packetdefault)$/) { + $errormessage = $Lang::tr{'name is invalid'}; + goto VPNCONF_ERROR; + } + + if (length($cgiparams{'NAME'}) >60) { + $errormessage = $Lang::tr{'name too long'}; + goto VPNCONF_ERROR; + } + + # Check if there is no other entry with this name + if (! $cgiparams{'KEY'}) { #only for add + foreach my $key (keys %confighash) { + if ($confighash{$key}[1] eq $cgiparams{'NAME'}) { + $errormessage = $Lang::tr{'a connection with this name already exists'}; + goto VPNCONF_ERROR; + } + } + } + + if (($cgiparams{'TYPE'} eq 'net') && (! $cgiparams{'REMOTE'})) { + $errormessage = $Lang::tr{'invalid input for remote host/ip'}; + goto VPNCONF_ERROR; + } + + if ($cgiparams{'REMOTE'}) { + if (! &General::validip($cgiparams{'REMOTE'})) { + if (! &General::validfqdn ($cgiparams{'REMOTE'})) { + $errormessage = $Lang::tr{'invalid input for remote host/ip'}; + goto VPNCONF_ERROR; + } else { + if (&valid_dns_host($cgiparams{'REMOTE'})) { + $warnmessage = "$Lang::tr{'check vpn lr'} $cgiparams{'REMOTE'}. $Lang::tr{'dns check failed'}"; + } + } + } + } + + unless (&General::validipandmask($cgiparams{'LOCAL_SUBNET'})) { + $errormessage = $Lang::tr{'local subnet is invalid'}; + goto VPNCONF_ERROR; + } + + # Allow only one roadwarrior/psk without remote IP-address + if ($cgiparams{'REMOTE'} eq '' && $cgiparams{'AUTH'} eq 'psk') { + foreach my $key (keys %confighash) { + if ( ($cgiparams{'KEY'} ne $key) && + ($confighash{$key}[4] eq 'psk') && + ($confighash{$key}[10] eq '') ) { + $errormessage = $Lang::tr{'you can only define one roadwarrior connection when using pre-shared key authentication'}; + goto VPNCONF_ERROR; + } + } + } + if (($cgiparams{'TYPE'} eq 'net') && (! &General::validipandmask($cgiparams{'REMOTE_SUBNET'}))) { + $errormessage = $Lang::tr{'remote subnet is invalid'}; + goto VPNCONF_ERROR; + } + + if ($cgiparams{'ENABLED'} !~ /^(on|off)$/) { + $errormessage = $Lang::tr{'invalid input'}; + goto VPNCONF_ERROR; + } + if ($cgiparams{'EDIT_ADVANCED'} !~ /^(on|off)$/) { + $errormessage = $Lang::tr{'invalid input'}; + goto VPNCONF_ERROR; + } + + # Allow nothing or a string (DN,FDQN,) beginning with @ + # with no comma but slashes between RID eg @O=FR/C=Paris/OU=myhome/CN=franck + if ( ($cgiparams{'LOCAL_ID'} !~ /^(|[\w.-]*@[\w. =*\/-]+|\d\.\d\.\d\.\d)$/) || + ($cgiparams{'REMOTE_ID'} !~ /^(|[\w.-]*@[\w. =*\/-]+|\d\.\d\.\d\.\d)$/) || + (($cgiparams{'REMOTE_ID'} eq $cgiparams{'LOCAL_ID'}) && ($cgiparams{'LOCAL_ID'} ne '')) + ) { + $errormessage = $Lang::tr{'invalid local-remote id'} . '
' . + 'DER_ASN1_DN: @c=FR/ou=Paris/ou=Home/cn=*
' . + 'FQDN: @ipfire.org
' . + 'USER_FQDN: info@ipfire.org
' . + 'IPV4_ADDR: @123.123.123.123'; + goto VPNCONF_ERROR; + } + # If Auth is DN, verify existance of Remote ID. + if ( $cgiparams{'REMOTE_ID'} eq '' && ( + $cgiparams{'AUTH'} eq 'auth-dn'|| # while creation + $confighash{$cgiparams{'KEY'}}[2] eq '%auth-dn')){ # while editing + $errormessage = $Lang::tr{'vpn missing remote id'}; + goto VPNCONF_ERROR; + } + + if ($cgiparams{'AUTH'} eq 'psk') { + if (! length($cgiparams{'PSK'}) ) { + $errormessage = $Lang::tr{'pre-shared key is too short'}; + goto VPNCONF_ERROR; + } + if ($cgiparams{'PSK'} =~ /'/) { + $cgiparams{'PSK'} =~ tr/'/ /; + $errormessage = $Lang::tr{'invalid characters found in pre-shared key'}; + goto VPNCONF_ERROR; + } + } elsif ($cgiparams{'AUTH'} eq 'certreq') { + if ($cgiparams{'KEY'}) { + $errormessage = $Lang::tr{'cant change certificates'}; + goto VPNCONF_ERROR; + } + if (ref ($cgiparams{'FH'}) ne 'Fh') { + $errormessage = $Lang::tr{'there was no file upload'}; + goto VPNCONF_ERROR; + } + + # Move uploaded certificate request to a temporary file + (my $fh, my $filename) = tempfile( ); + if (copy ($cgiparams{'FH'}, $fh) != 1) { + $errormessage = $!; + goto VPNCONF_ERROR; + } + + # Sign the certificate request + &General::log("ipsec", "Signing your cert $cgiparams{'NAME'}..."); + my $opt = " ca -days 999999"; + $opt .= " -batch -notext"; + $opt .= " -in $filename"; + $opt .= " -out ${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"; + + if ( $errormessage = &callssl ($opt) ) { + unlink ($filename); + unlink ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); + &cleanssldatabase(); + goto VPNCONF_ERROR; + } else { + unlink ($filename); + &cleanssldatabase(); + } + + $cgiparams{'CERT_NAME'} = getCNfromcert ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); + if ($cgiparams{'CERT_NAME'} eq '') { + $errormessage = $Lang::tr{'could not retrieve common name from certificate'}; + goto VPNCONF_ERROR; + } + } elsif ($cgiparams{'AUTH'} eq 'pkcs12') { + &General::log("ipsec", "Importing from p12..."); + + if (ref ($cgiparams{'FH'}) ne 'Fh') { + $errormessage = $Lang::tr{'there was no file upload'}; + goto ROOTCERT_ERROR; + } + + # Move uploaded certificate request to a temporary file + (my $fh, my $filename) = tempfile( ); + if (copy ($cgiparams{'FH'}, $fh) != 1) { + $errormessage = $!; + goto ROOTCERT_ERROR; + } + + # Extract the CA certificate from the file + &General::log("ipsec", "Extracting caroot from p12..."); + if (open(STDIN, "-|")) { + my $opt = " pkcs12 -cacerts -nokeys"; + $opt .= " -in $filename"; + $opt .= " -out /tmp/newcacert"; + $errormessage = &callssl ($opt); + } else { #child + print "$cgiparams{'P12_PASS'}\n"; + exit (0); + } + + # Extract the Host certificate from the file + if (!$errormessage) { + &General::log("ipsec", "Extracting host cert from p12..."); + if (open(STDIN, "-|")) { + my $opt = " pkcs12 -clcerts -nokeys"; + $opt .= " -in $filename"; + $opt .= " -out /tmp/newhostcert"; + $errormessage = &callssl ($opt); + } else { #child + print "$cgiparams{'P12_PASS'}\n"; + exit (0); + } + } + + if (!$errormessage) { + &General::log("ipsec", "Moving cacert..."); + #If CA have new subject, add it to our list of CA + my $casubject = &Header::cleanhtml(getsubjectfromcert ('/tmp/newcacert')); + my @names; + foreach my $x (keys %cahash) { + $casubject='' if ($cahash{$x}[1] eq $casubject); + unshift (@names,$cahash{$x}[0]); + } + if ($casubject) { # a new one! + my $temp = `/usr/bin/openssl x509 -text -in /tmp/newcacert`; + if ($temp !~ /CA:TRUE/i) { + $errormessage = $Lang::tr{'not a valid ca certificate'}; + } else { + #compute a name for it + my $idx=0; + while (grep(/Imported-$idx/, @names) ) {$idx++}; + $cgiparams{'CA_NAME'}="Imported-$idx"; + $cgiparams{'CERT_NAME'}=&Header::cleanhtml(getCNfromcert ('/tmp/newhostcert')); + move("/tmp/newcacert", "${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem"); + $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0); + if (!$errormessage) { + my $key = &General::findhasharraykey (\%cahash); + $cahash{$key}[0] = $cgiparams{'CA_NAME'}; + $cahash{$key}[1] = $casubject; + &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash); + system('/usr/local/bin/ipsecctrl', 'R'); + } + } + } + } + if (!$errormessage) { + &General::log("ipsec", "Moving host cert..."); + move("/tmp/newhostcert", "${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); + $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0); + } + + #cleanup temp files + unlink ($filename); + unlink ('/tmp/newcacert'); + unlink ('/tmp/newhostcert'); + if ($errormessage) { + unlink ("${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem"); + unlink ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); + goto VPNCONF_ERROR; + } + &General::log("ipsec", "p12 import completed!"); + } elsif ($cgiparams{'AUTH'} eq 'certfile') { + if ($cgiparams{'KEY'}) { + $errormessage = $Lang::tr{'cant change certificates'}; + goto VPNCONF_ERROR; + } + if (ref ($cgiparams{'FH'}) ne 'Fh') { + $errormessage = $Lang::tr{'there was no file upload'}; + goto VPNCONF_ERROR; + } + # Move uploaded certificate to a temporary file + (my $fh, my $filename) = tempfile( ); + if (copy ($cgiparams{'FH'}, $fh) != 1) { + $errormessage = $!; + goto VPNCONF_ERROR; + } + + # Verify the certificate has a valid CA and move it + &General::log("ipsec", "Validating imported cert against our known CA..."); + my $validca = 1; #assume ok + my $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/cacert.pem $filename`; + if ($test !~ /: OK/) { + my $validca = 0; + foreach my $key (keys %cahash) { + $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/$cahash{$key}[0]cert.pem $filename`; + if ($test =~ /: OK/) { + $validca = 1; + last; + } + } + } + if (! $validca) { + $errormessage = $Lang::tr{'certificate does not have a valid ca associated with it'}; + unlink ($filename); + goto VPNCONF_ERROR; + } else { + move($filename, "${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); + if ($? ne 0) { + $errormessage = "$Lang::tr{'certificate file move failed'}: $!"; + unlink ($filename); + goto VPNCONF_ERROR; + } + } + + $cgiparams{'CERT_NAME'} = getCNfromcert ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); + if ($cgiparams{'CERT_NAME'} eq '') { + unlink ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem"); + $errormessage = $Lang::tr{'could not retrieve common name from certificate'}; + goto VPNCONF_ERROR; + } + } elsif ($cgiparams{'AUTH'} eq 'certgen') { + if ($cgiparams{'KEY'}) { + $errormessage = $Lang::tr{'cant change certificates'}; + goto VPNCONF_ERROR; + } + # Validate input since the form was submitted + if (length($cgiparams{'CERT_NAME'}) >60) { + $errormessage = $Lang::tr{'name too long'}; + goto VPNCONF_ERROR; + } + if ($cgiparams{'CERT_NAME'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) { + $errormessage = $Lang::tr{'invalid input for name'}; + goto VPNCONF_ERROR; + } + if ($cgiparams{'CERT_EMAIL'} ne '' && (! &General::validemail($cgiparams{'CERT_EMAIL'}))) { + $errormessage = $Lang::tr{'invalid input for e-mail address'}; + goto VPNCONF_ERROR; + } + if (length($cgiparams{'CERT_EMAIL'}) > 40) { + $errormessage = $Lang::tr{'e-mail address too long'}; + goto VPNCONF_ERROR; + } + if ($cgiparams{'CERT_OU'} ne '' && $cgiparams{'CERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { + $errormessage = $Lang::tr{'invalid input for department'}; + goto VPNCONF_ERROR; + } + if (length($cgiparams{'CERT_ORGANIZATION'}) >60) { + $errormessage = $Lang::tr{'organization too long'}; + goto VPNCONF_ERROR; + } + if ($cgiparams{'CERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) { + $errormessage = $Lang::tr{'invalid input for organization'}; + goto VPNCONF_ERROR; + } + if ($cgiparams{'CERT_CITY'} ne '' && $cgiparams{'CERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { + $errormessage = $Lang::tr{'invalid input for city'}; + goto VPNCONF_ERROR; + } + if ($cgiparams{'CERT_STATE'} ne '' && $cgiparams{'CERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) { + $errormessage = $Lang::tr{'invalid input for state or province'}; + goto VPNCONF_ERROR; + } + if ($cgiparams{'CERT_COUNTRY'} !~ /^[A-Z]*$/) { + $errormessage = $Lang::tr{'invalid input for country'}; + goto VPNCONF_ERROR; + } + #the exact syntax is a list comma separated of + # email:any-validemail + # URI: a uniform resource indicator + # DNS: a DNS domain name + # RID: a registered OBJECT IDENTIFIER + # IP: an IP address + # example: email:franck@foo.com,IP:10.0.0.10,DNS:franck.foo.com + + if ($cgiparams{'SUBJECTALTNAME'} ne '' && $cgiparams{'SUBJECTALTNAME'} !~ /^(email|URI|DNS|RID|IP):[a-zA-Z0-9 :\/,\.\-_@]*$/) { + $errormessage = $Lang::tr{'vpn altname syntax'}; + goto VPNCONF_ERROR; + } + + if (length($cgiparams{'CERT_PASS1'}) < 5) { + $errormessage = $Lang::tr{'password too short'}; + goto VPNCONF_ERROR; + } + if ($cgiparams{'CERT_PASS1'} ne $cgiparams{'CERT_PASS2'}) { + $errormessage = $Lang::tr{'passwords do not match'}; + goto VPNCONF_ERROR; + } + + # Replace empty strings with a . + (my $ou = $cgiparams{'CERT_OU'}) =~ s/^\s*$/\./; + (my $city = $cgiparams{'CERT_CITY'}) =~ s/^\s*$/\./; + (my $state = $cgiparams{'CERT_STATE'}) =~ s/^\s*$/\./; + + # Create the Host certificate request + &General::log("ipsec", "Creating a cert..."); + + if (open(STDIN, "-|")) { + my $opt = " req -nodes -rand /proc/interrupts:/proc/net/rt_cache"; + $opt .= " -newkey rsa:1024"; + $opt .= " -keyout ${General::swroot}/certs/$cgiparams{'NAME'}key.pem"; + $opt .= " -out ${General::swroot}/certs/$cgiparams{'NAME'}req.pem"; + + if ( $errormessage = &callssl ($opt) ) { + unlink ("${General::swroot}/certs/$cgiparams{'NAME'}key.pem"); + unlink ("${General::swroot}/certs/$cgiparams{'NAME'}req.pem"); + goto VPNCONF_ERROR; + } + } else { #child + print "$cgiparams{'CERT_COUNTRY'}\n"; + print "$state\n"; + print "$city\n"; + print "$cgiparams{'CERT_ORGANIZATION'}\n"; + print "$ou\n"; + print "$cgiparams{'CERT_NAME'}\n"; + print "$cgiparams{'CERT_EMAIL'}\n"; + print ".\n"; + print ".\n"; + exit (0); + } + + # Sign the host certificate request + &General::log("ipsec", "Signing the cert $cgiparams{'NAME'}..."); + + #No easy way for specifying the contain of subjectAltName without writing a config file... + my ($fh, $v3extname) = tempfile ('/tmp/XXXXXXXX'); + print $fh <$errormessage"; + print " "; + &Header::closebox(); + } + + if ($warnmessage) { + &Header::openbox('100%', 'left', "$Lang::tr{'warning messages'}:"); + print "$warnmessage"; + print " "; + &Header::closebox(); + } + + print "
"; + print< + + + + + + + + + + + + + +END + ; + if ($cgiparams{'KEY'}) { + print ""; + print ""; + } + + &Header::openbox('100%', 'left', "$Lang::tr{'connection'}:"); + print ""; + print ""; + if ($cgiparams{'KEY'}) { + print ""; + } else { + print ""; + } + print ""; + print ''; + + my $disabled; + my $blob; + if ($cgiparams{'TYPE'} eq 'host') { + $disabled = "disabled='disabled'"; + $blob = "*"; + }; + + print ""; + print ""; + print <$Lang::tr{'remote host/ip'}: $blob + + + + + + + + + + + + + + + + + + + + +END + ; + if (!$cgiparams{'KEY'}) { + print ""; + } + print "
$Lang::tr{'name'}:$cgiparams{'NAME'}$Lang::tr{'enabled'}

$Lang::tr{'host ip'}:
$Lang::tr{'local subnet'}$Lang::tr{'remote subnet'}
$Lang::tr{'vpn local id'}: * +
($Lang::tr{'eg'} @xy.example.com)
$Lang::tr{'vpn remote id'}: *

$Lang::tr{'dpd action'}:  ? +
$Lang::tr{'remark title'} *
$Lang::tr{'edit advanced settings when done'}
"; + &Header::closebox(); + + if ($cgiparams{'KEY'} && $cgiparams{'AUTH'} eq 'psk') { + &Header::openbox('100%', 'left', $Lang::tr{'authentication'}); + print < + $Lang::tr{'use a pre-shared key'} + + + +END + ; + &Header::closebox(); + } elsif (! $cgiparams{'KEY'}) { + my $pskdisabled = ($vpnsettings{'VPN_IP'} eq '%defaultroute') ? "disabled='disabled'" : '' ; + $cgiparams{'PSK'} = $Lang::tr{'vpn incompatible use of defaultroute'} if ($pskdisabled); + my $cakeydisabled = ( ! -f "${General::swroot}/private/cakey.pem" ) ? "disabled='disabled'" : ''; + $cgiparams{'CERT_NAME'} = $Lang::tr{'vpn no full pki'} if ($cakeydisabled); + my $cacrtdisabled = ( ! -f "${General::swroot}/ca/cacert.pem" ) ? "disabled='disabled'" : ''; + + &Header::openbox('100%', 'left', $Lang::tr{'authentication'}); + print < + + $Lang::tr{'use a pre-shared key'} + + + +
$Lang::tr{'upload a certificate request'} + + + $Lang::tr{'upload a certificate'} + + $Lang::tr{'upload p12 file'} $Lang::tr{'pkcs12 file password'}: + +
$Lang::tr{'vpn auth-dn'} + + +
$Lang::tr{'generate a certificate'}  +   + $Lang::tr{'users fullname or system hostname'}: + +   + $Lang::tr{'users email'}: * + +   + $Lang::tr{'users department'}: * + +   + $Lang::tr{'organization name'}: * + +   + $Lang::tr{'city'}: * + +   + $Lang::tr{'state or province'}: * + +   + $Lang::tr{'country'}: + +   + $Lang::tr{'pkcs12 file password'}: + +  $Lang::tr{'pkcs12 file password'}:($Lang::tr{'confirmation'}) + + +END + ; + &Header::closebox(); + } + + print "
"; + if ($cgiparams{'KEY'}) { + print ""; + } + print "
"; + &Header::closebigbox(); + &Header::closepage(); + exit (0); + + VPNCONF_END: +} + +### +### Advanced settings +### +if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) || + ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'ADVANCED'} eq 'yes')) { + &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings); + &General::readhasharray("${General::swroot}/vpn/config", \%confighash); + if (! $confighash{$cgiparams{'KEY'}}) { + $errormessage = $Lang::tr{'invalid key'}; + goto ADVANCED_END; + } + + if ($cgiparams{'ACTION'} eq $Lang::tr{'save'}) { + # I didn't read any incompatibilities here.... + #if ($cgiparams{'VHOST'} eq 'on' && $cgiparams{'COMPRESSION'} eq 'on') { + # $errormessage = $Lang::tr{'cannot enable both nat traversal and compression'}; + # goto ADVANCED_ERROR; + #} + my @temp = split('\|', $cgiparams{'IKE_ENCRYPTION'}); + if ($#temp < 0) { + $errormessage = $Lang::tr{'invalid input'}; + goto ADVANCED_ERROR; + } + foreach my $val (@temp) { + if ($val !~ /^(aes256|aes128|3des|twofish256|twofish128|serpent256|serpent128|blowfish256|blowfish128|cast128)$/) { + $errormessage = $Lang::tr{'invalid input'}; + goto ADVANCED_ERROR; + } + } + @temp = split('\|', $cgiparams{'IKE_INTEGRITY'}); + if ($#temp < 0) { + $errormessage = $Lang::tr{'invalid input'}; + goto ADVANCED_ERROR; + } + foreach my $val (@temp) { + if ($val !~ /^(sha2_512|sha2_256|sha|md5)$/) { + $errormessage = $Lang::tr{'invalid input'}; + goto ADVANCED_ERROR; + } + } + @temp = split('\|', $cgiparams{'IKE_GROUPTYPE'}); + if ($#temp < 0) { + $errormessage = $Lang::tr{'invalid input'}; + goto ADVANCED_ERROR; + } + foreach my $val (@temp) { + if ($val !~ /^(768|1024|1536|2048|3072|4096|6144|8192)$/) { + $errormessage = $Lang::tr{'invalid input'}; + goto ADVANCED_ERROR; + } + } + if ($cgiparams{'IKE_LIFETIME'} !~ /^\d+$/) { + $errormessage = $Lang::tr{'invalid input for ike lifetime'}; + goto ADVANCED_ERROR; + } + if ($cgiparams{'IKE_LIFETIME'} < 1 || $cgiparams{'IKE_LIFETIME'} > 8) { + $errormessage = $Lang::tr{'ike lifetime should be between 1 and 8 hours'}; + goto ADVANCED_ERROR; + } + @temp = split('\|', $cgiparams{'ESP_ENCRYPTION'}); + if ($#temp < 0) { + $errormessage = $Lang::tr{'invalid input'}; + goto ADVANCED_ERROR; + } + foreach my $val (@temp) { + if ($val !~ /^(aes256|aes128|3des|twofish256|twofish128|serpent256|serpent128|blowfish256|blowfish128)$/) { + $errormessage = $Lang::tr{'invalid input'}; + goto ADVANCED_ERROR; + } + } + @temp = split('\|', $cgiparams{'ESP_INTEGRITY'}); + if ($#temp < 0) { + $errormessage = $Lang::tr{'invalid input'}; + goto ADVANCED_ERROR; + } + foreach my $val (@temp) { + if ($val !~ /^(sha2_512|sha2_256|sha1|md5)$/) { + $errormessage = $Lang::tr{'invalid input'}; + goto ADVANCED_ERROR; + } + } + if ($cgiparams{'ESP_GROUPTYPE'} ne '' && + $cgiparams{'ESP_GROUPTYPE'} !~ /^modp(768|1024|1536|2048|3072|4096)$/) { + $errormessage = $Lang::tr{'invalid input'}; + goto ADVANCED_ERROR; + } + + if ($cgiparams{'ESP_KEYLIFE'} !~ /^\d+$/) { + $errormessage = $Lang::tr{'invalid input for esp keylife'}; + goto ADVANCED_ERROR; + } + if ($cgiparams{'ESP_KEYLIFE'} < 1 || $cgiparams{'ESP_KEYLIFE'} > 24) { + $errormessage = $Lang::tr{'esp keylife should be between 1 and 24 hours'}; + goto ADVANCED_ERROR; + } + + if ( + ($cgiparams{'AGGRMODE'} !~ /^(|on|off)$/) || + ($cgiparams{'COMPRESSION'} !~ /^(|on|off)$/) || + ($cgiparams{'ONLY_PROPOSED'} !~ /^(|on|off)$/) || + ($cgiparams{'PFS'} !~ /^(|on|off)$/) || + ($cgiparams{'VHOST'} !~ /^(|on|off)$/) + ){ + $errormessage = $Lang::tr{'invalid input'}; + goto ADVANCED_ERROR; + } + + $confighash{$cgiparams{'KEY'}}[18] = $cgiparams{'IKE_ENCRYPTION'}; + $confighash{$cgiparams{'KEY'}}[19] = $cgiparams{'IKE_INTEGRITY'}; + $confighash{$cgiparams{'KEY'}}[20] = $cgiparams{'IKE_GROUPTYPE'}; + $confighash{$cgiparams{'KEY'}}[16] = $cgiparams{'IKE_LIFETIME'}; + $confighash{$cgiparams{'KEY'}}[21] = $cgiparams{'ESP_ENCRYPTION'}; + $confighash{$cgiparams{'KEY'}}[22] = $cgiparams{'ESP_INTEGRITY'}; + $confighash{$cgiparams{'KEY'}}[23] = $cgiparams{'ESP_GROUPTYPE'}; + $confighash{$cgiparams{'KEY'}}[17] = $cgiparams{'ESP_KEYLIFE'}; + $confighash{$cgiparams{'KEY'}}[12] = $cgiparams{'AGGRMODE'}; + $confighash{$cgiparams{'KEY'}}[13] = $cgiparams{'COMPRESSION'}; + $confighash{$cgiparams{'KEY'}}[24] = $cgiparams{'ONLY_PROPOSED'}; + $confighash{$cgiparams{'KEY'}}[28] = $cgiparams{'PFS'}; + $confighash{$cgiparams{'KEY'}}[14] = $cgiparams{'VHOST'}; + &General::writehasharray("${General::swroot}/vpn/config", \%confighash); + &writeipsecfiles(); + if (&vpnenabled) { + system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'}); + sleep $sleepDelay; + } + goto ADVANCED_END; + } else { + $cgiparams{'IKE_ENCRYPTION'} = $confighash{$cgiparams{'KEY'}}[18]; + $cgiparams{'IKE_INTEGRITY'} = $confighash{$cgiparams{'KEY'}}[19]; + $cgiparams{'IKE_GROUPTYPE'} = $confighash{$cgiparams{'KEY'}}[20]; + $cgiparams{'IKE_LIFETIME'} = $confighash{$cgiparams{'KEY'}}[16]; + $cgiparams{'ESP_ENCRYPTION'} = $confighash{$cgiparams{'KEY'}}[21]; + $cgiparams{'ESP_INTEGRITY'} = $confighash{$cgiparams{'KEY'}}[22]; + $cgiparams{'ESP_GROUPTYPE'} = $confighash{$cgiparams{'KEY'}}[23]; + $cgiparams{'ESP_KEYLIFE'} = $confighash{$cgiparams{'KEY'}}[17]; + $cgiparams{'AGGRMODE'} = $confighash{$cgiparams{'KEY'}}[12]; + $cgiparams{'COMPRESSION'} = $confighash{$cgiparams{'KEY'}}[13]; + $cgiparams{'ONLY_PROPOSED'} = $confighash{$cgiparams{'KEY'}}[24]; + $cgiparams{'PFS'} = $confighash{$cgiparams{'KEY'}}[28]; + $cgiparams{'VHOST'} = $confighash{$cgiparams{'KEY'}}[14]; + + if ($confighash{$cgiparams{'KEY'}}[3] eq 'net' || $confighash{$cgiparams{'KEY'}}[10]) { + $cgiparams{'VHOST'} = 'off'; + } + } + + ADVANCED_ERROR: + $checked{'IKE_ENCRYPTION'}{'aes256'} = ''; + $checked{'IKE_ENCRYPTION'}{'aes128'} = ''; + $checked{'IKE_ENCRYPTION'}{'3des'} = ''; + $checked{'IKE_ENCRYPTION'}{'twofish256'} = ''; + $checked{'IKE_ENCRYPTION'}{'twofish128'} = ''; + $checked{'IKE_ENCRYPTION'}{'serpent256'} = ''; + $checked{'IKE_ENCRYPTION'}{'serpent128'} = ''; + $checked{'IKE_ENCRYPTION'}{'blowfish256'} = ''; + $checked{'IKE_ENCRYPTION'}{'blowfish128'} = ''; + $checked{'IKE_ENCRYPTION'}{'cast128'} = ''; + my @temp = split('\|', $cgiparams{'IKE_ENCRYPTION'}); + foreach my $key (@temp) {$checked{'IKE_ENCRYPTION'}{$key} = "selected='selected'"; } + $checked{'IKE_INTEGRITY'}{'sha2_512'} = ''; + $checked{'IKE_INTEGRITY'}{'sha2_256'} = ''; + $checked{'IKE_INTEGRITY'}{'sha'} = ''; + $checked{'IKE_INTEGRITY'}{'md5'} = ''; + @temp = split('\|', $cgiparams{'IKE_INTEGRITY'}); + foreach my $key (@temp) {$checked{'IKE_INTEGRITY'}{$key} = "selected='selected'"; } + $checked{'IKE_GROUPTYPE'}{'768'} = ''; + $checked{'IKE_GROUPTYPE'}{'1024'} = ''; + $checked{'IKE_GROUPTYPE'}{'1536'} = ''; + $checked{'IKE_GROUPTYPE'}{'2048'} = ''; + $checked{'IKE_GROUPTYPE'}{'3072'} = ''; + $checked{'IKE_GROUPTYPE'}{'4096'} = ''; + $checked{'IKE_GROUPTYPE'}{'6144'} = ''; + $checked{'IKE_GROUPTYPE'}{'8192'} = ''; + @temp = split('\|', $cgiparams{'IKE_GROUPTYPE'}); + foreach my $key (@temp) {$checked{'IKE_GROUPTYPE'}{$key} = "selected='selected'"; } + $checked{'ESP_ENCRYPTION'}{'aes256'} = ''; + $checked{'ESP_ENCRYPTION'}{'aes128'} = ''; + $checked{'ESP_ENCRYPTION'}{'3des'} = ''; + $checked{'ESP_ENCRYPTION'}{'twofish256'} = ''; + $checked{'ESP_ENCRYPTION'}{'twofish128'} = ''; + $checked{'ESP_ENCRYPTION'}{'serpent256'} = ''; + $checked{'ESP_ENCRYPTION'}{'serpent128'} = ''; + $checked{'ESP_ENCRYPTION'}{'blowfish256'} = ''; + $checked{'ESP_ENCRYPTION'}{'blowfish128'} = ''; + @temp = split('\|', $cgiparams{'ESP_ENCRYPTION'}); + foreach my $key (@temp) {$checked{'ESP_ENCRYPTION'}{$key} = "selected='selected'"; } + $checked{'ESP_INTEGRITY'}{'sha2_512'} = ''; + $checked{'ESP_INTEGRITY'}{'sha2_256'} = ''; + $checked{'ESP_INTEGRITY'}{'sha1'} = ''; + $checked{'ESP_INTEGRITY'}{'md5'} = ''; + @temp = split('\|', $cgiparams{'ESP_INTEGRITY'}); + foreach my $key (@temp) {$checked{'ESP_INTEGRITY'}{$key} = "selected='selected'"; } + $checked{'ESP_GROUPTYPE'}{$cgiparams{'ESP_GROUPTYPE'}} = "selected='selected'"; + + $checked{'AGGRMODE'} = $cgiparams{'AGGRMODE'} eq 'on' ? "checked='checked'" : '' ; + $checked{'COMPRESSION'} = $cgiparams{'COMPRESSION'} eq 'on' ? "checked='checked'" : '' ; + $checked{'ONLY_PROPOSED'} = $cgiparams{'ONLY_PROPOSED'} eq 'on' ? "checked='checked'" : '' ; + $checked{'PFS'} = $cgiparams{'PFS'} eq 'on' ? "checked='checked'" : '' ; + $checked{'VHOST'} = $cgiparams{'VHOST'} eq 'on' ? "checked='checked'" : '' ; + + &Header::showhttpheaders(); + &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); + &Header::openbigbox('100%', 'left', '', $errormessage); + + if ($errormessage) { + &Header::openbox('100%', 'left', $Lang::tr{'error messages'}); + print "$errormessage"; + print " "; + &Header::closebox(); + } + + if ($warnmessage) { + &Header::openbox('100%', 'left', $Lang::tr{'warning messages'}); + print "$warnmessage"; + print " "; + &Header::closebox(); + } + + &Header::openbox('100%', 'left', "$Lang::tr{'advanced'}:"); + print < + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +EOF + ; + if ($confighash{$cgiparams{'KEY'}}[3] eq 'net') { + print ""; + } elsif ($confighash{$cgiparams{'KEY'}}[10]) { + print ""; + } else { + print ""; + } + + print "
$Lang::tr{'ike encryption'} + $Lang::tr{'ike integrity'} + $Lang::tr{'ike grouptype'} +
$Lang::tr{'ike lifetime'} + $Lang::tr{'hours'}

$Lang::tr{'esp encryption'} + $Lang::tr{'esp integrity'} + $Lang::tr{'esp grouptype'} +
$Lang::tr{'esp keylife'} + $Lang::tr{'hours'}

+ IKE+ESP: $Lang::tr{'use only proposed settings'}
+ $Lang::tr{'vpn aggrmode'}
+ $Lang::tr{'pfs yes no'}
+ $Lang::tr{'vpn payload compression'}
"; + print " $Lang::tr{'vpn vhost'}
"; + print " $Lang::tr{'vpn vhost'}
"; + &Header::closebox(); + &Header::closebigbox(); + &Header::closepage(); + exit(0); + + ADVANCED_END: +} + +### +### Default status page +### + %cgiparams = (); + %cahash = (); + %confighash = (); + &General::readhash("${General::swroot}/vpn/settings", \%cgiparams); + &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash); + &General::readhasharray("${General::swroot}/vpn/config", \%confighash); + $cgiparams{'CA_NAME'} = ''; + + my @status = `/usr/sbin/ipsec auto --status`; + + # suggest a default name for this side + if ($cgiparams{'VPN_IP'} eq '' && -e "${General::swroot}/red/active") { + if (open(IPADDR, "${General::swroot}/red/local-ipaddress")) { + my $ipaddr = ; + close IPADDR; + chomp ($ipaddr); + $cgiparams{'VPN_IP'} = (gethostbyaddr(pack("C4", split(/\./, $ipaddr)), 2))[0]; + if ($cgiparams{'VPN_IP'} eq '') { + $cgiparams{'VPN_IP'} = $ipaddr; + } + } + } + # no IP found, use %defaultroute + $cgiparams{'VPN_IP'} ='%defaultroute' if ($cgiparams{'VPN_IP'} eq ''); + + $cgiparams{'VPN_DELAYED_START'} = 0 if (! defined ($cgiparams{'VPN_DELAYED_START'})); + $checked{'VPN_WATCH'} = $cgiparams{'VPN_WATCH'} eq 'on' ? "checked='checked'" : '' ; + map ($checked{$_} = $cgiparams{$_} eq 'on' ? "checked='checked'" : '', + ('ENABLED','DBG_CRYPT','DBG_PARSING','DBG_EMITTING','DBG_CONTROL', + 'DBG_KLIPS','DBG_DNS','DBG_NAT_T')); + + + &Header::showhttpheaders(); + &Header::openpage($Lang::tr{'vpn configuration main'}, 1, ''); + &Header::openbigbox('100%', 'left', '', $errormessage); + + if ($errormessage) { + &Header::openbox('100%', 'left', $Lang::tr{'error messages'}); + print "$errormessage\n"; + print " \n"; + &Header::closebox(); + } + + &Header::openbox('100%', 'left', $Lang::tr{'global settings'}); + print < + + + + + + +END + ; + print < + + + +END + ; +print < + + + +
$Lang::tr{'vpn red name'}:$Lang::tr{'enabled'}
$Lang::tr{'override mtu'}: *
$Lang::tr{'vpn delayed start'}: **
+

$Lang::tr{'vpn watch'}:

+

PLUTO DEBUG = +crypt:,  +parsing:,  +emitting:,  +control:,  +klips:,  +dns:,  +nat_t:

+ +
+ + + + + + + + + + +
*$Lang::tr{'this field may be blank'}
**  $Lang::tr{'vpn delayed start help'}
+END +; + print ""; + &Header::closebox(); + + &Header::openbox('100%', 'left', $Lang::tr{'connection status and controlc'}); + print < + + $Lang::tr{'name'} + $Lang::tr{'type'} + $Lang::tr{'common name'} + $Lang::tr{'remark'} + $Lang::tr{'status'} + $Lang::tr{'action'} + +END + ; + my $id = 0; + my $gif; + foreach my $key (keys %confighash) { + if ($confighash{$key}[0] eq 'on') { $gif = 'on.gif'; } else { $gif = 'off.gif'; } + + if ($id % 2) { + print "\n"; + } else { + print "\n"; + } + print "$confighash{$key}[1]"; + print "" . $Lang::tr{"$confighash{$key}[3]"} . " (" . $Lang::tr{"$confighash{$key}[4]"} . ")"; + if ($confighash{$key}[2] eq '%auth-dn') { + print "$confighash{$key}[9]"; + } elsif ($confighash{$key}[4] eq 'cert') { + print "$confighash{$key}[2]"; + } else { + print " "; + } + print "$confighash{$key}[25]"; + # get real state + my $active = "
$Lang::tr{'capsclosed'}
"; + foreach my $line (@status) { + if ($line =~ /\"$confighash{$key}[1]\".*IPsec SA established/) { + $active = "
$Lang::tr{'capsopen'}
"; + } + } + # move to blueif really down + if ($confighash{$key}[0] eq 'off' && $active =~ /${Header::colourred}/ ) { + $active = "
$Lang::tr{'capsclosed'}
"; + } + print <$active + +
+ + + +
+ +END + ; + if (($confighash{$key}[4] eq 'cert') && ($confighash{$key}[2] ne '%auth-dn')) { + print < +
+ + + +
+ +END + ; } else { + print " "; + } + if ($confighash{$key}[4] eq 'cert' && -f "${General::swroot}/certs/$confighash{$key}[1].p12") { + print < +
+ + + +
+ +END + ; } elsif (($confighash{$key}[4] eq 'cert') && ($confighash{$key}[2] ne '%auth-dn')) { + print < +
+ + + +
+ +END + ; } else { + print " "; + } + print < +
+ + + +
+ + + +
+ + + +
+ + +
+ + + +
+ + +END + ; + $id++; + } + print ""; + + # If the config file contains entries, print Key to action icons + if ( $id ) { + print < + +   $Lang::tr{'legend'}: +   $Lang::tr{ + $Lang::tr{'click to disable'} +     $Lang::tr{ + $Lang::tr{'show certificate'} +     $Lang::tr{ + $Lang::tr{'edit'} +     $Lang::tr{ + $Lang::tr{'remove'} + + +   +   ?OFF + $Lang::tr{'click to enable'} +     ?FLOPPY + $Lang::tr{'download certificate'} +     ?RELOAD + $Lang::tr{'restart'} + + +END + ; + } + + print < + +
+ +
+ + +END + ; + &Header::closebox(); + + &Header::openbox('100%', 'left', "$Lang::tr{'certificate authorities'}:"); + print < + + $Lang::tr{'name'} + $Lang::tr{'subject'} + $Lang::tr{'action'} + +EOF + ; + if (-f "${General::swroot}/ca/cacert.pem") { + my $casubject = &Header::cleanhtml(getsubjectfromcert ("${General::swroot}/ca/cacert.pem")); + + print < + $Lang::tr{'root certificate'} + $casubject + +
+ + +
+ + +
+ + +
+ +   +END + ; + } else { + # display rootcert generation buttons + print < + $Lang::tr{'root certificate'}: + $Lang::tr{'not present'} +   +END + ; + } + + if (-f "${General::swroot}/certs/hostcert.pem") { + my $hostsubject = &Header::cleanhtml(getsubjectfromcert ("${General::swroot}/certs/hostcert.pem")); + + print < + $Lang::tr{'host certificate'} + $hostsubject + +
+ + +
+ + +
+ + +
+ +   +END + ; + } else { + # Nothing + print < + $Lang::tr{'host certificate'}: + $Lang::tr{'not present'} +   +END + ; + } + + my $rowcolor = 0; + if (keys %cahash > 0) { + foreach my $key (keys %cahash) { + if ($rowcolor++ % 2) { + print "\n"; + } else { + print "\n"; + } + print "$cahash{$key}[0]\n"; + print "$cahash{$key}[1]\n"; + print < +
+ + + +
+ + +
+ + + +
+ + +
+ + + +
+ + +END + ; + } + } + print ""; + + # If the file contains entries, print Key to action icons + if ( -f "${General::swroot}/ca/cacert.pem") { + print < +   $Lang::tr{'legend'}: +     $Lang::tr{ + $Lang::tr{'show certificate'} +     $Lang::tr{ + $Lang::tr{'download certificate'} + +END + ; + } + my $createCA = -f "${General::swroot}/ca/cacert.pem" ? '' : ""; + print < +
+ + $createCA + + + + + + + + + + +
$Lang::tr{'ca name'}:
$Lang::tr{'resetting the vpn configuration will remove the root ca, the host certificate and all certificate based connections'}:
+
+END + ; + &Header::closebox(); + &Header::closebigbox(); + &Header::closepage();