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