kernel: update rpi-patchset and some sound options.
[ipfire-2.x.git] / html / cgi-bin / vpnmain.cgi
1 #!/usr/bin/perl
2 ###############################################################################
3 #                                                                             #
4 # IPFire.org - A linux based firewall                                         #
5 # Copyright (C) 2007-2011  IPFire Team  info@ipfire.org                       #
6 #                                                                             #
7 # This program is free software: you can redistribute it and/or modify        #
8 # it under the terms of the GNU General Public License as published by        #
9 # the Free Software Foundation, either version 3 of the License, or           #
10 # (at your option) any later version.                                         #
11 #                                                                             #
12 # This program is distributed in the hope that it will be useful,             #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of              #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
15 # GNU General Public License for more details.                                #
16 #                                                                             #
17 # You should have received a copy of the GNU General Public License           #
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
19 #                                                                             #
20 ###############################################################################
21
22 use Net::DNS;
23 use File::Copy;
24 use File::Temp qw/ tempfile tempdir /;
25 use strict;
26
27 # enable only the following on debugging purpose
28 #use warnings;
29 #use CGI::Carp 'fatalsToBrowser';
30
31 require '/var/ipfire/general-functions.pl';
32 require "${General::swroot}/lang.pl";
33 require "${General::swroot}/header.pl";
34 require "${General::swroot}/countries.pl";
35
36 #workaround to suppress a warning when a variable is used only once
37 my @dummy = ( ${Header::colourgreen}, ${Header::colourblue} );
38 undef (@dummy);
39
40 ###
41 ### Initialize variables
42 ###
43 my $sleepDelay = 4;     # after a call to ipsecctrl S or R, wait this delay (seconds) before reading status
44                         # (let the ipsec do its job)
45 my %netsettings=();
46 our %cgiparams=();
47 our %vpnsettings=();
48 my %checked=();
49 my %confighash=();
50 my %cahash=();
51 my %selected=();
52 my $warnmessage = '';
53 my $errormessage = '';
54
55 my %color = ();
56 my %mainsettings = ();
57 &General::readhash("${General::swroot}/main/settings", \%mainsettings);
58 &General::readhash("/srv/web/ipfire/html/themes/".$mainsettings{'THEME'}."/include/colors.txt", \%color);
59
60 &General::readhash("${General::swroot}/ethernet/settings", \%netsettings);
61
62 my $green_cidr = &General::ipcidr("$netsettings{'GREEN_NETADDRESS'}/$netsettings{'GREEN_NETMASK'}");
63 my $blue_cidr = "# Blue not defined";
64 if ($netsettings{'BLUE_DEV'}) {
65         $blue_cidr = &General::ipcidr("$netsettings{'BLUE_NETADDRESS'}/$netsettings{'BLUE_NETMASK'}");
66 }
67 my $orange_cidr = "# Orange not defined";
68 if ($netsettings{'ORANGE_DEV'}) {
69         $orange_cidr = &General::ipcidr("$netsettings{'ORANGE_NETADDRESS'}/$netsettings{'ORANGE_NETMASK'}");
70 }
71
72 $cgiparams{'ENABLED'} = 'off';
73 $cgiparams{'EDIT_ADVANCED'} = 'off';
74 $cgiparams{'ACTION'} = '';
75 $cgiparams{'CA_NAME'} = '';
76 $cgiparams{'KEY'} = '';
77 $cgiparams{'TYPE'} = '';
78 $cgiparams{'ADVANCED'} = '';
79 $cgiparams{'NAME'} = '';
80 $cgiparams{'LOCAL_SUBNET'} = '';
81 $cgiparams{'REMOTE_SUBNET'} = '';
82 $cgiparams{'REMOTE'} = '';
83 $cgiparams{'LOCAL_ID'} = '';
84 $cgiparams{'REMOTE_ID'} = '';
85 $cgiparams{'REMARK'} = '';
86 $cgiparams{'PSK'} = '';
87 $cgiparams{'CERT_NAME'} = '';
88 $cgiparams{'CERT_EMAIL'} = '';
89 $cgiparams{'CERT_OU'} = '';
90 $cgiparams{'CERT_ORGANIZATION'} = '';
91 $cgiparams{'CERT_CITY'} = '';
92 $cgiparams{'CERT_STATE'} = '';
93 $cgiparams{'CERT_COUNTRY'} = '';
94 $cgiparams{'SUBJECTALTNAME'} = '';
95 $cgiparams{'CERT_PASS1'} = '';
96 $cgiparams{'CERT_PASS2'} = '';
97 $cgiparams{'ROOTCERT_HOSTNAME'} = '';
98 $cgiparams{'ROOTCERT_COUNTRY'} = '';
99 $cgiparams{'P12_PASS'} = '';
100 $cgiparams{'ROOTCERT_ORGANIZATION'} = '';
101 $cgiparams{'ROOTCERT_HOSTNAME'} = '';
102 $cgiparams{'ROOTCERT_EMAIL'} = '';
103 $cgiparams{'ROOTCERT_OU'} = '';
104 $cgiparams{'ROOTCERT_CITY'} = '';
105 $cgiparams{'ROOTCERT_STATE'} = '';
106 $cgiparams{'RW_NET'} = '';
107
108 &Header::getcgihash(\%cgiparams, {'wantfile' => 1, 'filevar' => 'FH'});
109
110 ###
111 ### Useful functions
112 ###
113 sub valid_dns_host {
114         my $hostname = $_[0];
115         unless ($hostname) { return "No hostname"};
116         my $res = new Net::DNS::Resolver;
117         my $query = $res->search("$hostname");
118         if ($query) {
119                 foreach my $rr ($query->answer) {
120                         ## Potential bug - we are only looking at A records:
121                         return 0 if $rr->type eq "A";
122                 }
123         } else {
124                 return $res->errorstring;
125         }
126 }
127 ###
128 ### Just return true is one interface is vpn enabled
129 ###
130 sub vpnenabled {
131     return ($vpnsettings{'ENABLED'} eq 'on');
132 }
133 ###
134 ### old version: maintain serial number to one, without explication. 
135 ### this             : let the counter go, so that each cert is numbered.
136 ###
137 sub cleanssldatabase
138 {
139     if (open(FILE, ">${General::swroot}/certs/serial")) {
140         print FILE "01";
141         close FILE;
142     }
143     if (open(FILE, ">${General::swroot}/certs/index.txt")) {
144         print FILE "";
145         close FILE;
146     }
147     unlink ("${General::swroot}/certs/index.txt.old");
148     unlink ("${General::swroot}/certs/serial.old");
149     unlink ("${General::swroot}/certs/01.pem");
150 }
151 sub newcleanssldatabase
152 {
153     if (! -s "${General::swroot}/certs/serial" )  {
154         open(FILE, ">${General::swroot}/certs/serial");
155         print FILE "01";
156         close FILE;
157     }
158     if (! -s ">${General::swroot}/certs/index.txt") {
159         system ("touch ${General::swroot}/certs/index.txt");
160     }
161     unlink ("${General::swroot}/certs/index.txt.old");
162     unlink ("${General::swroot}/certs/serial.old");
163 #   unlink ("${General::swroot}/certs/01.pem");         numbering evolves. Wrong place to delete
164 }
165
166 ###
167 ### Call openssl and return errormessage if any
168 ###
169 sub callssl ($) {
170     my $opt = shift;
171     my $retssl =  `/usr/bin/openssl $opt 2>&1`; #redirect stderr
172     my $ret = '';
173     foreach my $line (split (/\n/, $retssl)) {
174         &General::log("ipsec", "$line") if (0);         # 1 for verbose logging
175         $ret .= '<br>'.$line if ( $line =~ /error|unknown/ );
176     }
177     if ($ret) {
178         $ret= &Header::cleanhtml($ret);
179     }
180     return $ret ? "$Lang::tr{'openssl produced an error'}: $ret" : '' ;
181 }
182 ###
183 ### Obtain a CN from given cert
184 ###
185 sub getCNfromcert ($) {
186     #&General::log("ipsec", "Extracting name from $_[0]...");
187     my $temp = `/usr/bin/openssl x509 -text -in $_[0]`;
188     $temp =~ /Subject:.*CN=(.*)[\n]/;
189     $temp = $1;
190     $temp =~ s+/Email+, E+;
191     $temp =~ s/ ST=/ S=/;
192     $temp =~ s/,//g;
193     $temp =~ s/\'//g;
194     return $temp;
195 }
196 ###
197 ### Obtain Subject from given cert
198 ###
199 sub getsubjectfromcert ($) {
200     #&General::log("ipsec", "Extracting subject from $_[0]...");
201     my $temp = `/usr/bin/openssl x509 -text -in $_[0]`;
202     $temp =~ /Subject: (.*)[\n]/;
203     $temp = $1;
204     $temp =~ s+/Email+, E+;
205     $temp =~ s/ ST=/ S=/;
206     return $temp;
207 }
208 ###
209 ### Combine local subnet and connection name to make a unique name for each connection section 
210 ### (this sub is not used now)
211 ###
212 sub makeconnname ($) {
213     my $conn = shift;
214     my $subnet = shift;
215
216     $subnet =~ /^(.*?)\/(.*?)$/;        # $1=IP $2=mask
217     my $ip = unpack('N', &Socket::inet_aton($1));
218     if (length ($2) > 2) {
219         my $mm =  unpack('N', &Socket::inet_aton($2));
220         while ( ($mm & 1)==0 ) {
221             $ip >>= 1; 
222             $mm >>= 1;
223         };
224     } else {
225         $ip >>=  (32 - $2);
226     }
227     return sprintf ("%s-%X", $conn, $ip);
228 }
229 ###
230 ### Write a config file.
231 ###
232 ###Type=Host : GUI can choose the interface used (RED,GREEN,BLUE) and
233 ###             the side is always defined as 'left'.
234 ###             configihash[14]: 'VHOST' is allowed
235 ###
236
237 sub writeipsecfiles {
238     my %lconfighash = ();
239     my %lvpnsettings = ();
240     &General::readhasharray("${General::swroot}/vpn/config", \%lconfighash);
241     &General::readhash("${General::swroot}/vpn/settings", \%lvpnsettings);
242
243     open(CONF,    ">${General::swroot}/vpn/ipsec.conf") or die "Unable to open ${General::swroot}/vpn/ipsec.conf: $!";
244     open(SECRETS, ">${General::swroot}/vpn/ipsec.secrets") or die "Unable to open ${General::swroot}/vpn/ipsec.secrets: $!";
245     flock CONF, 2;
246     flock SECRETS, 2;
247     print CONF "version 2\n\n";
248     print CONF "config setup\n";
249     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";
250     print CONF "\n";
251     print CONF "conn %default\n";
252     print CONF "\tkeyingtries=%forever\n";
253     print CONF "\n";
254
255     # Add user includes to config file
256     print CONF "include /etc/ipsec.user.conf\n";
257     print CONF "\n";
258
259     print SECRETS "include /etc/ipsec.user.secrets\n";
260
261     if (-f "${General::swroot}/certs/hostkey.pem") {
262         print SECRETS ": RSA ${General::swroot}/certs/hostkey.pem\n"
263     }
264     my $last_secrets = ''; # old the less specifics connections
265     
266     foreach my $key (keys %lconfighash) {
267         next if ($lconfighash{$key}[0] ne 'on');
268
269         #remote peer is not set? => use '%any'
270         $lconfighash{$key}[10] = '%any' if ($lconfighash{$key}[10] eq '');
271
272         my $localside;
273         if ($lconfighash{$key}[26] eq 'BLUE') {
274                 $localside = $netsettings{'BLUE_ADDRESS'};
275         } elsif ($lconfighash{$key}[26] eq 'GREEN') {
276                 $localside = $netsettings{'GREEN_ADDRESS'};
277         } elsif ($lconfighash{$key}[26] eq 'ORANGE') {
278                 $localside = $netsettings{'ORANGE_ADDRESS'};
279         } else {        # it is RED
280                 $localside = $lvpnsettings{'VPN_IP'};
281         }
282
283         print CONF "conn $lconfighash{$key}[1]\n";
284         print CONF "\tleft=$localside\n";
285         my $cidr_net=&General::ipcidr($lconfighash{$key}[8]);
286         print CONF "\tleftsubnet=$cidr_net\n";
287         print CONF "\tleftfirewall=yes\n";
288         print CONF "\tlefthostaccess=yes\n";
289
290         print CONF "\tright=$lconfighash{$key}[10]\n";
291         if ($lconfighash{$key}[3] eq 'net') {
292             my $cidr_net=&General::ipcidr($lconfighash{$key}[11]);
293             print CONF "\trightsubnet=$cidr_net\n";
294         } elsif ($lconfighash{$key}[10] eq '%any' && $lconfighash{$key}[14] eq 'on') { #vhost allowed for roadwarriors?
295             print CONF "\trightsubnet=vhost:%no,%priv\n";
296         }
297
298         # Local Cert and Remote Cert (unless auth is DN dn-auth)
299         if ($lconfighash{$key}[4] eq 'cert') {
300             print CONF "\tleftcert=${General::swroot}/certs/hostcert.pem\n";
301             print CONF "\trightcert=${General::swroot}/certs/$lconfighash{$key}[1]cert.pem\n" if ($lconfighash{$key}[2] ne '%auth-dn');
302         }
303
304         # Local and Remote IDs
305         print CONF "\tleftid=\"$lconfighash{$key}[7]\"\n" if ($lconfighash{$key}[7]);
306         print CONF "\trightid=\"$lconfighash{$key}[9]\"\n" if ($lconfighash{$key}[9]);
307
308         # Is PFS enabled?
309         my $pfs = $lconfighash{$key}[28] eq 'on' ? 'on' : 'off';
310
311         # Algorithms
312         if ($lconfighash{$key}[18] && $lconfighash{$key}[19] && $lconfighash{$key}[20]) {
313             print CONF "\tike=";
314             my @encs   = split('\|', $lconfighash{$key}[18]);
315             my @ints   = split('\|', $lconfighash{$key}[19]);
316             my @groups = split('\|', $lconfighash{$key}[20]);
317             my $comma = 0;
318             foreach my $i (@encs) {
319                 foreach my $j (@ints) {
320                     foreach my $k (@groups) {
321                         if ($comma != 0) { print CONF ","; } else { $comma = 1; }
322                     print CONF "$i-$j-modp$k";
323                 }
324                     }
325             }
326             if ($lconfighash{$key}[24] eq 'on') {       #only proposed algorythms?
327                 print CONF "!\n";
328             } else {
329                 print CONF "\n";
330             }
331         }
332         if ($lconfighash{$key}[21] && $lconfighash{$key}[22]) {
333             print CONF "\tesp=";
334             my @encs   = split('\|', $lconfighash{$key}[21]);
335             my @ints   = split('\|', $lconfighash{$key}[22]);
336             my @groups = split('\|', $lconfighash{$key}[20]);
337             my $comma = 0;
338             foreach my $i (@encs) {
339                 foreach my $j (@ints) {
340                         my $modp = "";
341                         if ($pfs eq "on") {
342                                 foreach my $k (@groups) {
343                                     if ($comma != 0) { print CONF ","; } else { $comma = 1; }
344                                     if ($pfs eq "on") {
345                                         $modp = "-modp$k";
346                                     } else {
347                                         $modp = "";
348                                     }
349                                     print CONF "$i-$j$modp";
350                                 }
351                         } else {
352                                 if ($comma != 0) { print CONF ","; } else { $comma = 1; }
353                                 print CONF "$i-$j";
354                         }
355                 }
356             }
357             if ($lconfighash{$key}[24] eq 'on') {       #only proposed algorythms?
358                 print CONF "!\n";
359             } else {
360                 print CONF "\n";
361             }
362         }
363
364         # IKE V1 or V2
365         if (! $lconfighash{$key}[29]) {
366            $lconfighash{$key}[29] = "ikev1";
367         }
368         print CONF "\tkeyexchange=$lconfighash{$key}[29]\n";
369
370         # Lifetimes
371         print CONF "\tikelifetime=$lconfighash{$key}[16]h\n" if ($lconfighash{$key}[16]);
372         print CONF "\tkeylife=$lconfighash{$key}[17]h\n" if ($lconfighash{$key}[17]);
373
374         # Compression
375         print CONF "\tcompress=yes\n" if ($lconfighash{$key}[13] eq 'on');
376
377         # Dead Peer Detection
378         print CONF "\tdpddelay=30\n";
379         print CONF "\tdpdtimeout=120\n";
380         print CONF "\tdpdaction=$lconfighash{$key}[27]\n";
381
382         # Build Authentication details:  LEFTid RIGHTid : PSK psk
383         my $psk_line;
384         if ($lconfighash{$key}[4] eq 'psk') {
385             $psk_line = ($lconfighash{$key}[7] ? $lconfighash{$key}[7] : $localside) . " " ;
386             $psk_line .= $lconfighash{$key}[9] ? $lconfighash{$key}[9] : $lconfighash{$key}[10];  #remoteid or remote address?
387             $psk_line .= " : PSK '$lconfighash{$key}[5]'\n";
388             # if the line contains %any, it is less specific than two IP or ID, so move it at end of file.
389             if ($psk_line =~ /%any/) {
390                 $last_secrets .= $psk_line;
391             } else {
392                 print SECRETS $psk_line;
393             }
394             print CONF "\tauthby=secret\n";
395         } else {
396             print CONF "\tauthby=rsasig\n";
397             print CONF "\tleftrsasigkey=%cert\n";
398             print CONF "\trightrsasigkey=%cert\n";
399         }
400
401         # Automatically start only if a net-to-net connection
402         if ($lconfighash{$key}[3] eq 'host') {
403             print CONF "\tauto=add\n";
404             print CONF "\trightsourceip=$lvpnsettings{'RW_NET'}\n";
405         } else {
406             print CONF "\tauto=start\n";
407         }
408         print CONF "\n";
409     }#foreach key
410     print SECRETS $last_secrets if ($last_secrets);
411     close(CONF);
412     close(SECRETS);
413 }
414
415 # Hook to regenerate the configuration files.
416 if ($ENV{"REMOTE_ADDR"} eq "") {
417         writeipsecfiles;
418         exit(0);
419 }
420
421 ###
422 ### Save main settings
423 ###
424 if ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'TYPE'} eq '' && $cgiparams{'KEY'} eq '') {
425     &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings);
426     unless (&General::validfqdn($cgiparams{'VPN_IP'}) || &General::validip($cgiparams{'VPN_IP'})
427             || $cgiparams{'VPN_IP'} eq '%defaultroute' ) {
428         $errormessage = $Lang::tr{'invalid input for hostname'};
429         goto SAVE_ERROR;
430     }
431
432     unless ($cgiparams{'VPN_DELAYED_START'} =~ /^[0-9]{1,3}$/ ) { #allow 0-999 seconds !
433         $errormessage = $Lang::tr{'invalid time period'};
434         goto SAVE_ERROR;
435     }
436
437     if ( $cgiparams{'RW_NET'} ne '' and !&General::validipandmask($cgiparams{'RW_NET'}) ) {
438         $errormessage = $Lang::tr{'urlfilter invalid ip or mask error'};
439         goto SAVE_ERROR;
440     }
441
442     $vpnsettings{'ENABLED'} = $cgiparams{'ENABLED'};
443     $vpnsettings{'VPN_IP'} = $cgiparams{'VPN_IP'};
444     $vpnsettings{'VPN_DELAYED_START'} = $cgiparams{'VPN_DELAYED_START'};
445     $vpnsettings{'RW_NET'} = $cgiparams{'RW_NET'};
446     &General::writehash("${General::swroot}/vpn/settings", \%vpnsettings);
447     &writeipsecfiles();
448     if (&vpnenabled) {
449         system('/usr/local/bin/ipsecctrl', 'S');
450     } else {
451         system('/usr/local/bin/ipsecctrl', 'D');
452     }
453     sleep $sleepDelay;
454     SAVE_ERROR:
455 ###
456 ### Reset all step 2
457 ###
458 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove x509'} && $cgiparams{'AREUSURE'} eq 'yes') {
459     &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
460
461     foreach my $key (keys %confighash) {
462         if ($confighash{$key}[4] eq 'cert') {
463             delete $confighash{$key};
464         }
465     }
466     while (my $file = glob("${General::swroot}/{ca,certs,crls,private}/*")) {
467         unlink $file
468     }
469     &cleanssldatabase();
470     if (open(FILE, ">${General::swroot}/vpn/caconfig")) {
471         print FILE "";
472         close FILE;
473     }
474     &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
475     &writeipsecfiles();
476     system('/usr/local/bin/ipsecctrl', 'R');
477     sleep $sleepDelay;
478
479 ###
480 ### Reset all step 1
481 ###
482 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove x509'}) {
483     &Header::showhttpheaders();
484     &Header::openpage($Lang::tr{'vpn configuration main'}, 1, '');
485     &Header::openbigbox('100%', 'left', '', '');
486     &Header::openbox('100%', 'left', $Lang::tr{'are you sure'});
487     print <<END
488         <form method='post' action='$ENV{'SCRIPT_NAME'}'>
489         <table width='100%'>
490             <tr>
491                 <td align='center'>
492                 <input type='hidden' name='AREUSURE' value='yes' />
493                 <b><font color='${Header::colourred}'>$Lang::tr{'capswarning'}</font></b>:
494                 $Lang::tr{'resetting the vpn configuration will remove the root ca, the host certificate and all certificate based connections'}</td>
495             </tr><tr>
496                 <td align='center'>
497                 <input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' />
498                 <input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></td>
499             </tr>
500         </table>
501         </form>
502 END
503     ;
504     &Header::closebox();
505     &Header::closebigbox();
506     &Header::closepage();
507     exit (0);
508
509 ###
510 ### Upload CA Certificate
511 ###
512 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'upload ca certificate'}) {
513     &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash);
514
515     if ($cgiparams{'CA_NAME'} !~ /^[a-zA-Z0-9]+$/) {
516         $errormessage = $Lang::tr{'name must only contain characters'};
517         goto UPLOADCA_ERROR;
518     }
519
520     if (length($cgiparams{'CA_NAME'}) >60) {
521         $errormessage = $Lang::tr{'name too long'};
522         goto VPNCONF_ERROR;
523     }
524
525     if ($cgiparams{'CA_NAME'} eq 'ca') {
526         $errormessage = $Lang::tr{'name is invalid'};
527         goto UPLOAD_CA_ERROR;
528     }
529
530     # Check if there is no other entry with this name
531     foreach my $key (keys %cahash) {
532         if ($cahash{$key}[0] eq $cgiparams{'CA_NAME'}) {
533             $errormessage = $Lang::tr{'a ca certificate with this name already exists'};
534             goto UPLOADCA_ERROR;
535         }
536     }
537
538     if (ref ($cgiparams{'FH'}) ne 'Fh') {
539         $errormessage = $Lang::tr{'there was no file upload'};
540         goto UPLOADCA_ERROR;
541     }
542     # Move uploaded ca to a temporary file
543     (my $fh, my $filename) = tempfile( );
544     if (copy ($cgiparams{'FH'}, $fh) != 1) {
545         $errormessage = $!;
546         goto UPLOADCA_ERROR;
547     }
548     my $temp = `/usr/bin/openssl x509 -text -in $filename`;
549     if ($temp !~ /CA:TRUE/i) {
550         $errormessage = $Lang::tr{'not a valid ca certificate'};
551         unlink ($filename);
552         goto UPLOADCA_ERROR;
553     } else {
554         move($filename, "${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem");
555         if ($? ne 0) {
556             $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
557             unlink ($filename);
558             goto UPLOADCA_ERROR;
559         }
560     }
561
562     my $key = &General::findhasharraykey (\%cahash);
563     $cahash{$key}[0] = $cgiparams{'CA_NAME'};
564     $cahash{$key}[1] = &Header::cleanhtml(getsubjectfromcert ("${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem"));
565     &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash);
566
567     system('/usr/local/bin/ipsecctrl', 'R');
568     sleep $sleepDelay;
569
570     UPLOADCA_ERROR:
571
572 ###
573 ### Display ca certificate
574 ###
575 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show ca certificate'}) {
576     &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash);
577
578     if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem") {
579         &Header::showhttpheaders();
580         &Header::openpage($Lang::tr{'vpn configuration main'}, 1, '');
581         &Header::openbigbox('100%', 'left', '', '');
582         &Header::openbox('100%', 'left', "$Lang::tr{'ca certificate'}:");
583         my $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem`;
584         $output = &Header::cleanhtml($output,"y");
585         print "<pre>$output</pre>\n";
586         &Header::closebox();
587         print "<div align='center'><a href='/cgi-bin/vpnmain.cgi'>$Lang::tr{'back'}</a></div>";
588         &Header::closebigbox();
589         &Header::closepage();
590         exit(0);
591     } else {
592         $errormessage = $Lang::tr{'invalid key'};
593     }
594
595 ###
596 ### Export ca certificate to browser
597 ###
598 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download ca certificate'}) {
599     &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash);
600
601     if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
602         print "Content-Type: application/force-download\n";
603         print "Content-Type: application/octet-stream\r\n";
604         print "Content-Disposition: attachment; filename=$cahash{$cgiparams{'KEY'}}[0]cert.pem\r\n\r\n";
605         print `/usr/bin/openssl x509 -in ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem`;
606         exit(0);
607     } else {
608         $errormessage = $Lang::tr{'invalid key'};
609     }
610
611 ###
612 ### Remove ca certificate (step 2)
613 ###
614 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove ca certificate'} && $cgiparams{'AREUSURE'} eq 'yes') {
615     &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
616     &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash);
617
618     if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
619         foreach my $key (keys %confighash) {
620             my $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem ${General::swroot}/certs/$confighash{$key}[1]cert.pem`;
621             if ($test =~ /: OK/) {
622                 # Delete connection
623                 system('/usr/local/bin/ipsecctrl', 'D', $key) if (&vpnenabled);
624                 unlink ("${General::swroot}/certs/$confighash{$key}[1]cert.pem");
625                 unlink ("${General::swroot}/certs/$confighash{$key}[1].p12");
626                 delete $confighash{$key};
627                 &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
628                 &writeipsecfiles();
629             }
630         }
631         unlink ("${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
632         delete $cahash{$cgiparams{'KEY'}};
633         &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash);
634         system('/usr/local/bin/ipsecctrl', 'R');
635         sleep $sleepDelay;
636     } else {
637         $errormessage = $Lang::tr{'invalid key'};
638     }
639 ###
640 ### Remove ca certificate (step 1)
641 ###
642 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove ca certificate'}) {
643     &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
644     &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash);
645
646     my $assignedcerts = 0;
647     if ( -f "${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
648         foreach my $key (keys %confighash) {
649             my $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem ${General::swroot}/certs/$confighash{$key}[1]cert.pem`;
650             if ($test =~ /: OK/) {
651                 $assignedcerts++;
652             }
653         }
654         if ($assignedcerts) {
655             &Header::showhttpheaders();
656             &Header::openpage($Lang::tr{'vpn configuration main'}, 1, '');
657             &Header::openbigbox('100%', 'left', '', '');
658             &Header::openbox('100%', 'left', $Lang::tr{'are you sure'});
659             print <<END
660             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
661             <table width='100%'>
662                 <tr>
663                     <td align='center'>
664                     <input type='hidden' name='KEY' value='$cgiparams{'KEY'}' />
665                     <input type='hidden' name='AREUSURE' value='yes' /></td>
666                 </tr><tr>
667                     <td align='center'>
668                     <b><font color='${Header::colourred}'>$Lang::tr{'capswarning'}</font></b>
669                     $Lang::tr{'connections are associated with this ca.  deleting the ca will delete these connections as well.'}</td>
670                 </tr><tr>
671                     <td align='center'>
672                     <input type='submit' name='ACTION' value='$Lang::tr{'remove ca certificate'}' />
673                     <input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></td>
674                 </tr>
675             </table>
676             </form>
677 END
678             ;
679             &Header::closebox();
680             &Header::closebigbox();
681             &Header::closepage();
682             exit (0);
683         } else {
684             unlink ("${General::swroot}/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
685             delete $cahash{$cgiparams{'KEY'}};
686             &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash);
687             system('/usr/local/bin/ipsecctrl', 'R');
688             sleep $sleepDelay;
689         }
690     } else {
691         $errormessage = $Lang::tr{'invalid key'};
692     }
693
694 ###
695 ### Display root certificate
696 ###
697 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show root certificate'} ||
698         $cgiparams{'ACTION'} eq $Lang::tr{'show host certificate'}) {
699     my $output;
700     &Header::showhttpheaders();
701     &Header::openpage($Lang::tr{'vpn configuration main'}, 1, '');
702     &Header::openbigbox('100%', 'left', '', '');
703     if ($cgiparams{'ACTION'} eq $Lang::tr{'show root certificate'}) {
704         &Header::openbox('100%', 'left', "$Lang::tr{'root certificate'}:");
705         $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/ca/cacert.pem`;
706     } else {
707         &Header::openbox('100%', 'left', "$Lang::tr{'host certificate'}:");
708         $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/certs/hostcert.pem`;
709     }
710     $output = &Header::cleanhtml($output,"y");
711     print "<pre>$output</pre>\n";
712     &Header::closebox();
713     print "<div align='center'><a href='/cgi-bin/vpnmain.cgi'>$Lang::tr{'back'}</a></div>";
714     &Header::closebigbox();
715     &Header::closepage();
716     exit(0);
717
718 ###
719 ### Export root certificate to browser
720 ###
721 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download root certificate'}) {
722     if ( -f "${General::swroot}/ca/cacert.pem" ) {
723         print "Content-Type: application/force-download\n";
724         print "Content-Disposition: attachment; filename=cacert.pem\r\n\r\n";
725         print `/usr/bin/openssl x509 -in ${General::swroot}/ca/cacert.pem`;
726         exit(0);
727     }
728 ###
729 ### Export host certificate to browser
730 ###
731 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download host certificate'}) {
732     if ( -f "${General::swroot}/certs/hostcert.pem" ) {
733         print "Content-Type: application/force-download\n";
734         print "Content-Disposition: attachment; filename=hostcert.pem\r\n\r\n";
735         print `/usr/bin/openssl x509 -in ${General::swroot}/certs/hostcert.pem`;
736         exit(0);
737     }
738 ###
739 ### Form for generating/importing the caroot+host certificate
740 ###
741 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'generate root/host certificates'} ||
742          $cgiparams{'ACTION'} eq $Lang::tr{'upload p12 file'}) {
743
744     if (-f "${General::swroot}/ca/cacert.pem") {
745         $errormessage = $Lang::tr{'valid root certificate already exists'};
746         goto ROOTCERT_SKIP;
747     }
748
749     &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings);
750     # fill in initial values
751     if ($cgiparams{'ROOTCERT_HOSTNAME'} eq '') {
752         if (-e "${General::swroot}/red/active" && open(IPADDR, "${General::swroot}/red/local-ipaddress")) {
753             my $ipaddr = <IPADDR>;
754             close IPADDR;
755             chomp ($ipaddr);
756             $cgiparams{'ROOTCERT_HOSTNAME'} = (gethostbyaddr(pack("C4", split(/\./, $ipaddr)), 2))[0];
757             if ($cgiparams{'ROOTCERT_HOSTNAME'} eq '') {
758                 $cgiparams{'ROOTCERT_HOSTNAME'} = $ipaddr;
759             }
760         }
761         $cgiparams{'ROOTCERT_COUNTRY'} = $vpnsettings{'ROOTCERT_COUNTRY'} if (!$cgiparams{'ROOTCERT_COUNTRY'});
762     } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'upload p12 file'}) {
763         &General::log("ipsec", "Importing from p12...");
764
765         if (ref ($cgiparams{'FH'}) ne 'Fh') {
766             $errormessage = $Lang::tr{'there was no file upload'};
767             goto ROOTCERT_ERROR;
768         }
769
770         # Move uploaded certificate request to a temporary file
771         (my $fh, my $filename) = tempfile( );
772         if (copy ($cgiparams{'FH'}, $fh) != 1) {
773             $errormessage = $!;
774             goto ROOTCERT_ERROR;
775         }
776
777         # Extract the CA certificate from the file
778         &General::log("ipsec", "Extracting caroot from p12...");
779         if (open(STDIN, "-|")) {
780             my  $opt  = " pkcs12 -cacerts -nokeys";
781                 $opt .= " -in $filename";
782                 $opt .= " -out /tmp/newcacert";
783             $errormessage = &callssl ($opt);
784         } else {        #child
785             print "$cgiparams{'P12_PASS'}\n";
786             exit (0);
787         }
788
789         # Extract the Host certificate from the file
790         if (!$errormessage) {
791             &General::log("ipsec", "Extracting host cert from p12...");
792             if (open(STDIN, "-|")) {
793                 my  $opt  = " pkcs12 -clcerts -nokeys";
794                     $opt .= " -in $filename";
795                     $opt .= " -out /tmp/newhostcert";
796                 $errormessage = &callssl ($opt);
797             } else {    #child
798                 print "$cgiparams{'P12_PASS'}\n";
799                 exit (0);
800             }
801         }
802
803         # Extract the Host key from the file
804         if (!$errormessage) {
805             &General::log("ipsec", "Extracting private key from p12...");
806             if (open(STDIN, "-|")) {
807                 my  $opt  = " pkcs12 -nocerts -nodes";
808                     $opt .= " -in $filename";
809                     $opt .= " -out /tmp/newhostkey";
810                 $errormessage = &callssl ($opt);
811             } else {    #child
812                 print "$cgiparams{'P12_PASS'}\n";
813                 exit (0);
814             }
815         }
816
817         if (!$errormessage) {
818             &General::log("ipsec", "Moving cacert...");
819             move("/tmp/newcacert", "${General::swroot}/ca/cacert.pem");
820             $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0);
821         }
822
823         if (!$errormessage) {
824             &General::log("ipsec", "Moving host cert...");
825             move("/tmp/newhostcert", "${General::swroot}/certs/hostcert.pem");
826             $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0);
827         }
828
829         if (!$errormessage) {
830             &General::log("ipsec", "Moving private key...");
831             move("/tmp/newhostkey", "${General::swroot}/certs/hostkey.pem");
832             $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0);
833         }
834         
835         #cleanup temp files
836         unlink ($filename);
837         unlink ('/tmp/newcacert');
838         unlink ('/tmp/newhostcert');
839         unlink ('/tmp/newhostkey');
840         if ($errormessage) {
841             unlink ("${General::swroot}/ca/cacert.pem");
842             unlink ("${General::swroot}/certs/hostcert.pem");
843             unlink ("${General::swroot}/certs/hostkey.pem");
844             goto ROOTCERT_ERROR;
845         }
846
847         # Create empty CRL cannot be done because we don't have
848         # the private key for this CAROOT
849         # IPFire can only import certificates
850
851         &General::log("ipsec", "p12 import completed!");
852         &cleanssldatabase();
853         goto ROOTCERT_SUCCESS;
854
855     } elsif ($cgiparams{'ROOTCERT_COUNTRY'} ne '') {
856
857         # Validate input since the form was submitted
858         if ($cgiparams{'ROOTCERT_ORGANIZATION'} eq ''){
859             $errormessage = $Lang::tr{'organization cant be empty'};
860             goto ROOTCERT_ERROR;
861         }
862         if (length($cgiparams{'ROOTCERT_ORGANIZATION'}) >60) {
863             $errormessage = $Lang::tr{'organization too long'};
864             goto ROOTCERT_ERROR;
865         }
866         if ($cgiparams{'ROOTCERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
867             $errormessage = $Lang::tr{'invalid input for organization'};
868             goto ROOTCERT_ERROR;
869         }
870         if ($cgiparams{'ROOTCERT_HOSTNAME'} eq ''){
871             $errormessage = $Lang::tr{'hostname cant be empty'};
872             goto ROOTCERT_ERROR;
873         }
874         unless (&General::validfqdn($cgiparams{'ROOTCERT_HOSTNAME'}) || &General::validip($cgiparams{'ROOTCERT_HOSTNAME'})) {
875             $errormessage = $Lang::tr{'invalid input for hostname'};
876             goto ROOTCERT_ERROR;
877         }
878         if ($cgiparams{'ROOTCERT_EMAIL'} ne '' && (! &General::validemail($cgiparams{'ROOTCERT_EMAIL'}))) {
879             $errormessage = $Lang::tr{'invalid input for e-mail address'};
880             goto ROOTCERT_ERROR;
881         }
882         if (length($cgiparams{'ROOTCERT_EMAIL'}) > 40) {
883             $errormessage = $Lang::tr{'e-mail address too long'};
884             goto ROOTCERT_ERROR;
885         }
886         if ($cgiparams{'ROOTCERT_OU'} ne '' && $cgiparams{'ROOTCERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
887             $errormessage = $Lang::tr{'invalid input for department'};
888             goto ROOTCERT_ERROR;
889         }
890         if ($cgiparams{'ROOTCERT_CITY'} ne '' && $cgiparams{'ROOTCERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
891             $errormessage = $Lang::tr{'invalid input for city'};
892             goto ROOTCERT_ERROR;
893         }
894         if ($cgiparams{'ROOTCERT_STATE'} ne '' && $cgiparams{'ROOTCERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
895             $errormessage = $Lang::tr{'invalid input for state or province'};
896             goto ROOTCERT_ERROR;
897         }
898         if ($cgiparams{'ROOTCERT_COUNTRY'} !~ /^[A-Z]*$/) {
899             $errormessage = $Lang::tr{'invalid input for country'};
900             goto ROOTCERT_ERROR;
901         }
902         #the exact syntax is a list comma separated of 
903         #  email:any-validemail
904         #       URI: a uniform resource indicator
905         #   DNS: a DNS domain name
906         #   RID: a registered OBJECT IDENTIFIER
907         #   IP: an IP address
908         # example: email:franck@foo.com,IP:10.0.0.10,DNS:franck.foo.com
909
910         if ($cgiparams{'SUBJECTALTNAME'} ne '' && $cgiparams{'SUBJECTALTNAME'} !~ /^(email|URI|DNS|RID|IP):[a-zA-Z0-9 :\/,\.\-_@]*$/) {
911             $errormessage = $Lang::tr{'vpn altname syntax'};
912             goto VPNCONF_ERROR;
913         }
914
915         # Copy the cgisettings to vpnsettings and save the configfile
916         $vpnsettings{'ROOTCERT_ORGANIZATION'}   = $cgiparams{'ROOTCERT_ORGANIZATION'};
917         $vpnsettings{'ROOTCERT_HOSTNAME'}       = $cgiparams{'ROOTCERT_HOSTNAME'};
918         $vpnsettings{'ROOTCERT_EMAIL'}          = $cgiparams{'ROOTCERT_EMAIL'};
919         $vpnsettings{'ROOTCERT_OU'}             = $cgiparams{'ROOTCERT_OU'};
920         $vpnsettings{'ROOTCERT_CITY'}           = $cgiparams{'ROOTCERT_CITY'};
921         $vpnsettings{'ROOTCERT_STATE'}          = $cgiparams{'ROOTCERT_STATE'};
922         $vpnsettings{'ROOTCERT_COUNTRY'}        = $cgiparams{'ROOTCERT_COUNTRY'};
923         &General::writehash("${General::swroot}/vpn/settings", \%vpnsettings);
924
925         # Replace empty strings with a .
926         (my $ou = $cgiparams{'ROOTCERT_OU'}) =~ s/^\s*$/\./;
927         (my $city = $cgiparams{'ROOTCERT_CITY'}) =~ s/^\s*$/\./;
928         (my $state = $cgiparams{'ROOTCERT_STATE'}) =~ s/^\s*$/\./;
929
930         # Create the CA certificate
931         if (!$errormessage) {
932             &General::log("ipsec", "Creating cacert...");
933             if (open(STDIN, "-|")) {
934                 my $opt  = " req -x509 -nodes -rand /proc/interrupts:/proc/net/rt_cache";
935                    $opt .= " -days 999999";
936                    $opt .= " -newkey rsa:2048";
937                    $opt .= " -keyout ${General::swroot}/private/cakey.pem";
938                    $opt .= " -out ${General::swroot}/ca/cacert.pem";
939
940                 $errormessage = &callssl ($opt);
941             } else {    #child
942                 print  "$cgiparams{'ROOTCERT_COUNTRY'}\n";
943                 print  "$state\n";
944                 print  "$city\n";
945                 print  "$cgiparams{'ROOTCERT_ORGANIZATION'}\n";
946                 print  "$ou\n";
947                 print  "$cgiparams{'ROOTCERT_ORGANIZATION'} CA\n";
948                 print  "$cgiparams{'ROOTCERT_EMAIL'}\n";
949                 exit (0);
950             }
951         }
952
953         # Create the Host certificate request
954         if (!$errormessage) {
955             &General::log("ipsec", "Creating host cert...");
956             if (open(STDIN, "-|")) {
957                 my $opt  = " req -nodes -rand /proc/interrupts:/proc/net/rt_cache";
958                    $opt .= " -newkey rsa:1024";
959                    $opt .= " -keyout ${General::swroot}/certs/hostkey.pem";
960                    $opt .= " -out ${General::swroot}/certs/hostreq.pem";
961                 $errormessage = &callssl ($opt);
962             } else {    #child
963                 print  "$cgiparams{'ROOTCERT_COUNTRY'}\n";
964                 print  "$state\n";
965                 print  "$city\n";
966                 print  "$cgiparams{'ROOTCERT_ORGANIZATION'}\n";
967                 print  "$ou\n";
968                 print  "$cgiparams{'ROOTCERT_HOSTNAME'}\n";
969                 print  "$cgiparams{'ROOTCERT_EMAIL'}\n";
970                 print  ".\n";
971                 print  ".\n";
972                 exit (0);
973             }
974         }
975
976         # Sign the host certificate request
977         if (!$errormessage) {
978             &General::log("ipsec", "Self signing host cert...");
979
980             #No easy way for specifying the contain of subjectAltName without writing a config file...
981             my ($fh, $v3extname) = tempfile ('/tmp/XXXXXXXX');
982             print $fh <<END
983             basicConstraints=CA:FALSE
984             nsComment="OpenSSL Generated Certificate"
985             subjectKeyIdentifier=hash
986             authorityKeyIdentifier=keyid,issuer:always
987             extendedKeyUsage = serverAuth
988 END
989 ;
990             print $fh "subjectAltName=$cgiparams{'SUBJECTALTNAME'}" if ($cgiparams{'SUBJECTALTNAME'});
991             close ($fh);
992             
993             my  $opt  = " ca -days 999999";
994                 $opt .= " -batch -notext";
995                 $opt .= " -in ${General::swroot}/certs/hostreq.pem";
996                 $opt .= " -out ${General::swroot}/certs/hostcert.pem";
997                 $opt .= " -extfile $v3extname";
998             $errormessage = &callssl ($opt);
999             unlink ("${General::swroot}/certs/hostreq.pem"); #no more needed
1000             unlink ($v3extname);
1001         }
1002
1003         # Create an empty CRL
1004         if (!$errormessage) {
1005             &General::log("ipsec", "Creating emptycrl...");
1006             my  $opt  = " ca -gencrl";
1007                 $opt .= " -out ${General::swroot}/crls/cacrl.pem";
1008             $errormessage = &callssl ($opt);
1009         }
1010         
1011         # Successfully build CA / CERT!
1012         if (!$errormessage) {
1013             &cleanssldatabase();
1014             goto ROOTCERT_SUCCESS;
1015         }
1016         
1017         #Cleanup
1018         unlink ("${General::swroot}/ca/cacert.pem");
1019         unlink ("${General::swroot}/certs/hostkey.pem");
1020         unlink ("${General::swroot}/certs/hostcert.pem");
1021         unlink ("${General::swroot}/crls/cacrl.pem");
1022         &cleanssldatabase();
1023     }
1024
1025     ROOTCERT_ERROR:
1026     &Header::showhttpheaders();
1027     &Header::openpage($Lang::tr{'vpn configuration main'}, 1, '');
1028     &Header::openbigbox('100%', 'left', '', $errormessage);
1029     if ($errormessage) {
1030         &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
1031         print "<class name='base'>$errormessage";
1032         print "&nbsp;</class>";
1033         &Header::closebox();
1034     }
1035     &Header::openbox('100%', 'left', "$Lang::tr{'generate root/host certificates'}:");
1036     print <<END
1037     <form method='post' enctype='multipart/form-data' action='$ENV{'SCRIPT_NAME'}'>
1038     <table width='100%' border='0' cellspacing='1' cellpadding='0'>
1039     <tr><td width='40%' class='base'>$Lang::tr{'organization name'}:</td>
1040         <td width='60%' class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_ORGANIZATION' value='$cgiparams{'ROOTCERT_ORGANIZATION'}' size='32' /></td></tr>
1041     <tr><td class='base'>$Lang::tr{'ipfires hostname'}:</td>
1042         <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_HOSTNAME' value='$cgiparams{'ROOTCERT_HOSTNAME'}' size='32' /></td></tr>
1043     <tr><td class='base'>$Lang::tr{'your e-mail'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
1044         <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_EMAIL' value='$cgiparams{'ROOTCERT_EMAIL'}' size='32' /></td></tr>
1045     <tr><td class='base'>$Lang::tr{'your department'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
1046         <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_OU' value='$cgiparams{'ROOTCERT_OU'}' size='32' /></td></tr>
1047     <tr><td class='base'>$Lang::tr{'city'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
1048         <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_CITY' value='$cgiparams{'ROOTCERT_CITY'}' size='32' /></td></tr>
1049     <tr><td class='base'>$Lang::tr{'state or province'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
1050         <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_STATE' value='$cgiparams{'ROOTCERT_STATE'}' size='32' /></td></tr>
1051     <tr><td class='base'>$Lang::tr{'country'}:</td>
1052         <td class='base'><select name='ROOTCERT_COUNTRY'>
1053 END
1054     ;
1055     foreach my $country (sort keys %{Countries::countries}) {
1056         print "<option value='$Countries::countries{$country}'";
1057         if ( $Countries::countries{$country} eq $cgiparams{'ROOTCERT_COUNTRY'} ) {
1058             print " selected='selected'";
1059         }
1060         print ">$country</option>";
1061     }
1062     print <<END
1063         </select></td></tr>
1064     <tr><td class='base'>$Lang::tr{'vpn subjectaltname'} (subjectAltName=email:*,URI:*,DNS:*,RID:*) <img src='/blob.gif' alt='*' /></td>
1065         <td class='base' nowrap='nowrap'><input type='text' name='SUBJECTALTNAME' value='$cgiparams{'SUBJECTALTNAME'}' size='32' /></td></tr>
1066     <tr><td>&nbsp;</td>
1067         <td><br /><input type='submit' name='ACTION' value='$Lang::tr{'generate root/host certificates'}' /><br /><br /></td></tr>
1068     <tr><td class='base' colspan='2' align='left'>
1069         <b><font color='${Header::colourred}'>$Lang::tr{'capswarning'}</font></b>: 
1070         $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'}
1071     </td></tr>
1072     <tr><td colspan='2'><hr /></td></tr>
1073     <tr><td class='base' nowrap='nowrap'>$Lang::tr{'upload p12 file'}:</td>
1074         <td nowrap='nowrap'><input type='file' name='FH' size='32' /></td></tr>
1075     <tr><td class='base'>$Lang::tr{'pkcs12 file password'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
1076         <td class='base' nowrap='nowrap'><input type='password' name='P12_PASS' value='$cgiparams{'P12_PASS'}' size='32' /></td></tr>
1077     <tr><td>&nbsp;</td>
1078         <td><input type='submit' name='ACTION' value='$Lang::tr{'upload p12 file'}' /></td></tr>
1079     <tr><td class='base' colspan='2' align='left'>
1080         <img src='/blob.gif' alt='*' />&nbsp;$Lang::tr{'this field may be blank'}</td></tr>
1081     </table></form>
1082 END
1083     ;
1084     &Header::closebox();
1085     &Header::closebigbox();
1086     &Header::closepage();
1087     exit(0);
1088
1089     ROOTCERT_SUCCESS:
1090     if (&vpnenabled) {
1091         system('/usr/local/bin/ipsecctrl', 'S');
1092         sleep $sleepDelay;
1093     }
1094     ROOTCERT_SKIP:
1095 ###
1096 ### Export PKCS12 file to browser
1097 ###
1098 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download pkcs12 file'}) {
1099     &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
1100     print "Content-Type: application/force-download\n";
1101     print "Content-Disposition: attachment; filename=" . $confighash{$cgiparams{'KEY'}}[1] . ".p12\r\n";
1102     print "Content-Type: application/octet-stream\r\n\r\n";
1103     print `/bin/cat ${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1].p12`;
1104     exit (0);
1105
1106 ###
1107 ### Display certificate
1108 ###
1109 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show certificate'}) {
1110     &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
1111
1112     if ( -f "${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") {
1113         &Header::showhttpheaders();
1114         &Header::openpage($Lang::tr{'vpn configuration main'}, 1, '');
1115         &Header::openbigbox('100%', 'left', '', '');
1116         &Header::openbox('100%', 'left', "$Lang::tr{'cert'}:");
1117         my $output = `/usr/bin/openssl x509 -text -in ${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem`;
1118         $output = &Header::cleanhtml($output,"y");
1119         print "<pre>$output</pre>\n";
1120         &Header::closebox();
1121         print "<div align='center'><a href='/cgi-bin/vpnmain.cgi'>$Lang::tr{'back'}</a></div>";
1122         &Header::closebigbox();
1123         &Header::closepage();
1124         exit(0);
1125     }
1126
1127 ###
1128 ### Export Certificate to browser
1129 ###
1130 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download certificate'}) {
1131     &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
1132
1133     if ( -f "${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") {
1134         print "Content-Type: application/force-download\n";
1135         print "Content-Disposition: attachment; filename=" . $confighash{$cgiparams{'KEY'}}[1] . "cert.pem\n\n";
1136         print `/bin/cat ${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem`;
1137         exit (0);
1138     }
1139
1140 ###
1141 ### Enable/Disable connection
1142 ###
1143 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'toggle enable disable'}) {
1144     
1145     &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings);
1146     &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
1147
1148     if ($confighash{$cgiparams{'KEY'}}) {
1149         if ($confighash{$cgiparams{'KEY'}}[0] eq 'off') {
1150             $confighash{$cgiparams{'KEY'}}[0] = 'on';
1151             &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
1152             &writeipsecfiles();
1153             system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'}) if (&vpnenabled);
1154         } else {
1155             system('/usr/local/bin/ipsecctrl', 'D', $cgiparams{'KEY'}) if (&vpnenabled);
1156             $confighash{$cgiparams{'KEY'}}[0] = 'off';
1157             &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
1158             &writeipsecfiles();
1159         }
1160         sleep $sleepDelay;
1161     } else {
1162         $errormessage = $Lang::tr{'invalid key'};
1163     }
1164
1165 ###
1166 ### Restart connection
1167 ###
1168 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'restart'}) {
1169     &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings);
1170     &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
1171
1172     if ($confighash{$cgiparams{'KEY'}}) {
1173         if (&vpnenabled) {
1174             system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'});
1175             sleep $sleepDelay;
1176         }
1177     } else {
1178         $errormessage = $Lang::tr{'invalid key'};
1179     }
1180
1181 ###
1182 ### Remove connection
1183 ###
1184 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove'}) {
1185     &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings);
1186     &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
1187
1188     if ($confighash{$cgiparams{'KEY'}}) {
1189         system('/usr/local/bin/ipsecctrl', 'D', $cgiparams{'KEY'}) if (&vpnenabled);
1190         unlink ("${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
1191         unlink ("${General::swroot}/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
1192         delete $confighash{$cgiparams{'KEY'}};
1193         &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
1194         &writeipsecfiles();
1195     } else {
1196         $errormessage = $Lang::tr{'invalid key'};
1197     }
1198
1199 ###
1200 ### Choose between adding a host-net or net-net connection
1201 ###
1202 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'add'} && $cgiparams{'TYPE'} eq '') {
1203         &Header::showhttpheaders();
1204         &Header::openpage($Lang::tr{'vpn configuration main'}, 1, '');
1205         &Header::openbigbox('100%', 'left', '', '');
1206         &Header::openbox('100%', 'left', $Lang::tr{'connection type'});
1207         print <<END
1208             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
1209             <b>$Lang::tr{'connection type'}:</b><br />
1210             <table>
1211             <tr><td><input type='radio' name='TYPE' value='host' checked='checked' /></td>
1212                 <td class='base'>$Lang::tr{'host to net vpn'}</td>
1213             </tr><tr>
1214                 <td><input type='radio' name='TYPE' value='net' /></td>
1215                 <td class='base'>$Lang::tr{'net to net vpn'}</td>
1216             </tr><tr>
1217                 <td align='center' colspan='2'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' /></td>
1218             </tr>
1219             </table></form>
1220 END
1221         ;
1222         &Header::closebox();
1223         &Header::closebigbox();
1224         &Header::closepage();
1225         exit (0);
1226 ###
1227 ### Adding/Editing/Saving a  connection
1228 ###
1229 } elsif (($cgiparams{'ACTION'} eq $Lang::tr{'add'}) ||
1230          ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}) ||
1231          ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'ADVANCED'} eq '')) {
1232
1233     &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings);
1234     &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash);
1235     &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
1236
1237     if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}) {
1238         if (! $confighash{$cgiparams{'KEY'}}[0]) {
1239             $errormessage = $Lang::tr{'invalid key'};
1240             goto VPNCONF_END;
1241         }
1242         $cgiparams{'ENABLED'}           = $confighash{$cgiparams{'KEY'}}[0];
1243         $cgiparams{'NAME'}              = $confighash{$cgiparams{'KEY'}}[1];
1244         $cgiparams{'TYPE'}              = $confighash{$cgiparams{'KEY'}}[3];
1245         $cgiparams{'AUTH'}              = $confighash{$cgiparams{'KEY'}}[4];
1246         $cgiparams{'PSK'}               = $confighash{$cgiparams{'KEY'}}[5];
1247         #$cgiparams{'free'}             = $confighash{$cgiparams{'KEY'}}[6];
1248         $cgiparams{'LOCAL_ID'}          = $confighash{$cgiparams{'KEY'}}[7];
1249         $cgiparams{'LOCAL_SUBNET'}      = $confighash{$cgiparams{'KEY'}}[8];
1250         $cgiparams{'REMOTE_ID'}         = $confighash{$cgiparams{'KEY'}}[9];
1251         $cgiparams{'REMOTE'}            = $confighash{$cgiparams{'KEY'}}[10];
1252         $cgiparams{'REMOTE_SUBNET'}     = $confighash{$cgiparams{'KEY'}}[11];
1253         $cgiparams{'REMARK'}            = $confighash{$cgiparams{'KEY'}}[25];
1254         $cgiparams{'DPD_ACTION'}        = $confighash{$cgiparams{'KEY'}}[27];
1255         $cgiparams{'IKE_VERSION'}       = $confighash{$cgiparams{'KEY'}}[29];
1256         $cgiparams{'IKE_ENCRYPTION'}    = $confighash{$cgiparams{'KEY'}}[18];
1257         $cgiparams{'IKE_INTEGRITY'}     = $confighash{$cgiparams{'KEY'}}[19];
1258         $cgiparams{'IKE_GROUPTYPE'}     = $confighash{$cgiparams{'KEY'}}[20];
1259         $cgiparams{'IKE_LIFETIME'}      = $confighash{$cgiparams{'KEY'}}[16];
1260         $cgiparams{'ESP_ENCRYPTION'}    = $confighash{$cgiparams{'KEY'}}[21];
1261         $cgiparams{'ESP_INTEGRITY'}     = $confighash{$cgiparams{'KEY'}}[22];
1262         $cgiparams{'ESP_GROUPTYPE'}     = $confighash{$cgiparams{'KEY'}}[23];
1263         $cgiparams{'ESP_KEYLIFE'}       = $confighash{$cgiparams{'KEY'}}[17];
1264         $cgiparams{'COMPRESSION'}       = $confighash{$cgiparams{'KEY'}}[13];
1265         $cgiparams{'ONLY_PROPOSED'}     = $confighash{$cgiparams{'KEY'}}[24];
1266         $cgiparams{'PFS'}               = $confighash{$cgiparams{'KEY'}}[28];
1267         $cgiparams{'VHOST'}             = $confighash{$cgiparams{'KEY'}}[14];
1268
1269     } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'save'}) {
1270         $cgiparams{'REMARK'} = &Header::cleanhtml($cgiparams{'REMARK'});
1271         if ($cgiparams{'TYPE'} !~ /^(host|net)$/) {
1272             $errormessage = $Lang::tr{'connection type is invalid'};
1273             goto VPNCONF_ERROR;
1274         }
1275
1276         if ($cgiparams{'NAME'} !~ /^[a-zA-Z0-9]+$/) {
1277             $errormessage = $Lang::tr{'name must only contain characters'};
1278             goto VPNCONF_ERROR;
1279         }
1280
1281         if ($cgiparams{'NAME'} =~ /^(host|01|block|private|clear|packetdefault)$/) {
1282             $errormessage = $Lang::tr{'name is invalid'};
1283             goto VPNCONF_ERROR;
1284         }
1285
1286         if (length($cgiparams{'NAME'}) >60) {
1287             $errormessage = $Lang::tr{'name too long'};
1288             goto VPNCONF_ERROR;
1289         }
1290
1291         # Check if there is no other entry with this name
1292         if (! $cgiparams{'KEY'}) {  #only for add
1293             foreach my $key (keys %confighash) {
1294                 if ($confighash{$key}[1] eq $cgiparams{'NAME'}) {
1295                     $errormessage = $Lang::tr{'a connection with this name already exists'};
1296                     goto VPNCONF_ERROR;
1297                 }
1298             }
1299         }
1300
1301         if (($cgiparams{'TYPE'} eq 'net') && (! $cgiparams{'REMOTE'})) {
1302             $errormessage = $Lang::tr{'invalid input for remote host/ip'};
1303             goto VPNCONF_ERROR;
1304         }
1305
1306         if ($cgiparams{'REMOTE'}) {
1307             if (($cgiparams{'REMOTE'} ne '%any') && (! &General::validip($cgiparams{'REMOTE'}))) {
1308                 if (! &General::validfqdn ($cgiparams{'REMOTE'}))  {
1309                     $errormessage = $Lang::tr{'invalid input for remote host/ip'};
1310                     goto VPNCONF_ERROR;
1311                 } else {
1312                     if (&valid_dns_host($cgiparams{'REMOTE'})) {
1313                         $warnmessage = "$Lang::tr{'check vpn lr'} $cgiparams{'REMOTE'}. $Lang::tr{'dns check failed'}";
1314                     }
1315                 }
1316             }
1317         }
1318
1319         unless (&General::validipandmask($cgiparams{'LOCAL_SUBNET'})) {
1320             $errormessage = $Lang::tr{'local subnet is invalid'};
1321             goto VPNCONF_ERROR;
1322         }
1323
1324         # Allow only one roadwarrior/psk without remote IP-address
1325         if ($cgiparams{'REMOTE'} eq '' && $cgiparams{'AUTH'} eq 'psk') {
1326             foreach my $key (keys %confighash) {
1327                 if ( ($cgiparams{'KEY'} ne $key) && 
1328                       ($confighash{$key}[4] eq 'psk') && 
1329                       ($confighash{$key}[10] eq '') ) {
1330                         $errormessage = $Lang::tr{'you can only define one roadwarrior connection when using pre-shared key authentication'};
1331                         goto VPNCONF_ERROR;
1332                 }
1333             }
1334         }
1335         if (($cgiparams{'TYPE'} eq 'net') && (! &General::validipandmask($cgiparams{'REMOTE_SUBNET'}))) {
1336             $errormessage = $Lang::tr{'remote subnet is invalid'};
1337             goto VPNCONF_ERROR;
1338         }
1339
1340         if ($cgiparams{'ENABLED'} !~ /^(on|off)$/) {
1341             $errormessage = $Lang::tr{'invalid input'};
1342             goto VPNCONF_ERROR;
1343         }
1344         if ($cgiparams{'EDIT_ADVANCED'} !~ /^(on|off)$/) {
1345             $errormessage = $Lang::tr{'invalid input'};
1346             goto VPNCONF_ERROR;
1347         }
1348
1349         # Allow nothing or a string (DN,FDQN,) beginning with @
1350         # with no comma but slashes between RID eg @O=FR/C=Paris/OU=myhome/CN=franck
1351         if ( ($cgiparams{'LOCAL_ID'} !~ /^(|[\w.-]*@[\w. =*\/-]+|\d+\.\d+\.\d+\.\d+)$/) ||
1352             ($cgiparams{'REMOTE_ID'} !~ /^(|[\w.-]*@[\w. =*\/-]+|\d+\.\d+\.\d+\.\d+)$/) ||
1353             (($cgiparams{'REMOTE_ID'} eq $cgiparams{'LOCAL_ID'}) && ($cgiparams{'LOCAL_ID'} ne ''))
1354            ) {
1355             $errormessage = $Lang::tr{'invalid local-remote id'} . '<br />' .
1356             'DER_ASN1_DN: @c=FR/ou=Paris/ou=Home/cn=*<br />' .
1357             'FQDN: @ipfire.org<br />' .
1358             'USER_FQDN: info@ipfire.org<br />' .
1359             'IPV4_ADDR: 123.123.123.123';
1360             goto VPNCONF_ERROR;
1361         }
1362         # If Auth is DN, verify existance of Remote ID.
1363         if ( $cgiparams{'REMOTE_ID'} eq '' && (
1364                 $cgiparams{'AUTH'} eq 'auth-dn'||                  # while creation
1365                 $confighash{$cgiparams{'KEY'}}[2] eq '%auth-dn')){ # while editing
1366             $errormessage = $Lang::tr{'vpn missing remote id'};
1367             goto VPNCONF_ERROR;
1368         }
1369
1370         if ($cgiparams{'AUTH'} eq 'psk') {
1371             if (! length($cgiparams{'PSK'}) ) {
1372                 $errormessage = $Lang::tr{'pre-shared key is too short'};
1373                 goto VPNCONF_ERROR;
1374             }
1375             if ($cgiparams{'PSK'} =~ /'/) {
1376                 $cgiparams{'PSK'} =~ tr/'/ /;
1377                 $errormessage = $Lang::tr{'invalid characters found in pre-shared key'};
1378                 goto VPNCONF_ERROR;
1379             }
1380         } elsif ($cgiparams{'AUTH'} eq 'certreq') {
1381             if ($cgiparams{'KEY'}) {
1382                 $errormessage = $Lang::tr{'cant change certificates'};
1383                 goto VPNCONF_ERROR;
1384             }
1385             if (ref ($cgiparams{'FH'}) ne 'Fh') {
1386                 $errormessage = $Lang::tr{'there was no file upload'};
1387                 goto VPNCONF_ERROR;
1388             }
1389
1390             # Move uploaded certificate request to a temporary file
1391             (my $fh, my $filename) = tempfile( );
1392             if (copy ($cgiparams{'FH'}, $fh) != 1) {
1393                 $errormessage = $!;
1394                 goto VPNCONF_ERROR;
1395             }
1396
1397             # Sign the certificate request
1398             &General::log("ipsec", "Signing your cert $cgiparams{'NAME'}...");
1399             my  $opt  = " ca -days 999999";
1400                 $opt .= " -batch -notext";
1401                 $opt .= " -in $filename";
1402                 $opt .= " -out ${General::swroot}/certs/$cgiparams{'NAME'}cert.pem";
1403
1404             if ( $errormessage = &callssl ($opt) ) {
1405                 unlink ($filename);
1406                 unlink ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem");
1407                 &cleanssldatabase();
1408                 goto VPNCONF_ERROR;
1409             } else {
1410                 unlink ($filename);
1411                 &cleanssldatabase();
1412             }
1413
1414             $cgiparams{'CERT_NAME'} = getCNfromcert ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem");
1415             if ($cgiparams{'CERT_NAME'} eq '') {
1416                 $errormessage = $Lang::tr{'could not retrieve common name from certificate'};
1417                 goto VPNCONF_ERROR;
1418             }
1419         } elsif ($cgiparams{'AUTH'} eq 'pkcs12') {
1420                 &General::log("ipsec", "Importing from p12...");
1421
1422                 if (ref ($cgiparams{'FH'}) ne 'Fh') {
1423                     $errormessage = $Lang::tr{'there was no file upload'};
1424                     goto ROOTCERT_ERROR;
1425                 }
1426
1427                 # Move uploaded certificate request to a temporary file
1428                 (my $fh, my $filename) = tempfile( );
1429                 if (copy ($cgiparams{'FH'}, $fh) != 1) {
1430                     $errormessage = $!;
1431                     goto ROOTCERT_ERROR;
1432                 }
1433
1434                 # Extract the CA certificate from the file
1435                 &General::log("ipsec", "Extracting caroot from p12...");
1436                 if (open(STDIN, "-|")) {
1437                     my  $opt  = " pkcs12 -cacerts -nokeys";
1438                         $opt .= " -in $filename";
1439                         $opt .= " -out /tmp/newcacert";
1440                     $errormessage = &callssl ($opt);
1441                 } else {        #child
1442                     print "$cgiparams{'P12_PASS'}\n";
1443                     exit (0);
1444                 }
1445
1446                 # Extract the Host certificate from the file
1447                 if (!$errormessage) {
1448                     &General::log("ipsec", "Extracting host cert from p12...");
1449                     if (open(STDIN, "-|")) {
1450                         my  $opt  = " pkcs12 -clcerts -nokeys";
1451                         $opt .= " -in $filename";
1452                         $opt .= " -out /tmp/newhostcert";
1453                         $errormessage = &callssl ($opt);
1454                     } else {    #child
1455                         print "$cgiparams{'P12_PASS'}\n";
1456                         exit (0);
1457                     }
1458                 }
1459
1460                 if (!$errormessage) {           
1461                     &General::log("ipsec", "Moving cacert...");
1462                     #If CA have new subject, add it to our list of CA
1463                     my $casubject = &Header::cleanhtml(getsubjectfromcert ('/tmp/newcacert'));
1464                     my @names;
1465                     foreach my $x (keys %cahash) {
1466                         $casubject='' if ($cahash{$x}[1] eq $casubject);
1467                         unshift (@names,$cahash{$x}[0]);
1468                     }
1469                     if ($casubject) { # a new one!
1470                         my $temp = `/usr/bin/openssl x509 -text -in /tmp/newcacert`;
1471                         if ($temp !~ /CA:TRUE/i) {
1472                             $errormessage = $Lang::tr{'not a valid ca certificate'};
1473                         } else {
1474                             #compute a name for it
1475                             my $idx=0;
1476                             while (grep(/Imported-$idx/, @names) ) {$idx++};
1477                             $cgiparams{'CA_NAME'}="Imported-$idx";
1478                             $cgiparams{'CERT_NAME'}=&Header::cleanhtml(getCNfromcert ('/tmp/newhostcert'));
1479                             move("/tmp/newcacert", "${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem");
1480                             $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0);
1481                             if (!$errormessage) {
1482                                 my $key = &General::findhasharraykey (\%cahash);
1483                                 $cahash{$key}[0] = $cgiparams{'CA_NAME'};
1484                                 $cahash{$key}[1] = $casubject;
1485                                 &General::writehasharray("${General::swroot}/vpn/caconfig", \%cahash);
1486                                 system('/usr/local/bin/ipsecctrl', 'R');
1487                             }
1488                         }
1489                     }   
1490                 }
1491                 if (!$errormessage) {
1492                     &General::log("ipsec", "Moving host cert...");
1493                     move("/tmp/newhostcert", "${General::swroot}/certs/$cgiparams{'NAME'}cert.pem");
1494                     $errormessage = "$Lang::tr{'certificate file move failed'}: $!" if ($? ne 0);
1495                 }
1496
1497                 #cleanup temp files
1498                 unlink ($filename);
1499                 unlink ('/tmp/newcacert');
1500                 unlink ('/tmp/newhostcert');
1501                 if ($errormessage) {
1502                     unlink ("${General::swroot}/ca/$cgiparams{'CA_NAME'}cert.pem");
1503                     unlink ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem");
1504                     goto VPNCONF_ERROR;
1505                 }
1506                 &General::log("ipsec", "p12 import completed!");
1507         } elsif ($cgiparams{'AUTH'} eq 'certfile') {
1508             if ($cgiparams{'KEY'}) {
1509                 $errormessage = $Lang::tr{'cant change certificates'};
1510                 goto VPNCONF_ERROR;
1511             }
1512             if (ref ($cgiparams{'FH'}) ne 'Fh') {
1513                 $errormessage = $Lang::tr{'there was no file upload'};
1514                 goto VPNCONF_ERROR;
1515             }
1516             # Move uploaded certificate to a temporary file
1517             (my $fh, my $filename) = tempfile( );
1518             if (copy ($cgiparams{'FH'}, $fh) != 1) {
1519                 $errormessage = $!;
1520                 goto VPNCONF_ERROR;
1521             }
1522
1523             # Verify the certificate has a valid CA and move it
1524             &General::log("ipsec", "Validating imported cert against our known CA...");
1525             my $validca = 1;  #assume ok
1526             my $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/cacert.pem $filename`;
1527             if ($test !~ /: OK/) {
1528                 my $validca = 0;
1529                 foreach my $key (keys %cahash) {
1530                     $test = `/usr/bin/openssl verify -CAfile ${General::swroot}/ca/$cahash{$key}[0]cert.pem $filename`;
1531                     if ($test =~ /: OK/) {
1532                         $validca = 1;
1533                         last;
1534                     }
1535                 }
1536             }
1537             if (! $validca) {
1538                 $errormessage = $Lang::tr{'certificate does not have a valid ca associated with it'};
1539                 unlink ($filename);
1540                 goto VPNCONF_ERROR;
1541             } else {
1542                 move($filename, "${General::swroot}/certs/$cgiparams{'NAME'}cert.pem");
1543                 if ($? ne 0) {
1544                     $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1545                     unlink ($filename);
1546                     goto VPNCONF_ERROR;
1547                 }
1548             }
1549
1550             $cgiparams{'CERT_NAME'} = getCNfromcert ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem");
1551             if ($cgiparams{'CERT_NAME'} eq '') {
1552                 unlink ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem");
1553                 $errormessage = $Lang::tr{'could not retrieve common name from certificate'};
1554                 goto VPNCONF_ERROR;
1555             }
1556         } elsif ($cgiparams{'AUTH'} eq 'certgen') {
1557             if ($cgiparams{'KEY'}) {
1558                 $errormessage = $Lang::tr{'cant change certificates'};
1559                 goto VPNCONF_ERROR;
1560             }
1561             # Validate input since the form was submitted
1562             if (length($cgiparams{'CERT_NAME'}) >60) {
1563                 $errormessage = $Lang::tr{'name too long'};
1564                 goto VPNCONF_ERROR;
1565             }
1566             if ($cgiparams{'CERT_NAME'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) {
1567                 $errormessage = $Lang::tr{'invalid input for name'};
1568                 goto VPNCONF_ERROR;
1569             }
1570             if ($cgiparams{'CERT_EMAIL'} ne '' && (! &General::validemail($cgiparams{'CERT_EMAIL'}))) {
1571                 $errormessage = $Lang::tr{'invalid input for e-mail address'};
1572                 goto VPNCONF_ERROR;
1573             }
1574             if (length($cgiparams{'CERT_EMAIL'}) > 40) {
1575                 $errormessage = $Lang::tr{'e-mail address too long'};
1576                 goto VPNCONF_ERROR;
1577             }
1578             if ($cgiparams{'CERT_OU'} ne '' && $cgiparams{'CERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1579                 $errormessage = $Lang::tr{'invalid input for department'};
1580                 goto VPNCONF_ERROR;
1581             }
1582             if (length($cgiparams{'CERT_ORGANIZATION'}) >60) {
1583                 $errormessage = $Lang::tr{'organization too long'};
1584                 goto VPNCONF_ERROR;
1585             }
1586             if ($cgiparams{'CERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) {
1587                 $errormessage = $Lang::tr{'invalid input for organization'};
1588                 goto VPNCONF_ERROR;
1589             }
1590             if ($cgiparams{'CERT_CITY'} ne '' && $cgiparams{'CERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1591                 $errormessage = $Lang::tr{'invalid input for city'};
1592                 goto VPNCONF_ERROR;
1593             }
1594             if ($cgiparams{'CERT_STATE'} ne '' && $cgiparams{'CERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1595                 $errormessage = $Lang::tr{'invalid input for state or province'};
1596                 goto VPNCONF_ERROR;
1597             }
1598             if ($cgiparams{'CERT_COUNTRY'} !~ /^[A-Z]*$/) {
1599                 $errormessage = $Lang::tr{'invalid input for country'};
1600                 goto VPNCONF_ERROR;
1601             }
1602             #the exact syntax is a list comma separated of 
1603             #  email:any-validemail
1604             #   URI: a uniform resource indicator
1605             #   DNS: a DNS domain name
1606             #   RID: a registered OBJECT IDENTIFIER
1607             #   IP: an IP address
1608             # example: email:franck@foo.com,IP:10.0.0.10,DNS:franck.foo.com
1609
1610             if ($cgiparams{'SUBJECTALTNAME'} ne '' && $cgiparams{'SUBJECTALTNAME'} !~ /^(email|URI|DNS|RID|IP):[a-zA-Z0-9 :\/,\.\-_@]*$/) {
1611                 $errormessage = $Lang::tr{'vpn altname syntax'};
1612                 goto VPNCONF_ERROR;
1613             }
1614
1615             if (length($cgiparams{'CERT_PASS1'}) < 5) {
1616                 $errormessage = $Lang::tr{'password too short'};
1617                 goto VPNCONF_ERROR;
1618             }
1619             if ($cgiparams{'CERT_PASS1'} ne $cgiparams{'CERT_PASS2'}) {
1620                 $errormessage = $Lang::tr{'passwords do not match'};
1621                 goto VPNCONF_ERROR;
1622             }
1623
1624             # Replace empty strings with a .
1625             (my $ou = $cgiparams{'CERT_OU'}) =~ s/^\s*$/\./;
1626             (my $city = $cgiparams{'CERT_CITY'}) =~ s/^\s*$/\./;
1627             (my $state = $cgiparams{'CERT_STATE'}) =~ s/^\s*$/\./;
1628
1629             # Create the Host certificate request
1630             &General::log("ipsec", "Creating a cert...");
1631
1632             if (open(STDIN, "-|")) {
1633                 my $opt  = " req -nodes -rand /proc/interrupts:/proc/net/rt_cache";
1634                    $opt .= " -newkey rsa:1024";
1635                    $opt .= " -keyout ${General::swroot}/certs/$cgiparams{'NAME'}key.pem";
1636                    $opt .= " -out ${General::swroot}/certs/$cgiparams{'NAME'}req.pem";
1637
1638                 if ( $errormessage = &callssl ($opt) ) {
1639                     unlink ("${General::swroot}/certs/$cgiparams{'NAME'}key.pem");
1640                     unlink ("${General::swroot}/certs/$cgiparams{'NAME'}req.pem");
1641                     goto VPNCONF_ERROR;
1642                 }
1643             } else {    #child
1644                 print  "$cgiparams{'CERT_COUNTRY'}\n";
1645                 print  "$state\n";
1646                 print  "$city\n";
1647                 print  "$cgiparams{'CERT_ORGANIZATION'}\n";
1648                 print  "$ou\n";
1649                 print  "$cgiparams{'CERT_NAME'}\n";
1650                 print  "$cgiparams{'CERT_EMAIL'}\n";
1651                 print  ".\n";
1652                 print  ".\n";
1653                 exit (0);
1654             }
1655             
1656             # Sign the host certificate request
1657             &General::log("ipsec", "Signing the cert $cgiparams{'NAME'}...");
1658
1659             #No easy way for specifying the contain of subjectAltName without writing a config file...
1660             my ($fh, $v3extname) = tempfile ('/tmp/XXXXXXXX');
1661             print $fh <<END
1662             basicConstraints=CA:FALSE
1663             nsComment="OpenSSL Generated Certificate"
1664             subjectKeyIdentifier=hash
1665             authorityKeyIdentifier=keyid,issuer:always
1666 END
1667 ;
1668             print $fh "subjectAltName=$cgiparams{'SUBJECTALTNAME'}" if ($cgiparams{'SUBJECTALTNAME'});
1669             close ($fh);
1670
1671             my $opt  = " ca -days 999999 -batch -notext";
1672                $opt .= " -in ${General::swroot}/certs/$cgiparams{'NAME'}req.pem";
1673                $opt .= " -out ${General::swroot}/certs/$cgiparams{'NAME'}cert.pem";
1674                $opt .= " -extfile $v3extname";
1675
1676             if ( $errormessage = &callssl ($opt) ) {
1677                 unlink ($v3extname);
1678                 unlink ("${General::swroot}/certs/$cgiparams{'NAME'}key.pem");
1679                 unlink ("${General::swroot}/certs/$cgiparams{'NAME'}req.pem");
1680                 unlink ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem");
1681                 &cleanssldatabase();
1682                 goto VPNCONF_ERROR;
1683             } else {
1684                 unlink ($v3extname);
1685                 unlink ("${General::swroot}/certs/$cgiparams{'NAME'}req.pem");
1686                 &cleanssldatabase();
1687             }
1688
1689             # Create the pkcs12 file
1690             &General::log("ipsec", "Packing a pkcs12 file...");
1691                $opt  = " pkcs12 -export"; 
1692                $opt .= " -inkey ${General::swroot}/certs/$cgiparams{'NAME'}key.pem";
1693                $opt .= " -in ${General::swroot}/certs/$cgiparams{'NAME'}cert.pem";
1694                $opt .= " -name \"$cgiparams{'NAME'}\"";
1695                $opt .= " -passout pass:$cgiparams{'CERT_PASS1'}";
1696                $opt .= " -certfile ${General::swroot}/ca/cacert.pem";
1697                $opt .= " -caname \"$vpnsettings{'ROOTCERT_ORGANIZATION'} CA\"";
1698                $opt .= " -out ${General::swroot}/certs/$cgiparams{'NAME'}.p12";
1699
1700             if ( $errormessage = &callssl ($opt) ) {
1701                 unlink ("${General::swroot}/certs/$cgiparams{'NAME'}key.pem");
1702                 unlink ("${General::swroot}/certs/$cgiparams{'NAME'}cert.pem");
1703                 unlink ("${General::swroot}/certs/$cgiparams{'NAME'}.p12");
1704                 goto VPNCONF_ERROR;
1705             } else {
1706                 unlink ("${General::swroot}/certs/$cgiparams{'NAME'}key.pem");
1707             }
1708         } elsif ($cgiparams{'AUTH'} eq 'cert') {
1709             ;# Nothing, just editing
1710         } elsif ($cgiparams{'AUTH'} eq 'auth-dn') {
1711             $cgiparams{'CERT_NAME'} = '%auth-dn';       # a special value saying 'no cert file'     
1712         } else {
1713             $errormessage = $Lang::tr{'invalid input for authentication method'};
1714             goto VPNCONF_ERROR;
1715         }
1716
1717         # 1)Error message here is not accurate.
1718         # 2)Test is superfluous, openswan can reference same cert multiple times
1719         # 3)Present since initial version (1.3.2.11), it isn't a bug correction
1720         # Check if there is no other entry with this certificate name
1721         #if ((! $cgiparams{'KEY'}) && ($cgiparams{'AUTH'} ne 'psk') && ($cgiparams{'AUTH'} ne 'auth-dn')) {
1722         #    foreach my $key (keys %confighash) {
1723         #       if ($confighash{$key}[2] eq $cgiparams{'CERT_NAME'}) {
1724         #           $errormessage = $Lang::tr{'a connection with this common name already exists'};
1725         #           goto VPNCONF_ERROR;
1726         #       }
1727         #    }
1728         #}
1729         # Save the config
1730
1731         my $key = $cgiparams{'KEY'};
1732         if (! $key) {
1733             $key = &General::findhasharraykey (\%confighash);
1734             foreach my $i (0 .. 28) { $confighash{$key}[$i] = "";}
1735         }
1736         $confighash{$key}[0] = $cgiparams{'ENABLED'};
1737         $confighash{$key}[1] = $cgiparams{'NAME'};
1738         if ((! $cgiparams{'KEY'}) && $cgiparams{'AUTH'} ne 'psk') {
1739             $confighash{$key}[2] = $cgiparams{'CERT_NAME'};
1740         }
1741         $confighash{$key}[3] = $cgiparams{'TYPE'};
1742         if ($cgiparams{'AUTH'} eq 'psk') {
1743             $confighash{$key}[4] = 'psk';
1744             $confighash{$key}[5] = $cgiparams{'PSK'};
1745         } else {
1746             $confighash{$key}[4] = 'cert';
1747         }
1748         if ($cgiparams{'TYPE'} eq 'net') {
1749             $confighash{$key}[11] = $cgiparams{'REMOTE_SUBNET'};
1750         }
1751         $confighash{$key}[7] = $cgiparams{'LOCAL_ID'};
1752         $confighash{$key}[8] = $cgiparams{'LOCAL_SUBNET'};
1753         $confighash{$key}[9] = $cgiparams{'REMOTE_ID'};
1754         $confighash{$key}[10] = $cgiparams{'REMOTE'};
1755         $confighash{$key}[25] = $cgiparams{'REMARK'};
1756         $confighash{$key}[26] = ""; # Formerly INTERFACE
1757         $confighash{$key}[27] = $cgiparams{'DPD_ACTION'};
1758         $confighash{$key}[29] = $cgiparams{'IKE_VERSION'};
1759
1760         #dont forget advanced value
1761         $confighash{$key}[18] = $cgiparams{'IKE_ENCRYPTION'};
1762         $confighash{$key}[19] = $cgiparams{'IKE_INTEGRITY'};
1763         $confighash{$key}[20] = $cgiparams{'IKE_GROUPTYPE'};
1764         $confighash{$key}[16] = $cgiparams{'IKE_LIFETIME'};
1765         $confighash{$key}[21] = $cgiparams{'ESP_ENCRYPTION'};
1766         $confighash{$key}[22] = $cgiparams{'ESP_INTEGRITY'};
1767         $confighash{$key}[23] = $cgiparams{'ESP_GROUPTYPE'};
1768         $confighash{$key}[17] = $cgiparams{'ESP_KEYLIFE'};
1769         $confighash{$key}[12] = 'off'; # $cgiparams{'AGGRMODE'};
1770         $confighash{$key}[13] = $cgiparams{'COMPRESSION'};
1771         $confighash{$key}[24] = $cgiparams{'ONLY_PROPOSED'};
1772         $confighash{$key}[28] = $cgiparams{'PFS'};
1773         $confighash{$key}[14] = $cgiparams{'VHOST'};
1774
1775         #free unused fields!
1776         $confighash{$key}[6] = 'off';
1777         $confighash{$key}[15] = 'off';
1778
1779         &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
1780         &writeipsecfiles();
1781         if (&vpnenabled) {
1782             system('/usr/local/bin/ipsecctrl', 'S', $key);
1783             sleep $sleepDelay;
1784         }
1785         if ($cgiparams{'EDIT_ADVANCED'} eq 'on') {
1786             $cgiparams{'KEY'} = $key;
1787             $cgiparams{'ACTION'} = $Lang::tr{'advanced'};
1788         }
1789         goto VPNCONF_END;
1790     } else { # add new connection
1791         $cgiparams{'ENABLED'} = 'on';
1792         if ( ! -f "${General::swroot}/private/cakey.pem" ) {
1793             $cgiparams{'AUTH'} = 'psk';
1794         } elsif ( ! -f "${General::swroot}/ca/cacert.pem") {
1795             $cgiparams{'AUTH'} = 'certfile';
1796         } else {
1797             $cgiparams{'AUTH'} = 'certgen';
1798         }
1799         $cgiparams{'LOCAL_SUBNET'}      ="$netsettings{'GREEN_NETADDRESS'}/$netsettings{'GREEN_NETMASK'}";
1800         $cgiparams{'CERT_EMAIL'}        = $vpnsettings{'ROOTCERT_EMAIL'};
1801         $cgiparams{'CERT_OU'}           = $vpnsettings{'ROOTCERT_OU'};
1802         $cgiparams{'CERT_ORGANIZATION'} = $vpnsettings{'ROOTCERT_ORGANIZATION'};
1803         $cgiparams{'CERT_CITY'}         = $vpnsettings{'ROOTCERT_CITY'};
1804         $cgiparams{'CERT_STATE'}        = $vpnsettings{'ROOTCERT_STATE'};
1805         $cgiparams{'CERT_COUNTRY'}      = $vpnsettings{'ROOTCERT_COUNTRY'};
1806
1807         # choose appropriate dpd action 
1808         if ($cgiparams{'TYPE'} eq 'host') {
1809             $cgiparams{'DPD_ACTION'} = 'clear';
1810         } else {
1811             $cgiparams{'DPD_ACTION'} = 'restart';
1812         }
1813
1814         # Default IKE Version to v2
1815         if (!$cgiparams{'IKE_VERSION'}) {
1816             $cgiparams{'IKE_VERSION'} = 'ikev2';
1817         }
1818
1819         # ID are empty
1820         $cgiparams{'LOCAL_ID'}  = '';
1821         $cgiparams{'REMOTE_ID'} = '';
1822
1823         #use default advanced value
1824         $cgiparams{'IKE_ENCRYPTION'} = 'aes256|aes192|aes128|3des';     #[18];
1825         $cgiparams{'IKE_INTEGRITY'}  = 'sha2_256|sha|md5';      #[19];
1826         $cgiparams{'IKE_GROUPTYPE'}  = '8192|6144|4096|3072|2048|1536|1024';            #[20];
1827         $cgiparams{'IKE_LIFETIME'}   = '1';             #[16];
1828         $cgiparams{'ESP_ENCRYPTION'} = 'aes256|aes192|aes128|3des';     #[21];
1829         $cgiparams{'ESP_INTEGRITY'}  = 'sha2_256|sha1|md5';     #[22];
1830         $cgiparams{'ESP_GROUPTYPE'}  = '';              #[23];
1831         $cgiparams{'ESP_KEYLIFE'}    = '8';             #[17];
1832         $cgiparams{'COMPRESSION'}    = 'on';            #[13];
1833         $cgiparams{'ONLY_PROPOSED'}  = 'off';           #[24];
1834         $cgiparams{'PFS'}            = 'on';            #[28];
1835         $cgiparams{'VHOST'}          = 'on';            #[14];
1836     }
1837
1838     VPNCONF_ERROR:
1839     $checked{'ENABLED'}{'off'} = '';
1840     $checked{'ENABLED'}{'on'} = '';
1841     $checked{'ENABLED'}{$cgiparams{'ENABLED'}} = "checked='checked'";
1842
1843     $checked{'EDIT_ADVANCED'}{'off'} = '';
1844     $checked{'EDIT_ADVANCED'}{'on'} = '';
1845     $checked{'EDIT_ADVANCED'}{$cgiparams{'EDIT_ADVANCED'}} = "checked='checked'";
1846
1847     $checked{'AUTH'}{'psk'} = '';
1848     $checked{'AUTH'}{'certreq'} = '';
1849     $checked{'AUTH'}{'certgen'} = '';
1850     $checked{'AUTH'}{'certfile'} = '';
1851     $checked{'AUTH'}{'pkcs12'} = '';
1852     $checked{'AUTH'}{'auth-dn'} = '';
1853     $checked{'AUTH'}{$cgiparams{'AUTH'}} = "checked='checked'";
1854
1855     $selected{'DPD_ACTION'}{'clear'} = '';
1856     $selected{'DPD_ACTION'}{'hold'} = '';
1857     $selected{'DPD_ACTION'}{'restart'} = '';
1858     $selected{'DPD_ACTION'}{$cgiparams{'DPD_ACTION'}} = "selected='selected'";
1859
1860     $selected{'IKE_VERSION'}{'ikev1'} = '';
1861     $selected{'IKE_VERSION'}{'ikev2'} = '';
1862     $selected{'IKE_VERSION'}{$cgiparams{'IKE_VERSION'}} = "selected='selected'";
1863
1864     &Header::showhttpheaders();
1865     &Header::openpage($Lang::tr{'vpn configuration main'}, 1, '');
1866     &Header::openbigbox('100%', 'left', '', $errormessage);
1867     if ($errormessage) {
1868         &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
1869         print "<class name='base'>$errormessage";
1870         print "&nbsp;</class>";
1871         &Header::closebox();
1872     }
1873
1874     if ($warnmessage) {
1875         &Header::openbox('100%', 'left', "$Lang::tr{'warning messages'}:");
1876         print "<class name='base'>$warnmessage";
1877         print "&nbsp;</class>";
1878         &Header::closebox();
1879     }
1880
1881     print "<form method='post' enctype='multipart/form-data' action='$ENV{'SCRIPT_NAME'}'>";
1882     print<<END
1883         <input type='hidden' name='TYPE' value='$cgiparams{'TYPE'}' />
1884         <input type='hidden' name='IKE_ENCRYPTION' value='$cgiparams{'IKE_ENCRYPTION'}' />
1885         <input type='hidden' name='IKE_INTEGRITY' value='$cgiparams{'IKE_INTEGRITY'}' />
1886         <input type='hidden' name='IKE_GROUPTYPE' value='$cgiparams{'IKE_GROUPTYPE'}' />
1887         <input type='hidden' name='IKE_LIFETIME' value='$cgiparams{'IKE_LIFETIME'}' />
1888         <input type='hidden' name='ESP_ENCRYPTION' value='$cgiparams{'ESP_ENCRYPTION'}' />
1889         <input type='hidden' name='ESP_INTEGRITY' value='$cgiparams{'ESP_INTEGRITY'}' />
1890         <input type='hidden' name='ESP_GROUPTYPE' value='$cgiparams{'ESP_GROUPTYPE'}' />
1891         <input type='hidden' name='ESP_KEYLIFE' value='$cgiparams{'ESP_KEYLIFE'}' />
1892         <input type='hidden' name='COMPRESSION' value='$cgiparams{'COMPRESSION'}' />
1893         <input type='hidden' name='ONLY_PROPOSED' value='$cgiparams{'ONLY_PROPOSED'}' />
1894         <input type='hidden' name='PFS' value='$cgiparams{'PFS'}' />
1895         <input type='hidden' name='VHOST' value='$cgiparams{'VHOST'}' />
1896 END
1897     ;
1898     if ($cgiparams{'KEY'}) {
1899         print "<input type='hidden' name='KEY' value='$cgiparams{'KEY'}' />";
1900         print "<input type='hidden' name='AUTH' value='$cgiparams{'AUTH'}' />";
1901     }
1902
1903     &Header::openbox('100%', 'left', "$Lang::tr{'connection'}:");
1904     print "<table width='100%'>";
1905     print "<tr><td width='25%' class='boldbase'>$Lang::tr{'name'}:</td>";
1906     if ($cgiparams{'KEY'}) {
1907         print "<td width='25%' class='base'><input type='hidden' name='NAME' value='$cgiparams{'NAME'}' /><b>$cgiparams{'NAME'}</b></td>";
1908     } else {
1909         print "<td width='25%'><input type='text' name='NAME' value='$cgiparams{'NAME'}' size='30' /></td>";
1910     }
1911     print "<td>$Lang::tr{'enabled'}</td><td><input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} /></td></tr>";
1912     print '</tr><td><br /></td><tr>';
1913
1914     my $disabled;
1915     my $blob;
1916     if ($cgiparams{'TYPE'} eq 'host') {
1917         $disabled = "disabled='disabled'";
1918         $blob = "<img src='/blob.gif' alt='*' />";
1919     };
1920
1921     print <<END
1922         <tr>
1923             <td class='boldbase'>$Lang::tr{'remote host/ip'}:&nbsp;$blob</td>
1924             <td>
1925                 <input type='text' name='REMOTE' value='$cgiparams{'REMOTE'}' size='30' />
1926             </td>
1927             <td class='boldbase' nowrap='nowrap'>$Lang::tr{'remote subnet'}</td>
1928             <td>
1929                 <input $disabled type='text' name='REMOTE_SUBNET' value='$cgiparams{'REMOTE_SUBNET'}' size='30' />
1930             </td>
1931         </tr>
1932         <tr>
1933             <td class='boldbase' nowrap='nowrap'>$Lang::tr{'local subnet'}</td>
1934             <td colspan='3'>
1935                 <input type='text' name='LOCAL_SUBNET' value='$cgiparams{'LOCAL_SUBNET'}' size='30' />
1936             </td>
1937         </tr>
1938         <tr>
1939             <td class='boldbase'>$Lang::tr{'vpn local id'}:<br />($Lang::tr{'eg'} <tt>&#64;xy.example.com</tt>)</td>
1940             <td><input type='text' name='LOCAL_ID' value='$cgiparams{'LOCAL_ID'}' /></td>
1941             <td class='boldbase'>$Lang::tr{'vpn remote id'}:</td>
1942             <td><input type='text' name='REMOTE_ID' value='$cgiparams{'REMOTE_ID'}' /></td>
1943         </tr><tr>
1944         </tr><td><br /></td><tr>
1945             <td>$Lang::tr{'vpn keyexchange'}:</td>
1946             <td><select name='IKE_VERSION'>
1947                 <option value='ikev2' $selected{'IKE_VERSION'}{'ikev2'}>IKEv2</option>
1948                 <option value='ikev1' $selected{'IKE_VERSION'}{'ikev1'}>IKEv1</option>
1949                 </select>
1950             </td>
1951             <td>$Lang::tr{'dpd action'}:</td>
1952             <td><select name='DPD_ACTION'>
1953                 <option value='clear' $selected{'DPD_ACTION'}{'clear'}>clear</option>
1954                 <option value='hold' $selected{'DPD_ACTION'}{'hold'}>hold</option>
1955                 <option value='restart' $selected{'DPD_ACTION'}{'restart'}>restart</option>
1956                 </select>
1957             </td>
1958         </tr><tr>
1959             <td class='boldbase'>$Lang::tr{'remark title'}&nbsp;<img src='/blob.gif' alt='*' /></td>
1960             <td colspan='3'><input type='text' name='REMARK' value='$cgiparams{'REMARK'}' size='55' maxlength='50' /></td>
1961         </tr>
1962 END
1963     ;
1964     if (!$cgiparams{'KEY'}) {
1965         print "<tr><td colspan='3'><input type='checkbox' name='EDIT_ADVANCED' $checked{'EDIT_ADVANCED'}{'on'} /> $Lang::tr{'edit advanced settings when done'}</td></tr>";
1966     }
1967     print "</table>";
1968     &Header::closebox();
1969         
1970     if ($cgiparams{'KEY'} && $cgiparams{'AUTH'} eq 'psk') {
1971         &Header::openbox('100%', 'left', $Lang::tr{'authentication'});
1972         print <<END
1973         <table width='100%' cellpadding='0' cellspacing='5' border='0'>
1974         <tr><td class='base' width='50%'>$Lang::tr{'use a pre-shared key'}</td>
1975             <td class='base' width='50%'><input type='password' name='PSK' size='30' value='$cgiparams{'PSK'}' /></td>
1976         </tr>
1977         </table>
1978 END
1979         ;
1980         &Header::closebox();
1981     } elsif (! $cgiparams{'KEY'}) {
1982         my $pskdisabled = ($vpnsettings{'VPN_IP'} eq '%defaultroute') ? "disabled='disabled'" : '' ;
1983         $cgiparams{'PSK'} =  $Lang::tr{'vpn incompatible use of defaultroute'} if ($pskdisabled);
1984         my $cakeydisabled = ( ! -f "${General::swroot}/private/cakey.pem" ) ? "disabled='disabled'" : '';
1985         $cgiparams{'CERT_NAME'} = $Lang::tr{'vpn no full pki'} if ($cakeydisabled);
1986         my $cacrtdisabled = ( ! -f "${General::swroot}/ca/cacert.pem" ) ? "disabled='disabled'" : '';
1987
1988         &Header::openbox('100%', 'left', $Lang::tr{'authentication'});
1989         print <<END
1990         <table width='100%' cellpadding='0' cellspacing='5' border='0'>
1991         <tr><td width='5%'><input type='radio' name='AUTH' value='psk' $checked{'AUTH'}{'psk'} $pskdisabled/></td>
1992             <td class='base' width='55%'>$Lang::tr{'use a pre-shared key'}</td>
1993             <td class='base' width='40%'><input type='password' name='PSK' size='30' value='$cgiparams{'PSK'}' $pskdisabled/></td></tr>
1994         <tr><td colspan='3' bgcolor='#000000'></td></tr>
1995         <tr><td><input type='radio' name='AUTH' value='certreq' $checked{'AUTH'}{'certreq'} $cakeydisabled /></td>
1996             <td class='base'><hr />$Lang::tr{'upload a certificate request'}</td>
1997             <td class='base' rowspan='3' valign='middle'><input type='file' name='FH' size='30' $cacrtdisabled /></td></tr>
1998         <tr><td><input type='radio' name='AUTH' value='certfile' $checked{'AUTH'}{'certfile'} $cacrtdisabled /></td>
1999             <td class='base'>$Lang::tr{'upload a certificate'}</td></tr>
2000         <tr><td><input type='radio' name='AUTH' value='pkcs12' $cacrtdisabled /></td>
2001             <td class='base'>$Lang::tr{'upload p12 file'} $Lang::tr{'pkcs12 file password'}:<input type='password' name='P12_PASS'/></td></tr>
2002         <tr><td><input type='radio' name='AUTH' value='auth-dn' $checked{'AUTH'}{'auth-dn'} $cacrtdisabled /></td>
2003             <td class='base'><hr />$Lang::tr{'vpn auth-dn'}</td></tr>
2004         <tr><td colspan='3' bgcolor='#000000'></td></tr>
2005         <tr><td><input type='radio' name='AUTH' value='certgen' $checked{'AUTH'}{'certgen'} $cakeydisabled /></td>
2006             <td class='base'><hr />$Lang::tr{'generate a certificate'}</td><td>&nbsp;</td></tr>
2007         <tr><td>&nbsp;</td>
2008             <td class='base'>$Lang::tr{'users fullname or system hostname'}:</td>
2009             <td class='base' nowrap='nowrap'><input type='text' name='CERT_NAME' value='$cgiparams{'CERT_NAME'}' size='32' $cakeydisabled /></td></tr>
2010         <tr><td>&nbsp;</td>
2011             <td class='base'>$Lang::tr{'users email'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
2012             <td class='base' nowrap='nowrap'><input type='text' name='CERT_EMAIL' value='$cgiparams{'CERT_EMAIL'}' size='32' $cakeydisabled /></td></tr>
2013         <tr><td>&nbsp;</td>
2014             <td class='base'>$Lang::tr{'users department'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
2015             <td class='base' nowrap='nowrap'><input type='text' name='CERT_OU' value='$cgiparams{'CERT_OU'}' size='32' $cakeydisabled /></td></tr>
2016         <tr><td>&nbsp;</td>
2017             <td class='base'>$Lang::tr{'organization name'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
2018             <td class='base' nowrap='nowrap'><input type='text' name='CERT_ORGANIZATION' value='$cgiparams{'CERT_ORGANIZATION'}' size='32' $cakeydisabled /></td></tr>
2019         <tr><td>&nbsp;</td>
2020             <td class='base'>$Lang::tr{'city'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
2021             <td class='base' nowrap='nowrap'><input type='text' name='CERT_CITY' value='$cgiparams{'CERT_CITY'}' size='32' $cakeydisabled /></td></tr>
2022         <tr><td>&nbsp;</td>
2023             <td class='base'>$Lang::tr{'state or province'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
2024             <td class='base' nowrap='nowrap'><input type='text' name='CERT_STATE' value='$cgiparams{'CERT_STATE'}' size='32' $cakeydisabled /></td></tr>
2025         <tr><td>&nbsp;</td>
2026             <td class='base'>$Lang::tr{'country'}:</td>
2027             <td class='base'><select name='CERT_COUNTRY' $cakeydisabled>
2028 END
2029         ;
2030         foreach my $country (sort keys %{Countries::countries}) {
2031             print "\t\t\t<option value='$Countries::countries{$country}'";
2032             if ( $Countries::countries{$country} eq $cgiparams{'CERT_COUNTRY'} ) {
2033                 print " selected='selected'";
2034             }
2035             print ">$country</option>\n";
2036         }
2037         print <<END
2038             </select></td></tr>
2039
2040         <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'vpn subjectaltname'} (subjectAltName=email:*,URI:*,DNS:*,RID:*)<img src='/blob.gif' alt='*' /></td>
2041             <td class='base' nowrap='nowrap'><input type='text' name='SUBJECTALTNAME' value='$cgiparams{'SUBJECTALTNAME'}' size='32' $cakeydisabled /></td></tr>
2042         <tr><td>&nbsp;</td>
2043             <td class='base'>$Lang::tr{'pkcs12 file password'}:</td>
2044             <td class='base' nowrap='nowrap'><input type='password' name='CERT_PASS1' value='$cgiparams{'CERT_PASS1'}' size='32' $cakeydisabled /></td></tr>
2045         <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'pkcs12 file password'}:($Lang::tr{'confirmation'})</td>
2046             <td class='base' nowrap='nowrap'><input type='password' name='CERT_PASS2' value='$cgiparams{'CERT_PASS2'}' size='32' $cakeydisabled /></td></tr>
2047         </table>
2048 END
2049         ;
2050         &Header::closebox();
2051     }
2052
2053     print "<div align='center'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' />";
2054     if ($cgiparams{'KEY'}) {
2055         print "<input type='submit' name='ACTION' value='$Lang::tr{'advanced'}' />";
2056     }
2057     print "<input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></div></form>";
2058     &Header::closebigbox();
2059     &Header::closepage();
2060     exit (0);
2061     
2062     VPNCONF_END:
2063 }
2064
2065 ###
2066 ### Advanced settings
2067 ###
2068 if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
2069         ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'ADVANCED'} eq 'yes')) {
2070     &General::readhash("${General::swroot}/vpn/settings", \%vpnsettings);
2071     &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
2072     if (! $confighash{$cgiparams{'KEY'}}) {
2073         $errormessage = $Lang::tr{'invalid key'};
2074         goto ADVANCED_END;
2075     }
2076
2077     if ($cgiparams{'ACTION'} eq $Lang::tr{'save'}) {
2078         # I didn't read any incompatibilities here....
2079         #if ($cgiparams{'VHOST'} eq 'on' && $cgiparams{'COMPRESSION'} eq 'on') {
2080         #    $errormessage = $Lang::tr{'cannot enable both nat traversal and compression'};
2081         #    goto ADVANCED_ERROR;
2082         #}
2083         my @temp = split('\|', $cgiparams{'IKE_ENCRYPTION'});
2084         if ($#temp < 0) {
2085             $errormessage = $Lang::tr{'invalid input'};
2086             goto ADVANCED_ERROR;
2087         }
2088         foreach my $val (@temp) {
2089             if ($val !~ /^(aes256|aes128|3des)$/) {
2090                 $errormessage = $Lang::tr{'invalid input'};
2091                 goto ADVANCED_ERROR;
2092             }
2093         }
2094         @temp = split('\|', $cgiparams{'IKE_INTEGRITY'});
2095         if ($#temp < 0) {
2096             $errormessage = $Lang::tr{'invalid input'};
2097             goto ADVANCED_ERROR;
2098         }
2099         foreach my $val (@temp) {
2100             if ($val !~ /^(sha2_512|sha2_384|sha2_256|sha|md5|aesxcbc)$/) {
2101                 $errormessage = $Lang::tr{'invalid input'};
2102                 goto ADVANCED_ERROR;
2103             }
2104         }
2105         @temp = split('\|', $cgiparams{'IKE_GROUPTYPE'});
2106         if ($#temp < 0) {
2107             $errormessage = $Lang::tr{'invalid input'};
2108             goto ADVANCED_ERROR;
2109         }
2110         foreach my $val (@temp) {
2111             if ($val !~ /^(1024|1536|2048|3072|4096|6144|8192)$/) {
2112                 $errormessage = $Lang::tr{'invalid input'};
2113                 goto ADVANCED_ERROR;
2114             }
2115         }
2116         if ($cgiparams{'IKE_LIFETIME'} !~ /^\d+$/) {
2117             $errormessage = $Lang::tr{'invalid input for ike lifetime'};
2118             goto ADVANCED_ERROR;
2119         }
2120         if ($cgiparams{'IKE_LIFETIME'} < 1 || $cgiparams{'IKE_LIFETIME'} > 8) {
2121             $errormessage = $Lang::tr{'ike lifetime should be between 1 and 8 hours'};
2122             goto ADVANCED_ERROR;
2123         }
2124         @temp = split('\|', $cgiparams{'ESP_ENCRYPTION'});
2125         if ($#temp < 0) {
2126             $errormessage = $Lang::tr{'invalid input'};
2127             goto ADVANCED_ERROR;
2128         }
2129         foreach my $val (@temp) {
2130             if ($val !~ /^(aes256|aes192|aes128|3des)$/) {
2131                 $errormessage = $Lang::tr{'invalid input'};
2132                 goto ADVANCED_ERROR;
2133             }
2134         }
2135         @temp = split('\|', $cgiparams{'ESP_INTEGRITY'});
2136         if ($#temp < 0) {
2137             $errormessage = $Lang::tr{'invalid input'};
2138             goto ADVANCED_ERROR;
2139         }
2140         foreach my $val (@temp) {
2141             if ($val !~ /^(sha2_512|sha2_384|sha2_256|sha1|md5|aesxcbc)$/) {
2142                 $errormessage = $Lang::tr{'invalid input'};
2143                 goto ADVANCED_ERROR;
2144             }
2145         }
2146         if ($cgiparams{'ESP_GROUPTYPE'} ne '' &&
2147             $cgiparams{'ESP_GROUPTYPE'} !~  /^modp(1024|1536|2048|3072|4096|6144|8192)$/) {
2148             $errormessage = $Lang::tr{'invalid input'};
2149             goto ADVANCED_ERROR;
2150         }
2151
2152         if ($cgiparams{'ESP_KEYLIFE'} !~ /^\d+$/) {
2153             $errormessage = $Lang::tr{'invalid input for esp keylife'};
2154             goto ADVANCED_ERROR;
2155         }
2156         if ($cgiparams{'ESP_KEYLIFE'} < 1 || $cgiparams{'ESP_KEYLIFE'} > 24) {
2157             $errormessage = $Lang::tr{'esp keylife should be between 1 and 24 hours'};
2158             goto ADVANCED_ERROR;
2159         }
2160
2161         if (
2162             ($cgiparams{'COMPRESSION'} !~ /^(|on|off)$/) ||
2163             ($cgiparams{'ONLY_PROPOSED'} !~ /^(|on|off)$/) ||
2164             ($cgiparams{'PFS'} !~ /^(|on|off)$/) ||
2165             ($cgiparams{'VHOST'} !~ /^(|on|off)$/)
2166         ){
2167             $errormessage = $Lang::tr{'invalid input'};
2168             goto ADVANCED_ERROR;
2169         }
2170
2171         $confighash{$cgiparams{'KEY'}}[18] = $cgiparams{'IKE_ENCRYPTION'};
2172         $confighash{$cgiparams{'KEY'}}[19] = $cgiparams{'IKE_INTEGRITY'};
2173         $confighash{$cgiparams{'KEY'}}[20] = $cgiparams{'IKE_GROUPTYPE'};
2174         $confighash{$cgiparams{'KEY'}}[16] = $cgiparams{'IKE_LIFETIME'};
2175         $confighash{$cgiparams{'KEY'}}[21] = $cgiparams{'ESP_ENCRYPTION'};
2176         $confighash{$cgiparams{'KEY'}}[22] = $cgiparams{'ESP_INTEGRITY'};
2177         $confighash{$cgiparams{'KEY'}}[23] = $cgiparams{'ESP_GROUPTYPE'};
2178         $confighash{$cgiparams{'KEY'}}[17] = $cgiparams{'ESP_KEYLIFE'};
2179         $confighash{$cgiparams{'KEY'}}[12] = 'off'; #$cgiparams{'AGGRMODE'};
2180         $confighash{$cgiparams{'KEY'}}[13] = $cgiparams{'COMPRESSION'};
2181         $confighash{$cgiparams{'KEY'}}[24] = $cgiparams{'ONLY_PROPOSED'};
2182         $confighash{$cgiparams{'KEY'}}[28] = $cgiparams{'PFS'};
2183         $confighash{$cgiparams{'KEY'}}[14] = $cgiparams{'VHOST'};
2184         &General::writehasharray("${General::swroot}/vpn/config", \%confighash);
2185         &writeipsecfiles();
2186         if (&vpnenabled) {
2187             system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'});
2188             sleep $sleepDelay;
2189         }
2190         goto ADVANCED_END;
2191     } else {
2192         $cgiparams{'IKE_ENCRYPTION'} = $confighash{$cgiparams{'KEY'}}[18];
2193         $cgiparams{'IKE_INTEGRITY'}  = $confighash{$cgiparams{'KEY'}}[19];
2194         $cgiparams{'IKE_GROUPTYPE'}  = $confighash{$cgiparams{'KEY'}}[20];
2195         $cgiparams{'IKE_LIFETIME'}   = $confighash{$cgiparams{'KEY'}}[16];
2196         $cgiparams{'ESP_ENCRYPTION'} = $confighash{$cgiparams{'KEY'}}[21];
2197         $cgiparams{'ESP_INTEGRITY'}  = $confighash{$cgiparams{'KEY'}}[22];
2198         $cgiparams{'ESP_GROUPTYPE'}  = $confighash{$cgiparams{'KEY'}}[23];
2199         $cgiparams{'ESP_KEYLIFE'}    = $confighash{$cgiparams{'KEY'}}[17];
2200         $cgiparams{'COMPRESSION'}    = $confighash{$cgiparams{'KEY'}}[13];
2201         $cgiparams{'ONLY_PROPOSED'}  = $confighash{$cgiparams{'KEY'}}[24];
2202         $cgiparams{'PFS'}            = $confighash{$cgiparams{'KEY'}}[28];
2203         $cgiparams{'VHOST'}          = $confighash{$cgiparams{'KEY'}}[14];
2204
2205         if ($confighash{$cgiparams{'KEY'}}[3] eq 'net' || $confighash{$cgiparams{'KEY'}}[10]) {
2206             $cgiparams{'VHOST'}            = 'off';
2207         }
2208     }
2209
2210     ADVANCED_ERROR:
2211     $checked{'IKE_ENCRYPTION'}{'aes256'} = '';
2212     $checked{'IKE_ENCRYPTION'}{'aes192'} = '';
2213     $checked{'IKE_ENCRYPTION'}{'aes128'} = '';
2214     $checked{'IKE_ENCRYPTION'}{'3des'} = '';
2215     my @temp = split('\|', $cgiparams{'IKE_ENCRYPTION'});
2216     foreach my $key (@temp) {$checked{'IKE_ENCRYPTION'}{$key} = "selected='selected'"; }
2217     $checked{'IKE_INTEGRITY'}{'sha2_512'} = '';
2218     $checked{'IKE_INTEGRITY'}{'sha2_384'} = '';
2219     $checked{'IKE_INTEGRITY'}{'sha2_256'} = '';
2220     $checked{'IKE_INTEGRITY'}{'sha'} = '';
2221     $checked{'IKE_INTEGRITY'}{'md5'} = '';
2222     $checked{'IKE_INTEGRITY'}{'aesxcbc'} = '';
2223     @temp = split('\|', $cgiparams{'IKE_INTEGRITY'});
2224     foreach my $key (@temp) {$checked{'IKE_INTEGRITY'}{$key} = "selected='selected'"; }
2225     $checked{'IKE_GROUPTYPE'}{'768'} = '';
2226     $checked{'IKE_GROUPTYPE'}{'1024'} = '';
2227     $checked{'IKE_GROUPTYPE'}{'1536'} = '';
2228     $checked{'IKE_GROUPTYPE'}{'2048'} = '';
2229     $checked{'IKE_GROUPTYPE'}{'3072'} = '';
2230     $checked{'IKE_GROUPTYPE'}{'4096'} = '';
2231     $checked{'IKE_GROUPTYPE'}{'6144'} = '';
2232     $checked{'IKE_GROUPTYPE'}{'8192'} = '';
2233     @temp = split('\|', $cgiparams{'IKE_GROUPTYPE'});
2234     foreach my $key (@temp) {$checked{'IKE_GROUPTYPE'}{$key} = "selected='selected'"; }
2235
2236     # 768 is not supported by strongswan
2237     $checked{'IKE_GROUPTYPE'}{'768'} = '';
2238
2239     $checked{'ESP_ENCRYPTION'}{'aes256'} = '';
2240     $checked{'ESP_ENCRYPTION'}{'aes192'} = '';
2241     $checked{'ESP_ENCRYPTION'}{'aes128'} = '';
2242     $checked{'ESP_ENCRYPTION'}{'3des'} = '';
2243     @temp = split('\|', $cgiparams{'ESP_ENCRYPTION'});
2244     foreach my $key (@temp) {$checked{'ESP_ENCRYPTION'}{$key} = "selected='selected'"; }
2245     $checked{'ESP_INTEGRITY'}{'sha2_512'} = '';
2246     $checked{'ESP_INTEGRITY'}{'sha2_384'} = '';
2247     $checked{'ESP_INTEGRITY'}{'sha2_256'} = '';
2248     $checked{'ESP_INTEGRITY'}{'sha1'} = '';
2249     $checked{'ESP_INTEGRITY'}{'md5'} = '';
2250     $checked{'ESP_INTEGRITY'}{'aesxcbc'} = '';
2251     @temp = split('\|', $cgiparams{'ESP_INTEGRITY'});
2252     foreach my $key (@temp) {$checked{'ESP_INTEGRITY'}{$key} = "selected='selected'"; }
2253     $checked{'ESP_GROUPTYPE'}{$cgiparams{'ESP_GROUPTYPE'}} = "selected='selected'";
2254
2255     $checked{'COMPRESSION'} = $cgiparams{'COMPRESSION'} eq 'on' ? "checked='checked'" : '' ;
2256     $checked{'ONLY_PROPOSED'} = $cgiparams{'ONLY_PROPOSED'} eq 'on' ? "checked='checked'" : '' ;
2257     $checked{'PFS'} = $cgiparams{'PFS'} eq 'on' ? "checked='checked'" : '' ;
2258     $checked{'VHOST'} = $cgiparams{'VHOST'} eq 'on' ? "checked='checked'" : '' ;
2259
2260     &Header::showhttpheaders();
2261     &Header::openpage($Lang::tr{'vpn configuration main'}, 1, '');
2262     &Header::openbigbox('100%', 'left', '', $errormessage);
2263
2264     if ($errormessage) {
2265         &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
2266         print "<class name='base'>$errormessage";
2267         print "&nbsp;</class>";
2268         &Header::closebox();
2269     }
2270
2271     if ($warnmessage) {
2272         &Header::openbox('100%', 'left', $Lang::tr{'warning messages'});
2273         print "<class name='base'>$warnmessage";
2274         print "&nbsp;</class>";
2275         &Header::closebox();
2276     }
2277
2278     &Header::openbox('100%', 'left', "$Lang::tr{'advanced'}:");
2279     print <<EOF
2280     <form method='post' enctype='multipart/form-data' action='$ENV{'SCRIPT_NAME'}'>
2281     <input type='hidden' name='ADVANCED' value='yes' />
2282     <input type='hidden' name='KEY' value='$cgiparams{'KEY'}' />
2283
2284     <table width='100%'>
2285         <tr><td class='boldbase' align='right' valign='top'>$Lang::tr{'ike encryption'}</td><td class='boldbase' valign='top'>
2286                 <select name='IKE_ENCRYPTION' multiple='multiple' size='4'>
2287                 <option value='aes256' $checked{'IKE_ENCRYPTION'}{'aes256'}>AES (256 bit)</option>
2288                 <option value='aes192' $checked{'IKE_ENCRYPTION'}{'aes192'}>AES (192 bit)</option>
2289                 <option value='aes128' $checked{'IKE_ENCRYPTION'}{'aes128'}>AES (128 bit)</option>
2290                 <option value='3des' $checked{'IKE_ENCRYPTION'}{'3des'}>3DES</option>
2291                 </select></td>
2292
2293             <td class='boldbase' align='right' valign='top'>$Lang::tr{'ike integrity'}</td><td class='boldbase' valign='top'>
2294                 <select name='IKE_INTEGRITY' multiple='multiple' size='4'>
2295                 <option value='sha2_512' $checked{'IKE_INTEGRITY'}{'sha2_512'}>SHA2 512 bit</option>
2296                 <option value='sha2_384' $checked{'IKE_INTEGRITY'}{'sha2_384'}>SHA2 384 bit</option>
2297                 <option value='sha2_256' $checked{'IKE_INTEGRITY'}{'sha2_256'}>SHA2 256 bit</option>
2298                 <option value='sha' $checked{'IKE_INTEGRITY'}{'sha'}>SHA1</option>
2299                 <option value='md5' $checked{'IKE_INTEGRITY'}{'md5'}>MD5</option>
2300                 <option value='aesxcbc' $checked{'IKE_INTEGRITY'}{'aesxcbc'}>AES XCBC</option>
2301                 </select></td>
2302         
2303             <td class='boldbase' align='right' valign='top'>$Lang::tr{'ike grouptype'}</td><td class='boldbase' valign='top'>
2304                 <select name='IKE_GROUPTYPE' multiple='multiple' size='4'>
2305                 <option value='8192' $checked{'IKE_GROUPTYPE'}{'8192'}>MODP-8192</option>
2306                 <option value='6144' $checked{'IKE_GROUPTYPE'}{'6144'}>MODP-6144</option>
2307                 <option value='4096' $checked{'IKE_GROUPTYPE'}{'4096'}>MODP-4096</option>
2308                 <option value='3072' $checked{'IKE_GROUPTYPE'}{'3072'}>MODP-3072</option>
2309                 <option value='2048' $checked{'IKE_GROUPTYPE'}{'2048'}>MODP-2048</option>
2310                 <option value='1536' $checked{'IKE_GROUPTYPE'}{'1536'}>MODP-1536</option>
2311                 <option value='1024' $checked{'IKE_GROUPTYPE'}{'1024'}>MODP-1024</option>
2312                 </select></td>
2313         </tr><tr>
2314             <td class='boldbase' align='right' valign='top'>$Lang::tr{'ike lifetime'}</td><td class='boldbase' valign='top'>
2315             <input type='text' name='IKE_LIFETIME' value='$cgiparams{'IKE_LIFETIME'}' size='5' /> $Lang::tr{'hours'}</td>
2316
2317         </tr><tr>
2318             <td colspan='1'><hr /></td>
2319         </tr><tr>
2320             <td class='boldbase' align='right' valign='top'>$Lang::tr{'esp encryption'}</td><td class='boldbase' valign='top'>
2321                 <select name='ESP_ENCRYPTION' multiple='multiple' size='4'>
2322                 <option value='aes256' $checked{'ESP_ENCRYPTION'}{'aes256'}>AES (256 bit)</option>
2323                 <option value='aes192' $checked{'ESP_ENCRYPTION'}{'aes192'}>AES (192 bit)</option>
2324                 <option value='aes128' $checked{'ESP_ENCRYPTION'}{'aes128'}>AES (128 bit)</option>
2325                 <option value='3des' $checked{'ESP_ENCRYPTION'}{'3des'}>3DES</option>
2326
2327             <td class='boldbase' align='right' valign='top'>$Lang::tr{'esp integrity'}</td><td class='boldbase' valign='top'>
2328                 <select name='ESP_INTEGRITY' multiple='multiple' size='4'>
2329                 <option value='sha2_512' $checked{'ESP_INTEGRITY'}{'sha2_512'}>SHA2 512 bit</option>
2330                 <option value='sha2_384' $checked{'ESP_INTEGRITY'}{'sha2_384'}>SHA2 384 bit</option>
2331                 <option value='sha2_256' $checked{'ESP_INTEGRITY'}{'sha2_256'}>SHA2 256 bit</option>
2332                 <option value='sha1' $checked{'ESP_INTEGRITY'}{'sha1'}>SHA1</option>
2333                 <option value='md5' $checked{'ESP_INTEGRITY'}{'md5'}>MD5</option>
2334                 <option value='aesxcbc' $checked{'ESP_INTEGRITY'}{'aesxcbc'}>AES XCBC</option>
2335                 </select></td>
2336
2337             <td class='boldbase' align='right' valign='top'>$Lang::tr{'esp grouptype'}</td><td class='boldbase' valign='top'>
2338                 <select name='ESP_GROUPTYPE'>
2339                 <option value=''>$Lang::tr{'phase1 group'}</option></select></td>
2340         </tr><tr>
2341             <td class='boldbase' align='right' valign='top'>$Lang::tr{'esp keylife'}</td><td class='boldbase' valign='top'>
2342                 <input type='text' name='ESP_KEYLIFE' value='$cgiparams{'ESP_KEYLIFE'}' size='5' /> $Lang::tr{'hours'}</td>
2343         </tr><tr>
2344             <td colspan='1'><hr /></td>
2345         </tr><tr>
2346             <td colspan='5'><input type='checkbox' name='ONLY_PROPOSED' $checked{'ONLY_PROPOSED'} />
2347                 IKE+ESP: $Lang::tr{'use only proposed settings'}</td>
2348         </tr><tr>
2349             <td colspan='5'><input type='checkbox' name='PFS' $checked{'PFS'} />
2350                 $Lang::tr{'pfs yes no'}</td>
2351                 <td align='right'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' /></td>
2352         </tr><tr>
2353             <td colspan='5'><input type='checkbox' name='COMPRESSION' $checked{'COMPRESSION'} />
2354                 $Lang::tr{'vpn payload compression'}</td>
2355                 <td align='right'><input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></td>
2356         </tr>
2357 EOF
2358     ;
2359     if ($confighash{$cgiparams{'KEY'}}[3] eq 'net') {
2360         print "<tr><td><input type='hidden' name='VHOST' value='off' /></td></tr>";
2361     } elsif ($confighash{$cgiparams{'KEY'}}[10]) {
2362         print "<tr><td colspan='5'><input type='checkbox' name='VHOST' $checked{'VHOST'} disabled='disabled' />";
2363         print " $Lang::tr{'vpn vhost'}</td></tr>";
2364     } else {
2365         print "<tr><td colspan='5'><input type='checkbox' name='VHOST' $checked{'VHOST'} />";
2366         print " $Lang::tr{'vpn vhost'}</td></tr>";
2367     }
2368
2369     print "</table></form>";
2370     &Header::closebox();
2371     &Header::closebigbox();
2372     &Header::closepage();
2373     exit(0);
2374
2375     ADVANCED_END:
2376 }
2377
2378 ###
2379 ### Default status page
2380 ###
2381     %cgiparams = ();
2382     %cahash = ();
2383     %confighash = ();
2384     &General::readhash("${General::swroot}/vpn/settings", \%cgiparams);
2385     &General::readhasharray("${General::swroot}/vpn/caconfig", \%cahash);
2386     &General::readhasharray("${General::swroot}/vpn/config", \%confighash);
2387     $cgiparams{'CA_NAME'} = '';
2388
2389     my @status = `/usr/local/bin/ipsecctrl I 2>/dev/null`;
2390
2391     # suggest a default name for this side
2392     if ($cgiparams{'VPN_IP'} eq '' && -e "${General::swroot}/red/active") {
2393         if (open(IPADDR, "${General::swroot}/red/local-ipaddress")) {
2394             my $ipaddr = <IPADDR>;
2395             close IPADDR;
2396             chomp ($ipaddr);
2397             $cgiparams{'VPN_IP'} = (gethostbyaddr(pack("C4", split(/\./, $ipaddr)), 2))[0];
2398             if ($cgiparams{'VPN_IP'} eq '') {
2399                 $cgiparams{'VPN_IP'} = $ipaddr;
2400             }
2401         }
2402     }
2403     # no IP found, use %defaultroute
2404     $cgiparams{'VPN_IP'} ='%defaultroute' if ($cgiparams{'VPN_IP'} eq '');
2405     
2406     $cgiparams{'VPN_DELAYED_START'} = 0 if (! defined ($cgiparams{'VPN_DELAYED_START'}));
2407     $checked{'ENABLED'} = $cgiparams{'ENABLED'} eq 'on' ? "checked='checked'" : '';
2408
2409     &Header::showhttpheaders();
2410     &Header::openpage($Lang::tr{'vpn configuration main'}, 1, '');
2411     &Header::openbigbox('100%', 'left', '', $errormessage);
2412
2413     if ($errormessage) {
2414         &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
2415         print "<class name='base'>$errormessage\n";
2416         print "&nbsp;</class>\n";
2417         &Header::closebox();
2418     }
2419
2420     &Header::openbox('100%', 'left', $Lang::tr{'global settings'});
2421     print <<END
2422     <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2423     <table width='100%'>
2424     <tr>
2425         <td width='20%' class='base' nowrap='nowrap'>$Lang::tr{'vpn red name'}:</td>
2426         <td width='20%'><input type='text' name='VPN_IP' value='$cgiparams{'VPN_IP'}' /></td>
2427         <td width='20%' class='base'>$Lang::tr{'enabled'}<input type='checkbox' name='ENABLED' $checked{'ENABLED'} /></td>
2428     </tr>
2429 END
2430     ;
2431 print <<END
2432     <tr>
2433         <td  class='base' nowrap='nowrap'>$Lang::tr{'vpn delayed start'}:&nbsp;<img src='/blob.gif' alt='*' /><img src='/blob.gif' alt='*' /></td>
2434         <td ><input type='text' name='VPN_DELAYED_START' value='$cgiparams{'VPN_DELAYED_START'}' /></td>
2435     </tr>
2436     <tr>
2437         <td  class='base' nowrap='nowrap'>$Lang::tr{'host to net vpn'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
2438         <td ><input type='text' name='RW_NET' value='$cgiparams{'RW_NET'}' /></td>
2439     </tr>
2440  </table>
2441 <hr />
2442 <table width='100%'>
2443 <tr>
2444     <td class='base' valign='top'><img src='/blob.gif' alt='*' /></td>
2445     <td width='70%' class='base' valign='top'>$Lang::tr{'this field may be blank'}</td>
2446 </tr>
2447 <tr>
2448     <td class='base' valign='top' nowrap='nowrap'><img src='/blob.gif' alt='*' /><img src='/blob.gif' alt='*' />&nbsp;</td>
2449     <td class='base'>   <font class='base'>$Lang::tr{'vpn delayed start help'}</font></td>
2450     <td width='30%' align='center' class='base'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' /></td>
2451 </tr>
2452 </table>
2453 END
2454 ;               
2455     print "</form>";
2456     &Header::closebox();
2457
2458     &Header::openbox('100%', 'left', $Lang::tr{'connection status and controlc'});
2459     print <<END
2460     <table width='100%' border='0' cellspacing='1' cellpadding='0'>
2461     <tr>
2462         <td width='10%' class='boldbase' align='center'><b>$Lang::tr{'name'}</b></td>
2463         <td width='22%' class='boldbase' align='center'><b>$Lang::tr{'type'}</b></td>
2464         <td width='23%' class='boldbase' align='center'><b>$Lang::tr{'common name'}</b></td>
2465         <td width='30%' class='boldbase' align='center'><b>$Lang::tr{'remark'}</b></td>
2466         <td width='10%' class='boldbase' align='center'><b>$Lang::tr{'status'}</b></td>
2467         <td class='boldbase' align='center' colspan='6'><b>$Lang::tr{'action'}</b></td>
2468     </tr>
2469 END
2470     ;
2471     my $id = 0;
2472     my $gif;
2473     foreach my $key (keys %confighash) {
2474         if ($confighash{$key}[0] eq 'on') { $gif = 'on.gif'; } else { $gif = 'off.gif'; }
2475
2476         if ($id % 2) {
2477             print "<tr bgcolor='$color{'color20'}'>\n";
2478         } else {
2479             print "<tr bgcolor='$color{'color22'}'>\n";
2480         }
2481         print "<td align='center' nowrap='nowrap'>$confighash{$key}[1]</td>";
2482         print "<td align='center' nowrap='nowrap'>" . $Lang::tr{"$confighash{$key}[3]"} . " (" . $Lang::tr{"$confighash{$key}[4]"} . ") $confighash{$key}[29]</td>";
2483         if ($confighash{$key}[2] eq '%auth-dn') {
2484             print "<td align='left' nowrap='nowrap'>$confighash{$key}[9]</td>";
2485         } elsif ($confighash{$key}[4] eq 'cert') {
2486             print "<td align='left' nowrap='nowrap'>$confighash{$key}[2]</td>";
2487         } else {
2488             print "<td align='left'>&nbsp;</td>";
2489         }
2490         print "<td align='center'>$confighash{$key}[25]</td>";
2491         # get real state
2492         my $active = "<table cellpadding='2' cellspacing='0' bgcolor='${Header::colourred}' width='100%'><tr><td align='center'><b><font color='#FFFFFF'>$Lang::tr{'capsclosed'}</font></b></td></tr></table>";
2493         foreach my $line (@status) {
2494             if (($line =~ /\"$confighash{$key}[1]\".*IPsec SA established/) ||
2495                ($line =~ /$confighash{$key}[1]\{.*INSTALLED/))
2496             {
2497                 $active = "<table cellpadding='2' cellspacing='0' bgcolor='${Header::colourgreen}' width='100%'><tr><td align='center'><b><font color='#FFFFFF'>$Lang::tr{'capsopen'}</font></b></td></tr></table>";
2498             }
2499         }
2500         # move to blueif really down
2501         if ($confighash{$key}[0] eq 'off' && $active =~ /${Header::colourred}/ ) {
2502             $active = "<table cellpadding='2' cellspacing='0' bgcolor='${Header::colourblue}' width='100%'><tr><td align='center'><b><font color='#FFFFFF'>$Lang::tr{'capsclosed'}</font></b></td></tr></table>";
2503         }
2504         print <<END
2505         <td align='center'>$active</td>
2506         <td align='center'>
2507             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2508             <input type='image'  name='$Lang::tr{'restart'}' src='/images/reload.gif' alt='$Lang::tr{'restart'}' title='$Lang::tr{'restart'}' />
2509             <input type='hidden' name='ACTION' value='$Lang::tr{'restart'}' />
2510             <input type='hidden' name='KEY' value='$key' />
2511             </form>
2512         </td>
2513 END
2514         ;
2515         if (($confighash{$key}[4] eq 'cert') && ($confighash{$key}[2] ne '%auth-dn')) {
2516             print <<END
2517             <td align='center'>
2518             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2519                 <input type='image' name='$Lang::tr{'show certificate'}' src='/images/info.gif' alt='$Lang::tr{'show certificate'}' title='$Lang::tr{'show certificate'}' />
2520                 <input type='hidden' name='ACTION' value='$Lang::tr{'show certificate'}' />
2521                 <input type='hidden' name='KEY' value='$key' />
2522             </form>
2523             </td>
2524 END
2525         ; } else {
2526             print "<td width='2%'>&nbsp;</td>";
2527         }
2528         if ($confighash{$key}[4] eq 'cert' && -f "${General::swroot}/certs/$confighash{$key}[1].p12") { 
2529             print <<END
2530             <td align='center'>
2531             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2532                 <input type='image' name='$Lang::tr{'download pkcs12 file'}' src='/images/floppy.gif' alt='$Lang::tr{'download pkcs12 file'}' title='$Lang::tr{'download pkcs12 file'}' />
2533                 <input type='hidden' name='ACTION' value='$Lang::tr{'download pkcs12 file'}' />
2534                 <input type='hidden' name='KEY' value='$key' />
2535             </form>
2536         </td>
2537 END
2538         ; } elsif (($confighash{$key}[4] eq 'cert') && ($confighash{$key}[2] ne '%auth-dn')) {
2539             print <<END
2540             <td align='center'>
2541             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2542                 <input type='image' name='$Lang::tr{'download certificate'}' src='/images/floppy.gif' alt='$Lang::tr{'download certificate'}' title='$Lang::tr{'download certificate'}' />
2543                 <input type='hidden' name='ACTION' value='$Lang::tr{'download certificate'}' />
2544                 <input type='hidden' name='KEY' value='$key' />
2545             </form>
2546         </td>
2547 END
2548         ; } else {
2549             print "<td width='2%'>&nbsp;</td>";
2550         }
2551         print <<END
2552         <td align='center'>
2553             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2554             <input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$Lang::tr{'toggle enable disable'}' title='$Lang::tr{'toggle enable disable'}' />
2555             <input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />
2556             <input type='hidden' name='KEY' value='$key' />
2557             </form>
2558         </td>
2559
2560         <td align='center'>
2561             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2562             <input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />
2563             <input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
2564             <input type='hidden' name='KEY' value='$key' />
2565             </form>
2566         </td>
2567         <td align='center' >
2568             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2569             <input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />
2570             <input type='image'  name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
2571             <input type='hidden' name='KEY' value='$key' />
2572             </form>
2573         </td>
2574         </tr>
2575 END
2576         ;
2577         $id++;
2578     }
2579     print "</table>";
2580
2581     # If the config file contains entries, print Key to action icons
2582     if ( $id ) {
2583     print <<END
2584     <table>
2585     <tr>
2586         <td class='boldbase'>&nbsp; <b>$Lang::tr{'legend'}:</b></td>
2587         <td>&nbsp; <img src='/images/on.gif' alt='$Lang::tr{'click to disable'}' /></td>
2588         <td class='base'>$Lang::tr{'click to disable'}</td>
2589         <td>&nbsp; &nbsp; <img src='/images/info.gif' alt='$Lang::tr{'show certificate'}' /></td>
2590         <td class='base'>$Lang::tr{'show certificate'}</td>
2591         <td>&nbsp; &nbsp; <img src='/images/edit.gif' alt='$Lang::tr{'edit'}' /></td>
2592         <td class='base'>$Lang::tr{'edit'}</td>
2593         <td>&nbsp; &nbsp; <img src='/images/delete.gif' alt='$Lang::tr{'remove'}' /></td>
2594         <td class='base'>$Lang::tr{'remove'}</td>
2595     </tr>
2596     <tr>
2597         <td>&nbsp; </td>
2598         <td>&nbsp; <img src='/images/off.gif' alt='?OFF' /></td>
2599         <td class='base'>$Lang::tr{'click to enable'}</td>
2600         <td>&nbsp; &nbsp; <img src='/images/floppy.gif' alt='?FLOPPY' /></td>
2601         <td class='base'>$Lang::tr{'download certificate'}</td>
2602         <td>&nbsp; &nbsp; <img src='/images/reload.gif' alt='?RELOAD'/></td>
2603         <td class='base'>$Lang::tr{'restart'}</td>
2604     </tr>
2605     </table>
2606 END
2607     ;
2608     }
2609
2610     print <<END
2611     <table width='100%'>
2612     <tr><td align='center' colspan='9'>
2613         <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2614         <input type='submit' name='ACTION' value='$Lang::tr{'add'}' />
2615         </form>
2616     </td></tr>
2617     </table>
2618 END
2619     ;
2620     &Header::closebox();
2621
2622     &Header::openbox('100%', 'left', "$Lang::tr{'certificate authorities'}:");
2623     print <<EOF
2624     <table width='100%' border='0' cellspacing='1' cellpadding='0'>
2625     <tr>
2626         <td width='25%' class='boldbase' align='center'><b>$Lang::tr{'name'}</b></td>
2627         <td width='65%' class='boldbase' align='center'><b>$Lang::tr{'subject'}</b></td>
2628         <td width='10%' class='boldbase' colspan='3' align='center'><b>$Lang::tr{'action'}</b></td>
2629     </tr>
2630 EOF
2631     ;
2632     if (-f "${General::swroot}/ca/cacert.pem") {
2633         my $casubject = &Header::cleanhtml(getsubjectfromcert ("${General::swroot}/ca/cacert.pem"));
2634
2635         print <<END
2636         <tr bgcolor='$color{'color22'}'>
2637         <td class='base'>$Lang::tr{'root certificate'}</td>
2638         <td class='base'>$casubject</td>
2639         <td width='3%' align='center'>
2640             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2641             <input type='hidden' name='ACTION' value='$Lang::tr{'show root certificate'}' />
2642             <input type='image' name='$Lang::tr{'edit'}' src='/images/info.gif' alt='$Lang::tr{'show root certificate'}' title='$Lang::tr{'show root certificate'}' />
2643             </form>
2644         </td>
2645         <td width='3%' align='center'>
2646             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2647             <input type='image' name='$Lang::tr{'download root certificate'}' src='/images/floppy.gif' alt='$Lang::tr{'download root certificate'}' title='$Lang::tr{'download root certificate'}' />
2648             <input type='hidden' name='ACTION' value='$Lang::tr{'download root certificate'}' />
2649             </form>
2650         </td>
2651         <td width='4%'>&nbsp;</td></tr>
2652 END
2653         ;
2654     } else {
2655         # display rootcert generation buttons
2656         print <<END
2657         <tr bgcolor='$color{'color22'}'>
2658         <td class='base'>$Lang::tr{'root certificate'}:</td>
2659         <td class='base'>$Lang::tr{'not present'}</td>
2660         <td colspan='3'>&nbsp;</td></tr>
2661 END
2662         ;
2663     }
2664
2665     if (-f "${General::swroot}/certs/hostcert.pem") {
2666         my $hostsubject = &Header::cleanhtml(getsubjectfromcert ("${General::swroot}/certs/hostcert.pem"));
2667
2668         print <<END
2669         <tr bgcolor='$color{'color20'}'>
2670         <td class='base'>$Lang::tr{'host certificate'}</td>
2671         <td class='base'>$hostsubject</td>
2672         <td width='3%' align='center'>
2673             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2674             <input type='hidden' name='ACTION' value='$Lang::tr{'show host certificate'}' />
2675             <input type='image' name='$Lang::tr{'show host certificate'}' src='/images/info.gif' alt='$Lang::tr{'show host certificate'}' title='$Lang::tr{'show host certificate'}' />
2676             </form>
2677         </td>
2678         <td width='3%' align='center'>
2679             <form method='post' action='$ENV{'SCRIPT_NAME'}'>
2680             <input type='image' name='$Lang::tr{'download host certificate'}' src='/images/floppy.gif' alt='$Lang::tr{'download host certificate'}' title='$Lang::tr{'download host certificate'}' />
2681             <input type='hidden' name='ACTION' value='$Lang::tr{'download host certificate'}' />
2682             </form>
2683         </td>
2684         <td width='4%'>&nbsp;</td></tr>
2685 END
2686         ;
2687     } else {
2688         # Nothing
2689         print <<END
2690         <tr bgcolor='$color{'color20'}'>
2691         <td width='25%' class='base'>$Lang::tr{'host certificate'}:</td>
2692         <td class='base'>$Lang::tr{'not present'}</td>
2693         <td colspan='3'>&nbsp;</td></tr>
2694 END
2695         ;
2696     }
2697  
2698     my $rowcolor = 0;
2699     if (keys %cahash > 0) {
2700    foreach my $key (keys %cahash) {
2701        if ($rowcolor++ % 2) {
2702       print "<tr bgcolor='$color{'color20'}'>\n";
2703        } else {
2704       print "<tr bgcolor='$color{'color22'}'>\n";
2705        }
2706             print "<td class='base'>$cahash{$key}[0]</td>\n";
2707             print "<td class='base'>$cahash{$key}[1]</td>\n";
2708             print <<END
2709             <td align='center'>
2710                 <form method='post' name='cafrm${key}a' action='$ENV{'SCRIPT_NAME'}'>
2711                 <input type='image' name='$Lang::tr{'show ca certificate'}' src='/images/info.gif' alt='$Lang::tr{'show ca certificate'}' title='$Lang::tr{'show ca certificate'}' />
2712                 <input type='hidden' name='ACTION' value='$Lang::tr{'show ca certificate'}' />
2713                 <input type='hidden' name='KEY' value='$key' />
2714                 </form>
2715             </td>
2716             <td align='center'>
2717                 <form method='post' name='cafrm${key}b' action='$ENV{'SCRIPT_NAME'}'>
2718                 <input type='image' name='$Lang::tr{'download ca certificate'}' src='/images/floppy.gif' alt='$Lang::tr{'download ca certificate'}' title='$Lang::tr{'download ca certificate'}' />
2719                 <input type='hidden' name='ACTION' value='$Lang::tr{'download ca certificate'}' />
2720                 <input type='hidden' name='KEY' value='$key' />
2721                 </form>
2722             </td>
2723             <td align='center'>
2724                 <form method='post' name='cafrm${key}c' action='$ENV{'SCRIPT_NAME'}'>
2725                 <input type='hidden' name='ACTION' value='$Lang::tr{'remove ca certificate'}' />
2726                 <input type='image'  name='$Lang::tr{'remove ca certificate'}' src='/images/delete.gif' alt='$Lang::tr{'remove ca certificate'}' title='$Lang::tr{'remove ca certificate'}' />
2727                 <input type='hidden' name='KEY' value='$key' />
2728                 </form>
2729             </td>
2730             </tr>
2731 END
2732             ;
2733         }
2734     }
2735     print "</table>";
2736
2737     # If the file contains entries, print Key to action icons
2738     if ( -f "${General::swroot}/ca/cacert.pem") {
2739         print <<END
2740         <table><tr>
2741         <td class='boldbase'>&nbsp; <b>$Lang::tr{'legend'}:</b></td>
2742         <td>&nbsp; &nbsp; <img src='/images/info.gif' alt='$Lang::tr{'show certificate'}' /></td>
2743         <td class='base'>$Lang::tr{'show certificate'}</td>
2744         <td>&nbsp; &nbsp; <img src='/images/floppy.gif' alt='$Lang::tr{'download certificate'}' /></td>
2745         <td class='base'>$Lang::tr{'download certificate'}</td>
2746         </tr></table>
2747 END
2748         ;
2749     }
2750     my $createCA = -f "${General::swroot}/ca/cacert.pem" ? '' : "<tr><td colspan='3'></td><td><input type='submit' name='ACTION' value='$Lang::tr{'generate root/host certificates'}' /></td></tr>";
2751     print <<END
2752     <hr />
2753     <form method='post' enctype='multipart/form-data' action='$ENV{'SCRIPT_NAME'}'>
2754     <table width='100%' border='0' cellspacing='1' cellpadding='0'>
2755     $createCA
2756     <tr>
2757         <td class='base' nowrap='nowrap'>$Lang::tr{'ca name'}:</td>
2758         <td nowrap='nowrap'><input type='text' name='CA_NAME' value='$cgiparams{'CA_NAME'}' size='15' /> </td>
2759         <td nowrap='nowrap'><input type='file' name='FH' size='30' /></td>
2760         <td nowrap='nowrap'><input type='submit' name='ACTION' value='$Lang::tr{'upload ca certificate'}' /></td>
2761     </tr>
2762     <tr>
2763         <td colspan='3'>$Lang::tr{'resetting the vpn configuration will remove the root ca, the host certificate and all certificate based connections'}:</td>
2764         <td><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' /></td>
2765     </tr>
2766     </table>
2767     </form>
2768 END
2769     ;
2770     &Header::closebox();
2771     &Header::closebigbox();
2772     &Header::closepage();