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