#!/usr/bin/perl ############################################################################### # # # IPFire.org - A linux based firewall # # Copyright (C) 2007-2011 IPFire Team info@ipfire.org # # # # 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); my $green_cidr = &General::ipcidr("$netsettings{'GREEN_NETADDRESS'}/$netsettings{'GREEN_NETMASK'}"); my $blue_cidr = "# Blue not defined"; if ($netsettings{'BLUE_DEV'}) { $blue_cidr = &General::ipcidr("$netsettings{'BLUE_NETADDRESS'}/$netsettings{'BLUE_NETMASK'}"); } my $orange_cidr = "# Orange not defined"; if ($netsettings{'ORANGE_DEV'}) { $orange_cidr = &General::ipcidr("$netsettings{'ORANGE_NETADDRESS'}/$netsettings{'ORANGE_NETMASK'}"); } $cgiparams{'ENABLED'} = 'off'; $cgiparams{'EDIT_ADVANCED'} = 'off'; $cgiparams{'ACTION'} = ''; $cgiparams{'CA_NAME'} = ''; $cgiparams{'KEY'} = ''; $cgiparams{'TYPE'} = ''; $cgiparams{'ADVANCED'} = ''; $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'} = ''; $cgiparams{'RW_NET'} = ''; &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"; print CONF "\tcharondebug=\"dmn 0, mgr 0, ike 0, chd 0, job 0, cfg 0, knl 0, net 0, asn 0, enc 0, lib 0, esp 0, tls 0, tnc 0, imc 0, imv 0, pts 0\"\n"; print CONF "\n"; print CONF "conn %default\n"; print CONF "\tkeyingtries=%forever\n"; print CONF "\n"; # Add user includes to config file print CONF "include /etc/ipsec.user.conf\n"; print CONF "\n"; print SECRETS "include /etc/ipsec.user.secrets\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"; my $cidr_net=&General::ipcidr($lconfighash{$key}[8]); print CONF "\tleftsubnet=$cidr_net\n"; print CONF "\tleftfirewall=yes\n"; print CONF "\tlefthostaccess=yes\n"; print CONF "\tright=$lconfighash{$key}[10]\n"; if ($lconfighash{$key}[3] eq 'net') { my $cidr_net=&General::ipcidr($lconfighash{$key}[11]); print CONF "\trightsubnet=$cidr_net\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]); # Is PFS enabled? my $pfs = $lconfighash{$key}[28] eq 'on' ? 'on' : 'off'; # 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 @groups = split('\|', $lconfighash{$key}[20]); my $comma = 0; foreach my $i (@encs) { foreach my $j (@ints) { my $modp = ""; if ($pfs eq "on") { foreach my $k (@groups) { if ($comma != 0) { print CONF ","; } else { $comma = 1; } if ($pfs eq "on") { $modp = "-modp$k"; } else { $modp = ""; } print CONF "$i-$j$modp"; } } else { 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"; } } # IKE V1 or V2 if (! $lconfighash{$key}[29]) { $lconfighash{$key}[29] = "ikev1"; } print CONF "\tkeyexchange=$lconfighash{$key}[29]\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]); # 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"; # 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"; print CONF "\trightsourceip=$lvpnsettings{'RW_NET'}\n"; } else { print CONF "\tauto=start\n"; } print CONF "\n"; }#foreach key print SECRETS $last_secrets if ($last_secrets); close(CONF); close(SECRETS); } # Hook to regenerate the configuration files. if ($ENV{"REMOTE_ADDR"} eq "") { writeipsecfiles; exit(0); } ### ### 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; } if ( $cgiparams{'RW_NET'} ne '' and !&General::validipandmask($cgiparams{'RW_NET'}) ) { $errormessage = $Lang::tr{'urlfilter invalid ip or mask error'}; goto SAVE_ERROR; } $vpnsettings{'ENABLED'} = $cgiparams{'ENABLED'}; $vpnsettings{'VPN_IP'} = $cgiparams{'VPN_IP'}; $vpnsettings{'VPN_DELAYED_START'} = $cgiparams{'VPN_DELAYED_START'}; $vpnsettings{'RW_NET'} = $cgiparams{'RW_NET'}; &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 "
$Lang::tr{'back'}
"; &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 "
$Lang::tr{'back'}
"; &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{'DPD_ACTION'} = $confighash{$cgiparams{'KEY'}}[27]; $cgiparams{'IKE_VERSION'} = $confighash{$cgiparams{'KEY'}}[29]; $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{'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 (($cgiparams{'REMOTE'} ne '%any') && (! &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{'TYPE'} eq 'net'){ $errormessage=&General::checksubnets($cgiparams{'NAME'},$cgiparams{'REMOTE_SUBNET'}); if ($errormessage ne ''){ 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 < END ; if (!$cgiparams{'KEY'}) { print ""; } print "
$Lang::tr{'name'}:$cgiparams{'NAME'}$Lang::tr{'enabled'}

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

$Lang::tr{'vpn keyexchange'}: $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)$/) { $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_384|sha2_256|sha|md5|aesxcbc)$/) { $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 !~ /^(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|aes192|aes128|3des)$/) { $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_384|sha2_256|sha1|md5|aesxcbc)$/) { $errormessage = $Lang::tr{'invalid input'}; goto ADVANCED_ERROR; } } if ($cgiparams{'ESP_GROUPTYPE'} ne '' && $cgiparams{'ESP_GROUPTYPE'} !~ /^modp(1024|1536|2048|3072|4096|6144|8192)$/) { $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{'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] = 'off'; #$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{'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'}{'aes192'} = ''; $checked{'IKE_ENCRYPTION'}{'aes128'} = ''; $checked{'IKE_ENCRYPTION'}{'3des'} = ''; 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_384'} = ''; $checked{'IKE_INTEGRITY'}{'sha2_256'} = ''; $checked{'IKE_INTEGRITY'}{'sha'} = ''; $checked{'IKE_INTEGRITY'}{'md5'} = ''; $checked{'IKE_INTEGRITY'}{'aesxcbc'} = ''; @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'"; } # 768 is not supported by strongswan $checked{'IKE_GROUPTYPE'}{'768'} = ''; $checked{'ESP_ENCRYPTION'}{'aes256'} = ''; $checked{'ESP_ENCRYPTION'}{'aes192'} = ''; $checked{'ESP_ENCRYPTION'}{'aes128'} = ''; $checked{'ESP_ENCRYPTION'}{'3des'} = ''; @temp = split('\|', $cgiparams{'ESP_ENCRYPTION'}); foreach my $key (@temp) {$checked{'ESP_ENCRYPTION'}{$key} = "selected='selected'"; } $checked{'ESP_INTEGRITY'}{'sha2_512'} = ''; $checked{'ESP_INTEGRITY'}{'sha2_384'} = ''; $checked{'ESP_INTEGRITY'}{'sha2_256'} = ''; $checked{'ESP_INTEGRITY'}{'sha1'} = ''; $checked{'ESP_INTEGRITY'}{'md5'} = ''; $checked{'ESP_INTEGRITY'}{'aesxcbc'} = ''; @temp = split('\|', $cgiparams{'ESP_INTEGRITY'}); foreach my $key (@temp) {$checked{'ESP_INTEGRITY'}{$key} = "selected='selected'"; } $checked{'ESP_GROUPTYPE'}{$cgiparams{'ESP_GROUPTYPE'}} = "selected='selected'"; $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{'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/local/bin/ipsecctrl I 2>/dev/null`; # 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{'ENABLED'} = $cgiparams{'ENABLED'} 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\n"; print " \n"; &Header::closebox(); } &Header::openbox('100%', 'left', $Lang::tr{'global settings'}); print < END ; print <
$Lang::tr{'vpn red name'}: $Lang::tr{'enabled'}
$Lang::tr{'vpn delayed start'}: **
$Lang::tr{'host to net vpn'}: *

* $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]"} . ") $confighash{$key}[29]"; 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/) || ($line =~ /$confighash{$key}[1]\{.*INSTALLED/)) { $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();