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