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