]> git.ipfire.org Git - ipfire-2.x.git/blob - html/cgi-bin/ovpnmain.cgi
dfe7f8ad58da866cb57719fc179e46e36eaeec83
[ipfire-2.x.git] / html / cgi-bin / ovpnmain.cgi
1 #!/usr/bin/perl
2 ###############################################################################
3 # #
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2007-2023 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 strict;
23 use Archive::Zip qw(:ERROR_CODES :CONSTANTS);
24 use CGI;
25 use CGI qw/:standard/;
26 use Date::Parse;
27 use File::Copy;
28 use File::Temp qw/ tempfile tempdir /;
29 use Imager::QRCode;
30 use MIME::Base32;
31 use MIME::Base64;
32 use Net::DNS;
33 use Net::Ping;
34 use Net::Telnet;
35 use Sort::Naturally;
36 use URI::Encode qw(uri_encode uri_decode);;
37
38 require '/var/ipfire/general-functions.pl';
39 require "${General::swroot}/header.pl";
40 require "${General::swroot}/countries.pl";
41 require "${General::swroot}/location-functions.pl";
42
43 # enable only the following on debugging purpose
44 #use warnings;
45 #use CGI::Carp 'fatalsToBrowser';
46
47 my %mainsettings = ();
48 &General::readhash("${General::swroot}/main/settings", \%mainsettings);
49
50 # Supported ciphers for NCP
51 my @SUPPORTED_CIPHERS = (
52 "AES-256-GCM",
53 "AES-128-GCM",
54 "AES-256-CBC",
55 "AES-128-CBC",
56 "CHACHA20-POLY1305",
57 );
58
59 my @LEGACY_CIPHERS = (
60 "BF-CBC",
61 "CAST5-CBC",
62 "DES-CBC",
63 "DESX-CBC",
64 "SEED-CBC",
65 );
66
67 my @LEGACY_AUTHS = (
68 "whirlpool",
69 );
70
71 # Translations for the cipher selection
72 my %CIPHERS = (
73 # AES
74 "AES-256-GCM" => $Lang::tr{'AES-256-GCM'},
75 "AES-128-GCM" => $Lang::tr{'AES-128-GCM'},
76 "AES-256-CBC" => $Lang::tr{'AES-256-CBC'},
77 "AES-128-CBC" => $Lang::tr{'AES-128-CBC'},
78
79 # ChaCha20-Poly1305
80 "CHACHA20-POLY1305" => $Lang::tr{'CHACHA20-POLY1305'},
81 );
82
83 # Use the precomputed DH paramter from RFC7919
84 my $DHPARAM = "/etc/ssl/ffdhe4096.pem";
85
86 my $RW_PID = "/var/run/openvpn-rw.pid";
87 my $RW_STATUS = "/var/run/openvpn-rw.log";
88
89 ###
90 ### Initialize variables
91 ###
92 my %ccdconfhash=();
93 my %ccdroutehash=();
94 my %ccdroute2hash=();
95 my %vpnsettings=();
96 my %checked=();
97 my %confighash=();
98 my %cahash=();
99 my %selected=();
100 my %cgiparams = ();
101 my $warnmessage = '';
102 my $errormessage = '';
103 my %settings=();
104 my $routes_push_file = "${General::swroot}/ovpn/routes_push";
105 my $confighost="${General::swroot}/fwhosts/customhosts";
106 my $configgrp="${General::swroot}/fwhosts/customgroups";
107 my $customnet="${General::swroot}/fwhosts/customnetworks";
108 my $name;
109 my $col="";
110
111 # Load the configuration (once)
112 &General::readhash("${General::swroot}/ovpn/settings", \%vpnsettings);
113 &read_routepushfile(\%vpnsettings);
114
115
116 # Configure any defaults
117 &General::set_defaults(\%vpnsettings, {
118 # The RW Server is disabled by default
119 "ENABLED" => "off",
120 "VPN_IP" => "$mainsettings{'HOSTNAME'}.$mainsettings{'DOMAINNAME'}",
121 "DOVPN_SUBNET" => sprintf("10.%d.%d.0/24", rand(256), rand(256)),
122
123 # Cryptographic Settings
124 "DATACIPHERS" => "AES-256-GCM|AES-128-GCM|CHACHA20-POLY1305",
125 "DAUTH" => "SHA512",
126 "DCIPHER" => "", # no fallback cipher
127
128 # Advanced Settings
129 "DPROTOCOL" => "udp",
130 "DDEST_PORT" => 1194,
131 "DMTU" => 1500,
132 "MAX_CLIENTS" => 100,
133 "MSSFIX" => "off",
134 "TLSAUTH" => "on",
135 }) unless (%vpnsettings);
136
137 # Load CGI parameters
138 &Header::getcgihash(\%cgiparams, {'wantfile' => 1, 'filevar' => 'FH'});
139
140 ###
141 ### Useful functions
142 ###
143 sub iscertlegacy
144 {
145 my $file=$_[0];
146 my @certinfo = &General::system_output("/usr/bin/openssl", "pkcs12", "-info", "-nodes",
147 "-in", "$file.p12", "-noout", "-passin", "pass:''");
148 if (index ($certinfo[0], "MAC: sha1") != -1) {
149 return 1;
150 }
151 return 0;
152 }
153
154 sub is_cert_rfc3280_compliant($) {
155 my $path = shift;
156
157 my @output = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", $path);
158
159 return grep(/TLS Web Server Authentication/, @output);
160 }
161
162 sub is_legacy_cipher($) {
163 my $cipher = shift;
164
165 foreach my $c (@LEGACY_CIPHERS) {
166 return 1 if ($cipher eq $c);
167 }
168
169 return 0;
170 }
171
172 sub is_legacy_auth($) {
173 my $auth = shift;
174
175 foreach my $a (@LEGACY_AUTHS) {
176 return 1 if ($auth eq $a);
177 }
178
179 return 0;
180 }
181
182 sub cleanssldatabase() {
183 if (open(FILE, ">${General::swroot}/ovpn/certs/serial")) {
184 print FILE "01";
185 close FILE;
186 }
187
188 if (open(FILE, ">${General::swroot}/ovpn/certs/index.txt")) {
189 print FILE "";
190 close FILE;
191 }
192
193 if (open(FILE, ">${General::swroot}/ovpn/certs/index.txt.attr")) {
194 print FILE "";
195 close FILE;
196 }
197
198 unlink("${General::swroot}/ovpn/certs/index.txt.old");
199 unlink("${General::swroot}/ovpn/certs/index.txt.attr.old");
200 unlink("${General::swroot}/ovpn/certs/serial.old");
201 unlink("${General::swroot}/ovpn/certs/01.pem");
202 }
203
204 sub deletebackupcert
205 {
206 if (open(FILE, "${General::swroot}/ovpn/certs/serial.old")) {
207 my $hexvalue = <FILE>;
208 chomp $hexvalue;
209 close FILE;
210 unlink ("${General::swroot}/ovpn/certs/$hexvalue.pem");
211 }
212 }
213
214 sub writeserverconf {
215 # Do we require the OpenSSL Legacy Provider?
216 my $requires_legacy_provider = 0;
217
218 open(CONF, ">${General::swroot}/ovpn/server.conf") or die "Unable to open ${General::swroot}/ovpn/server.conf: $!";
219 flock CONF, 2;
220 print CONF "#OpenVPN Server conf\n";
221 print CONF "\n";
222 print CONF "daemon openvpnserver\n";
223 print CONF "writepid $RW_PID\n";
224 print CONF "#DAN prepare OpenVPN for listening on blue and orange\n";
225 print CONF ";local $vpnsettings{'VPN_IP'}\n";
226 print CONF "dev tun\n";
227 print CONF "proto $vpnsettings{'DPROTOCOL'}\n";
228 print CONF "port $vpnsettings{'DDEST_PORT'}\n";
229 print CONF "script-security 3\n";
230 print CONF "ifconfig-pool-persist /var/ipfire/ovpn/ovpn-leases.db 3600\n";
231 print CONF "client-config-dir /var/ipfire/ovpn/ccd\n";
232 print CONF "tls-server\n";
233 print CONF "ca ${General::swroot}/ovpn/ca/cacert.pem\n";
234 print CONF "cert ${General::swroot}/ovpn/certs/servercert.pem\n";
235 print CONF "key ${General::swroot}/ovpn/certs/serverkey.pem\n";
236 print CONF "dh $DHPARAM\n";
237
238 # Enable subnet topology
239 print CONF "# Topology\n";
240 print CONF "topology subnet\n\n";
241
242 my $netaddress = &Network::get_netaddress($vpnsettings{'DOVPN_SUBNET'});
243 my $subnetmask = &Network::get_netmask($vpnsettings{'DOVPN_SUBNET'});
244
245 print CONF "server $netaddress $subnetmask\n";
246 print CONF "tun-mtu $vpnsettings{'DMTU'}\n";
247
248 # Write custom routes
249 if ($vpnsettings{'ROUTES_PUSH'} ne '') {
250 my @routes = split(/\|/, $vpnsettings{'ROUTES_PUSH'});
251
252 foreach my $route (@routes) {
253 my $netaddr = &Network::get_netaddress($route);
254 my $netmask = &Network::get_netmask($route);
255
256 if (defined($netaddr) && defined($netmask)) {
257 print CONF "push \"route ${netaddr} ${netmask}\"\n";
258 }
259 }
260 }
261
262 my %ccdconfhash=();
263 &General::readhasharray("${General::swroot}/ovpn/ccd.conf", \%ccdconfhash);
264 foreach my $key (keys %ccdconfhash) {
265 my $a=$ccdconfhash{$key}[1];
266 my ($b,$c) = split (/\//, $a);
267 print CONF "route $b ".&General::cidrtosub($c)."\n";
268 }
269 my %ccdroutehash=();
270 &General::readhasharray("${General::swroot}/ovpn/ccdroute", \%ccdroutehash);
271 foreach my $key (keys %ccdroutehash) {
272 foreach my $i ( 1 .. $#{$ccdroutehash{$key}}){
273 my ($a,$b)=split (/\//,$ccdroutehash{$key}[$i]);
274 print CONF "route $a $b\n";
275 }
276 }
277
278 if ($vpnsettings{MSSFIX} eq 'on') {
279 print CONF "mssfix\n";
280 } else {
281 print CONF "mssfix 0\n";
282 }
283 if ($vpnsettings{FRAGMENT} ne '' && $vpnsettings{'DPROTOCOL'} ne 'tcp') {
284 print CONF "fragment $vpnsettings{'FRAGMENT'}\n";
285 }
286
287 # Regularly send keep-alive packets
288 print CONF "keepalive 10 60\n";
289
290 print CONF "status-version 1\n";
291 print CONF "status $RW_STATUS 30\n";
292
293 # Cryptography
294 if ($vpnsettings{'DATACIPHERS'} eq '') {
295 print CONF "ncp-disable\n";
296 } else {
297 print CONF "data-ciphers " . $vpnsettings{'DATACIPHERS'} =~ s/\|/:/gr . "\n";
298 }
299
300 # Enable fallback cipher?
301 if ($vpnsettings{'DCIPHER'} ne '') {
302 if (&is_legacy_cipher($vpnsettings{'DCIPHER'})) {
303 $requires_legacy_provider++;
304 }
305
306 print CONF "data-ciphers-fallback $vpnsettings{'DCIPHER'}\n";
307 }
308
309 print CONF "auth $vpnsettings{'DAUTH'}\n";
310
311 if (&is_legacy_auth($vpnsettings{'DAUTH'})) {
312 $requires_legacy_provider++;
313 }
314
315 # Set TLSv2 as minimum
316 print CONF "tls-version-min 1.2\n";
317
318 if ($vpnsettings{'TLSAUTH'} eq 'on') {
319 print CONF "tls-auth ${General::swroot}/ovpn/certs/ta.key\n";
320 }
321
322 # Compression
323 # Use migration to support clients that have compression enabled, but disable
324 # compression for everybody else.
325 print CONF "compress migrate\n";
326
327 if ($vpnsettings{REDIRECT_GW_DEF1} eq 'on') {
328 print CONF "push \"redirect-gateway def1\"\n";
329 }
330 if ($vpnsettings{DHCP_DOMAIN} ne '') {
331 print CONF "push \"dhcp-option DOMAIN $vpnsettings{DHCP_DOMAIN}\"\n";
332 }
333
334 if ($vpnsettings{DHCP_DNS} ne '') {
335 print CONF "push \"dhcp-option DNS $vpnsettings{DHCP_DNS}\"\n";
336 }
337
338 if ($vpnsettings{DHCP_WINS} ne '') {
339 print CONF "push \"dhcp-option WINS $vpnsettings{DHCP_WINS}\"\n";
340 }
341
342 if ($vpnsettings{MAX_CLIENTS} eq '') {
343 print CONF "max-clients 100\n";
344 }
345 if ($vpnsettings{MAX_CLIENTS} ne '') {
346 print CONF "max-clients $vpnsettings{MAX_CLIENTS}\n";
347 }
348 print CONF "tls-verify /usr/lib/openvpn/verify\n";
349 print CONF "crl-verify /var/ipfire/ovpn/crls/cacrl.pem\n";
350 print CONF "auth-user-pass-optional\n";
351 print CONF "reneg-sec 86400\n";
352 print CONF "user nobody\n";
353 print CONF "group nobody\n";
354 print CONF "persist-key\n";
355 print CONF "persist-tun\n";
356 print CONF "verb 3\n";
357
358 print CONF "# Log clients connecting/disconnecting\n";
359 print CONF "client-connect \"/usr/sbin/openvpn-metrics client-connect\"\n";
360 print CONF "client-disconnect \"/usr/sbin/openvpn-metrics client-disconnect\"\n";
361 print CONF "\n";
362
363 print CONF "# Enable Management Socket\n";
364 print CONF "management /var/run/openvpn.sock unix\n";
365 print CONF "management-client-auth\n";
366
367 # Enable the legacy provider
368 if ($requires_legacy_provider > 0) {
369 print CONF "providers legacy default\n";
370 }
371
372 # Send clients a message when the server is being shut down
373 print CONF "explicit-exit-notify\n";
374
375 close(CONF);
376
377 # Rewrite all CCD configurations
378 &write_ccd_configs();
379 }
380
381 ##
382 ## CCD Name
383 ##
384
385 # Checks a ccdname for letters, numbers and spaces
386 sub validccdname($) {
387 my $name = shift;
388
389 # name should be at least one character in length
390 # but no more than 63 characters
391 if (length ($name) < 1 || length ($name) > 63) {
392 return 0;
393 }
394
395 # Only valid characters are a-z, A-Z, 0-9, space and -
396 if ($name !~ /^[a-zA-Z0-9 -]*$/) {
397 return 0;
398 }
399
400 return 1;
401 }
402
403 sub delccdnet($) {
404 my $name = shift;
405
406 my %conns = ();
407 my %subnets = ();
408
409 # Load all connections
410 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%conns);
411
412 # Check if the subnet is in use
413 foreach my $key (keys %conns) {
414 if ($conns{$key}[32] eq $name) {
415 return $Lang::tr{'ccd err hostinnet'};
416 }
417 }
418
419 # Load all subnets
420 &General::readhasharray("${General::swroot}/ovpn/ccd.conf", \%subnets);
421
422 # Remove the subnet
423 foreach my $key (keys %subnets) {
424 if ($subnets{$key}[0] eq $name){
425 delete $subnets{$key};
426 }
427 }
428
429 # Write the subnets back
430 &General::writehasharray("${General::swroot}/ovpn/ccd.conf", \%subnets);
431
432 # Update the server configuration to remove routes
433 &writeserverconf();
434 }
435
436 # Returns the network with the matching name
437 sub get_cdd_network($) {
438 my $name = shift;
439 my %subnets = ();
440
441 # Load all subnets
442 &General::readhasharray("${General::swroot}/ovpn/ccd.conf", \%subnets);
443
444 # Find the matching subnet
445 foreach my $key (keys %subnets) {
446 if ($subnets{$key}[0] eq $name) {
447 return $subnets{$key}[1];
448 }
449 }
450
451 return undef;
452 }
453
454 sub addccdnet($$) {
455 my $name = shift;
456 my $network = shift;
457
458 my %ccdconfhash = ();
459
460 # Check if the name is valid
461 unless (&validccdname($name)) {
462 return $Lang::tr{'ccd err invalidname'};
463 }
464
465 # Fetch the network address & prefix
466 my $address = &Network::get_netaddress($network);
467 my $prefix = &Network::get_prefix($network);
468
469 # If we could not decode the subnet, it must be invalid
470 if (!defined $address || !defined $prefix) {
471 return $Lang::tr{'ccd err invalidnet'};
472
473 # If the network is smaller than /30, there is no point in using it
474 } elsif ($prefix > 30) {
475 return $Lang::tr{'ccd err invalidnet'};
476 }
477
478 # Read the configuration
479 &General::readhasharray("${General::swroot}/ovpn/ccd.conf", \%ccdconfhash);
480
481 # Create a new entry
482 my $key = &General::findhasharraykey(\%ccdconfhash);
483
484 # Store name
485 $ccdconfhash{$key}[0] = $name;
486 $ccdconfhash{$key}[1] = "$address/$prefix";
487
488 # Write the hash back
489 &General::writehasharray("${General::swroot}/ovpn/ccd.conf", \%ccdconfhash);
490
491 # Update the server configuration to add routes
492 &writeserverconf();
493 }
494
495 sub modccdnet($$) {
496 my $subnet = shift;
497 my $newname = shift;
498 my $oldname;
499
500 my %ccdconfhash=();
501 my %conns=();
502
503 # Check if the new name is valid
504 unless (&validccdname($newname)) {
505 $errormessage = $Lang::tr{'ccd err invalidname'};
506 return;
507 }
508
509 # Load all subnets
510 &General::readhasharray("${General::swroot}/ovpn/ccd.conf", \%ccdconfhash);
511
512 # Check if the name already exists
513 foreach my $key (keys %ccdconfhash) {
514 if ($ccdconfhash{$key}[0] eq $newname) {
515 return $Lang::tr{'ccd err netadrexist'};
516 }
517 }
518
519 # Update!
520 foreach my $key (keys %ccdconfhash) {
521 if ($ccdconfhash{$key}[1] eq $subnet) {
522 $oldname = $ccdconfhash{$key}[0];
523 $ccdconfhash{$key}[0] = $newname;
524 last;
525 }
526 }
527
528 # Load all configurations
529 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%conns);
530
531 # Update all matching connections
532 foreach my $key (keys %conns) {
533 if ($conns{$key}[32] eq $oldname) {
534 $conns{$key}[32] = $newname;
535 }
536 }
537
538 # Write back the configuration
539 &General::writehasharray("${General::swroot}/ovpn/ccd.conf", \%ccdconfhash);
540 &General::writehasharray("${General::swroot}/ovpn/ovpnconfig", \%conns);
541 }
542
543 sub get_ccd_client_routes($) {
544 my $name = shift;
545
546 my %client_routes = ();
547 my @routes = ();
548
549 # Load all client routes
550 &General::readhasharray("${General::swroot}/ovpn/ccdroute", \%client_routes);
551
552 foreach my $key (keys %client_routes) {
553 if ($client_routes{$key}[0] eq $name) {
554 push(@routes, $client_routes{$key}[1]);
555 }
556 }
557
558 return @routes;
559 }
560
561 sub get_ccd_server_routes($) {
562 my $name = shift;
563
564 my %server_routes = ();
565 my @routes = ();
566
567 # Load all server routes
568 &General::readhasharray("${General::swroot}/ovpn/ccdroute2", \%server_routes);
569
570 foreach my $key (keys %server_routes) {
571 if ($server_routes{$key}[0] eq $name) {
572 my $i = 1;
573
574 while (my $route = $server_routes{$key}[$i++]) {
575 push(@routes, $route);
576 }
577 }
578 }
579
580 return @routes;
581 }
582
583 # This function rewrites all CCD configuration files upon change
584 sub write_ccd_configs() {
585 my %conns = ();
586
587 # Load all configurations
588 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%conns);
589
590 foreach my $key (keys %conns) {
591 my $name = $conns{$key}[1];
592 my $type = $conns{$key}[3];
593
594 # Skip anything that isn't a host connection
595 next unless ($type eq "host");
596
597 my $filename = "${General::swroot}/ovpn/ccd/$conns{$key}[2]";
598
599 # Open the configuration file
600 open(CONF, ">${filename}") or die "Unable to open ${filename} for writing: $!";
601
602 # Write a header
603 print CONF "# OpenVPN Client Configuration File\n\n";
604
605 # Fetch the allocated IP address (if any)
606 my $pool = $conns{$key}[32];
607 my $address = $conns{$key}[33];
608
609 # If the client has a dynamically allocated IP address, there is nothing to do
610 if ($pool eq "dynamic") {
611 print CONF "# This client uses the dynamic pool\n\n";
612
613 # Otherwise we need to push the selected IP address
614 } else {
615 $address = &convert_top30_ccd_allocation($address);
616
617 # Fetch the network of the pool
618 my $network = &get_cdd_network($pool);
619 my $netmask = &Network::get_netmask($network);
620
621 if (defined $address && defined $network && defined $netmask) {
622 print CONF "# Allocated IP address from $pool\n";
623 print CONF "ifconfig-push ${address} ${netmask}\n\n";
624 }
625 }
626
627 # Redirect Gateway?
628 my $redirect = $conns{$key}[34];
629
630 if ($redirect eq "on") {
631 print CONF "# Redirect all traffic to us\n";
632 print CONF "push redirect-gateway\n\n";
633 }
634
635 # DHCP Options
636 my %options = (
637 "DNS" => (
638 $conns{$key}[35],
639 $conns{$key}[36],
640 ),
641
642 "WINS" => (
643 $conns{$key}[37],
644 ),
645 );
646
647 print CONF "# DHCP Options";
648
649 foreach my $option (keys %options) {
650 foreach (@options{$option}) {
651 # Skip empty options
652 next if ($_ eq "");
653
654 print CONF "push \"dhcp-option $option $_\"\n";
655 }
656 }
657
658 # Newline
659 print CONF "\n";
660
661 # Networks routed to client
662 my @client_routes = &get_ccd_client_routes($name);
663
664 if (scalar @client_routes) {
665 print CONF "# Networks routed to the client\n";
666
667 foreach my $route (@client_routes) {
668 my $netaddress = &Network::get_netaddress($route);
669 my $netmask = &Network::get_netmask($route);
670
671 if (!defined $netaddress || !defined $netmask) {
672 next;
673 }
674
675 print CONF "iroute $netaddress $netmask\n";
676 }
677
678 # Newline
679 print CONF "\n";
680 }
681
682 # Networks routed to server
683 my @server_routes = &get_ccd_server_routes($name);
684
685 if (scalar @server_routes) {
686 print CONF "# Networks routed to the server\n";
687
688 foreach my $route (@server_routes) {
689 my $netaddress = &Network::get_netaddress($route);
690 my $netmask = &Network::get_netmask($route);
691
692 if (!defined $netaddress || !defined $netmask) {
693 next;
694 }
695
696 print CONF "push \"route $netaddress $netmask\"\n";
697 }
698
699 # Newline
700 print CONF "\n";
701 }
702
703 close CONF;
704 }
705 }
706
707 sub ccdmaxclients($) {
708 my $network = shift;
709
710 # Fetch the prefix
711 my $prefix = &Network::get_prefix($network);
712
713 # Return undef on invalid input
714 if (!defined $prefix) {
715 return undef;
716 }
717
718 # We take three addresses away: the network base address, the gateway, and broadcast
719 return (1 << (32 - $prefix)) - 3;
720 }
721
722 # Lists all selectable CCD addresses for the given network
723 sub getccdadresses($) {
724 my $network = shift;
725
726 # Collect all available addresses
727 my @addresses = ();
728
729 # Convert the network into binary
730 my ($start, $netmask) = &Network::network2bin($network);
731
732 # Fetch the broadcast address
733 my $broadcast = &Network::get_broadcast($network);
734 $broadcast = &Network::ip2bin($broadcast);
735
736 # Fail if we could not parse the network
737 if (!defined $start || !defined $netmask || !defined $broadcast) {
738 return undef;
739 }
740
741 # Skip the base address and gateway
742 $start += 2;
743
744 while ($start < $broadcast) {
745 push(@addresses, &Network::bin2ip($start++));
746 }
747
748 return @addresses;
749 }
750
751 sub convert_top30_ccd_allocation($) {
752 my $address = shift;
753
754 # Do nothing if the address does not end on /30
755 return $address unless ($address =~ m/\/30$/);
756
757 # Fetch the network base address
758 my $netaddress = &Network::get_netaddress($address);
759
760 # Break on invalid input
761 return undef if (!defined $netaddress);
762
763 # The client IP address was the second address of the subnet
764 return &Network::find_next_ip_address($netaddress, 2);
765 }
766
767 sub get_addresses_in_use($) {
768 my $network = shift;
769
770 my %conns = ();
771
772 # Load all connections
773 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%conns);
774
775 my @addresses = ();
776
777 # Check if the address is in use
778 foreach my $key (keys %conns) {
779 my $address = &convert_top30_ccd_allocation($conns{$key}[33]);
780
781 # Skip on invalid inputs
782 next if (!defined $address);
783
784 # If the first address is part of the network, we have a match
785 if (&Network::ip_address_in_network($address, $network)) {
786 push(@addresses, $address);
787 }
788 }
789
790 return @addresses;
791 }
792
793 sub fillselectbox($$) {
794 my $boxname = shift;
795 my $network = shift;
796 my @selected = shift;
797
798 # Fetch all available addresses for this network
799 my @addresses = &getccdadresses($network);
800
801 # Fetch all addresses in use
802 my @addresses_in_use = &get_addresses_in_use($network);
803
804 print "<select name='$boxname'>";
805
806 foreach my $address (@addresses) {
807 print "<option value='$address'";
808
809 # Select any requested addresses
810 foreach (@selected) {
811 if ($address eq $_) {
812 print " selected";
813 goto NEXT;
814 }
815 }
816
817 # Disable any addresses that are not free
818 foreach (@addresses_in_use) {
819 if ($address eq $_) {
820 print " disabled";
821 goto NEXT;
822 }
823 }
824
825 NEXT:
826 print ">$address</option>";
827 }
828
829 print "</select>";
830 }
831
832 # XXX THIS WILL NO LONGER WORK
833 sub check_routes_push
834 {
835 my $val=$_[0];
836 my ($ip,$cidr) = split (/\//, $val);
837 ##check for existing routes in routes_push
838 if (-e "${General::swroot}/ovpn/routes_push") {
839 open(FILE,"${General::swroot}/ovpn/routes_push");
840 while (<FILE>) {
841 $_=~s/\s*$//g;
842
843 my ($ip2,$cidr2) = split (/\//,"$_");
844 my $val2=$ip2."/".&General::iporsubtodec($cidr2);
845
846 if($val eq $val2){
847 return 0;
848 }
849 #subnetcheck
850 if (&General::IpInSubnet ($ip,$ip2,&General::iporsubtodec($cidr2))){
851 return 0;
852 }
853 };
854 close(FILE);
855 }
856 return 1;
857 }
858
859 sub check_ccdroute
860 {
861 my %ccdroutehash=();
862 my $val=$_[0];
863 my ($ip,$cidr) = split (/\//, $val);
864 #check for existing routes in ccdroute
865 &General::readhasharray("${General::swroot}/ovpn/ccdroute", \%ccdroutehash);
866 foreach my $key (keys %ccdroutehash) {
867 foreach my $i (1 .. $#{$ccdroutehash{$key}}) {
868 if (&General::iporsubtodec($val) eq $ccdroutehash{$key}[$i] && $ccdroutehash{$key}[0] ne $cgiparams{'NAME'}){
869 return 0;
870 }
871 my ($ip2,$cidr2) = split (/\//,$ccdroutehash{$key}[$i]);
872 #subnetcheck
873 if (&General::IpInSubnet ($ip,$ip2,$cidr2)&& $ccdroutehash{$key}[0] ne $cgiparams{'NAME'} ){
874 return 0;
875 }
876 }
877 }
878 return 1;
879 }
880 sub check_ccdconf
881 {
882 my %ccdconfhash=();
883 my $val=$_[0];
884 my ($ip,$cidr) = split (/\//, $val);
885 #check for existing routes in ccdroute
886 &General::readhasharray("${General::swroot}/ovpn/ccd.conf", \%ccdconfhash);
887 foreach my $key (keys %ccdconfhash) {
888 if (&General::iporsubtocidr($val) eq $ccdconfhash{$key}[1]){
889 return 0;
890 }
891 my ($ip2,$cidr2) = split (/\//,$ccdconfhash{$key}[1]);
892 #subnetcheck
893 if (&General::IpInSubnet ($ip,$ip2,&General::cidrtosub($cidr2))){
894 return 0;
895 }
896
897 }
898 return 1;
899 }
900
901 # -------------------------------------------------------------------
902
903 sub read_routepushfile($) {
904 my $hash = shift;
905
906 # Don't read the legacy file if we already have a value
907 if ($hash->{'ROUTES_PUSH'} ne "") {
908 unlink($routes_push_file);
909
910 # This is some legacy code that reads the routes file if it is still present
911 } elsif (-e "$routes_push_file") {
912 delete $hash->{'ROUTES_PUSH'};
913
914 my @routes = ();
915
916 open(FILE,"$routes_push_file");
917 while (<FILE>) {
918 push(@routes, $_);
919 }
920 close(FILE);
921
922 $hash->{'ROUTES_PUSH'} = join("|", @routes);
923 }
924 }
925
926 sub writecollectdconf {
927 my $vpncollectd;
928 my %ccdhash=();
929
930 open(COLLECTDVPN, ">${General::swroot}/ovpn/collectd.vpn") or die "Unable to open collectd.vpn: $!";
931 print COLLECTDVPN "Loadplugin openvpn\n";
932 print COLLECTDVPN "\n";
933 print COLLECTDVPN "<Plugin openvpn>\n";
934 print COLLECTDVPN "Statusfile \"${RW_STATUS}\"\n";
935
936 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%ccdhash);
937 foreach my $key (keys %ccdhash) {
938 if ($ccdhash{$key}[0] eq 'on' && $ccdhash{$key}[3] eq 'net') {
939 print COLLECTDVPN "Statusfile \"/var/run/openvpn/$ccdhash{$key}[1]-n2n\"\n";
940 }
941 }
942
943 print COLLECTDVPN "</Plugin>\n";
944 close(COLLECTDVPN);
945
946 # Reload collectd afterwards
947 &General::system("/usr/local/bin/collectdctrl", "restart");
948 }
949
950 sub openvpn_status($) {
951 my $port = shift;
952
953 # Create a new Telnet session
954 my $telnet = new Net::Telnet(
955 Port => $port,
956 Timeout => 1,
957 Errmode => "return",
958 );
959
960 # Connect
961 $telnet->open("127.0.0.1");
962
963 # Send a command
964 my @output = $telnet->cmd(
965 String => "state",
966 Prompt => "/(END.*\n|ERROR:.*\n)/"
967 );
968
969 my ($time, $status) = split(/\,/, $output[1]);
970
971 ###
972 #CONNECTING -- OpenVPN's initial state.
973 #WAIT -- (Client only) Waiting for initial response from server.
974 #AUTH -- (Client only) Authenticating with server.
975 #GET_CONFIG -- (Client only) Downloading configuration options from server.
976 #ASSIGN_IP -- Assigning IP address to virtual network interface.
977 #ADD_ROUTES -- Adding routes to system.
978 #CONNECTED -- Initialization Sequence Completed.
979 #RECONNECTING -- A restart has occurred.
980 #EXITING -- A graceful exit is in progress.
981 ####
982
983 if ($status eq "CONNECTING") {
984 return "DISCONNECTED";
985 } elsif ($status eq "WAIT") {
986 return "DISCONNECTED";
987 } elsif ($status eq "AUTH") {
988 return "DISCONNECTED";
989 } elsif ($status eq "GET_CONFIG") {
990 return "DISCONNECTED";
991 } elsif ($status eq "ASSIGN_IP") {
992 return "DISCONNECTED";
993 } elsif ($status eq "ADD_ROUTES") {
994 return "DISCONNECTED";
995 } elsif ($status eq "RECONNECTING") {
996 return "CONNECTED";
997 } elsif ($status eq "EXITING") {
998 return "DISCONNECTED";
999 }
1000
1001 return $status;
1002 }
1003
1004 # Hook to regenerate the configuration files
1005 if ($ENV{"REMOTE_ADDR"} eq "") {
1006 &writeserverconf();
1007 exit(0);
1008 }
1009
1010 ###
1011 ### Save Advanced options
1012 ###
1013
1014 if ($cgiparams{'ACTION'} eq $Lang::tr{'save-adv-options'}) {
1015 $vpnsettings{'DPROTOCOL'} = $cgiparams{'DPROTOCOL'};
1016 $vpnsettings{'DDEST_PORT'} = $cgiparams{'DDEST_PORT'};
1017 $vpnsettings{'DMTU'} = $cgiparams{'DMTU'};
1018 $vpnsettings{'MAX_CLIENTS'} = $cgiparams{'MAX_CLIENTS'};
1019 $vpnsettings{'REDIRECT_GW_DEF1'} = $cgiparams{'REDIRECT_GW_DEF1'};
1020 $vpnsettings{'DHCP_DOMAIN'} = $cgiparams{'DHCP_DOMAIN'};
1021 $vpnsettings{'DHCP_DNS'} = $cgiparams{'DHCP_DNS'};
1022 $vpnsettings{'DHCP_WINS'} = $cgiparams{'DHCP_WINS'};
1023 $vpnsettings{'ROUTES_PUSH'} = $cgiparams{'ROUTES_PUSH'};
1024 $vpnsettings{'DATACIPHERS'} = $cgiparams{'DATACIPHERS'};
1025 $vpnsettings{'DCIPHER'} = $cgiparams{'DCIPHER'};
1026 $vpnsettings{'DAUTH'} = $cgiparams{'DAUTH'};
1027 $vpnsettings{'TLSAUTH'} = $cgiparams{'TLSAUTH'};
1028
1029 # We must have at least one cipher selected
1030 if ($cgiparams{'DATACIPHERS'} eq '') {
1031 $errormessage = $Lang::tr{'ovpn no cipher selected'};
1032 goto ADV_ERROR;
1033 }
1034
1035 # Split data ciphers
1036 my @dataciphers = split(/\|/, $cgiparams{'DATACIPHERS'});
1037
1038 # Check if all ciphers are supported
1039 foreach my $cipher (@dataciphers) {
1040 if (!grep(/^$cipher$/, @SUPPORTED_CIPHERS)) {
1041 $errormessage = $Lang::tr{'ovpn unsupported cipher selected'};
1042 goto ADV_ERROR;
1043 }
1044 }
1045
1046 # Check port
1047 unless (&General::validport($cgiparams{'DDEST_PORT'})) {
1048 $errormessage = $Lang::tr{'invalid port'};
1049 goto ADV_ERROR;
1050 }
1051
1052 # Check MTU
1053 if (($cgiparams{'DMTU'} eq "") || (($cgiparams{'DMTU'}) < 1280 )) {
1054 $errormessage = $Lang::tr{'invalid mtu input'};
1055 goto ADV_ERROR;
1056 }
1057
1058 if ($cgiparams{'FRAGMENT'} eq '') {
1059 delete $vpnsettings{'FRAGMENT'};
1060 } else {
1061 if ($cgiparams{'FRAGMENT'} !~ /^[0-9]+$/) {
1062 $errormessage = "Incorrect value, please insert only numbers.";
1063 goto ADV_ERROR;
1064 } else {
1065 $vpnsettings{'FRAGMENT'} = $cgiparams{'FRAGMENT'};
1066 }
1067 }
1068
1069 if ($cgiparams{'MSSFIX'} ne 'on') {
1070 delete $vpnsettings{'MSSFIX'};
1071 } else {
1072 $vpnsettings{'MSSFIX'} = $cgiparams{'MSSFIX'};
1073 }
1074
1075 if ($cgiparams{'DHCP_DOMAIN'} ne ''){
1076 unless (&General::validdomainname($cgiparams{'DHCP_DOMAIN'}) || &General::validip($cgiparams{'DHCP_DOMAIN'})) {
1077 $errormessage = $Lang::tr{'invalid input for dhcp domain'};
1078 goto ADV_ERROR;
1079 }
1080 }
1081 if ($cgiparams{'DHCP_DNS'} ne ''){
1082 unless (&General::validfqdn($cgiparams{'DHCP_DNS'}) || &General::validip($cgiparams{'DHCP_DNS'})) {
1083 $errormessage = $Lang::tr{'invalid input for dhcp dns'};
1084 goto ADV_ERROR;
1085 }
1086 }
1087 if ($cgiparams{'DHCP_WINS'} ne ''){
1088 unless (&General::validfqdn($cgiparams{'DHCP_WINS'}) || &General::validip($cgiparams{'DHCP_WINS'})) {
1089 $errormessage = $Lang::tr{'invalid input for dhcp wins'};
1090 goto ADV_ERROR;
1091 }
1092 }
1093
1094 # Validate pushed routes
1095 if ($cgiparams{'ROUTES_PUSH'} ne ''){
1096 my @temp = split(/\n/, $cgiparams{'ROUTES_PUSH'});
1097
1098 my @routes = ();
1099
1100 foreach my $route (@temp) {
1101 chomp($route);
1102
1103 # Remove any excess whitespace
1104 $route =~ s/^\s+//g;
1105 $route =~ s/\s+$//g;
1106
1107 # Skip empty lines
1108 next if ($route eq "");
1109
1110 unless (&Network::check_subnet($route)) {
1111 $errormessage = "$Lang::tr{'ovpn errmsg invalid route'}: $route";
1112 goto ADV_ERROR;
1113 }
1114
1115 push(@routes, $route);
1116 }
1117
1118 $vpnsettings{'ROUTES_PUSH'} = join("|", @routes);
1119 }
1120
1121 if ((length($cgiparams{'MAX_CLIENTS'}) == 0) || (($cgiparams{'MAX_CLIENTS'}) < 1 ) || (($cgiparams{'MAX_CLIENTS'}) > 1024 )) {
1122 $errormessage = $Lang::tr{'invalid input for max clients'};
1123 goto ADV_ERROR;
1124 }
1125
1126 # Store our configuration
1127 &General::writehash("${General::swroot}/ovpn/settings", \%vpnsettings);
1128
1129 # Write the server configuration
1130 &writeserverconf();
1131
1132 # Restart the server if it is enabled
1133 if ($vpnsettings{'ENABLED'} eq "on") {
1134 &General::system("/usr/local/bin/openvpnctrl", "rw", "restart");
1135 }
1136 }
1137
1138 if ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'TYPE'} eq 'net' && $cgiparams{'SIDE'} eq 'server')
1139 {
1140
1141 my @remsubnet = split(/\//,$cgiparams{'REMOTE_SUBNET'});
1142 my @ovsubnettemp = split(/\./,$cgiparams{'OVPN_SUBNET'});
1143 my $ovsubnet = "$ovsubnettemp[0].$ovsubnettemp[1].$ovsubnettemp[2]";
1144 my $tunmtu = '';
1145
1146 unless(-d "${General::swroot}/ovpn/n2nconf/"){mkdir "${General::swroot}/ovpn/n2nconf", 0755 or die "Unable to create dir $!";}
1147 unless(-d "${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}"){mkdir "${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}", 0770 or die "Unable to create dir $!";}
1148
1149 open(SERVERCONF, ">${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Unable to open ${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf: $!";
1150
1151 flock SERVERCONF, 2;
1152 print SERVERCONF "# IPFire n2n Open VPN Server Config by ummeegge und m.a.d\n";
1153 print SERVERCONF "\n";
1154 print SERVERCONF "# User Security\n";
1155 print SERVERCONF "user nobody\n";
1156 print SERVERCONF "group nobody\n";
1157 print SERVERCONF "persist-tun\n";
1158 print SERVERCONF "persist-key\n";
1159 print SERVERCONF "script-security 2\n";
1160 print SERVERCONF "# IP/DNS for remote Server Gateway\n";
1161
1162 if ($cgiparams{'REMOTE'} ne '') {
1163 print SERVERCONF "remote $cgiparams{'REMOTE'}\n";
1164 }
1165
1166 print SERVERCONF "float\n";
1167 print SERVERCONF "# IP adresses of the VPN Subnet\n";
1168 print SERVERCONF "ifconfig $ovsubnet.1 $ovsubnet.2\n";
1169 print SERVERCONF "# Client Gateway Network\n";
1170 print SERVERCONF "route $remsubnet[0] $remsubnet[1]\n";
1171 print SERVERCONF "up \"/etc/init.d/static-routes start\"\n";
1172 print SERVERCONF "# tun Device\n";
1173 print SERVERCONF "dev tun\n";
1174 print SERVERCONF "#Logfile for statistics\n";
1175 print SERVERCONF "status-version 1\n";
1176 print SERVERCONF "status /var/run/openvpn/$cgiparams{'NAME'}-n2n 10\n";
1177 print SERVERCONF "# Port and Protokol\n";
1178 print SERVERCONF "port $cgiparams{'DEST_PORT'}\n";
1179
1180 if ($cgiparams{'PROTOCOL'} eq 'tcp') {
1181 print SERVERCONF "proto tcp4-server\n";
1182 print SERVERCONF "# Packet size\n";
1183 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1400'} else {$tunmtu = $cgiparams{'MTU'}};
1184 print SERVERCONF "tun-mtu $tunmtu\n";
1185 }
1186
1187 if ($cgiparams{'PROTOCOL'} eq 'udp') {
1188 print SERVERCONF "proto udp4\n";
1189 print SERVERCONF "# Paketsize\n";
1190 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1500'} else {$tunmtu = $cgiparams{'MTU'}};
1191 print SERVERCONF "tun-mtu $tunmtu\n";
1192 if ($cgiparams{'FRAGMENT'} ne '') {print SERVERCONF "fragment $cgiparams{'FRAGMENT'}\n";}
1193 if ($cgiparams{'MSSFIX'} eq 'on') {print SERVERCONF "mssfix\n"; } else { print SERVERCONF "mssfix 0\n" };
1194 }
1195
1196 print SERVERCONF "# Auth. Server\n";
1197 print SERVERCONF "tls-server\n";
1198 print SERVERCONF "ca ${General::swroot}/ovpn/ca/cacert.pem\n";
1199 print SERVERCONF "cert ${General::swroot}/ovpn/certs/servercert.pem\n";
1200 print SERVERCONF "key ${General::swroot}/ovpn/certs/serverkey.pem\n";
1201 print SERVERCONF "dh $DHPARAM\n";
1202 print SERVERCONF "# Cipher\n";
1203 print SERVERCONF "cipher $cgiparams{'DCIPHER'}\n";
1204
1205 # If GCM cipher is used, do not use --auth
1206 if (($cgiparams{'DCIPHER'} eq 'AES-256-GCM') ||
1207 ($cgiparams{'DCIPHER'} eq 'AES-192-GCM') ||
1208 ($cgiparams{'DCIPHER'} eq 'AES-128-GCM')) {
1209 print SERVERCONF unless "# HMAC algorithm\n";
1210 print SERVERCONF unless "auth $cgiparams{'DAUTH'}\n";
1211 } else {
1212 print SERVERCONF "# HMAC algorithm\n";
1213 print SERVERCONF "auth $cgiparams{'DAUTH'}\n";
1214 }
1215
1216 # Set TLSv1.2 as minimum
1217 print SERVERCONF "tls-version-min 1.2\n";
1218
1219 if ($cgiparams{'COMPLZO'} eq 'on') {
1220 print SERVERCONF "# Enable Compression\n";
1221 print SERVERCONF "comp-lzo\n";
1222 }
1223 print SERVERCONF "# Debug Level\n";
1224 print SERVERCONF "verb 3\n";
1225 print SERVERCONF "# Tunnel check\n";
1226 print SERVERCONF "keepalive 10 60\n";
1227 print SERVERCONF "# Start as daemon\n";
1228 print SERVERCONF "daemon $cgiparams{'NAME'}n2n\n";
1229 print SERVERCONF "writepid /var/run/$cgiparams{'NAME'}n2n.pid\n";
1230 print SERVERCONF "# Activate Management Interface and Port\n";
1231 if ($cgiparams{'OVPN_MGMT'} eq '') {print SERVERCONF "management localhost $cgiparams{'DEST_PORT'}\n"}
1232 else {print SERVERCONF "management localhost $cgiparams{'OVPN_MGMT'}\n"};
1233 close(SERVERCONF);
1234
1235 }
1236
1237 if ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'TYPE'} eq 'net' && $cgiparams{'SIDE'} eq 'client')
1238 {
1239
1240 my @ovsubnettemp = split(/\./,$cgiparams{'OVPN_SUBNET'});
1241 my $ovsubnet = "$ovsubnettemp[0].$ovsubnettemp[1].$ovsubnettemp[2]";
1242 my @remsubnet = split(/\//,$cgiparams{'REMOTE_SUBNET'});
1243 my $tunmtu = '';
1244
1245 unless(-d "${General::swroot}/ovpn/n2nconf/"){mkdir "${General::swroot}/ovpn/n2nconf", 0755 or die "Unable to create dir $!";}
1246 unless(-d "${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}"){mkdir "${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}", 0770 or die "Unable to create dir $!";}
1247
1248 open(CLIENTCONF, ">${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Unable to open ${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf: $!";
1249
1250 flock CLIENTCONF, 2;
1251 print CLIENTCONF "# IPFire rewritten n2n Open VPN Client Config by ummeegge und m.a.d\n";
1252 print CLIENTCONF "#\n";
1253 print CLIENTCONF "# User Security\n";
1254 print CLIENTCONF "user nobody\n";
1255 print CLIENTCONF "group nobody\n";
1256 print CLIENTCONF "persist-tun\n";
1257 print CLIENTCONF "persist-key\n";
1258 print CLIENTCONF "script-security 2\n";
1259 print CLIENTCONF "# IP/DNS for remote Server Gateway\n";
1260 print CLIENTCONF "remote $cgiparams{'REMOTE'}\n";
1261 print CLIENTCONF "float\n";
1262 print CLIENTCONF "# IP adresses of the VPN Subnet\n";
1263 print CLIENTCONF "ifconfig $ovsubnet.2 $ovsubnet.1\n";
1264 print CLIENTCONF "# Server Gateway Network\n";
1265 print CLIENTCONF "route $remsubnet[0] $remsubnet[1]\n";
1266 print CLIENTCONF "up \"/etc/init.d/static-routes start\"\n";
1267 print CLIENTCONF "# tun Device\n";
1268 print CLIENTCONF "dev tun\n";
1269 print CLIENTCONF "#Logfile for statistics\n";
1270 print CLIENTCONF "status-version 1\n";
1271 print CLIENTCONF "status /var/run/openvpn/$cgiparams{'NAME'}-n2n 10\n";
1272 print CLIENTCONF "# Port and Protokol\n";
1273 print CLIENTCONF "port $cgiparams{'DEST_PORT'}\n";
1274
1275 if ($cgiparams{'PROTOCOL'} eq 'tcp') {
1276 print CLIENTCONF "proto tcp4-client\n";
1277 print CLIENTCONF "# Packet size\n";
1278 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1400'} else {$tunmtu = $cgiparams{'MTU'}};
1279 print CLIENTCONF "tun-mtu $tunmtu\n";
1280 }
1281
1282 if ($cgiparams{'PROTOCOL'} eq 'udp') {
1283 print CLIENTCONF "proto udp4\n";
1284 print CLIENTCONF "# Paketsize\n";
1285 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1500'} else {$tunmtu = $cgiparams{'MTU'}};
1286 print CLIENTCONF "tun-mtu $tunmtu\n";
1287 if ($cgiparams{'FRAGMENT'} ne '') {print CLIENTCONF "fragment $cgiparams{'FRAGMENT'}\n";}
1288 if ($cgiparams{'MSSFIX'} eq 'on') {print CLIENTCONF "mssfix\n"; } else { print CLIENTCONF "mssfix 0\n" };
1289 }
1290
1291 # Check host certificate if X509 is RFC3280 compliant.
1292 # If not, old --ns-cert-type directive will be used.
1293 # If appropriate key usage extension exists, new --remote-cert-tls directive will be used.
1294 my @hostcert = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
1295 if ( ! grep(/TLS Web Server Authentication/, @hostcert)) {
1296 print CLIENTCONF "ns-cert-type server\n";
1297 } else {
1298 print CLIENTCONF "remote-cert-tls server\n";
1299 }
1300 print CLIENTCONF "# Auth. Client\n";
1301 print CLIENTCONF "tls-client\n";
1302 print CLIENTCONF "# Cipher\n";
1303 print CLIENTCONF "cipher $cgiparams{'DCIPHER'}\n";
1304 print CLIENTCONF "pkcs12 ${General::swroot}/ovpn/certs/$cgiparams{'NAME'}.p12\r\n";
1305
1306 # If GCM cipher is used, do not use --auth
1307 if (($cgiparams{'DCIPHER'} eq 'AES-256-GCM') ||
1308 ($cgiparams{'DCIPHER'} eq 'AES-192-GCM') ||
1309 ($cgiparams{'DCIPHER'} eq 'AES-128-GCM')) {
1310 print CLIENTCONF unless "# HMAC algorithm\n";
1311 print CLIENTCONF unless "auth $cgiparams{'DAUTH'}\n";
1312 } else {
1313 print CLIENTCONF "# HMAC algorithm\n";
1314 print CLIENTCONF "auth $cgiparams{'DAUTH'}\n";
1315 }
1316
1317 # Set TLSv1.2 as minimum
1318 print CLIENTCONF "tls-version-min 1.2\n";
1319
1320 if ($cgiparams{'COMPLZO'} eq 'on') {
1321 print CLIENTCONF "# Enable Compression\n";
1322 print CLIENTCONF "comp-lzo\n";
1323 }
1324 print CLIENTCONF "# Debug Level\n";
1325 print CLIENTCONF "verb 3\n";
1326 print CLIENTCONF "# Tunnel check\n";
1327 print CLIENTCONF "keepalive 10 60\n";
1328 print CLIENTCONF "# Start as daemon\n";
1329 print CLIENTCONF "daemon $cgiparams{'NAME'}n2n\n";
1330 print CLIENTCONF "writepid /var/run/$cgiparams{'NAME'}n2n.pid\n";
1331 print CLIENTCONF "# Activate Management Interface and Port\n";
1332 if ($cgiparams{'OVPN_MGMT'} eq '') {print CLIENTCONF "management localhost $cgiparams{'DEST_PORT'}\n"}
1333 else {print CLIENTCONF "management localhost $cgiparams{'OVPN_MGMT'}\n"};
1334 if (&iscertlegacy("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}")) {
1335 print CLIENTCONF "providers legacy default\n";
1336 }
1337 close(CLIENTCONF);
1338
1339 }
1340
1341 ###
1342 ### Save main settings
1343 ###
1344
1345 if ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'TYPE'} eq '' && $cgiparams{'KEY'} eq '') {
1346 #DAN do we really need (to to check) this value? Besides if we listen on blue and orange too,
1347 #DAN this value has to leave.
1348 if ($cgiparams{'ENABLED'} eq 'on'){
1349 unless (&General::validfqdn($cgiparams{'VPN_IP'}) || &General::validip($cgiparams{'VPN_IP'})) {
1350 $errormessage = $Lang::tr{'invalid input for hostname'};
1351 goto SETTINGS_ERROR;
1352 }
1353 }
1354
1355 if (! &General::validipandmask($cgiparams{'DOVPN_SUBNET'})) {
1356 $errormessage = $Lang::tr{'ovpn subnet is invalid'};
1357 goto SETTINGS_ERROR;
1358 }
1359 my @tmpovpnsubnet = split("\/",$cgiparams{'DOVPN_SUBNET'});
1360
1361 if (&General::IpInSubnet ( $Network::ethernet{'RED_ADDRESS'},
1362 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1363 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire RED Network $Network::ethernet{'RED_ADDRESS'}";
1364 goto SETTINGS_ERROR;
1365 }
1366
1367 if (&General::IpInSubnet ( $Network::ethernet{'GREEN_ADDRESS'},
1368 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1369 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire Green Network $Network::ethernet{'GREEN_ADDRESS'}";
1370 goto SETTINGS_ERROR;
1371 }
1372
1373 if (&General::IpInSubnet ( $Network::ethernet{'BLUE_ADDRESS'},
1374 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1375 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire Blue Network $Network::ethernet{'BLUE_ADDRESS'}";
1376 goto SETTINGS_ERROR;
1377 }
1378
1379 if (&General::IpInSubnet ( $Network::ethernet{'ORANGE_ADDRESS'},
1380 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1381 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire Orange Network $Network::ethernet{'ORANGE_ADDRESS'}";
1382 goto SETTINGS_ERROR;
1383 }
1384 open(ALIASES, "${General::swroot}/ethernet/aliases") or die 'Unable to open aliases file.';
1385 while (<ALIASES>)
1386 {
1387 chomp($_);
1388 my @tempalias = split(/\,/,$_);
1389 if ($tempalias[1] eq 'on') {
1390 if (&General::IpInSubnet ($tempalias[0] ,
1391 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1392 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire alias entry $tempalias[0]";
1393 }
1394 }
1395 }
1396 close(ALIASES);
1397 if ($errormessage ne ''){
1398 goto SETTINGS_ERROR;
1399 }
1400 if ($cgiparams{'ENABLED'} !~ /^(on|off|)$/) {
1401 $errormessage = $Lang::tr{'invalid input'};
1402 goto SETTINGS_ERROR;
1403 }
1404
1405 # Create ta.key for tls-auth if not presant
1406 if ($cgiparams{'TLSAUTH'} eq 'on') {
1407 if ( ! -e "${General::swroot}/ovpn/certs/ta.key") {
1408 # This system call is safe, because all arguements are passed as an array.
1409 system("/usr/sbin/openvpn", "--genkey", "secret", "${General::swroot}/ovpn/certs/ta.key");
1410 if ($?) {
1411 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1412 goto SETTINGS_ERROR;
1413 }
1414 }
1415 }
1416
1417 $vpnsettings{'ENABLED'} = $cgiparams{'ENABLED'};
1418 $vpnsettings{'VPN_IP'} = $cgiparams{'VPN_IP'};
1419 $vpnsettings{'DOVPN_SUBNET'} = $cgiparams{'DOVPN_SUBNET'};
1420
1421 # Store our configuration
1422 &General::writehash("${General::swroot}/ovpn/settings", \%vpnsettings);
1423
1424 # Write the OpenVPN server configuration
1425 &writeserverconf();
1426
1427 # Start/Stop the server
1428 if ($vpnsettings{'ENABLED'} eq "on") {
1429 &General::system("/usr/local/bin/openvpnctrl", "rw", "restart");
1430 } else {
1431 &General::system("/usr/local/bin/openvpnctrl", "rw", "stop");
1432 }
1433
1434 SETTINGS_ERROR:
1435 ###
1436 ### Reset all step 2
1437 ###
1438 }elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove x509'} && $cgiparams{'AREUSURE'} eq 'yes') {
1439 my $file = '';
1440 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
1441
1442 # Stop all N2N connections
1443 &General::system("/usr/local/bin/openvpnctrl", "n2n", "stop");
1444
1445 foreach my $key (keys %confighash) {
1446 my $name = $confighash{$cgiparams{'$key'}}[1];
1447
1448 if ($confighash{$key}[4] eq 'cert') {
1449 delete $confighash{$cgiparams{'$key'}};
1450 }
1451
1452 &General::system("/usr/local/bin/openvpnctrl", "n2n", "delete", "$name");
1453 }
1454 while ($file = glob("${General::swroot}/ovpn/ca/*")) {
1455 unlink $file;
1456 }
1457 while ($file = glob("${General::swroot}/ovpn/certs/*")) {
1458 unlink $file;
1459 }
1460 while ($file = glob("${General::swroot}/ovpn/crls/*")) {
1461 unlink $file;
1462 }
1463 &cleanssldatabase();
1464 if (open(FILE, ">${General::swroot}/ovpn/caconfig")) {
1465 print FILE "";
1466 close FILE;
1467 }
1468 if (open(FILE, ">${General::swroot}/ovpn/ccdroute")) {
1469 print FILE "";
1470 close FILE;
1471 }
1472 if (open(FILE, ">${General::swroot}/ovpn/ccdroute2")) {
1473 print FILE "";
1474 close FILE;
1475 }
1476 while ($file = glob("${General::swroot}/ovpn/ccd/*")) {
1477 unlink $file
1478 }
1479 while ($file = glob("${General::swroot}/ovpn/ccd/*")) {
1480 unlink $file
1481 }
1482 if (open(FILE, ">${General::swroot}/ovpn/ovpn-leases.db")) {
1483 print FILE "";
1484 close FILE;
1485 }
1486 if (open(FILE, ">${General::swroot}/ovpn/ovpnconfig")) {
1487 print FILE "";
1488 close FILE;
1489 }
1490 while ($file = glob("${General::swroot}/ovpn/n2nconf/*")) {
1491 unlink($file);
1492 }
1493
1494 # Remove everything from the collectd configuration
1495 &writecollectdconf();
1496
1497 #&writeserverconf();
1498 ###
1499 ### Reset all step 1
1500 ###
1501 }elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove x509'}) {
1502 &Header::showhttpheaders();
1503 &Header::openpage($Lang::tr{'ovpn'}, 1, '');
1504 &Header::openbigbox('100%', 'left', '', '');
1505 &Header::openbox('100%', 'left', $Lang::tr{'are you sure'});
1506 print <<END;
1507 <form method='post'>
1508 <table width='100%'>
1509 <tr>
1510 <td align='center'>
1511 <input type='hidden' name='AREUSURE' value='yes' />
1512 <b><font color='${Header::colourred}'>$Lang::tr{'capswarning'}</font></b>:
1513 $Lang::tr{'resetting the vpn configuration will remove the root ca, the host certificate and all certificate based connections'}</td>
1514 </tr>
1515 <tr>
1516 <td align='center'><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' />
1517 <input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></td>
1518 </tr>
1519 </table>
1520 </form>
1521 END
1522 ;
1523 &Header::closebox();
1524 &Header::closebigbox();
1525 &Header::closepage();
1526 exit (0);
1527
1528 ###
1529 ### Upload CA Certificate
1530 ###
1531 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'upload ca certificate'}) {
1532 &General::readhasharray("${General::swroot}/ovpn/caconfig", \%cahash);
1533
1534 if ($cgiparams{'CA_NAME'} !~ /^[a-zA-Z0-9]+$/) {
1535 $errormessage = $Lang::tr{'name must only contain characters'};
1536 goto UPLOADCA_ERROR;
1537 }
1538
1539 if (length($cgiparams{'CA_NAME'}) >60) {
1540 $errormessage = $Lang::tr{'name too long'};
1541 goto VPNCONF_ERROR;
1542 }
1543
1544 if ($cgiparams{'CA_NAME'} eq 'ca') {
1545 $errormessage = $Lang::tr{'name is invalid'};
1546 goto UPLOADCA_ERROR;
1547 }
1548
1549 # Check if there is no other entry with this name
1550 foreach my $key (keys %cahash) {
1551 if ($cahash{$key}[0] eq $cgiparams{'CA_NAME'}) {
1552 $errormessage = $Lang::tr{'a ca certificate with this name already exists'};
1553 goto UPLOADCA_ERROR;
1554 }
1555 }
1556
1557 unless (ref ($cgiparams{'FH'})) {
1558 $errormessage = $Lang::tr{'there was no file upload'};
1559 goto UPLOADCA_ERROR;
1560 }
1561 # Move uploaded ca to a temporary file
1562 (my $fh, my $filename) = tempfile( );
1563 if (copy ($cgiparams{'FH'}, $fh) != 1) {
1564 $errormessage = $!;
1565 goto UPLOADCA_ERROR;
1566 }
1567 my @temp = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "$filename");
1568 if ( ! grep(/CA:TRUE/i, @temp )) {
1569 $errormessage = $Lang::tr{'not a valid ca certificate'};
1570 unlink ($filename);
1571 goto UPLOADCA_ERROR;
1572 } else {
1573 unless(move($filename, "${General::swroot}/ovpn/ca/$cgiparams{'CA_NAME'}cert.pem")) {
1574 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1575 unlink ($filename);
1576 goto UPLOADCA_ERROR;
1577 }
1578 }
1579
1580 my @casubject = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/$cgiparams{'CA_NAME'}cert.pem");
1581 my $casubject;
1582
1583 foreach my $line (@casubject) {
1584 if ($line =~ /Subject: (.*)[\n]/) {
1585 $casubject = $1;
1586 $casubject =~ s+/Email+, E+;
1587 $casubject =~ s/ ST=/ S=/;
1588
1589 last;
1590 }
1591 }
1592
1593 $casubject = &Header::cleanhtml($casubject);
1594
1595 my $key = &General::findhasharraykey (\%cahash);
1596 $cahash{$key}[0] = $cgiparams{'CA_NAME'};
1597 $cahash{$key}[1] = $casubject;
1598 &General::writehasharray("${General::swroot}/ovpn/caconfig", \%cahash);
1599 # system('/usr/local/bin/ipsecctrl', 'R');
1600
1601 UPLOADCA_ERROR:
1602
1603 ###
1604 ### Display ca certificate
1605 ###
1606 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show ca certificate'}) {
1607 &General::readhasharray("${General::swroot}/ovpn/caconfig", \%cahash);
1608
1609 if ( -f "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem") {
1610 &Header::showhttpheaders();
1611 &Header::openpage($Lang::tr{'ovpn'}, 1, '');
1612 &Header::openbigbox('100%', 'LEFT', '', $errormessage);
1613 &Header::openbox('100%', 'LEFT', "$Lang::tr{'ca certificate'}:");
1614 my @output = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1615 my $output = &Header::cleanhtml(join("", @output),"y");
1616 print "<pre>$output</pre>\n";
1617 &Header::closebox();
1618 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
1619 &Header::closebigbox();
1620 &Header::closepage();
1621 exit(0);
1622 } else {
1623 $errormessage = $Lang::tr{'invalid key'};
1624 }
1625
1626 ###
1627 ### Download ca certificate
1628 ###
1629 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download ca certificate'}) {
1630 &General::readhasharray("${General::swroot}/ovpn/caconfig", \%cahash);
1631
1632 if ( -f "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
1633 print "Content-Type: application/octet-stream\r\n";
1634 print "Content-Disposition: filename=$cahash{$cgiparams{'KEY'}}[0]cert.pem\r\n\r\n";
1635
1636 my @tmp = &General::system_output("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1637 print @tmp;
1638
1639 exit(0);
1640 } else {
1641 $errormessage = $Lang::tr{'invalid key'};
1642 }
1643
1644 ###
1645 ### Remove ca certificate (step 2)
1646 ###
1647 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove ca certificate'} && $cgiparams{'AREUSURE'} eq 'yes') {
1648 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
1649 &General::readhasharray("${General::swroot}/ovpn/caconfig", \%cahash);
1650
1651 if ( -f "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
1652 foreach my $key (keys %confighash) {
1653 my @test = &General::system_output("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem", "${General::swroot}/ovpn/certs/$confighash{$key}[1]cert.pem");
1654 if (grep(/: OK/, @test)) {
1655 # Delete connection
1656 # if ($vpnsettings{'ENABLED'} eq 'on' ||
1657 # $vpnsettings{'ENABLED_BLUE'} eq 'on') {
1658 # system('/usr/local/bin/ipsecctrl', 'D', $key);
1659 # }
1660 unlink ("${General::swroot}/ovpn//certs/$confighash{$key}[1]cert.pem");
1661 unlink ("${General::swroot}/ovpn/certs/$confighash{$key}[1].p12");
1662 delete $confighash{$key};
1663 &General::writehasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
1664 # &writeipsecfiles();
1665 }
1666 }
1667 unlink ("${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1668 delete $cahash{$cgiparams{'KEY'}};
1669 &General::writehasharray("${General::swroot}/ovpn/caconfig", \%cahash);
1670 # system('/usr/local/bin/ipsecctrl', 'R');
1671 } else {
1672 $errormessage = $Lang::tr{'invalid key'};
1673 }
1674 ###
1675 ### Remove ca certificate (step 1)
1676 ###
1677 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove ca certificate'}) {
1678 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
1679 &General::readhasharray("${General::swroot}/ovpn/caconfig", \%cahash);
1680
1681 my $assignedcerts = 0;
1682 if ( -f "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
1683 foreach my $key (keys %confighash) {
1684 my @test = &General::system_output("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem", "${General::swroot}/ovpn/certs/$confighash{$key}[1]cert.pem");
1685 if (grep(/: OK/, @test)) {
1686 $assignedcerts++;
1687 }
1688 }
1689 if ($assignedcerts) {
1690 &Header::showhttpheaders();
1691 &Header::openpage($Lang::tr{'ovpn'}, 1, '');
1692 &Header::openbigbox('100%', 'LEFT', '', $errormessage);
1693 &Header::openbox('100%', 'LEFT', $Lang::tr{'are you sure'});
1694 print <<END;
1695 <table><form method='post'><input type='hidden' name='AREUSURE' value='yes' />
1696 <input type='hidden' name='KEY' value='$cgiparams{'KEY'}' />
1697 <tr><td align='center'>
1698 <b><font color='${Header::colourred}'>$Lang::tr{'capswarning'}</font></b>: $assignedcerts
1699 $Lang::tr{'connections are associated with this ca. deleting the ca will delete these connections as well.'}
1700 <tr><td align='center'><input type='submit' name='ACTION' value='$Lang::tr{'remove ca certificate'}' />
1701 <input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></td></tr>
1702 </form></table>
1703 END
1704 ;
1705 &Header::closebox();
1706 &Header::closebigbox();
1707 &Header::closepage();
1708 exit (0);
1709 } else {
1710 unlink ("${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1711 delete $cahash{$cgiparams{'KEY'}};
1712 &General::writehasharray("${General::swroot}/ovpn/caconfig", \%cahash);
1713 # system('/usr/local/bin/ipsecctrl', 'R');
1714 }
1715 } else {
1716 $errormessage = $Lang::tr{'invalid key'};
1717 }
1718
1719 ###
1720 ### Display root certificate
1721 ###
1722 }elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show root certificate'} ||
1723 $cgiparams{'ACTION'} eq $Lang::tr{'show host certificate'}) {
1724 my @output;
1725 &Header::showhttpheaders();
1726 &Header::openpage($Lang::tr{'ovpn'}, 1, '');
1727 &Header::openbigbox('100%', 'LEFT', '', '');
1728 if ($cgiparams{'ACTION'} eq $Lang::tr{'show root certificate'}) {
1729 &Header::openbox('100%', 'LEFT', "$Lang::tr{'root certificate'}:");
1730 @output = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/cacert.pem");
1731 } else {
1732 &Header::openbox('100%', 'LEFT', "$Lang::tr{'host certificate'}:");
1733 @output = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
1734 }
1735 my $output = &Header::cleanhtml(join("", @output), "y");
1736 print "<pre>$output</pre>\n";
1737 &Header::closebox();
1738 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
1739 &Header::closebigbox();
1740 &Header::closepage();
1741 exit(0);
1742
1743 ###
1744 ### Download root certificate
1745 ###
1746 }elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download root certificate'}) {
1747 if ( -f "${General::swroot}/ovpn/ca/cacert.pem" ) {
1748 print "Content-Type: application/octet-stream\r\n";
1749 print "Content-Disposition: filename=cacert.pem\r\n\r\n";
1750
1751 my @tmp = &General::system_output("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ovpn/ca/cacert.pem");
1752 print @tmp;
1753
1754 exit(0);
1755 }
1756
1757 ###
1758 ### Download host certificate
1759 ###
1760 }elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download host certificate'}) {
1761 if ( -f "${General::swroot}/ovpn/certs/servercert.pem" ) {
1762 print "Content-Type: application/octet-stream\r\n";
1763 print "Content-Disposition: filename=servercert.pem\r\n\r\n";
1764
1765 my @tmp = &General::system_output("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
1766 print @tmp;
1767
1768 exit(0);
1769 }
1770
1771 ###
1772 ### Download tls-auth key
1773 ###
1774 }elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download tls-auth key'}) {
1775 if ( -f "${General::swroot}/ovpn/certs/ta.key" ) {
1776 print "Content-Type: application/octet-stream\r\n";
1777 print "Content-Disposition: filename=ta.key\r\n\r\n";
1778
1779 open(FILE, "${General::swroot}/ovpn/certs/ta.key");
1780 my @tmp = <FILE>;
1781 close(FILE);
1782
1783 print @tmp;
1784
1785 exit(0);
1786 }
1787
1788 ###
1789 ### Form for generating a root certificate
1790 ###
1791 }elsif ($cgiparams{'ACTION'} eq $Lang::tr{'generate root/host certificates'} ||
1792 $cgiparams{'ACTION'} eq $Lang::tr{'upload p12 file'}) {
1793
1794 if (-f "${General::swroot}/ovpn/ca/cacert.pem") {
1795 $errormessage = $Lang::tr{'valid root certificate already exists'};
1796 $cgiparams{'ACTION'} = '';
1797 goto ROOTCERT_ERROR;
1798 }
1799
1800 if (($cgiparams{'ROOTCERT_HOSTNAME'} eq '') && -e "${General::swroot}/red/active") {
1801 if (open(IPADDR, "${General::swroot}/red/local-ipaddress")) {
1802 my $ipaddr = <IPADDR>;
1803 close IPADDR;
1804 chomp ($ipaddr);
1805 $cgiparams{'ROOTCERT_HOSTNAME'} = (gethostbyaddr(pack("C4", split(/\./, $ipaddr)), 2))[0];
1806 if ($cgiparams{'ROOTCERT_HOSTNAME'} eq '') {
1807 $cgiparams{'ROOTCERT_HOSTNAME'} = $ipaddr;
1808 }
1809 }
1810 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'upload p12 file'}) {
1811 unless (ref ($cgiparams{'FH'})) {
1812 $errormessage = $Lang::tr{'there was no file upload'};
1813 goto ROOTCERT_ERROR;
1814 }
1815
1816 # Move uploaded certificate request to a temporary file
1817 (my $fh, my $filename) = tempfile( );
1818 if (copy ($cgiparams{'FH'}, $fh) != 1) {
1819 $errormessage = $!;
1820 goto ROOTCERT_ERROR;
1821 }
1822
1823 # Create a temporary dirctory
1824 my $tempdir = tempdir( CLEANUP => 1 );
1825
1826 # Extract the CA certificate from the file
1827 my $pid = open(OPENSSL, "|-");
1828 $SIG{ALRM} = sub { $errormessage = $Lang::tr{'broken pipe'}; goto ROOTCERT_ERROR;};
1829 if ($pid) { # parent
1830 if ($cgiparams{'P12_PASS'} ne '') {
1831 print OPENSSL "$cgiparams{'P12_PASS'}\n";
1832 }
1833 close (OPENSSL);
1834 if ($?) {
1835 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1836 unlink ($filename);
1837 goto ROOTCERT_ERROR;
1838 }
1839 } else { # child
1840 unless (exec ('/usr/bin/openssl', 'pkcs12', '-cacerts', '-nokeys',
1841 '-in', $filename,
1842 '-out', "$tempdir/cacert.pem")) {
1843 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
1844 unlink ($filename);
1845 goto ROOTCERT_ERROR;
1846 }
1847 }
1848
1849 # Extract the Host certificate from the file
1850 $pid = open(OPENSSL, "|-");
1851 $SIG{ALRM} = sub { $errormessage = $Lang::tr{'broken pipe'}; goto ROOTCERT_ERROR;};
1852 if ($pid) { # parent
1853 if ($cgiparams{'P12_PASS'} ne '') {
1854 print OPENSSL "$cgiparams{'P12_PASS'}\n";
1855 }
1856 close (OPENSSL);
1857 if ($?) {
1858 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1859 unlink ($filename);
1860 goto ROOTCERT_ERROR;
1861 }
1862 } else { # child
1863 unless (exec ('/usr/bin/openssl', 'pkcs12', '-clcerts', '-nokeys',
1864 '-in', $filename,
1865 '-out', "$tempdir/hostcert.pem")) {
1866 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
1867 unlink ($filename);
1868 goto ROOTCERT_ERROR;
1869 }
1870 }
1871
1872 # Extract the Host key from the file
1873 $pid = open(OPENSSL, "|-");
1874 $SIG{ALRM} = sub { $errormessage = $Lang::tr{'broken pipe'}; goto ROOTCERT_ERROR;};
1875 if ($pid) { # parent
1876 if ($cgiparams{'P12_PASS'} ne '') {
1877 print OPENSSL "$cgiparams{'P12_PASS'}\n";
1878 }
1879 close (OPENSSL);
1880 if ($?) {
1881 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1882 unlink ($filename);
1883 goto ROOTCERT_ERROR;
1884 }
1885 } else { # child
1886 unless (exec ('/usr/bin/openssl', 'pkcs12', '-nocerts',
1887 '-nodes',
1888 '-in', $filename,
1889 '-out', "$tempdir/serverkey.pem")) {
1890 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
1891 unlink ($filename);
1892 goto ROOTCERT_ERROR;
1893 }
1894 }
1895
1896 unless(move("$tempdir/cacert.pem", "${General::swroot}/ovpn/ca/cacert.pem")) {
1897 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1898 unlink ($filename);
1899 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
1900 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
1901 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
1902 goto ROOTCERT_ERROR;
1903 }
1904
1905 unless(move("$tempdir/hostcert.pem", "${General::swroot}/ovpn/certs/servercert.pem")) {
1906 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1907 unlink ($filename);
1908 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
1909 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
1910 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
1911 goto ROOTCERT_ERROR;
1912 }
1913
1914 unless(move("$tempdir/serverkey.pem", "${General::swroot}/ovpn/certs/serverkey.pem")) {
1915 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1916 unlink ($filename);
1917 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
1918 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
1919 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
1920 goto ROOTCERT_ERROR;
1921 }
1922
1923 goto ROOTCERT_SUCCESS;
1924
1925 } elsif ($cgiparams{'ROOTCERT_COUNTRY'} ne '') {
1926
1927 # Validate input since the form was submitted
1928 if ($cgiparams{'ROOTCERT_ORGANIZATION'} eq ''){
1929 $errormessage = $Lang::tr{'organization cant be empty'};
1930 goto ROOTCERT_ERROR;
1931 }
1932 if (length($cgiparams{'ROOTCERT_ORGANIZATION'}) >60) {
1933 $errormessage = $Lang::tr{'organization too long'};
1934 goto ROOTCERT_ERROR;
1935 }
1936 if ($cgiparams{'ROOTCERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1937 $errormessage = $Lang::tr{'invalid input for organization'};
1938 goto ROOTCERT_ERROR;
1939 }
1940 if ($cgiparams{'ROOTCERT_HOSTNAME'} eq ''){
1941 $errormessage = $Lang::tr{'hostname cant be empty'};
1942 goto ROOTCERT_ERROR;
1943 }
1944 unless (&General::validfqdn($cgiparams{'ROOTCERT_HOSTNAME'}) || &General::validip($cgiparams{'ROOTCERT_HOSTNAME'})) {
1945 $errormessage = $Lang::tr{'invalid input for hostname'};
1946 goto ROOTCERT_ERROR;
1947 }
1948 if ($cgiparams{'ROOTCERT_EMAIL'} ne '' && (! &General::validemail($cgiparams{'ROOTCERT_EMAIL'}))) {
1949 $errormessage = $Lang::tr{'invalid input for e-mail address'};
1950 goto ROOTCERT_ERROR;
1951 }
1952 if (length($cgiparams{'ROOTCERT_EMAIL'}) > 40) {
1953 $errormessage = $Lang::tr{'e-mail address too long'};
1954 goto ROOTCERT_ERROR;
1955 }
1956 if ($cgiparams{'ROOTCERT_OU'} ne '' && $cgiparams{'ROOTCERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1957 $errormessage = $Lang::tr{'invalid input for department'};
1958 goto ROOTCERT_ERROR;
1959 }
1960 if ($cgiparams{'ROOTCERT_CITY'} ne '' && $cgiparams{'ROOTCERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1961 $errormessage = $Lang::tr{'invalid input for city'};
1962 goto ROOTCERT_ERROR;
1963 }
1964 if ($cgiparams{'ROOTCERT_STATE'} ne '' && $cgiparams{'ROOTCERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1965 $errormessage = $Lang::tr{'invalid input for state or province'};
1966 goto ROOTCERT_ERROR;
1967 }
1968 if ($cgiparams{'ROOTCERT_COUNTRY'} !~ /^[A-Z]*$/) {
1969 $errormessage = $Lang::tr{'invalid input for country'};
1970 goto ROOTCERT_ERROR;
1971 }
1972
1973 # Copy the cgisettings to vpnsettings and save the configfile
1974 $vpnsettings{'ROOTCERT_ORGANIZATION'} = $cgiparams{'ROOTCERT_ORGANIZATION'};
1975 $vpnsettings{'ROOTCERT_HOSTNAME'} = $cgiparams{'ROOTCERT_HOSTNAME'};
1976 $vpnsettings{'ROOTCERT_EMAIL'} = $cgiparams{'ROOTCERT_EMAIL'};
1977 $vpnsettings{'ROOTCERT_OU'} = $cgiparams{'ROOTCERT_OU'};
1978 $vpnsettings{'ROOTCERT_CITY'} = $cgiparams{'ROOTCERT_CITY'};
1979 $vpnsettings{'ROOTCERT_STATE'} = $cgiparams{'ROOTCERT_STATE'};
1980 $vpnsettings{'ROOTCERT_COUNTRY'} = $cgiparams{'ROOTCERT_COUNTRY'};
1981 &General::writehash("${General::swroot}/ovpn/settings", \%vpnsettings);
1982
1983 # Replace empty strings with a .
1984 (my $ou = $cgiparams{'ROOTCERT_OU'}) =~ s/^\s*$/\./;
1985 (my $city = $cgiparams{'ROOTCERT_CITY'}) =~ s/^\s*$/\./;
1986 (my $state = $cgiparams{'ROOTCERT_STATE'}) =~ s/^\s*$/\./;
1987
1988 # Create the CA certificate
1989 my $pid = open(OPENSSL, "|-");
1990 $SIG{ALRM} = sub { $errormessage = $Lang::tr{'broken pipe'}; goto ROOTCERT_ERROR;};
1991 if ($pid) { # parent
1992 print OPENSSL "$cgiparams{'ROOTCERT_COUNTRY'}\n";
1993 print OPENSSL "$state\n";
1994 print OPENSSL "$city\n";
1995 print OPENSSL "$cgiparams{'ROOTCERT_ORGANIZATION'}\n";
1996 print OPENSSL "$ou\n";
1997 print OPENSSL "$cgiparams{'ROOTCERT_ORGANIZATION'} CA\n";
1998 print OPENSSL "$cgiparams{'ROOTCERT_EMAIL'}\n";
1999 close (OPENSSL);
2000 if ($?) {
2001 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2002 unlink ("${General::swroot}/ovpn/ca/cakey.pem");
2003 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2004 goto ROOTCERT_ERROR;
2005 }
2006 } else { # child
2007 unless (exec ('/usr/bin/openssl', 'req', '-x509', '-nodes',
2008 '-days', '999999', '-newkey', 'rsa:4096', '-sha512',
2009 '-keyout', "${General::swroot}/ovpn/ca/cakey.pem",
2010 '-out', "${General::swroot}/ovpn/ca/cacert.pem",
2011 '-config', "/usr/share/openvpn/ovpn.cnf")) {
2012 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
2013 goto ROOTCERT_ERROR;
2014 }
2015 }
2016
2017 # Create the Host certificate request
2018 $pid = open(OPENSSL, "|-");
2019 $SIG{ALRM} = sub { $errormessage = $Lang::tr{'broken pipe'}; goto ROOTCERT_ERROR;};
2020 if ($pid) { # parent
2021 print OPENSSL "$cgiparams{'ROOTCERT_COUNTRY'}\n";
2022 print OPENSSL "$state\n";
2023 print OPENSSL "$city\n";
2024 print OPENSSL "$cgiparams{'ROOTCERT_ORGANIZATION'}\n";
2025 print OPENSSL "$ou\n";
2026 print OPENSSL "$cgiparams{'ROOTCERT_HOSTNAME'}\n";
2027 print OPENSSL "$cgiparams{'ROOTCERT_EMAIL'}\n";
2028 print OPENSSL ".\n";
2029 print OPENSSL ".\n";
2030 close (OPENSSL);
2031 if ($?) {
2032 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2033 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
2034 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2035 goto ROOTCERT_ERROR;
2036 }
2037 } else { # child
2038 unless (exec ('/usr/bin/openssl', 'req', '-nodes',
2039 '-newkey', 'rsa:4096',
2040 '-keyout', "${General::swroot}/ovpn/certs/serverkey.pem",
2041 '-out', "${General::swroot}/ovpn/certs/serverreq.pem",
2042 '-extensions', 'server',
2043 '-config', "/usr/share/openvpn/ovpn.cnf" )) {
2044 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
2045 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
2046 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2047 unlink ("${General::swroot}/ovpn/ca/cakey.pem");
2048 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2049 goto ROOTCERT_ERROR;
2050 }
2051 }
2052
2053 # Sign the host certificate request
2054 # This system call is safe, because all argeuments are passed as an array.
2055 system('/usr/bin/openssl', 'ca', '-days', '999999',
2056 '-batch', '-notext',
2057 '-in', "${General::swroot}/ovpn/certs/serverreq.pem",
2058 '-out', "${General::swroot}/ovpn/certs/servercert.pem",
2059 '-extensions', 'server',
2060 '-config', "/usr/share/openvpn/ovpn.cnf");
2061 if ($?) {
2062 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2063 unlink ("${General::swroot}/ovpn/ca/cakey.pem");
2064 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2065 unlink ("${General::swroot}/ovpn/serverkey.pem");
2066 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2067 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
2068 &cleanssldatabase();
2069 goto ROOTCERT_ERROR;
2070 } else {
2071 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2072 &deletebackupcert();
2073 }
2074
2075 # Create an empty CRL
2076 # System call is safe, because all arguments are passed as array.
2077 system('/usr/bin/openssl', 'ca', '-gencrl',
2078 '-out', "${General::swroot}/ovpn/crls/cacrl.pem",
2079 '-config', "/usr/share/openvpn/ovpn.cnf" );
2080 if ($?) {
2081 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2082 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
2083 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
2084 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2085 unlink ("${General::swroot}/ovpn/crls/cacrl.pem");
2086 &cleanssldatabase();
2087 goto ROOTCERT_ERROR;
2088 # } else {
2089 # &cleanssldatabase();
2090 }
2091 # Create ta.key for tls-auth
2092 # This system call is safe, because all arguments are passed as an array.
2093 system('/usr/sbin/openvpn', '--genkey', 'secret', "${General::swroot}/ovpn/certs/ta.key");
2094 if ($?) {
2095 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2096 &cleanssldatabase();
2097 goto ROOTCERT_ERROR;
2098 }
2099 goto ROOTCERT_SUCCESS;
2100 }
2101 ROOTCERT_ERROR:
2102 if ($cgiparams{'ACTION'} ne '') {
2103 &Header::showhttpheaders();
2104 &Header::openpage($Lang::tr{'ovpn'}, 1, '');
2105 &Header::openbigbox('100%', 'LEFT', '', '');
2106
2107 # Show any errors
2108 &Header::errorbox($errormessage);
2109
2110 &Header::openbox('100%', 'LEFT', "$Lang::tr{'generate root/host certificates'}:");
2111 print <<END;
2112 <form method='post' enctype='multipart/form-data'>
2113 <table width='100%' border='0' cellspacing='1' cellpadding='0'>
2114 <tr><td width='30%' class='base'>$Lang::tr{'organization name'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
2115 <td width='35%' class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_ORGANIZATION' value='$cgiparams{'ROOTCERT_ORGANIZATION'}' size='32' /></td>
2116 <td width='35%' colspan='2'>&nbsp;</td></tr>
2117 <tr><td class='base'>$Lang::tr{'ipfires hostname'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
2118 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_HOSTNAME' value='$cgiparams{'ROOTCERT_HOSTNAME'}' size='32' /></td>
2119 <td colspan='2'>&nbsp;</td></tr>
2120 <tr><td class='base'>$Lang::tr{'your e-mail'}:</td>
2121 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_EMAIL' value='$cgiparams{'ROOTCERT_EMAIL'}' size='32' /></td>
2122 <td colspan='2'>&nbsp;</td></tr>
2123 <tr><td class='base'>$Lang::tr{'your department'}:</td>
2124 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_OU' value='$cgiparams{'ROOTCERT_OU'}' size='32' /></td>
2125 <td colspan='2'>&nbsp;</td></tr>
2126 <tr><td class='base'>$Lang::tr{'city'}:</td>
2127 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_CITY' value='$cgiparams{'ROOTCERT_CITY'}' size='32' /></td>
2128 <td colspan='2'>&nbsp;</td></tr>
2129 <tr><td class='base'>$Lang::tr{'state or province'}:</td>
2130 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_STATE' value='$cgiparams{'ROOTCERT_STATE'}' size='32' /></td>
2131 <td colspan='2'>&nbsp;</td></tr>
2132 <tr><td class='base'>$Lang::tr{'country'}:</td>
2133 <td class='base'><select name='ROOTCERT_COUNTRY'>
2134
2135 END
2136 ;
2137 foreach my $country (sort keys %{Countries::countries}) {
2138 print "<option value='$Countries::countries{$country}'";
2139 if ( $Countries::countries{$country} eq $cgiparams{'ROOTCERT_COUNTRY'} ) {
2140 print " selected='selected'";
2141 }
2142 print ">$country</option>";
2143 }
2144 print <<END;
2145 </select></td>
2146
2147 <tr><td>&nbsp;</td>
2148 <td><input type='submit' name='ACTION' value='$Lang::tr{'generate root/host certificates'}' /></td>
2149 <td>&nbsp;</td><td>&nbsp;</td></tr>
2150 <tr><td class='base' colspan='4' align='left'>
2151 <img src='/blob.gif' valign='top' alt='*' />&nbsp;$Lang::tr{'required field'}</td></tr>
2152 <tr><td colspan='2'><br></td></tr>
2153 </table>
2154
2155 <table width='100%'>
2156 <tr><td colspan='4'><hr></td></tr>
2157 <tr><td class='base' nowrap='nowrap'>$Lang::tr{'upload p12 file'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
2158 <td nowrap='nowrap'><input type='file' name='FH' size='32'></td>
2159 <td colspan='2'>&nbsp;</td></tr>
2160 <tr><td class='base'>$Lang::tr{'pkcs12 file password'}:</td>
2161 <td class='base' nowrap='nowrap'><input type='password' name='P12_PASS' value='$cgiparams{'P12_PASS'}' size='32' /></td>
2162 <td colspan='2'>&nbsp;</td></tr>
2163 <tr><td>&nbsp;</td>
2164 <td><input type='submit' name='ACTION' value='$Lang::tr{'upload p12 file'}' /></td>
2165 <td colspan='2'>&nbsp;</td></tr>
2166 <tr><td class='base' colspan='4' align='left'>
2167 <img src='/blob.gif' valign='top' alt='*' >&nbsp;$Lang::tr{'required field'}</td>
2168 </tr>
2169 </form></table>
2170 END
2171 ;
2172 &Header::closebox();
2173 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2174 &Header::closebigbox();
2175 &Header::closepage();
2176 exit(0)
2177 }
2178
2179 ROOTCERT_SUCCESS:
2180 &General::system("chmod", "600", "${General::swroot}/ovpn/certs/serverkey.pem");
2181 # if ($vpnsettings{'ENABLED'} eq 'on' ||
2182 # $vpnsettings{'ENABLE_BLUE'} eq 'on') {
2183 # system('/usr/local/bin/ipsecctrl', 'S');
2184 # }
2185
2186 ###
2187 ### Enable/Disable connection
2188 ###
2189
2190 }elsif ($cgiparams{'ACTION'} eq $Lang::tr{'toggle enable disable'}) {
2191 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2192 my $n2nactive = '';
2193 my @ps = &General::system_output("/bin/ps", "ax");
2194
2195 if(grep(/$confighash{$cgiparams{'KEY'}}[1]/, @ps)) {
2196 $n2nactive = "1";
2197 }
2198
2199 if ($confighash{$cgiparams{'KEY'}}) {
2200 if ($confighash{$cgiparams{'KEY'}}[0] eq 'off') {
2201 $confighash{$cgiparams{'KEY'}}[0] = 'on';
2202 &General::writehasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2203
2204 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net'){
2205 &General::system("/usr/local/bin/openvpnctrl", "n2n", "start", "$confighash{$cgiparams{'KEY'}}[1]");
2206 &writecollectdconf();
2207 }
2208 } else {
2209
2210 $confighash{$cgiparams{'KEY'}}[0] = 'off';
2211 &General::writehasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2212
2213 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net'){
2214 if ($n2nactive ne '') {
2215 &General::system("/usr/local/bin/openvpnctrl", "n2n", "stop", "$confighash{$cgiparams{'KEY'}}[1]");
2216 &writecollectdconf();
2217 }
2218 }
2219 }
2220 }
2221
2222 ###
2223 ### Download OpenVPN client package
2224 ###
2225
2226 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'dl client arch'}) {
2227 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2228 my $file = '';
2229 my $clientovpn = '';
2230 my @fileholder;
2231 my $tempdir = tempdir( CLEANUP => 1 );
2232 my $zippath = "$tempdir/";
2233
2234 # N2N
2235 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net'){
2236 my $zipname = "$confighash{$cgiparams{'KEY'}}[1]-Client.zip";
2237 my $zippathname = "$zippath$zipname";
2238 $clientovpn = "$confighash{$cgiparams{'KEY'}}[1].conf";
2239 my @ovsubnettemp = split(/\./,$confighash{$cgiparams{'KEY'}}[27]);
2240 my $ovsubnet = "$ovsubnettemp[0].$ovsubnettemp[1].$ovsubnettemp[2]";
2241 my $tunmtu = '';
2242 my @remsubnet = split(/\//,$confighash{$cgiparams{'KEY'}}[8]);
2243 my $n2nfragment = '';
2244
2245 open(CLIENTCONF, ">$tempdir/$clientovpn") or die "Unable to open tempfile: $!";
2246 flock CLIENTCONF, 2;
2247
2248 my $zip = Archive::Zip->new();
2249 print CLIENTCONF "# IPFire n2n Open VPN Client Config by ummeegge und m.a.d\n";
2250 print CLIENTCONF "# \n";
2251 print CLIENTCONF "# User Security\n";
2252 print CLIENTCONF "user nobody\n";
2253 print CLIENTCONF "group nobody\n";
2254 print CLIENTCONF "persist-tun\n";
2255 print CLIENTCONF "persist-key\n";
2256 print CLIENTCONF "script-security 2\n";
2257 print CLIENTCONF "# IP/DNS for remote Server Gateway\n";
2258 print CLIENTCONF "remote $vpnsettings{'VPN_IP'}\n";
2259 print CLIENTCONF "float\n";
2260 print CLIENTCONF "# IP adresses of the VPN Subnet\n";
2261 print CLIENTCONF "ifconfig $ovsubnet.2 $ovsubnet.1\n";
2262 print CLIENTCONF "# Server Gateway Network\n";
2263 print CLIENTCONF "route $remsubnet[0] $remsubnet[1]\n";
2264 print CLIENTCONF "# tun Device\n";
2265 print CLIENTCONF "dev tun\n";
2266 print CLIENTCONF "#Logfile for statistics\n";
2267 print CLIENTCONF "status-version 1\n";
2268 print CLIENTCONF "status /var/run/openvpn/$cgiparams{'NAME'}-n2n 10\n";
2269 print CLIENTCONF "# Port and Protokoll\n";
2270 print CLIENTCONF "port $confighash{$cgiparams{'KEY'}}[29]\n";
2271
2272 if ($confighash{$cgiparams{'KEY'}}[28] eq 'tcp') {
2273 print CLIENTCONF "proto tcp4-client\n";
2274 print CLIENTCONF "# Packet size\n";
2275 if ($confighash{$cgiparams{'KEY'}}[31] eq '') {
2276 $tunmtu = '1400';
2277 } else {
2278 $tunmtu = $confighash{$cgiparams{'KEY'}}[31];
2279 }
2280 print CLIENTCONF "tun-mtu $tunmtu\n";
2281 }
2282
2283 if ($confighash{$cgiparams{'KEY'}}[28] eq 'udp') {
2284 print CLIENTCONF "proto udp4\n";
2285 print CLIENTCONF "# Paketsize\n";
2286 if ($confighash{$cgiparams{'KEY'}}[31] eq '') {
2287 $tunmtu = '1500';
2288 } else {
2289 $tunmtu = $confighash{$cgiparams{'KEY'}}[31];
2290 }
2291 print CLIENTCONF "tun-mtu $tunmtu\n";
2292 if ($confighash{$cgiparams{'KEY'}}[24] ne '') {
2293 print CLIENTCONF "fragment $confighash{$cgiparams{'KEY'}}[24]\n";
2294 }
2295 if ($confighash{$cgiparams{'KEY'}}[23] eq 'on') {
2296 print CLIENTCONF "mssfix\n";
2297 } else {
2298 print CLIENTCONF "mssfix 0\n";
2299 }
2300 }
2301
2302 # Check host certificate if X509 is RFC3280 compliant.
2303 # If not, old --ns-cert-type directive will be used.
2304 # If appropriate key usage extension exists, new --remote-cert-tls directive will be used.
2305 my @hostcert = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
2306 if (! grep(/TLS Web Server Authentication/, @hostcert)) {
2307 print CLIENTCONF "ns-cert-type server\n";
2308 } else {
2309 print CLIENTCONF "remote-cert-tls server\n";
2310 }
2311 print CLIENTCONF "# Auth. Client\n";
2312 print CLIENTCONF "tls-client\n";
2313 print CLIENTCONF "# Cipher\n";
2314 print CLIENTCONF "cipher $confighash{$cgiparams{'KEY'}}[40]\n";
2315
2316 if ($confighash{$cgiparams{'KEY'}}[4] eq 'cert' && -f "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12") {
2317 print CLIENTCONF "pkcs12 ${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12\r\n";
2318 $zip->addFile( "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12", "$confighash{$cgiparams{'KEY'}}[1].p12") or die "Can't add file $confighash{$cgiparams{'KEY'}}[1].p12\n";
2319 }
2320
2321 # If GCM cipher is used, do not use --auth
2322 if (($confighash{$cgiparams{'KEY'}}[40] eq 'AES-256-GCM') ||
2323 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-192-GCM') ||
2324 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-128-GCM')) {
2325 print CLIENTCONF unless "# HMAC algorithm\n";
2326 print CLIENTCONF unless "auth $confighash{$cgiparams{'KEY'}}[39]\n";
2327 } else {
2328 print CLIENTCONF "# HMAC algorithm\n";
2329 print CLIENTCONF "auth $confighash{$cgiparams{'KEY'}}[39]\n";
2330 }
2331
2332 if ($confighash{$cgiparams{'KEY'}}[30] eq 'on') {
2333 print CLIENTCONF "# Enable Compression\n";
2334 print CLIENTCONF "comp-lzo\n";
2335 }
2336 print CLIENTCONF "# Debug Level\n";
2337 print CLIENTCONF "verb 3\n";
2338 print CLIENTCONF "# Tunnel check\n";
2339 print CLIENTCONF "keepalive 10 60\n";
2340 print CLIENTCONF "# Start as daemon\n";
2341 print CLIENTCONF "daemon $confighash{$cgiparams{'KEY'}}[1]n2n\n";
2342 print CLIENTCONF "writepid /var/run/$confighash{$cgiparams{'KEY'}}[1]n2n.pid\n";
2343 print CLIENTCONF "# Activate Management Interface and Port\n";
2344 if ($confighash{$cgiparams{'KEY'}}[22] eq '') {
2345 print CLIENTCONF "management localhost $confighash{$cgiparams{'KEY'}}[29]\n"
2346 } else {
2347 print CLIENTCONF "management localhost $confighash{$cgiparams{'KEY'}}[22]\n"
2348 };
2349 print CLIENTCONF "# remsub $confighash{$cgiparams{'KEY'}}[11]\n";
2350 if (&iscertlegacy("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]")) {
2351 print CLIENTCONF "providers legacy default\n";
2352 }
2353 close(CLIENTCONF);
2354
2355 $zip->addFile( "$tempdir/$clientovpn", $clientovpn) or die "Can't add file $clientovpn\n";
2356 my $status = $zip->writeToFileNamed($zippathname);
2357
2358 open(DLFILE, "<$zippathname") or die "Unable to open $zippathname: $!";
2359 @fileholder = <DLFILE>;
2360 print "Content-Type:application/x-download\n";
2361 print "Content-Disposition:attachment;filename=$zipname\n\n";
2362 print @fileholder;
2363
2364 # RW
2365 } else {
2366 my $name = $confighash{$cgiparams{'KEY'}}[1];
2367
2368 # Send HTTP Headers
2369 &Header::showhttpheaders({
2370 "Content-Type" => "application/x-openvpn-profile",
2371 "Content-Disposition" => "attachment; filename=${name}.ovpn",
2372 });
2373
2374 print "########################################################################\n";
2375 print "# IPFire OpenVPN Client Configuration for \"${name}\"\n";
2376 print "########################################################################\n";
2377
2378 # This is a client
2379 print "client\n";
2380
2381 # This is a layer 3 VPN
2382 print "dev tun\n";
2383
2384 # Point the client to this server
2385 print "remote $vpnsettings{'VPN_IP'} $vpnsettings{'DDEST_PORT'}\n";
2386 print "proto $vpnsettings{'DPROTOCOL'}\n";
2387
2388 # Configure the MTU of the tunnel interface
2389 print "tun-mtu $vpnsettings{'DMTU'}\n";
2390
2391 # Ask the client to verify the server certificate
2392 if (&is_cert_rfc3280_compliant("${General::swroot}/ovpn/certs/servercert.pem")) {
2393 print "remote-cert-tls server\n";
2394 }
2395 print "verify-x509-name $vpnsettings{'ROOTCERT_HOSTNAME'} name\n";
2396
2397 if ($vpnsettings{'MSSFIX'} eq 'on') {
2398 print "mssfix\n";
2399 } else {
2400 print "mssfix 0\n";
2401 }
2402 if ($vpnsettings{'FRAGMENT'} ne '' && $vpnsettings{'DPROTOCOL'} ne 'tcp' ) {
2403 print "fragment $vpnsettings{'FRAGMENT'}\n";
2404 }
2405
2406 # We no longer send any cryptographic configuration since 2.6.
2407 # That way, we will be able to push this from the server.
2408 # Therefore we always mandate NCP for new clients.
2409
2410 if ($vpnsettings{'DAUTH'} ne "") {
2411 print "auth $vpnsettings{'DAUTH'}\n";
2412 }
2413
2414 # Disable storing any credentials in memory
2415 print "auth-nocache\n";
2416
2417 # Set a fake user name for authentication
2418 print "auth-token-user USER\n";
2419 print "auth-token TOTP\n";
2420
2421 # If the server is asking for TOTP this needs to happen interactively
2422 print "auth-retry interact\n";
2423
2424 # Add provider line if certificate is legacy type
2425 if (&iscertlegacy("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]")) {
2426 print "providers legacy default\n";
2427 }
2428
2429 # CA
2430 open(FILE, "<${General::swroot}/ovpn/ca/cacert.pem");
2431 print "\n<ca>\n";
2432 while (<FILE>) {
2433 chomp($_);
2434 print "$_\n";
2435 }
2436 print "</ca>\n";
2437 close(FILE);
2438
2439 # PKCS12
2440 open(FILE, "<${General::swroot}/ovpn/certs/${name}.p12");
2441 print "\n<pkcs12>\n";
2442 print &MIME::Base64::encode_base64(do { local $/; <FILE> });
2443 print "</pkcs12>\n";
2444 close(FILE);
2445
2446 # TLS auth
2447 if ($vpnsettings{'TLSAUTH'} eq 'on') {
2448 open(FILE, "<${General::swroot}/ovpn/certs/ta.key");
2449 print "\n<tls-auth>\n";
2450 while (<FILE>) {
2451 chomp($_);
2452 print "$_\n";
2453 }
2454 print "</tls-auth>\n";
2455 close(FILE);
2456 }
2457 }
2458
2459 exit (0);
2460 ###
2461 ### Remove connection
2462 ###
2463
2464
2465 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'remove'}) {
2466 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2467
2468 if ($confighash{$cgiparams{'KEY'}}) {
2469 # Revoke certificate if certificate was deleted and rewrite the CRL
2470 &General::system("/usr/bin/openssl", "ca", "-revoke", "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem", "-config", "/usr/share/openvpn/ovpn.cnf");
2471 &General::system("/usr/bin/openssl", "ca", "-gencrl", "-out", "${General::swroot}/ovpn/crls/cacrl.pem", "-config", "/usr/share/openvpn/ovpn.cnf");
2472
2473 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net') {
2474 # Stop the N2N connection before it is removed
2475 &General::system("/usr/local/bin/openvpnctrl", "n2n", "stop", "$confighash{$cgiparams{'KEY'}}[1]");
2476
2477 my $conffile = glob("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]/$confighash{$cgiparams{'KEY'}}[1].conf");
2478 my $certfile = glob("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
2479 unlink ($certfile);
2480 unlink ($conffile);
2481
2482 if (-e "${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]") {
2483 rmdir ("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]") || die "Kann Verzeichnis nicht loeschen: $!";
2484 }
2485 }
2486
2487 unlink ("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
2488 unlink ("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
2489
2490 # Delete CCD files and routes
2491
2492 if (-f "${General::swroot}/ovpn/ccd/$confighash{$cgiparams{'KEY'}}[2]")
2493 {
2494 unlink "${General::swroot}/ovpn/ccd/$confighash{$cgiparams{'KEY'}}[2]";
2495 }
2496
2497 &General::readhasharray("${General::swroot}/ovpn/ccdroute", \%ccdroutehash);
2498 foreach my $key (keys %ccdroutehash) {
2499 if ($ccdroutehash{$key}[0] eq $confighash{$cgiparams{'KEY'}}[1]){
2500 delete $ccdroutehash{$key};
2501 }
2502 }
2503 &General::writehasharray("${General::swroot}/ovpn/ccdroute", \%ccdroutehash);
2504
2505 &General::readhasharray("${General::swroot}/ovpn/ccdroute2", \%ccdroute2hash);
2506 foreach my $key (keys %ccdroute2hash) {
2507 if ($ccdroute2hash{$key}[0] eq $confighash{$cgiparams{'KEY'}}[1]){
2508 delete $ccdroute2hash{$key};
2509 }
2510 }
2511 &General::writehasharray("${General::swroot}/ovpn/ccdroute2", \%ccdroute2hash);
2512 &writeserverconf;
2513
2514 # Update collectd configuration and delete all RRD files of the removed connection
2515 &writecollectdconf();
2516 &General::system("/usr/local/bin/openvpnctrl", "n2n", "delete", "$confighash{$cgiparams{'KEY'}}[1]");
2517
2518 delete $confighash{$cgiparams{'KEY'}};
2519 &General::system("/usr/bin/openssl", "ca", "-gencrl", "-out", "${General::swroot}/ovpn/crls/cacrl.pem", "-config", "/usr/share/openvpn/ovpn.cnf");
2520 &General::writehasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2521
2522 } else {
2523 $errormessage = $Lang::tr{'invalid key'};
2524 }
2525 &General::firewall_reload();
2526
2527 ###
2528 ### Download PKCS12 file
2529 ###
2530 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download pkcs12 file'}) {
2531 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2532
2533 print "Content-Disposition: filename=" . $confighash{$cgiparams{'KEY'}}[1] . ".p12\r\n";
2534 print "Content-Type: application/octet-stream\r\n\r\n";
2535
2536 open(FILE, "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
2537 my @tmp = <FILE>;
2538 close(FILE);
2539
2540 print @tmp;
2541 exit (0);
2542
2543 ###
2544 ### Display certificate
2545 ###
2546 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show certificate'}) {
2547 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2548
2549 if ( -f "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") {
2550 &Header::showhttpheaders();
2551 &Header::openpage($Lang::tr{'ovpn'}, 1, '');
2552 &Header::openbigbox('100%', 'LEFT', '', '');
2553 &Header::openbox('100%', 'LEFT', "$Lang::tr{'certificate'}:");
2554 my @output = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
2555 my $output = &Header::cleanhtml(join("", @output), "y");
2556 print "<pre>$output</pre>\n";
2557 &Header::closebox();
2558 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2559 &Header::closebigbox();
2560 &Header::closepage();
2561 exit(0);
2562 }
2563
2564 ###
2565 ### Display OTP QRCode
2566 ###
2567 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show otp qrcode'}) {
2568 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2569
2570 my $qrcode = Imager::QRCode->new(
2571 size => 6,
2572 margin => 0,
2573 version => 0,
2574 level => 'M',
2575 mode => '8-bit',
2576 casesensitive => 1,
2577 lightcolor => Imager::Color->new(255, 255, 255),
2578 darkcolor => Imager::Color->new(0, 0, 0),
2579 );
2580 my $cn = uri_encode($confighash{$cgiparams{'KEY'}}[2]);
2581 my $secret = encode_base32(pack('H*', $confighash{$cgiparams{'KEY'}}[44]));
2582 my $issuer = uri_encode("$mainsettings{'HOSTNAME'}.$mainsettings{'DOMAINNAME'}");
2583 my $qrcodeimg = $qrcode->plot("otpauth://totp/$cn?secret=$secret&issuer=$issuer");
2584 my $qrcodeimgdata;
2585 $qrcodeimg->write(data => \$qrcodeimgdata, type=> 'png')
2586 or die $qrcodeimg->errstr;
2587 $qrcodeimgdata = encode_base64($qrcodeimgdata, '');
2588
2589 &Header::showhttpheaders();
2590 &Header::openpage($Lang::tr{'ovpn'}, 1, '');
2591 &Header::openbigbox('100%', 'LEFT', '', '');
2592 &Header::openbox('100%', 'LEFT', "$Lang::tr{'otp qrcode'}:");
2593 print <<END;
2594 $Lang::tr{'secret'}:&nbsp;$secret</br></br>
2595 <img alt="$Lang::tr{'otp qrcode'}" src="data:image/png;base64,$qrcodeimgdata">
2596 END
2597 &Header::closebox();
2598 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2599 &Header::closebigbox();
2600 &Header::closepage();
2601 exit(0);
2602
2603 ###
2604 ### Display tls-auth key
2605 ###
2606 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show tls-auth key'}) {
2607
2608 if (! -e "${General::swroot}/ovpn/certs/ta.key") {
2609 $errormessage = $Lang::tr{'not present'};
2610 } else {
2611 &Header::showhttpheaders();
2612 &Header::openpage($Lang::tr{'ovpn'}, 1, '');
2613 &Header::openbigbox('100%', 'LEFT', '', '');
2614 &Header::openbox('100%', 'LEFT', "$Lang::tr{'ta key'}:");
2615
2616 open(FILE, "${General::swroot}/ovpn/certs/ta.key");
2617 my @output = <FILE>;
2618 close(FILE);
2619
2620 my $output = &Header::cleanhtml(join("", @output),"y");
2621 print "<pre>$output</pre>\n";
2622 &Header::closebox();
2623 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2624 &Header::closebigbox();
2625 &Header::closepage();
2626 exit(0);
2627 }
2628
2629 ###
2630 ### Display Certificate Revoke List
2631 ###
2632 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'show crl'}) {
2633 # &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2634
2635 if (! -e "${General::swroot}/ovpn/crls/cacrl.pem") {
2636 $errormessage = $Lang::tr{'not present'};
2637 } else {
2638 &Header::showhttpheaders();
2639 &Header::openpage($Lang::tr{'ovpn'}, 1, '');
2640 &Header::openbigbox('100%', 'LEFT', '', '');
2641 &Header::openbox('100%', 'LEFT', "$Lang::tr{'crl'}:");
2642 my @output = &General::system_output("/usr/bin/openssl", "crl", "-text", "-noout", "-in", "${General::swroot}/ovpn/crls/cacrl.pem");
2643 my $output = &Header::cleanhtml(join("", @output), "y");
2644 print "<pre>$output</pre>\n";
2645 &Header::closebox();
2646 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2647 &Header::closebigbox();
2648 &Header::closepage();
2649 exit(0);
2650 }
2651
2652 ###
2653 ### Advanced Server Settings
2654 ###
2655
2656 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'advanced server'}) {
2657 ADV_ERROR:
2658 $selected{'DPROTOCOL'}{'udp'} = '';
2659 $selected{'DPROTOCOL'}{'tcp'} = '';
2660 $selected{'DPROTOCOL'}{$vpnsettings{'DPROTOCOL'}} = 'SELECTED';
2661
2662 $checked{'REDIRECT_GW_DEF1'}{'off'} = '';
2663 $checked{'REDIRECT_GW_DEF1'}{'on'} = '';
2664 $checked{'REDIRECT_GW_DEF1'}{$vpnsettings{'REDIRECT_GW_DEF1'}} = 'CHECKED';
2665 $checked{'MSSFIX'}{'off'} = '';
2666 $checked{'MSSFIX'}{'on'} = '';
2667 $checked{'MSSFIX'}{$vpnsettings{'MSSFIX'}} = 'CHECKED';
2668
2669 # Split data ciphers
2670 my @data_ciphers = split(/\|/, $vpnsettings{'DATACIPHERS'});
2671
2672 # Select the correct ones
2673 $selected{'DATACIPHERS'} = ();
2674 foreach my $cipher (@SUPPORTED_CIPHERS) {
2675 $selected{'DATACIPHERS'}{$cipher} = grep(/^$cipher$/, @data_ciphers) ? "selected" : "";
2676 }
2677
2678 # Routes
2679 $vpnsettings{'ROUTES_PUSH'} =~ s/\|/\n/g;
2680
2681 $selected{'DCIPHER'}{'AES-256-GCM'} = '';
2682 $selected{'DCIPHER'}{'AES-192-GCM'} = '';
2683 $selected{'DCIPHER'}{'AES-128-GCM'} = '';
2684 $selected{'DCIPHER'}{'CAMELLIA-256-CBC'} = '';
2685 $selected{'DCIPHER'}{'CAMELLIA-192-CBC'} = '';
2686 $selected{'DCIPHER'}{'CAMELLIA-128-CBC'} = '';
2687 $selected{'DCIPHER'}{'AES-256-CBC'} = '';
2688 $selected{'DCIPHER'}{'AES-192-CBC'} = '';
2689 $selected{'DCIPHER'}{'AES-128-CBC'} = '';
2690 $selected{'DCIPHER'}{'DES-EDE3-CBC'} = '';
2691 $selected{'DCIPHER'}{'DESX-CBC'} = '';
2692 $selected{'DCIPHER'}{'SEED-CBC'} = '';
2693 $selected{'DCIPHER'}{'DES-EDE-CBC'} = '';
2694 $selected{'DCIPHER'}{'CAST5-CBC'} = '';
2695 $selected{'DCIPHER'}{'BF-CBC'} = '';
2696 $selected{'DCIPHER'}{'DES-CBC'} = '';
2697 $selected{'DCIPHER'}{$vpnsettings{'DCIPHER'}} = 'SELECTED';
2698
2699 $selected{'DAUTH'}{'whirlpool'} = '';
2700 $selected{'DAUTH'}{'SHA512'} = '';
2701 $selected{'DAUTH'}{'SHA384'} = '';
2702 $selected{'DAUTH'}{'SHA256'} = '';
2703 $selected{'DAUTH'}{'SHA1'} = '';
2704 $selected{'DAUTH'}{$vpnsettings{'DAUTH'}} = 'SELECTED';
2705
2706 $checked{'TLSAUTH'}{'off'} = '';
2707 $checked{'TLSAUTH'}{'on'} = '';
2708 $checked{'TLSAUTH'}{$vpnsettings{'TLSAUTH'}} = 'CHECKED';
2709
2710 &Header::showhttpheaders();
2711 &Header::openpage($Lang::tr{'status ovpn'}, 1, '');
2712 &Header::openbigbox('100%', 'LEFT', '', $errormessage);
2713
2714 # Show any errors
2715 &Header::errorbox($errormessage);
2716
2717 &Header::opensection();
2718
2719 print <<END;
2720 <form method='POST' enctype='multipart/form-data'>
2721 <h6>$Lang::tr{'ovpn protocol settings'}</h6>
2722
2723 <table class="form">
2724 <tr>
2725 <td>$Lang::tr{'ovpn transport protocol'}</td>
2726 <td>
2727 <select name='DPROTOCOL'>
2728 <option value='udp' $selected{'DPROTOCOL'}{'udp'}>UDP</option>
2729 <option value='tcp' $selected{'DPROTOCOL'}{'tcp'}>TCP</option>
2730 </select>
2731 </td>
2732 </tr>
2733
2734 <tr>
2735 <td>$Lang::tr{'destination port'}</td>
2736 <td>
2737 <input type='number' name='DDEST_PORT' value='$vpnsettings{'DDEST_PORT'}' />
2738 </td>
2739 </tr>
2740
2741 <tr>
2742 <td>$Lang::tr{'mtu'}</td>
2743 <td>
2744 <input type='number' name='DMTU' value='$vpnsettings{'DMTU'}' min="1280" max="9000" />
2745 </td>
2746 </tr>
2747
2748 <tr>
2749 <td>mssfix</td>
2750 <td>
2751 <input type='checkbox' name='MSSFIX' $checked{'MSSFIX'}{'on'} />
2752 </td>
2753 </tr>
2754
2755 <tr>
2756 <td>fragment</td>
2757 <td>
2758 <input type='TEXT' name='FRAGMENT' value='$vpnsettings{'FRAGMENT'}' />
2759 </td>
2760 </tr>
2761 </table>
2762
2763 <h6>$Lang::tr{'ovpn crypto settings'}</h6>
2764
2765 <table class="form">
2766 <tr>
2767 <td>
2768 $Lang::tr{'ovpn ciphers'}
2769 </td>
2770
2771 <td>
2772 <select name='DATACIPHERS' multiple required>
2773 END
2774
2775 foreach my $cipher (@SUPPORTED_CIPHERS) {
2776 my $name = $CIPHERS{$cipher} // $cipher;
2777
2778 print <<END;
2779 <option value='$cipher' $selected{'DATACIPHERS'}{$cipher}>
2780 $name
2781 </option>
2782 END
2783 }
2784
2785 print <<END;
2786 </select>
2787 </td>
2788 </tr>
2789
2790 <tr>
2791 <td>
2792 $Lang::tr{'ovpn ha'}
2793 </td>
2794
2795 <td>
2796 <select name='DAUTH'>
2797 <option value='whirlpool' $selected{'DAUTH'}{'whirlpool'}>Whirlpool (512 $Lang::tr{'bit'})</option>
2798 <option value='SHA512' $selected{'DAUTH'}{'SHA512'}>SHA2 (512 $Lang::tr{'bit'})</option>
2799 <option value='SHA384' $selected{'DAUTH'}{'SHA384'}>SHA2 (384 $Lang::tr{'bit'})</option>
2800 <option value='SHA256' $selected{'DAUTH'}{'SHA256'}>SHA2 (256 $Lang::tr{'bit'})</option>
2801 <option value='SHA1' $selected{'DAUTH'}{'SHA1'}>SHA1 (160 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2802 </select>
2803 </td>
2804 </tr>
2805
2806 <tr>
2807 <td>
2808 $Lang::tr{'ovpn tls auth'}
2809 </td>
2810
2811 <td>
2812 <input type='checkbox' name='TLSAUTH' $checked{'TLSAUTH'}{'on'} />
2813 </td>
2814 </tr>
2815
2816 <tr>
2817 <td>
2818 $Lang::tr{'ovpn fallback cipher'}
2819 </td>
2820
2821 <td>
2822 <select name='DCIPHER'>
2823 <option value='' $selected{'DCIPHER'}{''}>- $Lang::tr{'Disabled'} -</option>
2824 <option value='AES-256-GCM' $selected{'DCIPHER'}{'AES-256-GCM'}>AES-GCM (256 $Lang::tr{'bit'})</option>
2825 <option value='AES-192-GCM' $selected{'DCIPHER'}{'AES-192-GCM'}>AES-GCM (192 $Lang::tr{'bit'})</option>
2826 <option value='AES-128-GCM' $selected{'DCIPHER'}{'AES-128-GCM'}>AES-GCM (128 $Lang::tr{'bit'})</option>
2827 <option value='CAMELLIA-256-CBC' $selected{'DCIPHER'}{'CAMELLIA-256-CBC'}>CAMELLIA-CBC (256 $Lang::tr{'bit'})</option>
2828 <option value='CAMELLIA-192-CBC' $selected{'DCIPHER'}{'CAMELLIA-192-CBC'}>CAMELLIA-CBC (192 $Lang::tr{'bit'})</option>
2829 <option value='CAMELLIA-128-CBC' $selected{'DCIPHER'}{'CAMELLIA-128-CBC'}>CAMELLIA-CBC (128 $Lang::tr{'bit'})</option>
2830 <option value='AES-256-CBC' $selected{'DCIPHER'}{'AES-256-CBC'}>AES-CBC (256 $Lang::tr{'bit'})</option>
2831 <option value='AES-192-CBC' $selected{'DCIPHER'}{'AES-192-CBC'}>AES-CBC (192 $Lang::tr{'bit'})</option>
2832 <option value='AES-128-CBC' $selected{'DCIPHER'}{'AES-128-CBC'}>AES-CBC (128 $Lang::tr{'bit'})</option>
2833 <option value='SEED-CBC' $selected{'DCIPHER'}{'SEED-CBC'}>SEED-CBC (128 $Lang::tr{'bit'})</option>
2834 <option value='DES-EDE3-CBC' $selected{'DCIPHER'}{'DES-EDE3-CBC'}>DES-EDE3-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2835 <option value='DESX-CBC' $selected{'DCIPHER'}{'DESX-CBC'}>DESX-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2836 <option value='DES-EDE-CBC' $selected{'DCIPHER'}{'DES-EDE-CBC'}>DES-EDE-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2837 <option value='BF-CBC' $selected{'DCIPHER'}{'BF-CBC'}>BF-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2838 <option value='CAST5-CBC' $selected{'DCIPHER'}{'CAST5-CBC'}>CAST5-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2839 </select>
2840 </td>
2841 </tr>
2842
2843 <tr>
2844 <td></td>
2845 <td>
2846 $Lang::tr{'ovpn fallback cipher help'}
2847 </td>
2848 </tr>
2849 </table>
2850
2851 <h6>$Lang::tr{'ovpn dhcp settings'}</h6>
2852
2853 <table class="form">
2854 <tr>
2855 <td>Domain</td>
2856 <td>
2857 <input type='TEXT' name='DHCP_DOMAIN' value='$vpnsettings{'DHCP_DOMAIN'}' size='30' />
2858 </td>
2859 </tr>
2860 <tr>
2861 <td>DNS</td>
2862 <td>
2863 <input type='TEXT' name='DHCP_DNS' value='$vpnsettings{'DHCP_DNS'}' size='30' />
2864 </td>
2865 </tr>
2866 <tr>
2867 <td>WINS</td>
2868 <td>
2869 <input type='TEXT' name='DHCP_WINS' value='$vpnsettings{'DHCP_WINS'}' size='30' />
2870 </td>
2871 </tr>
2872 </table>
2873
2874 <h6>$Lang::tr{'ovpn routing settings'}</h6>
2875
2876 <table class="form">
2877 <tr>
2878 <td>$Lang::tr{'ovpn push default route'}</td>
2879 <td>
2880 <input type='checkbox' name='REDIRECT_GW_DEF1' $checked{'REDIRECT_GW_DEF1'}{'on'} />
2881 </td>
2882 </tr>
2883
2884 <tr>
2885 <td>$Lang::tr{'ovpn routes push'}</td>
2886 <td>
2887 <textarea name='ROUTES_PUSH' cols='26' rows='6' wrap='off'>$vpnsettings{'ROUTES_PUSH'}</textarea>
2888 </td>
2889 </tr>
2890 </table>
2891
2892 <h6>$Lang::tr{'ovpn misc settings'}</h6>
2893
2894 <table class="form">
2895 <tr>
2896 <td>Max-Clients</td>
2897 <td>
2898 <input type='text' name='MAX_CLIENTS' value='$vpnsettings{'MAX_CLIENTS'}' />
2899 </td>
2900 </tr>
2901
2902 <tr class="action">
2903 <td colspan="2">
2904 <input type='submit' name='ACTION' value='$Lang::tr{'save-adv-options'}' />
2905 <input type='submit' name='ACTION' value='$Lang::tr{'cancel-adv-options'}' />
2906 </td>
2907 </tr>
2908 </table>
2909 END
2910
2911 &Header::closesection();
2912 &Header::closebigbox();
2913
2914 &Header::closepage();
2915 exit(0);
2916
2917
2918 # Add, delete or edit CCD net
2919
2920 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'ccd net'} ||
2921 $cgiparams{'ACTION'} eq "ccd-add" ||
2922 $cgiparams{'ACTION'} eq "ccd-delete" ||
2923 $cgiparams{'ACTION'} eq "ccd-edit" ||
2924 $cgiparams{'ACTION'} eq 'ccd-edit-save'){
2925 &Header::showhttpheaders();
2926
2927 &Header::openpage($Lang::tr{'ccd net'}, 1, '');
2928
2929 &Header::openbigbox('100%', 'LEFT', '', '');
2930
2931 # Delete?
2932 if ($cgiparams{'ACTION'} eq "ccd-delete") {
2933 $errormessage = &delccdnet($cgiparams{'name'});
2934
2935 # Save after edit?
2936 } elsif ($cgiparams{'ACTION'} eq 'ccd-edit-save') {
2937 $errormessage = &modccdnet($cgiparams{'subnet'}, $cgiparams{'name'});
2938
2939 # Clear inputs
2940 if ($errormessage eq "") {
2941 $cgiparams{"name"} = "";
2942 $cgiparams{"subnet"} = "";
2943 }
2944
2945 # Add?
2946 } elsif ($cgiparams{'ACTION'} eq "ccd-add") {
2947 $errormessage = &addccdnet($cgiparams{'name'}, $cgiparams{'subnet'});
2948
2949 # Clear inputs
2950 if ($errormessage eq "") {
2951 $cgiparams{"name"} = "";
2952 $cgiparams{"subnet"} = "";
2953 }
2954 }
2955
2956 &Header::errorbox($errormessage);
2957
2958 my %ccdconfhash = ();
2959 &General::readhasharray("${General::swroot}/ovpn/ccd.conf", \%ccdconfhash);
2960
2961 &Header::opensection();
2962 print <<END;
2963 <table class="tbl">
2964 <tr>
2965 <th>
2966 $Lang::tr{'ccd name'}
2967 </th>
2968
2969 <th>
2970 $Lang::tr{'network'}
2971 </th>
2972
2973 <th>
2974 $Lang::tr{'ccd used'}
2975 </th>
2976
2977 <th colspan="2"></th>
2978 </tr>
2979 END
2980
2981 foreach my $key (sort { uc($ccdconfhash{$a}[0]) cmp uc($ccdconfhash{$b}[0]) } keys %ccdconfhash) {
2982 my $name = $ccdconfhash{$key}[0];
2983 my $subnet = $ccdconfhash{$key}[1];
2984
2985 my $ccdhosts = scalar &get_addresses_in_use($subnet);
2986 my $maxhosts = &ccdmaxclients($subnet);
2987
2988 print <<END;
2989 <tr>
2990 <th scope="row">
2991 $name
2992 </th>
2993
2994 <td class="text-center">
2995 $subnet
2996 </td>
2997
2998 <td class="text-center">
2999 ${ccdhosts}/${maxhosts}
3000 </td>
3001
3002 <td class="text-center">
3003 <form method='post' />
3004 <input type='image' src='/images/edit.gif' align='middle'
3005 alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
3006 <input type='hidden' name='ACTION' value='ccd-edit'/>
3007 <input type='hidden' name='name' value='$name' />
3008 <input type='hidden' name='subnet' value='$subnet' />
3009 </form>
3010 </td>
3011
3012 <td class="text-center">
3013 <form method='post' />
3014 <input type='hidden' name='ACTION' value='ccd-delete'/>
3015 <input type='hidden' name='name' value='$name' />
3016 <input type='image' src='/images/delete.gif' align='middle'
3017 alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
3018 </form>
3019 </td>
3020 </tr>
3021 END
3022 }
3023 print "</table>";
3024 &Header::closesection();
3025
3026 &Header::openbox('100%', 'LEFT',
3027 ($cgiparams{'ACTION'} eq "ccd-edit") ? $Lang::tr{'ccd modify'} : $Lang::tr{'ccd add'});
3028
3029 # The subnet cannot be edited
3030 my $readonly = ($cgiparams{'ACTION'} eq "ccd-edit") ? "readonly" : "";
3031 my $action = ($cgiparams{'ACTION'} eq "ccd-edit") ? "ccd-edit-save" : "ccd-add";
3032
3033 print <<END;
3034 <form method='post'>
3035 <table class="form">
3036 <tr>
3037 <td>$Lang::tr{'ccd name'}</td>
3038 <td>
3039 <input type='TEXT' name='name' value='$cgiparams{'name'}' />
3040 </td>
3041 </tr>
3042
3043 <tr>
3044 <td>$Lang::tr{'ccd subnet'}</td>
3045 <td>
3046 <input type='TEXT' name='subnet' value='$cgiparams{'subnet'}'
3047 $readonly />
3048 </td>
3049 </tr>
3050
3051 <tr class="action">
3052 <td colspan="2">
3053 <input type='hidden' name='ACTION' value='$action' />
3054 <input type='submit' value='$Lang::tr{'save'}' />
3055 </td>
3056 </tr>
3057 </table>
3058 </form>
3059 END
3060 &Header::closebox();
3061
3062 print <<END;
3063 <div class="text-center">
3064 <a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a>
3065 </div>
3066 END
3067
3068 &Header::closebigbox();
3069 &Header::closepage();
3070
3071 exit(0);
3072
3073 ###
3074 ### Openvpn Connections Statistics
3075 ###
3076 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'ovpn con stat'}) {
3077 &Header::showhttpheaders();
3078 &Header::openpage($Lang::tr{'ovpn con stat'}, 1, '');
3079 &Header::openbigbox('100%', 'LEFT', '', '');
3080
3081 &Header::opensection();
3082
3083 print <<END;
3084 <table class='tbl'>
3085 <tr>
3086 <th>$Lang::tr{'common name'}</th>
3087 <th>$Lang::tr{'real address'}</th>
3088 <th>$Lang::tr{'country'}</th>
3089 <th>$Lang::tr{'virtual address'}</th>
3090 <th>$Lang::tr{'loged in at'}</th>
3091 <th>$Lang::tr{'bytes sent'}</th>
3092 <th>$Lang::tr{'bytes received'}</th>
3093 <th>$Lang::tr{'last activity'}</th>
3094 </tr>
3095 END
3096
3097 open(FILE, "/usr/local/bin/openvpnctrl rw log |") or die "Unable to open $RW_STATUS: $!";
3098 my @current = <FILE>;
3099 close(FILE);
3100
3101 my @users = ();
3102 my $status;
3103 my $uid = 0;
3104 my @match = ();
3105 my %userlookup = ();
3106
3107 foreach my $line (@current) {
3108 chomp($line);
3109
3110 if ($line =~ /^Updated,(.+)/) {
3111 @match = split(/^Updated,(.+)/, $line);
3112 $status = $match[1];
3113
3114 } elsif ( $line =~ /^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/) {
3115 @match = split(m/^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/, $line);
3116
3117 # Skip the header
3118 next if ($match[1] eq "Common Name");
3119
3120 $userlookup{$match[2]} = $uid;
3121 $users[$uid]{'CommonName'} = $match[1];
3122 $users[$uid]{'RealAddress'} = $match[2];
3123 $users[$uid]{'BytesReceived'} = &General::formatBytes($match[3]);
3124 $users[$uid]{'BytesSent'} = &General::formatBytes($match[4]);
3125 $users[$uid]{'Since'} = $match[5];
3126
3127 my $address = (split ':', $users[$uid]{'RealAddress'})[0];
3128 $users[$uid]{'Country'} = &Location::Functions::lookup_country_code($address);
3129 $uid++;
3130
3131 } elsif ($line =~ /^(\d+\.\d+\.\d+\.\d+),(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(.+)/) {
3132 @match = split(m/^(\d+\.\d+\.\d+\.\d+),(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(.+)/, $line);
3133
3134 # Skip the header
3135 next if ($match[1] eq "Virtual Address");
3136
3137 my $address = $match[3];
3138 #find the uid in the lookup table
3139 $uid = $userlookup{$address};
3140 $users[$uid]{'VirtualAddress'} = $match[1];
3141 $users[$uid]{'LastRef'} = $match[4];
3142 }
3143 }
3144
3145 foreach my $id (keys @users) {
3146 my $user = $users[$id];
3147
3148 my $flag_icon = &Location::Functions::get_flag_icon($user->{"Country"});
3149
3150 print <<END;
3151 <tr>
3152 <th scope="row">
3153 $user->{"CommonName"}
3154 </th>
3155
3156 <td class="text-center">
3157 $user->{"RealAddress"}
3158 </td>
3159
3160 <td class="text-center">
3161 <a href="country.cgi#$user->{"Country"}">
3162 <img src="$flag_icon" border='0' align='absmiddle'
3163 alt='$user->{"Country"}' title='$user->{"Country"}' />
3164 </a>
3165 </td>
3166
3167 <td class="text-center">
3168 $user->{"VirtualAddress"}
3169 </td>
3170
3171 <td class="text-center">
3172 $user->{"Since"}
3173 </td>
3174
3175 <td class="text-right">
3176 $user->{"BytesSent"}
3177 </td>
3178
3179 <td class="text-right">
3180 $user->{"BytesReceived"}
3181 </td>
3182
3183 <td class="text-right">
3184 $user->{"LastRef"}
3185 </td>
3186 </tr>
3187 END
3188 }
3189
3190 print <<END;
3191 </table>
3192
3193 <p class="text-center">
3194 $Lang::tr{'the statistics were last updated at'} <b>$status</b>
3195 </p>
3196 END
3197 ;
3198
3199 &Header::closesection();
3200
3201 print <<END;
3202 <p class="text-center">
3203 <a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a>
3204 </p>
3205 END
3206
3207 &Header::closebigbox();
3208 &Header::closepage();
3209
3210 exit(0);
3211
3212 ###
3213 ### Download Certificate
3214 ###
3215 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'download certificate'}) {
3216 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
3217
3218 if ( -f "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") {
3219 print "Content-Disposition: filename=" . $confighash{$cgiparams{'KEY'}}[1] . "cert.pem\r\n";
3220 print "Content-Type: application/octet-stream\r\n\r\n";
3221
3222 open(FILE, "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
3223 my @tmp = <FILE>;
3224 close(FILE);
3225
3226 print @tmp;
3227 exit (0);
3228 }
3229
3230 ###
3231 ### Enable/Disable connection
3232 ###
3233
3234 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'toggle enable disable'}) {
3235 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
3236
3237 if ($confighash{$cgiparams{'KEY'}}) {
3238 if ($confighash{$cgiparams{'KEY'}}[0] eq 'off') {
3239 $confighash{$cgiparams{'KEY'}}[0] = 'on';
3240 &General::writehasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
3241 #&writeserverconf();
3242 # if ($vpnsettings{'ENABLED'} eq 'on' ||
3243 # $vpnsettings{'ENABLED_BLUE'} eq 'on') {
3244 # system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'});
3245 # }
3246 } else {
3247 $confighash{$cgiparams{'KEY'}}[0] = 'off';
3248 # if ($vpnsettings{'ENABLED'} eq 'on' ||
3249 # $vpnsettings{'ENABLED_BLUE'} eq 'on') {
3250 # system('/usr/local/bin/ipsecctrl', 'D', $cgiparams{'KEY'});
3251 # }
3252 &General::writehasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
3253 #&writeserverconf();
3254 }
3255 } else {
3256 $errormessage = $Lang::tr{'invalid key'};
3257 }
3258
3259 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'add'} && $cgiparams{'TYPE'} eq '') {
3260 &Header::showhttpheaders();
3261 &Header::openpage($Lang::tr{'ovpn'}, 1, '');
3262 &Header::openbigbox('100%', 'LEFT', '', '');
3263 &Header::openbox('100%', 'LEFT', $Lang::tr{'connection type'});
3264
3265 if ( -s "${General::swroot}/ovpn/settings") {
3266
3267 print <<END;
3268 <b>$Lang::tr{'connection type'}:</b><br />
3269 <table border='0' width='100%'><form method='post' ENCTYPE="multipart/form-data">
3270 <tr><td><input type='radio' name='TYPE' value='host' checked /></td>
3271 <td class='base'>$Lang::tr{'host to net vpn'}</td></tr>
3272 <tr><td><input type='radio' name='TYPE' value='net' /></td>
3273 <td class='base'>$Lang::tr{'net to net vpn'}</td></tr>
3274 <tr><td><input type='radio' name='TYPE' value='net2net' /></td>
3275 <td class='base'>$Lang::tr{'net to net vpn'} (Upload Client Package)</td></tr>
3276 <tr><td>&nbsp;</td><td class='base'><input type='file' name='FH' size='30'></td></tr>
3277 <tr><td>&nbsp;</td><td>Import Connection Name</td></tr>
3278 <tr><td>&nbsp;</td><td class='base'><input type='text' name='n2nname' size='30'>$Lang::tr{'openvpn default'}: Client Packagename</td></tr>
3279 <tr><td colspan='3'><hr /></td></tr>
3280 <tr><td align='right' colspan='3'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' /></td></tr>
3281 </form></table>
3282 END
3283 ;
3284
3285
3286 } else {
3287 print <<END;
3288 <b>$Lang::tr{'connection type'}:</b><br />
3289 <table border='0' width='100%'><form method='post' ENCTYPE="multipart/form-data">
3290 <tr><td><input type='radio' name='TYPE' value='host' checked /></td> <td class='base'>$Lang::tr{'host to net vpn'}</td></tr>
3291 <tr><td align='right' colspan'3'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' /></td></tr>
3292 </form></table>
3293 END
3294 ;
3295
3296 }
3297
3298 &Header::closebox();
3299 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
3300 &Header::closebigbox();
3301 &Header::closepage();
3302 exit (0);
3303
3304 } elsif (($cgiparams{'ACTION'} eq $Lang::tr{'add'}) && ($cgiparams{'TYPE'} eq 'net2net')){
3305
3306 my @firen2nconf;
3307 my @confdetails;
3308 my $uplconffilename ='';
3309 my $uplconffilename2 ='';
3310 my $uplp12name = '';
3311 my $uplp12name2 = '';
3312 my @rem_subnet;
3313 my @rem_subnet2;
3314 my @tmposupnet3;
3315 my $key;
3316 my @n2nname;
3317
3318 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
3319
3320 # Check if a file is uploaded
3321 unless (ref ($cgiparams{'FH'})) {
3322 $errormessage = $Lang::tr{'there was no file upload'};
3323 goto N2N_ERROR;
3324 }
3325
3326 # Move uploaded IPfire n2n package to temporary file
3327
3328 (my $fh, my $filename) = tempfile( );
3329 if (copy ($cgiparams{'FH'}, $fh) != 1) {
3330 $errormessage = $!;
3331 goto N2N_ERROR;
3332 }
3333
3334 my $zip = Archive::Zip->new();
3335 my $zipName = $filename;
3336 my $status = $zip->read( $zipName );
3337 if ($status != AZ_OK) {
3338 $errormessage = "Read of $zipName failed\n";
3339 goto N2N_ERROR;
3340 }
3341
3342 my $tempdir = tempdir( CLEANUP => 1 );
3343 my @files = $zip->memberNames();
3344 for(@files) {
3345 $zip->extractMemberWithoutPaths($_,"$tempdir/$_");
3346 }
3347 my $countfiles = @files;
3348
3349 # Check if we have not more then 2 files
3350
3351 if ( $countfiles == 2){
3352 foreach (@files){
3353 if ( $_ =~ /.conf$/){
3354 $uplconffilename = $_;
3355 }
3356 if ( $_ =~ /.p12$/){
3357 $uplp12name = $_;
3358 }
3359 }
3360 if (($uplconffilename eq '') || ($uplp12name eq '')){
3361 $errormessage = "Either no *.conf or no *.p12 file found\n";
3362 goto N2N_ERROR;
3363 }
3364
3365 open(FILE, "$tempdir/$uplconffilename") or die 'Unable to open*.conf file';
3366 @firen2nconf = <FILE>;
3367 close (FILE);
3368 chomp(@firen2nconf);
3369 } else {
3370
3371 $errormessage = "Filecount does not match only 2 files are allowed\n";
3372 goto N2N_ERROR;
3373 }
3374
3375 if ($cgiparams{'n2nname'} ne ''){
3376
3377 $uplconffilename2 = "$cgiparams{'n2nname'}.conf";
3378 $uplp12name2 = "$cgiparams{'n2nname'}.p12";
3379 $n2nname[0] = $cgiparams{'n2nname'};
3380 my @n2nname2 = split(/\./,$uplconffilename);
3381 $n2nname2[0] =~ s/\n|\r//g;
3382 my $input1 = "${General::swroot}/ovpn/certs/$uplp12name";
3383 my $output1 = "${General::swroot}/ovpn/certs/$uplp12name2";
3384 my $input2 = "$n2nname2[0]n2n";
3385 my $output2 = "$n2nname[0]n2n";
3386 my $filename = "$tempdir/$uplconffilename";
3387 open(FILE, "< $filename") or die 'Unable to open config file.';
3388 my @current = <FILE>;
3389 close(FILE);
3390 foreach (@current) {s/$input1/$output1/g;}
3391 foreach (@current) {s/$input2/$output2/g;}
3392 open (OUT, "> $filename") || die 'Unable to open config file.';
3393 print OUT @current;
3394 close OUT;
3395
3396 }else{
3397 $uplconffilename2 = $uplconffilename;
3398 $uplp12name2 = $uplp12name;
3399 @n2nname = split(/\./,$uplconffilename);
3400 $n2nname[0] =~ s/\n|\r//g;
3401 }
3402 unless(-d "${General::swroot}/ovpn/n2nconf/"){mkdir "${General::swroot}/ovpn/n2nconf", 0755 or die "Unable to create dir $!";}
3403 unless(-d "${General::swroot}/ovpn/n2nconf/$n2nname[0]"){mkdir "${General::swroot}/ovpn/n2nconf/$n2nname[0]", 0770 or die "Unable to create dir $!";}
3404
3405 #Add collectd settings to configfile
3406 open(FILE, ">> $tempdir/$uplconffilename") or die 'Unable to open config file.';
3407 print FILE "# Logfile\n";
3408 print FILE "status-version 1\n";
3409 print FILE "status /var/run/openvpn/$n2nname[0]-n2n 10\n";
3410 if (&iscertlegacy("${General::swroot}/ovpn/certs/$cgiparams{'n2nname'}")) {
3411 print CLIENTCONF "providers legacy default\n";
3412 }
3413
3414 close FILE;
3415
3416 unless(move("$tempdir/$uplconffilename", "${General::swroot}/ovpn/n2nconf/$n2nname[0]/$uplconffilename2")) {
3417 $errormessage = "*.conf move failed: $!";
3418 unlink ($filename);
3419 goto N2N_ERROR;
3420 }
3421
3422 unless(move("$tempdir/$uplp12name", "${General::swroot}/ovpn/certs/$uplp12name2")) {
3423 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
3424 unlink ($filename);
3425 goto N2N_ERROR;
3426 }
3427
3428 chmod 0600, "${General::swroot}/ovpn/certs/$uplp12name";
3429
3430 my $complzoactive;
3431 my $mssfixactive;
3432 my $authactive;
3433 my $n2nfragment;
3434 my @n2nproto2 = split(/ /, (grep { /^proto/ } @firen2nconf)[0]);
3435 my @n2nproto = split(/-/, $n2nproto2[1]);
3436 my @n2nport = split(/ /, (grep { /^port/ } @firen2nconf)[0]);
3437 my @n2ntunmtu = split(/ /, (grep { /^tun-mtu/ } @firen2nconf)[0]);
3438 my @n2ncomplzo = grep { /^comp-lzo/ } @firen2nconf;
3439 if ($n2ncomplzo[0] =~ /comp-lzo/){$complzoactive = "on";} else {$complzoactive = "off";}
3440 my @n2nmssfix = grep { /^mssfix/ } @firen2nconf;
3441 if ($n2nmssfix[0] =~ /mssfix/){$mssfixactive = "on";} else {$mssfixactive = "off";}
3442 #my @n2nmssfix = split(/ /, (grep { /^mssfix/ } @firen2nconf)[0]);
3443 my @n2nfragment = split(/ /, (grep { /^fragment/ } @firen2nconf)[0]);
3444 my @n2nremote = split(/ /, (grep { /^remote/ } @firen2nconf)[0]);
3445 my @n2novpnsuball = split(/ /, (grep { /^ifconfig/ } @firen2nconf)[0]);
3446 my @n2novpnsub = split(/\./,$n2novpnsuball[1]);
3447 my @n2nremsub = split(/ /, (grep { /^route/ } @firen2nconf)[0]);
3448 my @n2nmgmt = split(/ /, (grep { /^management/ } @firen2nconf)[0]);
3449 my @n2nlocalsub = split(/ /, (grep { /^# remsub/ } @firen2nconf)[0]);
3450 my @n2ncipher = split(/ /, (grep { /^cipher/ } @firen2nconf)[0]);
3451 my @n2nauth = split(/ /, (grep { /^auth/ } @firen2nconf)[0]);;
3452
3453 ###
3454 # m.a.d delete CR and LF from arrays for this chomp doesnt work
3455 ###
3456
3457 $n2nremote[1] =~ s/\n|\r//g;
3458 $n2novpnsub[0] =~ s/\n|\r//g;
3459 $n2novpnsub[1] =~ s/\n|\r//g;
3460 $n2novpnsub[2] =~ s/\n|\r//g;
3461 $n2nproto[0] =~ s/\n|\r//g;
3462 $n2nport[1] =~ s/\n|\r//g;
3463 $n2ntunmtu[1] =~ s/\n|\r//g;
3464 $n2nremsub[1] =~ s/\n|\r//g;
3465 $n2nremsub[2] =~ s/\n|\r//g;
3466 $n2nlocalsub[2] =~ s/\n|\r//g;
3467 $n2nfragment[1] =~ s/\n|\r//g;
3468 $n2nmgmt[2] =~ s/\n|\r//g;
3469 $n2ncipher[1] =~ s/\n|\r//g;
3470 $n2nauth[1] =~ s/\n|\r//g;
3471 chomp ($complzoactive);
3472 chomp ($mssfixactive);
3473
3474 ###
3475 # Check if there is no other entry with this name
3476 ###
3477
3478 foreach my $dkey (keys %confighash) {
3479 if ($confighash{$dkey}[1] eq $n2nname[0]) {
3480 $errormessage = $Lang::tr{'a connection with this name already exists'};
3481 unlink ("${General::swroot}/ovpn/n2nconf/$n2nname[0]/$n2nname[0].conf") or die "Removing Configfile fail: $!";
3482 unlink ("${General::swroot}/ovpn/certs/$n2nname[0].p12") or die "Removing Certfile fail: $!";
3483 rmdir ("${General::swroot}/ovpn/n2nconf/$n2nname[0]") || die "Removing Directory fail: $!";
3484 goto N2N_ERROR;
3485 }
3486 }
3487
3488 ###
3489 # Check if OpenVPN Subnet is valid
3490 ###
3491
3492 foreach my $dkey (keys %confighash) {
3493 if ($confighash{$dkey}[27] eq "$n2novpnsub[0].$n2novpnsub[1].$n2novpnsub[2].0/255.255.255.0") {
3494 $errormessage = 'The OpenVPN Subnet is already in use';
3495 unlink ("${General::swroot}/ovpn/n2nconf/$n2nname[0]/$n2nname[0].conf") or die "Removing Configfile fail: $!";
3496 unlink ("${General::swroot}/ovpn/certs/$n2nname[0].p12") or die "Removing Certfile fail: $!";
3497 rmdir ("${General::swroot}/ovpn/n2nconf/$n2nname[0]") || die "Removing Directory fail: $!";
3498 goto N2N_ERROR;
3499 }
3500 }
3501
3502 ###
3503 # Check if Dest Port is vaild
3504 ###
3505
3506 foreach my $dkey (keys %confighash) {
3507 if ($confighash{$dkey}[29] eq $n2nport[1] ) {
3508 $errormessage = 'The OpenVPN Port is already in use';
3509 unlink ("${General::swroot}/ovpn/n2nconf/$n2nname[0]/$n2nname[0].conf") or die "Removing Configfile fail: $!";
3510 unlink ("${General::swroot}/ovpn/certs/$n2nname[0].p12") or die "Removing Certfile fail: $!";
3511 rmdir ("${General::swroot}/ovpn/n2nconf/$n2nname[0]") || die "Removing Directory fail: $!";
3512 goto N2N_ERROR;
3513 }
3514 }
3515
3516
3517
3518 $key = &General::findhasharraykey (\%confighash);
3519
3520 foreach my $i (0 .. 42) { $confighash{$key}[$i] = "";}
3521
3522 $confighash{$key}[0] = 'off';
3523 $confighash{$key}[1] = $n2nname[0];
3524 $confighash{$key}[2] = $n2nname[0];
3525 $confighash{$key}[3] = 'net';
3526 $confighash{$key}[4] = 'cert';
3527 $confighash{$key}[6] = 'client';
3528 $confighash{$key}[8] = $n2nlocalsub[2];
3529 $confighash{$key}[10] = $n2nremote[1];
3530 $confighash{$key}[11] = "$n2nremsub[1]/$n2nremsub[2]";
3531 $confighash{$key}[22] = $n2nmgmt[2];
3532 $confighash{$key}[23] = $mssfixactive;
3533 $confighash{$key}[24] = $n2nfragment[1];
3534 $confighash{$key}[25] = 'IPFire n2n Client';
3535 $confighash{$key}[26] = 'red';
3536 $confighash{$key}[27] = "$n2novpnsub[0].$n2novpnsub[1].$n2novpnsub[2].0/255.255.255.0";
3537 $confighash{$key}[28] = $n2nproto[0];
3538 $confighash{$key}[29] = $n2nport[1];
3539 $confighash{$key}[30] = $complzoactive;
3540 $confighash{$key}[31] = $n2ntunmtu[1];
3541 $confighash{$key}[39] = $n2nauth[1];
3542 $confighash{$key}[40] = $n2ncipher[1];
3543 $confighash{$key}[41] = 'no-pass';
3544
3545 &General::writehasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
3546
3547 N2N_ERROR:
3548
3549 &Header::showhttpheaders();
3550 &Header::openpage('Validate imported configuration', 1, '');
3551 &Header::openbigbox('100%', 'LEFT', '', $errormessage);
3552 if ($errormessage) {
3553 &Header::openbox('100%', 'LEFT', $Lang::tr{'error messages'});
3554 print "<class name='base'>$errormessage";
3555 print "&nbsp;</class>";
3556 &Header::closebox();
3557
3558 } else
3559 {
3560 &Header::openbox('100%', 'LEFT', 'import ipfire net2net config');
3561 }
3562 if ($errormessage eq ''){
3563 print <<END;
3564 <!-- ipfire net2net config gui -->
3565 <table width='100%'>
3566 <tr><td width='25%'>&nbsp;</td><td width='25%'>&nbsp;</td></tr>
3567 <tr><td class='boldbase'>$Lang::tr{'name'}:</td><td><b>$n2nname[0]</b></td></tr>
3568 <tr><td>&nbsp;</td><td>&nbsp;</td></tr>
3569 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'Act as'}</td><td><b>$confighash{$key}[6]</b></td></tr>
3570 <tr><td class='boldbase' nowrap='nowrap'>Remote Host </td><td><b>$confighash{$key}[10]</b></td></tr>
3571 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'local subnet'}</td><td><b>$confighash{$key}[8]</b></td></tr>
3572 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'remote subnet'}:</td><td><b>$confighash{$key}[11]</b></td></tr>
3573 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'ovpn subnet'}</td><td><b>$confighash{$key}[27]</b></td></tr>
3574 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'protocol'}</td><td><b>$confighash{$key}[28]</b></td></tr>
3575 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'destination port'}:</td><td><b>$confighash{$key}[29]</b></td></tr>
3576 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'comp-lzo'}</td><td><b>$confighash{$key}[30]</b></td></tr>
3577 <tr><td class='boldbase' nowrap='nowrap'>MSSFIX:</td><td><b>$confighash{$key}[23]</b></td></tr>
3578 <tr><td class='boldbase' nowrap='nowrap'>Fragment:</td><td><b>$confighash{$key}[24]</b></td></tr>
3579 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'MTU'}</td><td><b>$confighash{$key}[31]</b></td></tr>
3580 <tr><td class='boldbase' nowrap='nowrap'>Management Port </td><td><b>$confighash{$key}[22]</b></td></tr>
3581 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'ovpn tls auth'}:</td><td><b>$confighash{$key}[39]</b></td></tr>
3582 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'cipher'}</td><td><b>$confighash{$key}[40]</b></td></tr>
3583 <tr><td>&nbsp;</td><td>&nbsp;</td></tr>
3584 </table>
3585 END
3586 ;
3587 &Header::closebox();
3588 }
3589
3590 if ($errormessage) {
3591 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
3592 } else {
3593 print "<div align='center'><form method='post' ENCTYPE='multipart/form-data'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' />";
3594 print "<input type='hidden' name='TYPE' value='net2netakn' />";
3595 print "<input type='hidden' name='KEY' value='$key' />";
3596 print "<input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></div></form>";
3597 }
3598 &Header::closebigbox();
3599 &Header::closepage();
3600 exit(0);
3601
3602
3603 ##
3604 ### Accept IPFire n2n Package Settings
3605 ###
3606
3607 } elsif (($cgiparams{'ACTION'} eq $Lang::tr{'add'}) && ($cgiparams{'TYPE'} eq 'net2netakn')){
3608
3609 ###
3610 ### Discard and Rollback IPFire n2n Package Settings
3611 ###
3612
3613 } elsif (($cgiparams{'ACTION'} eq $Lang::tr{'cancel'}) && ($cgiparams{'TYPE'} eq 'net2netakn')){
3614
3615 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
3616
3617 if ($confighash{$cgiparams{'KEY'}}) {
3618
3619 my $conffile = glob("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]/$confighash{$cgiparams{'KEY'}}[1].conf");
3620 my $certfile = glob("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
3621 unlink ($certfile) or die "Removing $certfile fail: $!";
3622 unlink ($conffile) or die "Removing $conffile fail: $!";
3623 rmdir ("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]") || die "Kann Verzeichnis nicht loeschen: $!";
3624 delete $confighash{$cgiparams{'KEY'}};
3625 &General::writehasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
3626
3627 } else {
3628 $errormessage = $Lang::tr{'invalid key'};
3629 }
3630
3631 ###
3632 ### Adding a new connection
3633 ###
3634 } elsif (($cgiparams{'ACTION'} eq $Lang::tr{'add'}) ||
3635 ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}) ||
3636 ($cgiparams{'ACTION'} eq $Lang::tr{'save'} && $cgiparams{'ADVANCED'} eq '')) {
3637 &General::readhasharray("${General::swroot}/ovpn/caconfig", \%cahash);
3638 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
3639
3640 if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}) {
3641 if (! $confighash{$cgiparams{'KEY'}}[0]) {
3642 $errormessage = $Lang::tr{'invalid key'};
3643 goto VPNCONF_END;
3644 }
3645 $cgiparams{'ENABLED'} = $confighash{$cgiparams{'KEY'}}[0];
3646 $cgiparams{'NAME'} = $confighash{$cgiparams{'KEY'}}[1];
3647 $cgiparams{'TYPE'} = $confighash{$cgiparams{'KEY'}}[3];
3648 $cgiparams{'AUTH'} = $confighash{$cgiparams{'KEY'}}[4];
3649 $cgiparams{'PSK'} = $confighash{$cgiparams{'KEY'}}[5];
3650 $cgiparams{'SIDE'} = $confighash{$cgiparams{'KEY'}}[6];
3651 $cgiparams{'LOCAL_SUBNET'} = $confighash{$cgiparams{'KEY'}}[8];
3652 $cgiparams{'REMOTE'} = $confighash{$cgiparams{'KEY'}}[10];
3653 $cgiparams{'REMOTE_SUBNET'} = $confighash{$cgiparams{'KEY'}}[11];
3654 $cgiparams{'OVPN_MGMT'} = $confighash{$cgiparams{'KEY'}}[22];
3655 $cgiparams{'MSSFIX'} = $confighash{$cgiparams{'KEY'}}[23];
3656 $cgiparams{'FRAGMENT'} = $confighash{$cgiparams{'KEY'}}[24];
3657 $cgiparams{'REMARK'} = $confighash{$cgiparams{'KEY'}}[25];
3658 $cgiparams{'INTERFACE'} = $confighash{$cgiparams{'KEY'}}[26];
3659 $cgiparams{'OVPN_SUBNET'} = $confighash{$cgiparams{'KEY'}}[27];
3660 $cgiparams{'PROTOCOL'} = $confighash{$cgiparams{'KEY'}}[28];
3661 $cgiparams{'DEST_PORT'} = $confighash{$cgiparams{'KEY'}}[29];
3662 $cgiparams{'COMPLZO'} = $confighash{$cgiparams{'KEY'}}[30];
3663 $cgiparams{'MTU'} = $confighash{$cgiparams{'KEY'}}[31];
3664 $cgiparams{'CHECK1'} = $confighash{$cgiparams{'KEY'}}[32];
3665 $name=$cgiparams{'CHECK1'} ;
3666 $cgiparams{$name} = $confighash{$cgiparams{'KEY'}}[33];
3667 $cgiparams{'RG'} = $confighash{$cgiparams{'KEY'}}[34];
3668 $cgiparams{'CCD_DNS1'} = $confighash{$cgiparams{'KEY'}}[35];
3669 $cgiparams{'CCD_DNS2'} = $confighash{$cgiparams{'KEY'}}[36];
3670 $cgiparams{'CCD_WINS'} = $confighash{$cgiparams{'KEY'}}[37];
3671 $cgiparams{'DAUTH'} = $confighash{$cgiparams{'KEY'}}[39];
3672 $cgiparams{'DCIPHER'} = $confighash{$cgiparams{'KEY'}}[40];
3673 $cgiparams{'TLSAUTH'} = $confighash{$cgiparams{'KEY'}}[41];
3674 $cgiparams{'OTP_STATE'} = $confighash{$cgiparams{'KEY'}}[43];
3675 } elsif ($cgiparams{'ACTION'} eq $Lang::tr{'save'}) {
3676 $cgiparams{'REMARK'} = &Header::cleanhtml($cgiparams{'REMARK'});
3677
3678 # CCD check iroute field and convert it to decimal
3679 if ($cgiparams{'TYPE'} eq 'host') {
3680 my @temp=();
3681 my %ccdroutehash=();
3682 my $keypoint=0;
3683 my $ip;
3684 my $cidr;
3685 if ($cgiparams{'IR'} ne ''){
3686 @temp = split("\n",$cgiparams{'IR'});
3687 &General::readhasharray("${General::swroot}/ovpn/ccdroute", \%ccdroutehash);
3688 #find key to use
3689 foreach my $key (keys %ccdroutehash) {
3690 if ($ccdroutehash{$key}[0] eq $cgiparams{'NAME'}) {
3691 $keypoint=$key;
3692 delete $ccdroutehash{$key};
3693 }else{
3694 $keypoint = &General::findhasharraykey (\%ccdroutehash);
3695 }
3696 }
3697 $ccdroutehash{$keypoint}[0]=$cgiparams{'NAME'};
3698 my $i=1;
3699 my $val=0;
3700 foreach $val (@temp){
3701 chomp($val);
3702 $val=~s/\s*$//g;
3703 #check if iroute exists in ccdroute or if new iroute is part of an existing one
3704 foreach my $key (keys %ccdroutehash) {
3705 foreach my $oldiroute ( 1 .. $#{$ccdroutehash{$key}}){
3706 if ($ccdroutehash{$key}[$oldiroute] eq "$val") {
3707 $errormessage=$errormessage.$Lang::tr{'ccd err irouteexist'};
3708 goto VPNCONF_ERROR;
3709 }
3710 my ($ip1,$cidr1) = split (/\//, $val);
3711 $ip1 = &General::getnetworkip($ip1,&General::iporsubtocidr($cidr1));
3712 my ($ip2,$cidr2) = split (/\//, $ccdroutehash{$key}[$oldiroute]);
3713 if (&General::IpInSubnet ($ip1,$ip2,$cidr2)){
3714 $errormessage=$errormessage.$Lang::tr{'ccd err irouteexist'};
3715 goto VPNCONF_ERROR;
3716 }
3717
3718 }
3719 }
3720 if (!&General::validipandmask($val)){
3721 $errormessage=$errormessage."Route ".$Lang::tr{'ccd invalid'}." ($val)";
3722 goto VPNCONF_ERROR;
3723 }else{
3724 ($ip,$cidr) = split(/\//,$val);
3725 $ip=&General::getnetworkip($ip,&General::iporsubtocidr($cidr));
3726 $cidr=&General::iporsubtodec($cidr);
3727 $ccdroutehash{$keypoint}[$i] = $ip."/".$cidr;
3728
3729 }
3730
3731 #check for existing network IP's
3732 if (&General::IpInSubnet ($ip,$Network::ethernet{GREEN_NETADDRESS},$Network::ethernet{GREEN_NETMASK}) && $Network::ethernet{GREEN_NETADDRESS} ne '0.0.0.0')
3733 {
3734 $errormessage=$Lang::tr{'ccd err green'};
3735 goto VPNCONF_ERROR;
3736 }elsif(&General::IpInSubnet ($ip,$Network::ethernet{RED_NETADDRESS},$Network::ethernet{RED_NETMASK}) && $Network::ethernet{RED_NETADDRESS} ne '0.0.0.0')
3737 {
3738 $errormessage=$Lang::tr{'ccd err red'};
3739 goto VPNCONF_ERROR;
3740 }elsif(&General::IpInSubnet ($ip,$Network::ethernet{BLUE_NETADDRESS},$Network::ethernet{BLUE_NETMASK}) && $Network::ethernet{BLUE_NETADDRESS} ne '0.0.0.0' && $Network::ethernet{BLUE_NETADDRESS} gt '')
3741 {
3742 $errormessage=$Lang::tr{'ccd err blue'};
3743 goto VPNCONF_ERROR;
3744 }elsif(&General::IpInSubnet ($ip,$Network::ethernet{ORANGE_NETADDRESS},$Network::ethernet{ORANGE_NETMASK}) && $Network::ethernet{ORANGE_NETADDRESS} ne '0.0.0.0' && $Network::ethernet{ORANGE_NETADDRESS} gt '' )
3745 {
3746 $errormessage=$Lang::tr{'ccd err orange'};
3747 goto VPNCONF_ERROR;
3748 }
3749
3750 if (&General::validipandmask($val)){
3751 $ccdroutehash{$keypoint}[$i] = $ip."/".$cidr;
3752 }else{
3753 $errormessage=$errormessage."Route ".$Lang::tr{'ccd invalid'}." ($ip/$cidr)";
3754 goto VPNCONF_ERROR;
3755 }
3756 $i++;
3757 }
3758 &General::writehasharray("${General::swroot}/ovpn/ccdroute", \%ccdroutehash);
3759 &writeserverconf;
3760 }else{
3761 &General::readhasharray("${General::swroot}/ovpn/ccdroute", \%ccdroutehash);
3762 foreach my $key (keys %ccdroutehash) {
3763 if ($ccdroutehash{$key}[0] eq $cgiparams{'NAME'}) {
3764 delete $ccdroutehash{$key};
3765 &General::writehasharray("${General::swroot}/ovpn/ccdroute", \%ccdroutehash);
3766 &writeserverconf;
3767 }
3768 }
3769 }
3770 undef @temp;
3771 #check route field and convert it to decimal
3772 my $val=0;
3773 my $i=1;
3774 &General::readhasharray("${General::swroot}/ovpn/ccdroute2", \%ccdroute2hash);
3775 #find key to use
3776 foreach my $key (keys %ccdroute2hash) {
3777 if ($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}) {
3778 $keypoint=$key;
3779 delete $ccdroute2hash{$key};
3780 }else{
3781 $keypoint = &General::findhasharraykey (\%ccdroute2hash);
3782 &General::writehasharray("${General::swroot}/ovpn/ccdroute", \%ccdroutehash);
3783 &writeserverconf;
3784 }
3785 }
3786 $ccdroute2hash{$keypoint}[0]=$cgiparams{'NAME'};
3787 if ($cgiparams{'IFROUTE'} eq ''){$cgiparams{'IFROUTE'} = $Lang::tr{'ccd none'};}
3788 @temp = split(/\|/,$cgiparams{'IFROUTE'});
3789 foreach $val (@temp){
3790 chomp($val);
3791 $val=~s/\s*$//g;
3792 if ($val eq $Lang::tr{'green'})
3793 {
3794 $val=$Network::ethernet{GREEN_NETADDRESS}."/".$Network::ethernet{GREEN_NETMASK};
3795 }
3796 if ($val eq $Lang::tr{'blue'})
3797 {
3798 $val=$Network::ethernet{BLUE_NETADDRESS}."/".$Network::ethernet{BLUE_NETMASK};
3799 }
3800 if ($val eq $Lang::tr{'orange'})
3801 {
3802 $val=$Network::ethernet{ORANGE_NETADDRESS}."/".$Network::ethernet{ORANGE_NETMASK};
3803 }
3804 my ($ip,$cidr) = split (/\//, $val);
3805
3806 if ($val ne $Lang::tr{'ccd none'})
3807 {
3808 if (! &check_routes_push($val)){$errormessage=$errormessage."Route $val ".$Lang::tr{'ccd err routeovpn2'}." ($val)";goto VPNCONF_ERROR;}
3809 if (! &check_ccdroute($val)){$errormessage=$errormessage."<br>Route $val ".$Lang::tr{'ccd err inuse'}." ($val)" ;goto VPNCONF_ERROR;}
3810 if (! &check_ccdconf($val)){$errormessage=$errormessage."<br>Route $val ".$Lang::tr{'ccd err routeovpn'}." ($val)";goto VPNCONF_ERROR;}
3811 if (&General::validipandmask($val)){
3812 $val=$ip."/".&General::iporsubtodec($cidr);
3813 $ccdroute2hash{$keypoint}[$i] = $val;
3814 }else{
3815 $errormessage=$errormessage."Route ".$Lang::tr{'ccd invalid'}." ($val)";
3816 goto VPNCONF_ERROR;
3817 }
3818 }else{
3819 $ccdroute2hash{$keypoint}[$i]='';
3820 }
3821 $i++;
3822 }
3823 &General::writehasharray("${General::swroot}/ovpn/ccdroute2", \%ccdroute2hash);
3824
3825 #check dns1 ip
3826 if ($cgiparams{'CCD_DNS1'} ne '' && ! &General::validip($cgiparams{'CCD_DNS1'})) {
3827 $errormessage=$errormessage."<br>".$Lang::tr{'invalid input for dhcp dns'}." 1";
3828 goto VPNCONF_ERROR;
3829 }
3830 #check dns2 ip
3831 if ($cgiparams{'CCD_DNS2'} ne '' && ! &General::validip($cgiparams{'CCD_DNS2'})) {
3832 $errormessage=$errormessage."<br>".$Lang::tr{'invalid input for dhcp dns'}." 2";
3833 goto VPNCONF_ERROR;
3834 }
3835 #check wins ip
3836 if ($cgiparams{'CCD_WINS'} ne '' && ! &General::validip($cgiparams{'CCD_WINS'})) {
3837 $errormessage=$errormessage."<br>".$Lang::tr{'invalid input for dhcp wins'};
3838 goto VPNCONF_ERROR;
3839 }
3840 }
3841
3842 if ($cgiparams{'TYPE'} !~ /^(host|net)$/) {
3843 $errormessage = $Lang::tr{'connection type is invalid'};
3844 if ($cgiparams{'TYPE'} eq 'net') {
3845 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3846 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3847 goto VPNCONF_ERROR;
3848 }
3849 goto VPNCONF_ERROR;
3850 }
3851
3852 if ($cgiparams{'NAME'} !~ /^[a-zA-Z0-9]+$/) {
3853 $errormessage = $Lang::tr{'name must only contain characters'};
3854 if ($cgiparams{'TYPE'} eq 'net') {
3855 goto VPNCONF_ERROR;
3856 }
3857 goto VPNCONF_ERROR;
3858 }
3859
3860 if ($cgiparams{'NAME'} =~ /^(host|01|block|private|clear|packetdefault)$/) {
3861 $errormessage = $Lang::tr{'name is invalid'};
3862 if ($cgiparams{'TYPE'} eq 'net') {
3863 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3864 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3865 goto VPNCONF_ERROR;
3866 }
3867 goto VPNCONF_ERROR;
3868 }
3869
3870 if (length($cgiparams{'NAME'}) >60) {
3871 $errormessage = $Lang::tr{'name too long'};
3872 if ($cgiparams{'TYPE'} eq 'net') {
3873 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3874 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3875 goto VPNCONF_ERROR;
3876 }
3877 goto VPNCONF_ERROR;
3878 }
3879
3880 if ($cgiparams{'TYPE'} eq 'net') {
3881 if ($cgiparams{'DEST_PORT'} eq $vpnsettings{'DDEST_PORT'}) {
3882 $errormessage = $Lang::tr{'openvpn destination port used'};
3883 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3884 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3885 goto VPNCONF_ERROR;
3886 }
3887 #Bugfix 10357
3888 foreach my $key (sort keys %confighash){
3889 if ( ($confighash{$key}[22] eq $cgiparams{'DEST_PORT'} && $cgiparams{'NAME'} ne $confighash{$key}[1]) || ($confighash{$key}[29] eq $cgiparams{'DEST_PORT'} && $cgiparams{'NAME'} ne $confighash{$key}[1])){
3890 $errormessage = $Lang::tr{'openvpn destination port used'};
3891 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3892 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3893 goto VPNCONF_ERROR;
3894 }
3895 }
3896 if ($cgiparams{'DEST_PORT'} eq '') {
3897 $errormessage = $Lang::tr{'invalid port'};
3898 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3899 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3900 goto VPNCONF_ERROR;
3901 }
3902
3903 # Check if the input for the transfer net is valid.
3904 if (!&General::validipandmask($cgiparams{'OVPN_SUBNET'})){
3905 $errormessage = $Lang::tr{'ccd err invalidnet'};
3906 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3907 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3908 goto VPNCONF_ERROR;
3909 }
3910
3911 if ($cgiparams{'OVPN_SUBNET'} eq $vpnsettings{'DOVPN_SUBNET'}) {
3912 $errormessage = $Lang::tr{'openvpn subnet is used'};
3913 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3914 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3915 goto VPNCONF_ERROR;
3916 }
3917
3918 if (($cgiparams{'PROTOCOL'} eq 'tcp') && ($cgiparams{'MSSFIX'} eq 'on')) {
3919 $errormessage = $Lang::tr{'openvpn mssfix allowed with udp'};
3920 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3921 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3922 goto VPNCONF_ERROR;
3923 }
3924
3925 if (($cgiparams{'PROTOCOL'} eq 'tcp') && ($cgiparams{'FRAGMENT'} ne '')) {
3926 $errormessage = $Lang::tr{'openvpn fragment allowed with udp'};
3927 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3928 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3929 goto VPNCONF_ERROR;
3930 }
3931
3932 if (!&Network::check_subnet($cgiparams{'LOCAL_SUBNET'})) {
3933 $errormessage = $Lang::tr{'openvpn prefix local subnet'};
3934 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3935 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3936 goto VPNCONF_ERROR;
3937 }
3938
3939 if (!&Network::check_subnet($cgiparams{'OVPN_SUBNET'})) {
3940 $errormessage = $Lang::tr{'openvpn prefix openvpn subnet'};
3941 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3942 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3943 goto VPNCONF_ERROR;
3944 }
3945
3946 if (!&Network::check_subnet($cgiparams{'REMOTE_SUBNET'})) {
3947 $errormessage = $Lang::tr{'openvpn prefix remote subnet'};
3948 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3949 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3950 goto VPNCONF_ERROR;
3951 }
3952
3953 if ($cgiparams{'DEST_PORT'} <= 1023) {
3954 $errormessage = $Lang::tr{'ovpn port in root range'};
3955 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3956 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3957 goto VPNCONF_ERROR;
3958 }
3959
3960 if ($cgiparams{'OVPN_MGMT'} eq '') {
3961 $cgiparams{'OVPN_MGMT'} = $cgiparams{'DEST_PORT'};
3962 }
3963
3964 if ($cgiparams{'OVPN_MGMT'} <= 1023) {
3965 $errormessage = $Lang::tr{'ovpn mgmt in root range'};
3966 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3967 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3968 goto VPNCONF_ERROR;
3969 }
3970 #Check if remote subnet is used elsewhere
3971 my ($n2nip,$n2nsub)=split("/",$cgiparams{'REMOTE_SUBNET'});
3972 $warnmessage=&General::checksubnets('',$n2nip,'ovpn');
3973 if ($warnmessage){
3974 $warnmessage=$Lang::tr{'remote subnet'}." ($cgiparams{'REMOTE_SUBNET'}) <br>".$warnmessage;
3975 }
3976 }
3977
3978 # Check if there is no other entry with this name
3979 if (! $cgiparams{'KEY'}) {
3980 foreach my $key (keys %confighash) {
3981 if ($confighash{$key}[1] eq $cgiparams{'NAME'}) {
3982 $errormessage = $Lang::tr{'a connection with this name already exists'};
3983 if ($cgiparams{'TYPE'} eq 'net') {
3984 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3985 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3986 }
3987 goto VPNCONF_ERROR;
3988 }
3989 }
3990 }
3991
3992 # Check if a remote host/IP has been set for the client.
3993 if ($cgiparams{'TYPE'} eq 'net') {
3994 if ($cgiparams{'SIDE'} ne 'server' && $cgiparams{'REMOTE'} eq '') {
3995 $errormessage = $Lang::tr{'invalid input for remote host/ip'};
3996
3997 # Check if this is a N2N connection and drop temporary config.
3998 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3999 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4000
4001 goto VPNCONF_ERROR;
4002 }
4003
4004 # Check if a remote host/IP has been configured - the field can be empty on the server side.
4005 if ($cgiparams{'REMOTE'} ne '') {
4006 # Check if the given IP is valid - otherwise check if it is a valid domain.
4007 if (! &General::validip($cgiparams{'REMOTE'})) {
4008 # Check for a valid domain.
4009 if (! &General::validfqdn ($cgiparams{'REMOTE'})) {
4010 $errormessage = $Lang::tr{'invalid input for remote host/ip'};
4011
4012 # Check if this is a N2N connection and drop temporary config.
4013 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4014 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4015
4016 goto VPNCONF_ERROR;
4017 }
4018 }
4019 }
4020 }
4021
4022 if ($cgiparams{'TYPE'} ne 'host') {
4023 unless (&General::validipandmask($cgiparams{'LOCAL_SUBNET'})) {
4024 $errormessage = $Lang::tr{'local subnet is invalid'};
4025 if ($cgiparams{'TYPE'} eq 'net') {
4026 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4027 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4028 }
4029 goto VPNCONF_ERROR;}
4030 }
4031 # Check if there is no other entry without IP-address and PSK
4032 if ($cgiparams{'REMOTE'} eq '') {
4033 foreach my $key (keys %confighash) {
4034 if(($cgiparams{'KEY'} ne $key) &&
4035 ($confighash{$key}[4] eq 'psk' || $cgiparams{'AUTH'} eq 'psk') &&
4036 $confighash{$key}[10] eq '') {
4037 $errormessage = $Lang::tr{'you can only define one roadwarrior connection when using pre-shared key authentication'};
4038 goto VPNCONF_ERROR;
4039 }
4040 }
4041 }
4042 if (($cgiparams{'TYPE'} eq 'net') && (! &General::validipandmask($cgiparams{'REMOTE_SUBNET'}))) {
4043 $errormessage = $Lang::tr{'remote subnet is invalid'};
4044 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4045 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4046 goto VPNCONF_ERROR;
4047 }
4048
4049 # Check for N2N that OpenSSL maximum of valid days will not be exceeded
4050 if ($cgiparams{'TYPE'} eq 'net') {
4051 if ($cgiparams{'DAYS_VALID'} >= '999999') {
4052 $errormessage = $Lang::tr{'invalid input for valid till days'};
4053 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4054 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4055 goto VPNCONF_ERROR;
4056 }
4057 }
4058
4059 if ($cgiparams{'ENABLED'} !~ /^(on|off|)$/) {
4060 $errormessage = $Lang::tr{'invalid input'};
4061 goto VPNCONF_ERROR;
4062 }
4063
4064 if ($cgiparams{'AUTH'} eq 'certreq') {
4065 if ($cgiparams{'KEY'}) {
4066 $errormessage = $Lang::tr{'cant change certificates'};
4067 goto VPNCONF_ERROR;
4068 }
4069 unless (ref ($cgiparams{'FH'})) {
4070 $errormessage = $Lang::tr{'there was no file upload'};
4071 goto VPNCONF_ERROR;
4072 }
4073
4074 # Move uploaded certificate request to a temporary file
4075 (my $fh, my $filename) = tempfile( );
4076 if (copy ($cgiparams{'FH'}, $fh) != 1) {
4077 $errormessage = $!;
4078 goto VPNCONF_ERROR;
4079 }
4080
4081 # Sign the certificate request and move it
4082 # Sign the host certificate request
4083 # The system call is safe, because all arguments are passed as an array.
4084 system('/usr/bin/openssl', 'ca', '-days', "$cgiparams{'DAYS_VALID'}",
4085 '-batch', '-notext',
4086 '-in', $filename,
4087 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem",
4088 '-config', "/usr/share/openvpn/ovpn.cnf");
4089 if ($?) {
4090 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4091 unlink ($filename);
4092 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4093 &cleanssldatabase();
4094 goto VPNCONF_ERROR;
4095 } else {
4096 unlink ($filename);
4097 &deletebackupcert();
4098 }
4099
4100 my @temp = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4101 my $temp;
4102
4103 foreach my $line (@temp) {
4104 if ($line =~ /Subject:.*CN\s?=\s?(.*)[\n]/) {
4105 $temp = $1;
4106 $temp =~ s+/Email+, E+;
4107 $temp =~ s/ ST=/ S=/;
4108
4109 last;
4110 }
4111 }
4112
4113 $cgiparams{'CERT_NAME'} = $temp;
4114 $cgiparams{'CERT_NAME'} =~ s/,//g;
4115 $cgiparams{'CERT_NAME'} =~ s/\'//g;
4116 if ($cgiparams{'CERT_NAME'} eq '') {
4117 $errormessage = $Lang::tr{'could not retrieve common name from certificate'};
4118 goto VPNCONF_ERROR;
4119 }
4120 } elsif ($cgiparams{'AUTH'} eq 'certfile') {
4121 if ($cgiparams{'KEY'}) {
4122 $errormessage = $Lang::tr{'cant change certificates'};
4123 goto VPNCONF_ERROR;
4124 }
4125 unless (ref ($cgiparams{'FH'})) {
4126 $errormessage = $Lang::tr{'there was no file upload'};
4127 goto VPNCONF_ERROR;
4128 }
4129 # Move uploaded certificate to a temporary file
4130 (my $fh, my $filename) = tempfile( );
4131 if (copy ($cgiparams{'FH'}, $fh) != 1) {
4132 $errormessage = $!;
4133 goto VPNCONF_ERROR;
4134 }
4135
4136 # Verify the certificate has a valid CA and move it
4137 my $validca = 0;
4138 my @test = &General::system_output("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ovpn/ca/cacert.pem", "$filename");
4139 if (grep(/: OK/, @test)) {
4140 $validca = 1;
4141 } else {
4142 foreach my $key (keys %cahash) {
4143 @test = &General::system_output("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ovpn/ca/$cahash{$key}[0]cert.pem", "$filename");
4144 if (grep(/: OK/, @test)) {
4145 $validca = 1;
4146 }
4147 }
4148 }
4149 if (! $validca) {
4150 $errormessage = $Lang::tr{'certificate does not have a valid ca associated with it'};
4151 unlink ($filename);
4152 goto VPNCONF_ERROR;
4153 } else {
4154 unless(move($filename, "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem")) {
4155 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
4156 unlink ($filename);
4157 goto VPNCONF_ERROR;
4158 }
4159 }
4160
4161 my @temp = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4162 my $temp;
4163
4164 foreach my $line (@temp) {
4165 if ($line =~ /Subject:.*CN\s?=\s?(.*)[\n]/) {
4166 $temp = $1;
4167 $temp =~ s+/Email+, E+;
4168 $temp =~ s/ ST=/ S=/;
4169
4170 last;
4171 }
4172 }
4173
4174 $cgiparams{'CERT_NAME'} = $temp;
4175 $cgiparams{'CERT_NAME'} =~ s/,//g;
4176 $cgiparams{'CERT_NAME'} =~ s/\'//g;
4177 if ($cgiparams{'CERT_NAME'} eq '') {
4178 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4179 $errormessage = $Lang::tr{'could not retrieve common name from certificate'};
4180 goto VPNCONF_ERROR;
4181 }
4182 } elsif ($cgiparams{'AUTH'} eq 'certgen') {
4183 if ($cgiparams{'KEY'}) {
4184 $errormessage = $Lang::tr{'cant change certificates'};
4185 goto VPNCONF_ERROR;
4186 }
4187 # Validate input since the form was submitted
4188 if (length($cgiparams{'CERT_NAME'}) >60) {
4189 $errormessage = $Lang::tr{'name too long'};
4190 goto VPNCONF_ERROR;
4191 }
4192 if ($cgiparams{'CERT_NAME'} eq '' || $cgiparams{'CERT_NAME'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) {
4193 $errormessage = $Lang::tr{'invalid input for name'};
4194 goto VPNCONF_ERROR;
4195 }
4196 if ($cgiparams{'CERT_EMAIL'} ne '' && (! &General::validemail($cgiparams{'CERT_EMAIL'}))) {
4197 $errormessage = $Lang::tr{'invalid input for e-mail address'};
4198 goto VPNCONF_ERROR;
4199 }
4200 if (length($cgiparams{'CERT_EMAIL'}) > 40) {
4201 $errormessage = $Lang::tr{'e-mail address too long'};
4202 goto VPNCONF_ERROR;
4203 }
4204 if ($cgiparams{'CERT_OU'} ne '' && $cgiparams{'CERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
4205 $errormessage = $Lang::tr{'invalid input for department'};
4206 goto VPNCONF_ERROR;
4207 }
4208 if (length($cgiparams{'CERT_ORGANIZATION'}) >60) {
4209 $errormessage = $Lang::tr{'organization too long'};
4210 goto VPNCONF_ERROR;
4211 }
4212 if ($cgiparams{'CERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) {
4213 $errormessage = $Lang::tr{'invalid input for organization'};
4214 goto VPNCONF_ERROR;
4215 }
4216 if ($cgiparams{'CERT_CITY'} ne '' && $cgiparams{'CERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
4217 $errormessage = $Lang::tr{'invalid input for city'};
4218 goto VPNCONF_ERROR;
4219 }
4220 if ($cgiparams{'CERT_STATE'} ne '' && $cgiparams{'CERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
4221 $errormessage = $Lang::tr{'invalid input for state or province'};
4222 goto VPNCONF_ERROR;
4223 }
4224 if ($cgiparams{'CERT_COUNTRY'} !~ /^[A-Z]*$/) {
4225 $errormessage = $Lang::tr{'invalid input for country'};
4226 goto VPNCONF_ERROR;
4227 }
4228 if ($cgiparams{'CERT_PASS1'} ne '' && $cgiparams{'CERT_PASS2'} ne ''){
4229 if (length($cgiparams{'CERT_PASS1'}) < 5) {
4230 $errormessage = $Lang::tr{'password too short'};
4231 goto VPNCONF_ERROR;
4232 }
4233 }
4234 if ($cgiparams{'CERT_PASS1'} ne $cgiparams{'CERT_PASS2'}) {
4235 $errormessage = $Lang::tr{'passwords do not match'};
4236 goto VPNCONF_ERROR;
4237 }
4238 if ($cgiparams{'DAYS_VALID'} eq '' && $cgiparams{'DAYS_VALID'} !~ /^[0-9]+$/) {
4239 $errormessage = $Lang::tr{'invalid input for valid till days'};
4240 goto VPNCONF_ERROR;
4241 }
4242
4243 # Check for RW that OpenSSL maximum of valid days will not be exceeded
4244 if ($cgiparams{'TYPE'} eq 'host') {
4245 if ($cgiparams{'DAYS_VALID'} >= '999999') {
4246 $errormessage = $Lang::tr{'invalid input for valid till days'};
4247 goto VPNCONF_ERROR;
4248 }
4249 }
4250
4251 # Check for RW if client name is already set
4252 if ($cgiparams{'TYPE'} eq 'host') {
4253 foreach my $key (keys %confighash) {
4254 if ($confighash{$key}[1] eq $cgiparams{'NAME'}) {
4255 $errormessage = $Lang::tr{'a connection with this name already exists'};
4256 goto VPNCONF_ERROR;
4257 }
4258 }
4259 }
4260
4261 # Check if there is no other entry with this common name
4262 if ((! $cgiparams{'KEY'}) && ($cgiparams{'AUTH'} ne 'psk')) {
4263 foreach my $key (keys %confighash) {
4264 if ($confighash{$key}[2] eq $cgiparams{'CERT_NAME'}) {
4265 $errormessage = $Lang::tr{'a connection with this common name already exists'};
4266 goto VPNCONF_ERROR;
4267 }
4268 }
4269 }
4270
4271 # Replace empty strings with a .
4272 (my $ou = $cgiparams{'CERT_OU'}) =~ s/^\s*$/\./;
4273 (my $city = $cgiparams{'CERT_CITY'}) =~ s/^\s*$/\./;
4274 (my $state = $cgiparams{'CERT_STATE'}) =~ s/^\s*$/\./;
4275
4276 # Create the Host certificate request client
4277 my $pid = open(OPENSSL, "|-");
4278 $SIG{ALRM} = sub { $errormessage = $Lang::tr{'broken pipe'}; goto VPNCONF_ERROR;};
4279 if ($pid) { # parent
4280 print OPENSSL "$cgiparams{'CERT_COUNTRY'}\n";
4281 print OPENSSL "$state\n";
4282 print OPENSSL "$city\n";
4283 print OPENSSL "$cgiparams{'CERT_ORGANIZATION'}\n";
4284 print OPENSSL "$ou\n";
4285 print OPENSSL "$cgiparams{'CERT_NAME'}\n";
4286 print OPENSSL "$cgiparams{'CERT_EMAIL'}\n";
4287 print OPENSSL ".\n";
4288 print OPENSSL ".\n";
4289 close (OPENSSL);
4290 if ($?) {
4291 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4292 unlink ("${General::swroot}ovpn/certs/$cgiparams{'NAME'}key.pem");
4293 unlink ("${General::swroot}ovpn/certs/$cgiparams{'NAME'}req.pem");
4294 goto VPNCONF_ERROR;
4295 }
4296 } else { # child
4297 unless (exec ('/usr/bin/openssl', 'req', '-nodes',
4298 '-newkey', 'rsa:4096',
4299 '-keyout', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem",
4300 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem",
4301 '-config', "/usr/share/openvpn/ovpn.cnf")) {
4302 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
4303 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4304 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem");
4305 goto VPNCONF_ERROR;
4306 }
4307 }
4308
4309 # Sign the host certificate request
4310 # The system call is safe, because all arguments are passed as an array.
4311 system('/usr/bin/openssl', 'ca', '-days', "$cgiparams{'DAYS_VALID'}",
4312 '-batch', '-notext',
4313 '-in', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem",
4314 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem",
4315 '-config', "/usr/share/openvpn/ovpn.cnf");
4316 if ($?) {
4317 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4318 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4319 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem");
4320 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4321 &cleanssldatabase();
4322 goto VPNCONF_ERROR;
4323 } else {
4324 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem");
4325 &deletebackupcert();
4326 }
4327
4328 # Create the pkcs12 file
4329 # The system call is safe, because all arguments are passed as an array.
4330 system('/usr/bin/openssl', 'pkcs12', '-export',
4331 '-inkey', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem",
4332 '-in', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem",
4333 '-name', $cgiparams{'NAME'},
4334 '-passout', "pass:$cgiparams{'CERT_PASS1'}",
4335 '-certfile', "${General::swroot}/ovpn/ca/cacert.pem",
4336 '-caname', "$vpnsettings{'ROOTCERT_ORGANIZATION'} CA",
4337 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}.p12");
4338 if ($?) {
4339 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4340 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4341 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4342 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}.p12");
4343 goto VPNCONF_ERROR;
4344 } else {
4345 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4346 }
4347 } elsif ($cgiparams{'AUTH'} eq 'cert') {
4348 ;# Nothing, just editing
4349 } else {
4350 $errormessage = $Lang::tr{'invalid input for authentication method'};
4351 goto VPNCONF_ERROR;
4352 }
4353
4354 # Save the config
4355 my $key = $cgiparams{'KEY'};
4356
4357 if (! $key) {
4358 $key = &General::findhasharraykey (\%confighash);
4359 foreach my $i (0 .. 43) { $confighash{$key}[$i] = "";}
4360 }
4361 $confighash{$key}[0] = $cgiparams{'ENABLED'};
4362 $confighash{$key}[1] = $cgiparams{'NAME'};
4363 if ((! $cgiparams{'KEY'}) && $cgiparams{'AUTH'} ne 'psk') {
4364 $confighash{$key}[2] = $cgiparams{'CERT_NAME'};
4365 }
4366
4367 $confighash{$key}[3] = $cgiparams{'TYPE'};
4368 if ($cgiparams{'AUTH'} eq 'psk') {
4369 $confighash{$key}[4] = 'psk';
4370 $confighash{$key}[5] = $cgiparams{'PSK'};
4371 } else {
4372 $confighash{$key}[4] = 'cert';
4373 }
4374 if ($cgiparams{'TYPE'} eq 'net') {
4375 $confighash{$key}[6] = $cgiparams{'SIDE'};
4376 $confighash{$key}[11] = $cgiparams{'REMOTE_SUBNET'};
4377 }
4378 $confighash{$key}[8] = $cgiparams{'LOCAL_SUBNET'};
4379 $confighash{$key}[10] = $cgiparams{'REMOTE'};
4380 if ($cgiparams{'OVPN_MGMT'} eq '') {
4381 $confighash{$key}[22] = $confighash{$key}[29];
4382 } else {
4383 $confighash{$key}[22] = $cgiparams{'OVPN_MGMT'};
4384 }
4385 $confighash{$key}[23] = $cgiparams{'MSSFIX'};
4386 $confighash{$key}[24] = $cgiparams{'FRAGMENT'};
4387 $confighash{$key}[25] = $cgiparams{'REMARK'};
4388 $confighash{$key}[26] = $cgiparams{'INTERFACE'};
4389 # new fields
4390 $confighash{$key}[27] = $cgiparams{'OVPN_SUBNET'};
4391 $confighash{$key}[28] = $cgiparams{'PROTOCOL'};
4392 $confighash{$key}[29] = $cgiparams{'DEST_PORT'};
4393 $confighash{$key}[30] = $cgiparams{'COMPLZO'};
4394 $confighash{$key}[31] = $cgiparams{'MTU'};
4395 $confighash{$key}[32] = $cgiparams{'CHECK1'};
4396 $name=$cgiparams{'CHECK1'};
4397 $confighash{$key}[33] = $cgiparams{$name};
4398 $confighash{$key}[34] = $cgiparams{'RG'};
4399 $confighash{$key}[35] = $cgiparams{'CCD_DNS1'};
4400 $confighash{$key}[36] = $cgiparams{'CCD_DNS2'};
4401 $confighash{$key}[37] = $cgiparams{'CCD_WINS'};
4402 $confighash{$key}[39] = $cgiparams{'DAUTH'};
4403 $confighash{$key}[40] = $cgiparams{'DCIPHER'};
4404
4405 if ($confighash{$key}[41] eq "") {
4406 if (($cgiparams{'TYPE'} eq 'host') && ($cgiparams{'CERT_PASS1'} eq "")) {
4407 $confighash{$key}[41] = "no-pass";
4408 } elsif (($cgiparams{'TYPE'} eq 'host') && ($cgiparams{'CERT_PASS1'} ne "")) {
4409 $confighash{$key}[41] = "pass";
4410 } elsif ($cgiparams{'TYPE'} eq 'net') {
4411 $confighash{$key}[41] = "no-pass";
4412 }
4413 }
4414
4415 $confighash{$key}[42] = 'HOTP/T30/6';
4416 $confighash{$key}[43] = $cgiparams{'OTP_STATE'};
4417 if (($confighash{$key}[43] eq 'on') && ($confighash{$key}[44] eq '')) {
4418 my @otp_secret = &General::system_output("/usr/bin/openssl", "rand", "-hex", "20");
4419 chomp($otp_secret[0]);
4420 $confighash{$key}[44] = $otp_secret[0];
4421 } elsif ($confighash{$key}[43] eq '') {
4422 $confighash{$key}[44] = '';
4423 }
4424
4425 &General::writehasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
4426
4427 # Rewrite the server configuration
4428 &writeserverconf();
4429
4430 if ($cgiparams{'TYPE'} eq 'net') {
4431
4432 if (-e "/var/run/$confighash{$key}[1]n2n.pid") {
4433 &General::system("/usr/local/bin/openvpnctrl", "n2n", "stop", "$confighash{$cgiparams{'KEY'}}[1]");
4434
4435 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
4436 my $key = $cgiparams{'KEY'};
4437 if (! $key) {
4438 $key = &General::findhasharraykey (\%confighash);
4439 foreach my $i (0 .. 31) {
4440 $confighash{$key}[$i] = "";
4441 }
4442 }
4443
4444 $confighash{$key}[0] = 'on';
4445 &General::writehasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
4446
4447 &General::system("/usr/local/bin/openvpnctrl", "n2n", "start", "$confighash{$cgiparams{'KEY'}}[1]");
4448 }
4449 }
4450
4451 goto VPNCONF_END;
4452 } else {
4453 $cgiparams{'ENABLED'} = 'on';
4454 $cgiparams{'MSSFIX'} = 'on';
4455 $cgiparams{'FRAGMENT'} = '1300';
4456 $cgiparams{'DAUTH'} = 'SHA512';
4457 $cgiparams{'SIDE'} = 'left';
4458 if ( ! -f "${General::swroot}/ovpn/ca/cakey.pem" ) {
4459 $cgiparams{'AUTH'} = 'psk';
4460 } elsif ( ! -f "${General::swroot}/ovpn/ca/cacert.pem") {
4461 $cgiparams{'AUTH'} = 'certfile';
4462 } else {
4463 $cgiparams{'AUTH'} = 'certgen';
4464 }
4465 $cgiparams{'LOCAL_SUBNET'} ="$Network::ethernet{'GREEN_NETADDRESS'}/$Network::ethernet{'GREEN_NETMASK'}";
4466 $cgiparams{'CERT_ORGANIZATION'} = $vpnsettings{'ROOTCERT_ORGANIZATION'};
4467 $cgiparams{'CERT_CITY'} = $vpnsettings{'ROOTCERT_CITY'};
4468 $cgiparams{'CERT_STATE'} = $vpnsettings{'ROOTCERT_STATE'};
4469 $cgiparams{'CERT_COUNTRY'} = $vpnsettings{'ROOTCERT_COUNTRY'};
4470 $cgiparams{'DAYS_VALID'} = $vpnsettings{'DAYS_VALID'} = '730';
4471 }
4472
4473 VPNCONF_ERROR:
4474 $checked{'ENABLED'}{'off'} = '';
4475 $checked{'ENABLED'}{'on'} = '';
4476 $checked{'ENABLED'}{$cgiparams{'ENABLED'}} = 'CHECKED';
4477
4478 $checked{'OTP_STATE'}{$cgiparams{'OTP_STATE'}} = 'CHECKED';
4479
4480 $selected{'SIDE'}{'server'} = '';
4481 $selected{'SIDE'}{'client'} = '';
4482 $selected{'SIDE'}{$cgiparams{'SIDE'}} = 'SELECTED';
4483
4484 $selected{'PROTOCOL'}{'udp'} = '';
4485 $selected{'PROTOCOL'}{'tcp'} = '';
4486 $selected{'PROTOCOL'}{$cgiparams{'PROTOCOL'}} = 'SELECTED';
4487
4488
4489 $checked{'AUTH'}{'psk'} = '';
4490 $checked{'AUTH'}{'certreq'} = '';
4491 $checked{'AUTH'}{'certgen'} = '';
4492 $checked{'AUTH'}{'certfile'} = '';
4493 $checked{'AUTH'}{$cgiparams{'AUTH'}} = 'CHECKED';
4494
4495 $selected{'INTERFACE'}{$cgiparams{'INTERFACE'}} = 'SELECTED';
4496
4497 $checked{'COMPLZO'}{'off'} = '';
4498 $checked{'COMPLZO'}{'on'} = '';
4499 $checked{'COMPLZO'}{$cgiparams{'COMPLZO'}} = 'CHECKED';
4500
4501 $checked{'MSSFIX'}{'off'} = '';
4502 $checked{'MSSFIX'}{'on'} = '';
4503 $checked{'MSSFIX'}{$cgiparams{'MSSFIX'}} = 'CHECKED';
4504
4505 $selected{'DCIPHER'}{'AES-256-GCM'} = '';
4506 $selected{'DCIPHER'}{'AES-192-GCM'} = '';
4507 $selected{'DCIPHER'}{'AES-128-GCM'} = '';
4508 $selected{'DCIPHER'}{'CAMELLIA-256-CBC'} = '';
4509 $selected{'DCIPHER'}{'CAMELLIA-192-CBC'} = '';
4510 $selected{'DCIPHER'}{'CAMELLIA-128-CBC'} = '';
4511 $selected{'DCIPHER'}{'AES-256-CBC'} = '';
4512 $selected{'DCIPHER'}{'AES-192-CBC'} = '';
4513 $selected{'DCIPHER'}{'AES-128-CBC'} = '';
4514 $selected{'DCIPHER'}{'DESX-CBC'} = '';
4515 $selected{'DCIPHER'}{'SEED-CBC'} = '';
4516 $selected{'DCIPHER'}{'DES-EDE3-CBC'} = '';
4517 $selected{'DCIPHER'}{'DES-EDE-CBC'} = '';
4518 $selected{'DCIPHER'}{'CAST5-CBC'} = '';
4519 $selected{'DCIPHER'}{'BF-CBC'} = '';
4520 $selected{'DCIPHER'}{'DES-CBC'} = '';
4521 $selected{'DCIPHER'}{$cgiparams{'DCIPHER'}} = 'SELECTED';
4522 $selected{'DAUTH'}{'whirlpool'} = '';
4523 $selected{'DAUTH'}{'SHA512'} = '';
4524 $selected{'DAUTH'}{'SHA384'} = '';
4525 $selected{'DAUTH'}{'SHA256'} = '';
4526 $selected{'DAUTH'}{'SHA1'} = '';
4527 $selected{'DAUTH'}{$cgiparams{'DAUTH'}} = 'SELECTED';
4528 $checked{'TLSAUTH'}{'off'} = '';
4529 $checked{'TLSAUTH'}{'on'} = '';
4530 $checked{'TLSAUTH'}{$cgiparams{'TLSAUTH'}} = 'CHECKED';
4531
4532 if (1) {
4533 &Header::showhttpheaders();
4534 &Header::openpage($Lang::tr{'ovpn'}, 1, '');
4535 &Header::openbigbox('100%', 'LEFT', '', $errormessage);
4536
4537 # Show any errors
4538 &Header::errorbox($errormessage);
4539
4540 if ($warnmessage) {
4541 &Header::openbox('100%', 'LEFT', "$Lang::tr{'warning messages'}:");
4542 print "<class name='base'>$warnmessage";
4543 print "&nbsp;</class>";
4544 &Header::closebox();
4545 }
4546
4547 print "<form method='post' enctype='multipart/form-data'>";
4548 print "<input type='hidden' name='TYPE' value='$cgiparams{'TYPE'}' />";
4549
4550 if ($cgiparams{'KEY'}) {
4551 print "<input type='hidden' name='KEY' value='$cgiparams{'KEY'}' />";
4552 print "<input type='hidden' name='AUTH' value='$cgiparams{'AUTH'}' />";
4553 }
4554
4555 &Header::openbox('100%', 'LEFT', "$Lang::tr{'connection'}:");
4556
4557 my $readonly = ($cgiparams{'KEY'}) ? "readonly" : "";
4558
4559 print <<END;
4560 <table class="form">
4561 <tr>
4562 <td>
4563 $Lang::tr{'name'}
4564 </td>
4565 <td>
4566 <input type="text" name="NAME" value="$cgiparams{'NAME'}" $readonly/>
4567 </td>
4568 </tr>
4569
4570 <tr>
4571 <td>
4572 $Lang::tr{'remark title'}
4573 </td>
4574 <td>
4575 <input type="text" name="REMARK" value="$cgiparams{'REMARK'}" />
4576 </td>
4577 </tr>
4578 END
4579
4580 if ($cgiparams{'TYPE'} eq 'host') {
4581 print <<END;
4582 <tr>
4583 <td>
4584 $Lang::tr{'enabled'}
4585 </td>
4586 <td>
4587 <input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} />
4588 </td>
4589 </tr>
4590
4591 <tr>
4592 <td>
4593 $Lang::tr{'enable otp'}
4594 </td>
4595 <td>
4596 <input type='checkbox' name='OTP_STATE' $checked{'OTP_STATE'}{'on'} />
4597 </td>
4598 </tr>
4599 END
4600 }
4601
4602 if ($cgiparams{'TYPE'} eq 'net') {
4603 # If GCM ciphers are in usage, HMAC menu is disabled
4604 my $hmacdisabled;
4605 if (($confighash{$cgiparams{'KEY'}}[40] eq 'AES-256-GCM') ||
4606 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-192-GCM') ||
4607 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-128-GCM')) {
4608 $hmacdisabled = "disabled='disabled'";
4609 };
4610
4611 print <<END;
4612 <tr>
4613 <td>$Lang::tr{'Act as'}</td>
4614 <td>
4615 <select name='SIDE'>
4616 <option value='server' $selected{'SIDE'}{'server'}>$Lang::tr{'openvpn server'}</option>
4617 <option value='client' $selected{'SIDE'}{'client'}>$Lang::tr{'openvpn client'}</option>
4618 </select>
4619 </td>
4620 </tr>
4621
4622 <tr>
4623 <td>$Lang::tr{'remote host/ip'}:</td>
4624 <td>
4625 <input type='TEXT' name='REMOTE' value='$cgiparams{'REMOTE'}' />
4626 </td>
4627 </tr>
4628
4629 <tr>
4630 <td>$Lang::tr{'local subnet'}&nbsp;<img src='/blob.gif' alt='*' /></td>
4631 <td>
4632 <input type='TEXT' name='LOCAL_SUBNET' value='$cgiparams{'LOCAL_SUBNET'}' />
4633 </td>
4634 </tr>
4635
4636 <tr>
4637 <td>$Lang::tr{'remote subnet'}&nbsp;<img src='/blob.gif' alt='*' /></td>
4638 <td>
4639 <input type='text' name='REMOTE_SUBNET' value='$cgiparams{'REMOTE_SUBNET'}' />
4640 </td>
4641 </tr>
4642
4643 <tr>
4644 <td>$Lang::tr{'ovpn subnet'}&nbsp;<img src='/blob.gif' alt='*' /></td>
4645 <td>
4646 <input type='TEXT' name='OVPN_SUBNET' value='$cgiparams{'OVPN_SUBNET'}' />
4647 </td>
4648 </tr>
4649
4650 <tr>
4651 <td>$Lang::tr{'protocol'}</td>
4652 <td>
4653 <select name='PROTOCOL'>
4654 <option value='udp' $selected{'PROTOCOL'}{'udp'}>UDP</option>
4655 <option value='tcp' $selected{'PROTOCOL'}{'tcp'}>TCP</option>
4656 </select>
4657 </td>
4658 </tr>
4659
4660 <tr>
4661 <td>$Lang::tr{'destination port'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
4662 <td>
4663 <input type='TEXT' name='DEST_PORT' value='$cgiparams{'DEST_PORT'}' size='5' />
4664 </td>
4665 </tr>
4666
4667 <tr>
4668 <td>Management Port ($Lang::tr{'openvpn default'}: <span class="base">$Lang::tr{'destination port'}):</td>
4669 <td>
4670 <input type='TEXT' name='OVPN_MGMT' VALUE='$cgiparams{'OVPN_MGMT'}'size='5' />
4671 </td>
4672 </tr>
4673 </table>
4674
4675 <h6>
4676 $Lang::tr{'MTU settings'}
4677 </h6>
4678
4679 <table class="form">
4680 <tr>
4681 <td>$Lang::tr{'MTU'}</td>
4682 <td>
4683 <input type='TEXT' name='MTU' VALUE='$cgiparams{'MTU'}'size='5' />
4684 </td>
4685 </tr>
4686
4687 <tr>
4688 <td>fragment:</td>
4689 <td>
4690 <input type='TEXT' name='FRAGMENT' VALUE='$cgiparams{'FRAGMENT'}'size='5' />
4691 </td>
4692 </tr>
4693
4694 <tr>
4695 <td>mssfix:</td>
4696 <td>
4697 <input type='checkbox' name='MSSFIX' $checked{'MSSFIX'}{'on'} />
4698 </td>
4699 </tr>
4700
4701 <tr>
4702 <td>$Lang::tr{'comp-lzo'}</td>
4703 <td>
4704 <input type='checkbox' name='COMPLZO' $checked{'COMPLZO'}{'on'} />
4705 </td>
4706 </tr>
4707 </table>
4708
4709 <h6>
4710 $Lang::tr{'ovpn crypto settings'}:
4711 </h6>
4712
4713 <table class="form">
4714 <tr>
4715 <td>$Lang::tr{'cipher'}</td>
4716 <td>
4717 <select name='DCIPHER' id="n2ncipher" required>
4718 <option value='AES-256-GCM' $selected{'DCIPHER'}{'AES-256-GCM'}>AES-GCM (256 $Lang::tr{'bit'})</option>
4719 <option value='AES-192-GCM' $selected{'DCIPHER'}{'AES-192-GCM'}>AES-GCM (192 $Lang::tr{'bit'})</option>
4720 <option value='AES-128-GCM' $selected{'DCIPHER'}{'AES-128-GCM'}>AES-GCM (128 $Lang::tr{'bit'})</option>
4721 <option value='CAMELLIA-256-CBC' $selected{'DCIPHER'}{'CAMELLIA-256-CBC'}>CAMELLIA-CBC (256 $Lang::tr{'bit'})</option>
4722 <option value='CAMELLIA-192-CBC' $selected{'DCIPHER'}{'CAMELLIA-192-CBC'}>CAMELLIA-CBC (192 $Lang::tr{'bit'})</option>
4723 <option value='CAMELLIA-128-CBC' $selected{'DCIPHER'}{'CAMELLIA-128-CBC'}>CAMELLIA-CBC (128 $Lang::tr{'bit'})</option>
4724 <option value='AES-256-CBC' $selected{'DCIPHER'}{'AES-256-CBC'}>AES-CBC (256 $Lang::tr{'bit'}, $Lang::tr{'default'})</option>
4725 <option value='AES-192-CBC' $selected{'DCIPHER'}{'AES-192-CBC'}>AES-CBC (192 $Lang::tr{'bit'})</option>
4726 <option value='AES-128-CBC' $selected{'DCIPHER'}{'AES-128-CBC'}>AES-CBC (128 $Lang::tr{'bit'})</option>
4727 <option value='SEED-CBC' $selected{'DCIPHER'}{'SEED-CBC'}>SEED-CBC (128 $Lang::tr{'bit'})</option>
4728 <option value='DES-EDE3-CBC' $selected{'DCIPHER'}{'DES-EDE3-CBC'}>DES-EDE3-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4729 <option value='DESX-CBC' $selected{'DCIPHER'}{'DESX-CBC'}>DESX-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4730 <option value='DES-EDE-CBC' $selected{'DCIPHER'}{'DES-EDE-CBC'}>DES-EDE-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4731 <option value='BF-CBC' $selected{'DCIPHER'}{'BF-CBC'}>BF-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4732 <option value='CAST5-CBC' $selected{'DCIPHER'}{'CAST5-CBC'}>CAST5-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4733 </select>
4734 </td>
4735 </tr>
4736
4737 <tr>
4738 <td>$Lang::tr{'ovpn ha'}:</td>
4739 <td>
4740 <select name='DAUTH' id="n2nhmac" $hmacdisabled>
4741 <option value='whirlpool' $selected{'DAUTH'}{'whirlpool'}>Whirlpool (512 $Lang::tr{'bit'})</option>
4742 <option value='SHA512' $selected{'DAUTH'}{'SHA512'}>SHA2 (512 $Lang::tr{'bit'})</option>
4743 <option value='SHA384' $selected{'DAUTH'}{'SHA384'}>SHA2 (384 $Lang::tr{'bit'})</option>
4744 <option value='SHA256' $selected{'DAUTH'}{'SHA256'}>SHA2 (256 $Lang::tr{'bit'})</option>
4745 <option value='SHA1' $selected{'DAUTH'}{'SHA1'}>SHA1 (160 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4746 </select>
4747 </td>
4748 </tr>
4749 </table>
4750 END
4751 ;
4752
4753 #### JAVA SCRIPT ####
4754 # Validate N2N cipher. If GCM will be used, HMAC menu will be disabled onchange
4755 print<<END;
4756 <script>
4757 var disable_options = false;
4758 document.getElementById('n2ncipher').onchange = function () {
4759 if((this.value == "AES-256-GCM"||this.value == "AES-192-GCM"||this.value == "AES-128-GCM")) {
4760 document.getElementById('n2nhmac').setAttribute('disabled', true);
4761 } else {
4762 document.getElementById('n2nhmac').removeAttribute('disabled');
4763 }
4764 }
4765 </script>
4766 END
4767 }
4768
4769 if ($cgiparams{'TYPE'} eq 'host') {
4770 print "<table border='0' width='100%' cellspacing='1' cellpadding='0'><tr><td colspan='3'><hr><br><b>$Lang::tr{'ccd choose net'}</td></tr><tr><td height='20' colspan='3'></td></tr>";
4771 my %vpnnet=();
4772 my $vpnip;
4773 &General::readhash("${General::swroot}/ovpn/settings", \%vpnnet);
4774 $vpnip=$vpnnet{'DOVPN_SUBNET'};
4775 &General::readhasharray("${General::swroot}/ovpn/ccd.conf", \%ccdconfhash);
4776 my @ccdconf=();
4777 my $count=0;
4778 my $checked;
4779 $checked{'check1'}{'off'} = '';
4780 $checked{'check1'}{'on'} = '';
4781 $checked{'check1'}{$cgiparams{'CHECK1'}} = 'CHECKED';
4782 print"<tr><td align='center' width='1%' valign='top'><input type='radio' name='CHECK1' value='dynamic' checked /></td><td align='left' valign='top' width='35%'>$Lang::tr{'ccd dynrange'} ($vpnip)</td><td width='30%'>";
4783 print"</td></tr></table><br><br>";
4784 my $name=$cgiparams{'CHECK1'};
4785 $checked{'RG'}{$cgiparams{'RG'}} = 'CHECKED';
4786
4787 if (! -z "${General::swroot}/ovpn/ccd.conf"){
4788 print"<table border='0' width='100%' cellspacing='1' cellpadding='0'><tr><td width='1%'></td><td width='30%' class='boldbase' align='center'><b>$Lang::tr{'ccd name'}</td><td width='15%' class='boldbase' align='center'><b>$Lang::tr{'network'}</td><td class='boldbase' align='center' width='18%'><b>$Lang::tr{'ccd clientip'}</td></tr>";
4789 foreach my $key (sort { uc($ccdconfhash{$a}[0]) cmp uc($ccdconfhash{$b}[0]) } keys %ccdconfhash) {
4790 $count++;
4791 @ccdconf=($ccdconfhash{$key}[0],$ccdconfhash{$key}[1]);
4792 if ($count % 2){print"<tr bgcolor='$Header::color{'color22'}'>";}else{print"<tr bgcolor='$Header::color{'color20'}'>";}
4793 print"<td align='center' width='1%'><input type='radio' name='CHECK1' value='$ccdconf[0]' $checked{'check1'}{$ccdconf[0]}/></td><td>$ccdconf[0]</td><td width='40%' align='center'>$ccdconf[1]</td><td align='left' width='10%'>";
4794 &fillselectbox($ccdconf[0], $ccdconf[1], &convert_top30_ccd_allocation($cgiparams{$name}));
4795 print"</td></tr>";
4796 }
4797 print "</table><br><br><hr><br><br>";
4798 }
4799 }
4800
4801 &Header::closebox();
4802 if ($cgiparams{'KEY'} && $cgiparams{'AUTH'} eq 'psk') {
4803
4804 } elsif (! $cgiparams{'KEY'}) {
4805
4806
4807 my $disabled='';
4808 my $cakeydisabled='';
4809 my $cacrtdisabled='';
4810 if ( ! -f "${General::swroot}/ovpn/ca/cakey.pem" ) { $cakeydisabled = "disabled='disabled'" } else { $cakeydisabled = "" };
4811 if ( ! -f "${General::swroot}/ovpn/ca/cacert.pem" ) { $cacrtdisabled = "disabled='disabled'" } else { $cacrtdisabled = "" };
4812
4813 &Header::openbox('100%', 'LEFT', $Lang::tr{'authentication'});
4814
4815
4816 if ($cgiparams{'TYPE'} eq 'host') {
4817
4818 print <<END;
4819 <table width='100%' cellpadding='0' cellspacing='5' border='0'>
4820
4821 <tr><td><input type='radio' name='AUTH' value='certreq' $checked{'AUTH'}{'certreq'} $cakeydisabled /></td><td class='base'>$Lang::tr{'upload a certificate request'}</td><td class='base' rowspan='2'><input type='file' name='FH' size='30' $cacrtdisabled></td></tr>
4822 <tr><td><input type='radio' name='AUTH' value='certfile' $checked{'AUTH'}{'certfile'} $cacrtdisabled /></td><td class='base'>$Lang::tr{'upload a certificate'}</td></tr>
4823 <tr><td colspan='3'>&nbsp;</td></tr>
4824 <tr><td colspan='3'><hr /></td></tr>
4825 <tr><td colspan='3'>&nbsp;</td></tr>
4826 <tr><td><input type='radio' name='AUTH' value='certgen' $checked{'AUTH'}{'certgen'} $cakeydisabled /></td><td class='base'>$Lang::tr{'generate a certificate'}</td><td>&nbsp;</td></tr>
4827 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'users fullname or system hostname'}:&nbsp;<img src='/blob.gif' alt='*' /></td><td class='base' nowrap='nowrap'><input type='text' name='CERT_NAME' value='$cgiparams{'CERT_NAME'}' SIZE='32' $cakeydisabled /></td></tr>
4828 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'users email'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_EMAIL' value='$cgiparams{'CERT_EMAIL'}' SIZE='32' $cakeydisabled /></td></tr>
4829 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'users department'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_OU' value='$cgiparams{'CERT_OU'}' SIZE='32' $cakeydisabled /></td></tr>
4830 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'organization name'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_ORGANIZATION' value='$cgiparams{'CERT_ORGANIZATION'}' SIZE='32' $cakeydisabled /></td></tr>
4831 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'city'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_CITY' value='$cgiparams{'CERT_CITY'}' SIZE='32' $cakeydisabled /></td></tr>
4832 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'state or province'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_STATE' value='$cgiparams{'CERT_STATE'}' SIZE='32' $cakeydisabled /></td></tr>
4833 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'country'}:</td><td class='base'><select name='CERT_COUNTRY' $cakeydisabled>
4834 END
4835 ;
4836
4837 } else {
4838
4839 print <<END;
4840 <table width='100%' cellpadding='0' cellspacing='5' border='0'>
4841
4842 <tr><td><input type='radio' name='AUTH' value='certgen' $checked{'AUTH'}{'certgen'} $cakeydisabled /></td><td class='base'>$Lang::tr{'generate a certificate'}</td><td>&nbsp;</td></tr>
4843 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'users fullname or system hostname'}:&nbsp;<img src='/blob.gif' alt='*' /></td><td class='base' nowrap='nowrap'><input type='text' name='CERT_NAME' value='$cgiparams{'CERT_NAME'}' SIZE='32' $cakeydisabled /></td></tr>
4844 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'users email'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_EMAIL' value='$cgiparams{'CERT_EMAIL'}' SIZE='32' $cakeydisabled /></td></tr>
4845 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'users department'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_OU' value='$cgiparams{'CERT_OU'}' SIZE='32' $cakeydisabled /></td></tr>
4846 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'organization name'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_ORGANIZATION' value='$cgiparams{'CERT_ORGANIZATION'}' SIZE='32' $cakeydisabled /></td></tr>
4847 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'city'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_CITY' value='$cgiparams{'CERT_CITY'}' SIZE='32' $cakeydisabled /></td></tr>
4848 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'state or province'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_STATE' value='$cgiparams{'CERT_STATE'}' SIZE='32' $cakeydisabled /></td></tr>
4849 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'country'}:</td><td class='base'><select name='CERT_COUNTRY' $cakeydisabled>
4850
4851
4852 END
4853 ;
4854
4855 }
4856
4857 foreach my $country (sort keys %{Countries::countries}) {
4858 print "<option value='$Countries::countries{$country}'";
4859 if ( $Countries::countries{$country} eq $cgiparams{'CERT_COUNTRY'} ) {
4860 print " selected='selected'";
4861 }
4862 print ">$country</option>";
4863 }
4864
4865 if ($cgiparams{'TYPE'} eq 'host') {
4866 print <<END;
4867 </select></td></tr>
4868 <td>&nbsp;</td><td class='base'>$Lang::tr{'valid till'} (days):&nbsp;<img src='/blob.gif' alt='*' /</td>
4869 <td class='base' nowrap='nowrap'><input type='text' name='DAYS_VALID' value='$cgiparams{'DAYS_VALID'}' size='32' $cakeydisabled /></td></tr>
4870 <tr><td>&nbsp;</td>
4871 <td class='base'>$Lang::tr{'pkcs12 file password'}:</td>
4872 <td class='base' nowrap='nowrap'><input type='password' name='CERT_PASS1' value='$cgiparams{'CERT_PASS1'}' size='32' $cakeydisabled /></td></tr>
4873 <tr><td>&nbsp;</td><td class='base'>$Lang::tr{'pkcs12 file password'}:<br>($Lang::tr{'confirmation'})</td>
4874 <td class='base' nowrap='nowrap'><input type='password' name='CERT_PASS2' value='$cgiparams{'CERT_PASS2'}' size='32' $cakeydisabled /></td></tr>
4875 <tr><td colspan='3'>&nbsp;</td></tr>
4876 <tr><td colspan='3'><hr /></td></tr>
4877 <tr><td class='base' colspan='3' align='left'><img src='/blob.gif' alt='*' />&nbsp;$Lang::tr{'required field'}</td></tr>
4878 </table>
4879 END
4880 }else{
4881 print <<END;
4882 </select></td></tr>
4883 <td>&nbsp;</td><td class='base'>$Lang::tr{'valid till'} (days):&nbsp;<img src='/blob.gif' alt='*' /</td>
4884 <td class='base' nowrap='nowrap'><input type='text' name='DAYS_VALID' value='$cgiparams{'DAYS_VALID'}' size='32' $cakeydisabled /></td></tr>
4885 <tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
4886 <tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
4887 <tr><td colspan='3'><hr /></td></tr>
4888 <tr><td class='base' colspan='3' align='left'><img src='/blob.gif' alt='*' />&nbsp;$Lang::tr{'required field'}</td></tr>
4889 </table>
4890
4891 END
4892 }
4893
4894 &Header::closebox();
4895
4896 }
4897
4898 if ($cgiparams{'TYPE'} eq 'host') {
4899 print"<br><br>";
4900 &Header::openbox('100%', 'LEFT', "$Lang::tr{'ccd client options'}:");
4901
4902
4903 print <<END;
4904 <table border='0' width='100%'>
4905 <tr><td width='20%'>Redirect Gateway:</td><td colspan='3'><input type='checkbox' name='RG' $checked{'RG'}{'on'} /></td></tr>
4906 <tr><td colspan='4'><b><br>$Lang::tr{'ccd routes'}</b></td></tr>
4907 <tr><td colspan='4'>&nbsp</td></tr>
4908 <tr><td valign='top'>$Lang::tr{'ccd iroute'}</td><td align='left' width='30%'><textarea name='IR' cols='26' rows='6' wrap='off'>
4909 END
4910
4911 if ($cgiparams{'IR'} ne ''){
4912 print $cgiparams{'IR'};
4913 }else{
4914 &General::readhasharray ("${General::swroot}/ovpn/ccdroute", \%ccdroutehash);
4915 foreach my $key (keys %ccdroutehash) {
4916 if( $cgiparams{'NAME'} eq $ccdroutehash{$key}[0]){
4917 foreach my $i (1 .. $#{$ccdroutehash{$key}}) {
4918 if ($ccdroutehash{$key}[$i] ne ''){
4919 print $ccdroutehash{$key}[$i]."\n";
4920 }
4921 $cgiparams{'IR'} .= $ccdroutehash{$key}[$i];
4922 }
4923 }
4924 }
4925 }
4926
4927 print <<END;
4928 </textarea></td><td valign='top' colspan='2'></td></tr>
4929 <tr><td colspan='4'><br></td></tr>
4930 <tr><td valign='top' rowspan='3'>$Lang::tr{'ccd iroute2'}</td><td align='left' valign='top' rowspan='3'><select name='IFROUTE' style="width: 205px"; size='6' multiple>
4931 END
4932
4933 my $set=0;
4934 my $selorange=0;
4935 my $selblue=0;
4936 my $selgreen=0;
4937 my $helpblue=0;
4938 my $helporange=0;
4939 my $other=0;
4940 my $none=0;
4941 my @temp=();
4942
4943 our @current = ();
4944 open(FILE, "${General::swroot}/main/routing") ;
4945 @current = <FILE>;
4946 close (FILE);
4947 &General::readhasharray ("${General::swroot}/ovpn/ccdroute2", \%ccdroute2hash);
4948 #check for "none"
4949 foreach my $key (keys %ccdroute2hash) {
4950 if($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}){
4951 if ($ccdroute2hash{$key}[1] eq ''){
4952 $none=1;
4953 last;
4954 }
4955 }
4956 }
4957 if ($none ne '1'){
4958 print"<option>$Lang::tr{'ccd none'}</option>";
4959 }else{
4960 print"<option selected>$Lang::tr{'ccd none'}</option>";
4961 }
4962 #check if static routes are defined for client
4963 foreach my $line (@current) {
4964 chomp($line);
4965 $line=~s/\s*$//g; # remove newline
4966 @temp=split(/\,/,$line);
4967 $temp[1] = '' unless defined $temp[1]; # not always populated
4968 my ($a,$b) = split(/\//,$temp[1]);
4969 $temp[1] = $a."/".&General::iporsubtocidr($b);
4970 foreach my $key (keys %ccdroute2hash) {
4971 if($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}){
4972 foreach my $i (1 .. $#{$ccdroute2hash{$key}}) {
4973 if($ccdroute2hash{$key}[$i] eq $a."/".&General::iporsubtodec($b)){
4974 $set=1;
4975 }
4976 }
4977 }
4978 }
4979 if ($set == '1' && $#temp != -1){ print"<option selected>$temp[1]</option>";$set=0;}elsif($set == '0' && $#temp != -1){print"<option>$temp[1]</option>";}
4980 }
4981
4982 my %vpnconfig = ();
4983 &General::readhasharray("${General::swroot}/vpn/config", \%vpnconfig);
4984 foreach my $vpn (keys %vpnconfig) {
4985 # Skip all disabled VPN connections
4986 my $enabled = $vpnconfig{$vpn}[0];
4987 next unless ($enabled eq "on");
4988
4989 my $name = $vpnconfig{$vpn}[1];
4990
4991 # Remote subnets
4992 my @networks = split(/\|/, $vpnconfig{$vpn}[11]);
4993 foreach my $network (@networks) {
4994 my $selected = "";
4995
4996 foreach my $key (keys %ccdroute2hash) {
4997 if ($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}) {
4998 foreach my $i (1 .. $#{$ccdroute2hash{$key}}) {
4999 if ($ccdroute2hash{$key}[$i] eq $network) {
5000 $selected = "selected";
5001 }
5002 }
5003 }
5004 }
5005
5006 print "<option value=\"$network\" $selected>$name ($network)</option>\n";
5007 }
5008 }
5009
5010 #check if green,blue,orange are defined for client
5011 foreach my $key (keys %ccdroute2hash) {
5012 if($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}){
5013 $other=1;
5014 foreach my $i (1 .. $#{$ccdroute2hash{$key}}) {
5015 if ($ccdroute2hash{$key}[$i] eq $Network::ethernet{'GREEN_NETADDRESS'}."/".&General::iporsubtodec($Network::ethernet{'GREEN_NETMASK'})){
5016 $selgreen=1;
5017 }
5018 if (&Header::blue_used()){
5019 if( $ccdroute2hash{$key}[$i] eq $Network::ethernet{'BLUE_NETADDRESS'}."/".&General::iporsubtodec($Network::ethernet{'BLUE_NETMASK'})) {
5020 $selblue=1;
5021 }
5022 }
5023 if (&Header::orange_used()){
5024 if( $ccdroute2hash{$key}[$i] eq $Network::ethernet{'ORANGE_NETADDRESS'}."/".&General::iporsubtodec($Network::ethernet{'ORANGE_NETMASK'}) ) {
5025 $selorange=1;
5026 }
5027 }
5028 }
5029 }
5030 }
5031 if (&Header::blue_used() && $selblue == '1'){ print"<option selected>$Lang::tr{'blue'}</option>";$selblue=0;}elsif(&Header::blue_used() && $selblue == '0'){print"<option>$Lang::tr{'blue'}</option>";}
5032 if (&Header::orange_used() && $selorange == '1'){ print"<option selected>$Lang::tr{'orange'}</option>";$selorange=0;}elsif(&Header::orange_used() && $selorange == '0'){print"<option>$Lang::tr{'orange'}</option>";}
5033 if ($selgreen == '1' || $other == '0'){ print"<option selected>$Lang::tr{'green'}</option>";$set=0;}else{print"<option>$Lang::tr{'green'}</option>";};
5034
5035 print<<END;
5036 </select></td><td valign='top'>DNS1:</td><td valign='top'><input type='TEXT' name='CCD_DNS1' value='$cgiparams{'CCD_DNS1'}' size='30' /></td></tr>
5037 <tr valign='top'><td>DNS2:</td><td><input type='TEXT' name='CCD_DNS2' value='$cgiparams{'CCD_DNS2'}' size='30' /></td></tr>
5038 <tr valign='top'><td valign='top'>WINS:</td><td><input type='TEXT' name='CCD_WINS' value='$cgiparams{'CCD_WINS'}' size='30' /></td></tr></table><br><hr>
5039
5040 END
5041 ;
5042 &Header::closebox();
5043 }
5044 print "<div align='center'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' />";
5045 print "<input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></div></form>";
5046 &Header::closebigbox();
5047 &Header::closepage();
5048 exit (0);
5049 }
5050 VPNCONF_END:
5051 }
5052
5053 %cahash = ();
5054 %confighash = ();
5055 &General::readhasharray("${General::swroot}/ovpn/caconfig", \%cahash);
5056 &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
5057
5058 my @status = ();
5059
5060 # Only load status when the RW server is enabled
5061 if ($vpnsettings{'ENABLED'} eq 'on') {
5062 open(FILE, "/usr/local/bin/openvpnctrl rw log |");
5063 @status = <FILE>;
5064 close(FILE);
5065 }
5066
5067 $checked{'ENABLED'}{'off'} = '';
5068 $checked{'ENABLED'}{'on'} = '';
5069 $checked{'ENABLED'}{$vpnsettings{'ENABLED'}} = 'CHECKED';
5070
5071 &Header::showhttpheaders();
5072 &Header::openpage($Lang::tr{'status ovpn'}, 1, '');
5073 &Header::openbigbox('100%', 'LEFT', '', $errormessage);
5074
5075 # Show any errors and warnings
5076 &Header::errorbox($errormessage);
5077
5078 if ($warnmessage) {
5079 &Header::openbox('100%', 'LEFT', $Lang::tr{'warning messages'});
5080 print "$warnmessage<br>";
5081 print "$Lang::tr{'fwdfw warn1'}<br>";
5082 &Header::closebox();
5083 print"<center><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'ok'}' style='width: 5em;'></form>";
5084 &Header::closepage();
5085 exit 0;
5086 }
5087
5088 &Header::openbox('100%', 'LEFT', $Lang::tr{'ovpn roadwarrior settings'});
5089
5090 # Show the service status
5091 &Header::ServiceStatus({
5092 $Lang::tr{'ovpn roadwarrior server'} => {
5093 "process" => "openvpn",
5094 "pidfile" => "/var/run/openvpn-rw.pid",
5095 }
5096 });
5097
5098 print <<END;
5099 <form method='POST'>
5100 <table class="form">
5101 <tr>
5102 <td class='boldbase'>
5103 $Lang::tr{'enabled'}
5104 </td>
5105 <td>
5106 <input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} />
5107 </td>
5108 </tr>
5109
5110 <tr>
5111 <td colspan='2'></td>
5112 </tr>
5113
5114 <tr>
5115 <td>
5116 $Lang::tr{'ovpn fqdn'}
5117 </td>
5118 <td>
5119 <input type='text' name='VPN_IP' value='$vpnsettings{'VPN_IP'}' />
5120 </td>
5121 </tr>
5122
5123 <tr>
5124 <td>
5125 $Lang::tr{'ovpn dynamic client subnet'}
5126 </td>
5127 <td>
5128 <input type='TEXT' name='DOVPN_SUBNET' value='$vpnsettings{'DOVPN_SUBNET'}' />
5129 </td>
5130 </tr>
5131
5132 <tr class="action">
5133 <td colspan="2">
5134 <input type='submit' name='ACTION' value='$Lang::tr{'save'}' />
5135 <input type='submit' name='ACTION' value='$Lang::tr{'ccd net'}' />
5136 <input type='submit' name='ACTION' value='$Lang::tr{'advanced server'}' />
5137 </td>
5138 </tr>
5139 </table>
5140 </form>
5141 END
5142
5143 &Header::closebox();
5144
5145 &Header::openbox('100%', 'LEFT', $Lang::tr{'connection status and controlc' });
5146 print <<END;
5147 <table class='tbl'>
5148 <tr>
5149 <th width='15%'>
5150 $Lang::tr{'name'}
5151 </th>
5152 <th width='10%'>
5153 $Lang::tr{'type'}
5154 </th>
5155 <th>
5156 $Lang::tr{'remark'}
5157 </th>
5158 <th width='10%'>
5159 $Lang::tr{'status'}
5160 </th>
5161 <th width='5%' colspan='8'>
5162 $Lang::tr{'action'}
5163 </th>
5164 </tr>
5165 END
5166
5167 my $gif;
5168
5169 foreach my $key (sort { ncmp ($confighash{$a}[1],$confighash{$b}[1]) } keys %confighash) {
5170 my $status = $confighash{$key}[0];
5171 my $name = $confighash{$key}[1];
5172 my $type = $confighash{$key}[3];
5173
5174 # Create some simple booleans to check the status
5175 my $hasExpired = 0;
5176 my $expiresSoon = 0;
5177
5178 # Fetch information about the certificate for non-N2N connections only
5179 if ($confighash{$key}[3] ne 'net') {
5180 my @cavalid = &General::system_output("/usr/bin/openssl", "x509", "-text",
5181 "-in", "${General::swroot}/ovpn/certs/$confighash{$key}[1]cert.pem");
5182
5183 my $expiryDate = 0;
5184
5185 # Parse the certificate information
5186 foreach my $line (@cavalid) {
5187 if ($line =~ /Not After : (.*)[\n]/) {
5188 $expiryDate = &Date::Parse::str2time($1);
5189 last;
5190 }
5191 }
5192
5193 # Calculate the remaining time
5194 my $remainingTime = $expiryDate - time();
5195
5196 # Determine whether the certificate has already expired, or will so soon
5197 $hasExpired = ($remainingTime <= 0);
5198 $expiresSoon = ($remainingTime <= 30 * 24 * 3600);
5199 }
5200
5201 my @classes = ();
5202
5203 # Highlight the row if the certificate has expired/will expire soon
5204 if ($hasExpired || $expiresSoon) {
5205 push(@classes, "is-warning");
5206 }
5207
5208 # Start a new row
5209 print "<tr class='@classes'>";
5210
5211 # Show the name of the connection
5212 print " <th scope='row'>$name";
5213 if ($hasExpired) {
5214 print " ($Lang::tr{'openvpn cert has expired'})";
5215 } elsif ($expiresSoon) {
5216 print " ($Lang::tr{'openvpn cert expires soon'})";
5217 }
5218 print "</th>";
5219
5220 # Show type
5221 print "<td class='text-center'>$Lang::tr{$type}</td>";
5222
5223 # Show remarks
5224 print "<td>$confighash{$key}[25]</td>";
5225
5226 my $connstatus = "DISCONNECTED";
5227
5228 # Disabled Connections
5229 if ($status eq "off") {
5230 $connstatus = "DISABLED";
5231
5232 # N2N Connections
5233 } elsif ($type eq "net") {
5234 if (-e "/var/run/${name}n2n.pid") {
5235 my $port = $confighash{$key}[22];
5236
5237 if ($port ne "") {
5238 $connstatus = &openvpn_status($confighash{$key}[22]);
5239 }
5240 }
5241
5242 # RW Connections
5243 } elsif ($type eq "host") {
5244 my $cn;
5245
5246 foreach my $line (@status) {
5247 chomp($line);
5248
5249 if ($line =~ /^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/) {
5250 my @match = split(m/^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/, $line);
5251
5252 if ($match[1] ne "Common Name") {
5253 $cn = $match[1];
5254 }
5255
5256 if ($cn eq "$confighash{$key}[2]") {
5257 $connstatus = "CONNECTED";
5258 }
5259 }
5260 }
5261 }
5262
5263 if ($connstatus eq "DISABLED") {
5264 print "<td class='status is-disabled'>$Lang::tr{'capsclosed'}</td>";
5265 } elsif ($connstatus eq "CONNECTED") {
5266 print "<td class='status is-connected'>$Lang::tr{'capsopen'}</td>";
5267 } elsif ($connstatus eq "DISCONNECTED") {
5268 print "<td class='status is-disconnected'>$Lang::tr{'capsclosed'}</td>";
5269 } else {
5270 print "<td class='status is-unknown'>$connstatus</td>";
5271 }
5272
5273 # Download Configuration
5274 print <<END;
5275 <td class="text-center">
5276 <form method='post' name='frm${key}a'>
5277 <input type='image' name='$Lang::tr{'dl client arch'}' src='/images/openvpn.png'
5278 alt='$Lang::tr{'dl client arch'}' title='$Lang::tr{'dl client arch'}' />
5279 <input type='hidden' name='ACTION' value='$Lang::tr{'dl client arch'}' />
5280 <input type='hidden' name='KEY' value='$key' />
5281 </form>
5282 </td>
5283 END
5284
5285 # Show Certificate
5286 if ($confighash{$key}[4] eq 'cert') {
5287 print <<END;
5288 <td class="text-center">
5289 <form method='post' name='frm${key}b'>
5290 <input type='image' name='$Lang::tr{'show certificate'}' src='/images/info.gif'
5291 alt='$Lang::tr{'show certificate'}' title='$Lang::tr{'show certificate'}' />
5292 <input type='hidden' name='ACTION' value='$Lang::tr{'show certificate'}' />
5293 <input type='hidden' name='KEY' value='$key' />
5294 </form>
5295 </td>
5296 END
5297
5298 } else {
5299 print "<td></td>";
5300 }
5301
5302 # Show OTP QR code
5303 if ($confighash{$key}[43] eq 'on') {
5304 print <<END;
5305 <td class="text-center">
5306 <form method='post' name='frm${key}o'>
5307 <input type='image' name='$Lang::tr{'show otp qrcode'}' src='/images/qr-code.png'
5308 alt='$Lang::tr{'show otp qrcode'}' title='$Lang::tr{'show otp qrcode'}' />
5309 <input type='hidden' name='ACTION' value='$Lang::tr{'show otp qrcode'}' />
5310 <input type='hidden' name='KEY' value='$key' />
5311 </form>
5312 </td>
5313 END
5314 } else {
5315 print "<td></td>";
5316 }
5317
5318 # Download Certificate
5319 if ($confighash{$key}[4] eq 'cert' && -f "${General::swroot}/ovpn/certs/$confighash{$key}[1].p12") {
5320 print <<END;
5321 <td class="text-center">
5322 <form method='post' name='frm${key}c'>
5323 <input type='image' name='$Lang::tr{'download pkcs12 file'}' src='/images/media-floppy.png'
5324 alt='$Lang::tr{'download pkcs12 file'}' title='$Lang::tr{'download pkcs12 file'}' />
5325 <input type='hidden' name='ACTION' value='$Lang::tr{'download pkcs12 file'}' />
5326 <input type='hidden' name='KEY' value='$key' />
5327 </form>
5328 </td>
5329 END
5330
5331 } elsif ($confighash{$key}[4] eq 'cert') {
5332 print <<END;
5333 <td class="text-center">
5334 <form method='post' name='frm${key}c'>
5335 <input type='image' name='$Lang::tr{'download certificate'}' src='/images/media-floppy.png'
5336 alt='$Lang::tr{'download certificate'}' title='$Lang::tr{'download certificate'}' />
5337 <input type='hidden' name='ACTION' value='$Lang::tr{'download certificate'}' />
5338 <input type='hidden' name='KEY' value='$key' />
5339 </form>
5340 </td>
5341 END
5342 } else {
5343 print "<td></td>";
5344 }
5345
5346 if ($status eq 'on') {
5347 $gif = 'on.gif';
5348 } else {
5349 $gif = 'off.gif';
5350 }
5351
5352 print <<END;
5353 <td class="text-center">
5354 <form method='post' name='frm${key}d'>
5355 <input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif'
5356 alt='$Lang::tr{'toggle enable disable'}' title='$Lang::tr{'toggle enable disable'}' />
5357 <input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />
5358 <input type='hidden' name='KEY' value='$key' />
5359 </form>
5360 </td>
5361
5362 <td class="text-center">
5363 <form method='post' name='frm${key}e'>
5364 <input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />
5365 <input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif'
5366 alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
5367 <input type='hidden' name='KEY' value='$key' />
5368 </form>
5369 </td>
5370
5371 <td class="text-center">
5372 <form method='post' name='frm${key}f'>
5373 <input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />
5374 <input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif'
5375 alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
5376 <input type='hidden' name='KEY' value='$key' />
5377 </form>
5378 </td>
5379 </tr>
5380 END
5381
5382 }
5383 print"</table>";
5384
5385 # Show controls
5386 print <<END;
5387 <table class="form">
5388 <tr class="action">
5389 <td>
5390 <form method='post'>
5391 <input type='submit' name='ACTION' value='$Lang::tr{'add'}' />
5392 <input type='submit' name='ACTION' value='$Lang::tr{'ovpn con stat'}' />
5393 </form>
5394 </td>
5395 </tr>
5396 </table>
5397 END
5398
5399 &Header::closebox();
5400
5401 # CA/key listing
5402 &Header::openbox('100%', 'LEFT', "$Lang::tr{'certificate authorities'}");
5403 print <<END;
5404 <table width='100%' cellspacing='1' cellpadding='0' class='tbl'>
5405 <tr>
5406 <th width='25%' class='boldbase' align='center'><b>$Lang::tr{'name'}</b></th>
5407 <th width='65%' class='boldbase' align='center'><b>$Lang::tr{'subject'}</b></th>
5408 <th width='10%' class='boldbase' colspan='3' align='center'><b>$Lang::tr{'action'}</b></th>
5409 </tr>
5410 END
5411 ;
5412 my $col1="bgcolor='$Header::color{'color22'}'";
5413 my $col2="bgcolor='$Header::color{'color20'}'";
5414 # DH parameter line
5415 my $col3="bgcolor='$Header::color{'color22'}'";
5416 # ta.key line
5417 my $col4="bgcolor='$Header::color{'color20'}'";
5418
5419 if (-f "${General::swroot}/ovpn/ca/cacert.pem") {
5420 my @casubject = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/cacert.pem");
5421 my $casubject;
5422
5423 foreach my $line (@casubject) {
5424 if ($line =~ /Subject: (.*)[\n]/) {
5425 $casubject = $1;
5426 $casubject =~ s+/Email+, E+;
5427 $casubject =~ s/ ST=/ S=/;
5428
5429 last;
5430 }
5431 }
5432
5433 print <<END;
5434 <tr>
5435 <td class='base' $col1>$Lang::tr{'root certificate'}</td>
5436 <td class='base' $col1>$casubject</td>
5437 <form method='post' name='frmrootcrta'><td width='3%' align='center' $col1>
5438 <input type='hidden' name='ACTION' value='$Lang::tr{'show root certificate'}' />
5439 <input type='image' name='$Lang::tr{'edit'}' src='/images/info.gif' alt='$Lang::tr{'show root certificate'}' title='$Lang::tr{'show root certificate'}' width='20' height='20' border='0' />
5440 </form>
5441 <form method='post' name='frmrootcrtb'><td width='3%' align='center' $col1>
5442 <input type='image' name='$Lang::tr{'download root certificate'}' src='/images/media-floppy.png' alt='$Lang::tr{'download root certificate'}' title='$Lang::tr{'download root certificate'}' border='0' />
5443 <input type='hidden' name='ACTION' value='$Lang::tr{'download root certificate'}' />
5444 </form>
5445 <td width='4%' $col1>&nbsp;</td>
5446 </tr>
5447 END
5448 ;
5449 } else {
5450 # display rootcert generation buttons
5451 print <<END;
5452 <tr>
5453 <td class='base' $col1>$Lang::tr{'root certificate'}:</td>
5454 <td class='base' $col1>$Lang::tr{'not present'}</td>
5455 <td colspan='3' $col1>&nbsp;</td>
5456 </tr>
5457 END
5458 ;
5459 }
5460
5461 if (-f "${General::swroot}/ovpn/certs/servercert.pem") {
5462 my @hostsubject = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
5463 my $hostsubject;
5464
5465 foreach my $line (@hostsubject) {
5466 if ($line =~ /Subject: (.*)[\n]/) {
5467 $hostsubject = $1;
5468 $hostsubject =~ s+/Email+, E+;
5469 $hostsubject =~ s/ ST=/ S=/;
5470
5471 last;
5472 }
5473 }
5474
5475 print <<END;
5476 <tr>
5477 <td class='base' $col2>$Lang::tr{'host certificate'}</td>
5478 <td class='base' $col2>$hostsubject</td>
5479 <form method='post' name='frmhostcrta'><td width='3%' align='center' $col2>
5480 <input type='hidden' name='ACTION' value='$Lang::tr{'show host certificate'}' />
5481 <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'}' width='20' height='20' border='0' />
5482 </form>
5483 <form method='post' name='frmhostcrtb'><td width='3%' align='center' $col2>
5484 <input type='image' name="$Lang::tr{'download host certificate'}" src='/images/media-floppy.png' alt="$Lang::tr{'download host certificate'}" title="$Lang::tr{'download host certificate'}" border='0' />
5485 <input type='hidden' name='ACTION' value="$Lang::tr{'download host certificate'}" />
5486 </td></form>
5487 <td width='4%' $col2>&nbsp;</td>
5488 </tr>
5489 END
5490 ;
5491 } else {
5492 # Nothing
5493 print <<END;
5494 <tr>
5495 <td width='25%' class='base' $col2>$Lang::tr{'host certificate'}:</td>
5496 <td class='base' $col2>$Lang::tr{'not present'}</td>
5497 </td><td colspan='3' $col2>&nbsp;</td>
5498 </tr>
5499 END
5500 ;
5501 }
5502
5503 # Adding ta.key to chart
5504 if (-f "${General::swroot}/ovpn/certs/ta.key") {
5505 open(FILE, "${General::swroot}/ovpn/certs/ta.key");
5506 my @tasubject = <FILE>;
5507 close(FILE);
5508
5509 my $tasubject;
5510 foreach my $line (@tasubject) {
5511 if($line =~ /# (.*)[\n]/) {
5512 $tasubject = $1;
5513
5514 last;
5515 }
5516 }
5517
5518 print <<END;
5519
5520 <tr>
5521 <td class='base' $col4>$Lang::tr{'ta key'}</td>
5522 <td class='base' $col4>$tasubject</td>
5523 <form method='post' name='frmtakey'><td width='3%' align='center' $col4>
5524 <input type='hidden' name='ACTION' value='$Lang::tr{'show tls-auth key'}' />
5525 <input type='image' name='$Lang::tr{'edit'}' src='/images/info.gif' alt='$Lang::tr{'show tls-auth key'}' title='$Lang::tr{'show tls-auth key'}' width='20' height='20' border='0' />
5526 </form>
5527 <form method='post' name='frmtakey'><td width='3%' align='center' $col4>
5528 <input type='image' name='$Lang::tr{'download tls-auth key'}' src='/images/media-floppy.png' alt='$Lang::tr{'download tls-auth key'}' title='$Lang::tr{'download tls-auth key'}' border='0' />
5529 <input type='hidden' name='ACTION' value='$Lang::tr{'download tls-auth key'}' />
5530 </form>
5531 <td width='4%' $col4>&nbsp;</td>
5532 </tr>
5533 END
5534 ;
5535 } else {
5536 # Nothing
5537 print <<END;
5538 <tr>
5539 <td width='25%' class='base' $col4>$Lang::tr{'ta key'}:</td>
5540 <td class='base' $col4>$Lang::tr{'not present'}</td>
5541 <td colspan='3' $col4>&nbsp;</td>
5542 </tr>
5543 END
5544 ;
5545 }
5546
5547 if (! -f "${General::swroot}/ovpn/ca/cacert.pem") {
5548 print "<tr><td colspan='5' align='center'><form method='post'>";
5549 print "<input type='submit' name='ACTION' value='$Lang::tr{'generate root/host certificates'}' />";
5550 print "</form></td></tr>\n";
5551 }
5552
5553 if (keys %cahash > 0) {
5554 foreach my $key (keys %cahash) {
5555 if (($key + 1) % 2) {
5556 print "<tr bgcolor='$Header::color{'color20'}'>\n";
5557 } else {
5558 print "<tr bgcolor='$Header::color{'color22'}'>\n";
5559 }
5560 print "<td class='base'>$cahash{$key}[0]</td>\n";
5561 print "<td class='base'>$cahash{$key}[1]</td>\n";
5562 print <<END;
5563 <form method='post' name='cafrm${key}a'><td align='center'>
5564 <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'}' border='0' />
5565 <input type='hidden' name='ACTION' value='$Lang::tr{'show ca certificate'}' />
5566 <input type='hidden' name='KEY' value='$key' />
5567 </td></form>
5568 <form method='post' name='cafrm${key}b'><td align='center'>
5569 <input type='image' name='$Lang::tr{'download ca certificate'}' src='/images/media-floppy.png' alt='$Lang::tr{'download ca certificate'}' title='$Lang::tr{'download ca certificate'}' border='0' />
5570 <input type='hidden' name='ACTION' value='$Lang::tr{'download ca certificate'}' />
5571 <input type='hidden' name='KEY' value='$key' />
5572 </td></form>
5573 <form method='post' name='cafrm${key}c'><td align='center'>
5574 <input type='hidden' name='ACTION' value='$Lang::tr{'remove ca certificate'}' />
5575 <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'}' width='20' height='20' border='0' />
5576 <input type='hidden' name='KEY' value='$key' />
5577 </td></form></tr>
5578 END
5579 ;
5580 }
5581 }
5582
5583 print "</table>";
5584
5585 # If the file contains entries, print Key to action icons
5586 if ( -f "${General::swroot}/ovpn/ca/cacert.pem") {
5587 print <<END;
5588 <table>
5589 <tr>
5590 <td class='boldbase'>&nbsp; <b>$Lang::tr{'legend'}:</b></td>
5591 <td>&nbsp; &nbsp; <img src='/images/info.gif' alt='$Lang::tr{'show certificate'}' /></td>
5592 <td class='base'>$Lang::tr{'show certificate'}</td>
5593 <td>&nbsp; &nbsp; <img src='/images/media-floppy.png' alt='$Lang::tr{'download certificate'}' /></td>
5594 <td class='base'>$Lang::tr{'download certificate'}</td>
5595 </tr>
5596 </table>
5597 END
5598 ;
5599 }
5600
5601 print <<END
5602
5603 <br><hr><br>
5604
5605 <form method='post' enctype='multipart/form-data'>
5606 <table border='0' width='100%'>
5607 <tr>
5608 <td colspan='4'><b>$Lang::tr{'upload ca certificate'}</b></td>
5609 </tr>
5610
5611 <tr>
5612 <td width='10%'>$Lang::tr{'ca name'}:</td>
5613 <td width='30%'><input type='text' name='CA_NAME' value='$cgiparams{'CA_NAME'}' size='15' align='left'></td>
5614 <td width='30%'><input type='file' name='FH' size='25'>
5615 <td width='30%'align='right'><input type='submit' name='ACTION' value='$Lang::tr{'upload ca certificate'}'></td>
5616 </tr>
5617
5618 <tr>
5619 <td colspan='3'>&nbsp;</td>
5620 <td align='right'><input type='submit' name='ACTION' value='$Lang::tr{'show crl'}' /></td>
5621 </tr>
5622 </table>
5623 </form>
5624
5625 <br><hr>
5626 END
5627 ;
5628
5629 if ($vpnsettings{'ENABLED'} eq "yes") {
5630 print "<div align='center'><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' disabled='disabled' /></div></form>\n";
5631 } else {
5632 print "<div align='center'><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' /></div></form>\n";
5633 }
5634 &Header::closebox();
5635 END
5636 ;
5637
5638 &Header::closepage();
5639