###############################################################################
# #
# IPFire.org - A linux based firewall #
-# Copyright (C) 2007-2022 IPFire Team <info@ipfire.org> #
+# Copyright (C) 2007-2023 IPFire Team <info@ipfire.org> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
use strict;
use Archive::Zip qw(:ERROR_CODES :CONSTANTS);
use Sort::Naturally;
+use Date::Parse;
require '/var/ipfire/general-functions.pl';
require "${General::swroot}/lang.pl";
require "${General::swroot}/header.pl";
###
### Useful functions
###
+sub iscertlegacy
+{
+ my $file=$_[0];
+ my @certinfo = &General::system_output("/usr/bin/openssl", "pkcs12", "-info", "-nodes",
+ "-in", "$file.p12", "-noout", "-passin", "pass:''");
+ if (index ($certinfo[0], "MAC: sha1") != -1) {
+ return 1;
+ }
+ return 0;
+}
+
sub haveOrangeNet
{
if ($netsettings{'CONFIG_TYPE'} == 2) {return 1;}
my %ccdhash=();
# Check if the new name is valid.
- if(!&General::validhostname($newname)) {
+ if(!&General::validccdname($newname)) {
$errormessage=$Lang::tr{'ccd err invalidname'};
return;
}
print CLIENTCONF "# Activate Management Interface and Port\n";
if ($cgiparams{'OVPN_MGMT'} eq '') {print CLIENTCONF "management localhost $cgiparams{'DEST_PORT'}\n"}
else {print CLIENTCONF "management localhost $cgiparams{'OVPN_MGMT'}\n"};
+ if (&iscertlegacy("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}")) {
+ print CLIENTCONF "providers legacy default\n";
+ }
close(CLIENTCONF);
}
if ($confighash{$cgiparams{'KEY'}}[22] eq '') {print CLIENTCONF "management localhost $confighash{$cgiparams{'KEY'}}[29]\n"}
else {print CLIENTCONF "management localhost $confighash{$cgiparams{'KEY'}}[22]\n"};
print CLIENTCONF "# remsub $confighash{$cgiparams{'KEY'}}[11]\n";
+ if (&iscertlegacy("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]")) {
+ print CLIENTCONF "providers legacy default\n";
+ }
+
close(CLIENTCONF);
# Extract the certificate
# This system call is safe, because all arguments are passed as an array.
- system('/usr/bin/openssl', 'pkcs12', '-in', "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12",
- '-clcerts', '-nokeys', '-nodes', '-out', "$file_crt" , '-passin', 'pass:');
- if ($?) {
- die "openssl error: $?";
+ if (&iscertlegacy("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]")) {
+ system('/usr/bin/openssl', 'pkcs12', '-legacy', '-in', "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12",
+ '-clcerts', '-nokeys', '-nodes', '-out', "$file_crt" , '-passin', 'pass:');
+ if ($?) {
+ die "openssl error: $?";
+ }
+ } else {
+ system('/usr/bin/openssl', 'pkcs12', '-in', "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12",
+ '-clcerts', '-nokeys', '-nodes', '-out', "$file_crt" , '-passin', 'pass:');
+ if ($?) {
+ die "openssl error: $?";
+ }
}
$zip->addFile("$file_crt", "$confighash{$cgiparams{'KEY'}}[1].pem") or die;
# Extract the key
# This system call is safe, because all arguments are passed as an array.
- system('/usr/bin/openssl', 'pkcs12', '-in', "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12",
- '-nocerts', '-nodes', '-out', "$file_key", '-passin', 'pass:');
- if ($?) {
- die "openssl error: $?";
+ if (&iscertlegacy("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]")) {
+ system('/usr/bin/openssl', 'pkcs12', '-legacy', '-in', "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12",
+ '-nocerts', '-nodes', '-out', "$file_key", '-passin', 'pass:');
+ if ($?) {
+ die "openssl error: $?";
+ }
+ } else {
+ system('/usr/bin/openssl', 'pkcs12', '-in', "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12",
+ '-nocerts', '-nodes', '-out', "$file_key", '-passin', 'pass:');
+ if ($?) {
+ die "openssl error: $?";
+ }
}
$zip->addFile("$file_key", "$confighash{$cgiparams{'KEY'}}[1].key") or die;
# If the server is asking for TOTP this needs to happen interactively
print CLIENTCONF "auth-retry interact\r\n";
+ # Add provider line if certificate is legacy type
+ if (&iscertlegacy("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]")) {
+ print CLIENTCONF "providers legacy default\r\n";
+ }
+
if ($include_certs) {
print CLIENTCONF "\r\n";
<hr size='1'>
<table width='100%'>
<tr>
- <td class'base'><b>$Lang::tr{'misc-options'}</b></td>
+ <td class='base'><b>$Lang::tr{'misc-options'}</b></td>
</tr>
<tr>
<hr size='1'>
<table width='100%'>
<tr>
- <td class'base'><b>$Lang::tr{'log-options'}</b></td>
+ <td class='base'><b>$Lang::tr{'log-options'}</b></td>
</tr>
<tr>
<td width='20%'></td> <td width='30%'> </td><td width='25%'> </td><td width='25%'></td>
print FILE "# Logfile\n";
print FILE "status-version 1\n";
print FILE "status /var/run/openvpn/$n2nname[0]-n2n 10\n";
+ if (&iscertlegacy("${General::swroot}/ovpn/certs/$cgiparams{'n2nname'}")) {
+ print CLIENTCONF "providers legacy default\n";
+ }
+
close FILE;
unless(move("$tempdir/$uplconffilename", "${General::swroot}/ovpn/n2nconf/$n2nname[0]/$uplconffilename2")) {
$confighash{$key}[31] = $n2ntunmtu[1];
$confighash{$key}[39] = $n2nauth[1];
$confighash{$key}[40] = $n2ncipher[1];
- $confighash{$key}[41] = 'disabled';
+ $confighash{$key}[41] = 'no-pass';
&General::writehasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
}
}
- # Check for RW if client name is already set
- if ($cgiparams{'TYPE'} eq 'host') {
- foreach my $key (keys %confighash) {
- if ($confighash{$key}[1] eq $cgiparams{'NAME'}) {
- $errormessage = $Lang::tr{'a connection with this name already exists'};
- goto VPNCONF_ERROR;
- }
- }
- }
+ # Check for RW if client name is already set
+ if ($cgiparams{'TYPE'} eq 'host') {
+ foreach my $key (keys %confighash) {
+ if ($confighash{$key}[1] eq $cgiparams{'NAME'}) {
+ $errormessage = $Lang::tr{'a connection with this name already exists'};
+ goto VPNCONF_ERROR;
+ }
+ }
+ }
+
+ # Check if there is no other entry with this common name
+ if ((! $cgiparams{'KEY'}) && ($cgiparams{'AUTH'} ne 'psk')) {
+ foreach my $key (keys %confighash) {
+ if ($confighash{$key}[2] eq $cgiparams{'CERT_NAME'}) {
+ $errormessage = $Lang::tr{'a connection with this common name already exists'};
+ goto VPNCONF_ERROR;
+ }
+ }
+ }
# Replace empty strings with a .
(my $ou = $cgiparams{'CERT_OU'}) =~ s/^\s*$/\./;
goto VPNCONF_ERROR;
}
- # Check if there is no other entry with this common name
- if ((! $cgiparams{'KEY'}) && ($cgiparams{'AUTH'} ne 'psk')) {
- foreach my $key (keys %confighash) {
- if ($confighash{$key}[2] eq $cgiparams{'CERT_NAME'}) {
- $errormessage = $Lang::tr{'a connection with this common name already exists'};
- goto VPNCONF_ERROR;
- }
- }
- }
-
# Save the config
my $key = $cgiparams{'KEY'};
$confighash{$key}[39] = $cgiparams{'DAUTH'};
$confighash{$key}[40] = $cgiparams{'DCIPHER'};
- if (($cgiparams{'TYPE'} eq 'host') && ($cgiparams{'CERT_PASS1'} eq "")) {
- $confighash{$key}[41] = "no-pass";
- }
+ if ($confighash{$key}[41] eq "") {
+ if (($cgiparams{'TYPE'} eq 'host') && ($cgiparams{'CERT_PASS1'} eq "")) {
+ $confighash{$key}[41] = "no-pass";
+ } elsif (($cgiparams{'TYPE'} eq 'host') && ($cgiparams{'CERT_PASS1'} ne "")) {
+ $confighash{$key}[41] = "pass";
+ } elsif ($cgiparams{'TYPE'} eq 'net') {
+ $confighash{$key}[41] = "no-pass";
+ }
+ }
$confighash{$key}[42] = 'HOTP/T30/6';
$confighash{$key}[43] = $cgiparams{'OTP_STATE'};
<tr><td colspan=4><hr /></td></tr><tr>
<tr>
- <td class'base'><b>$Lang::tr{'MTU settings'}</b></td>
+ <td class='base'><b>$Lang::tr{'MTU settings'}</b></td>
</tr>
<tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'MTU'}</td>
<tr><td colspan=4><hr /></td></tr><tr>
<tr>
- <td class'base'><b>$Lang::tr{'ovpn crypt options'}:</b></td>
+ <td class='base'><b>$Lang::tr{'ovpn crypt options'}:</b></td>
</tr>
<tr><td class='boldbase'>$Lang::tr{'cipher'}</td>
<tr><td colspan='4'><br></td></tr>
<tr>
- <td class'base'><b>$Lang::tr{'net config'}:</b></td>
+ <td class='base'><b>$Lang::tr{'net config'}:</b></td>
</tr>
<tr><td colspan='1'><br></td></tr>
<tr><td colspan='4'><br></td></tr>
<tr>
- <td class'base'><b>$Lang::tr{'ovpn crypt options'}:</b></td>
+ <td class='base'><b>$Lang::tr{'ovpn crypt options'}:</b></td>
</tr>
<tr><td colspan='1'><br></td></tr>
END
}
if ($confighash{$key}[0] eq 'on') { $gif = 'on.gif'; } else { $gif = 'off.gif'; }
- if ($id % 2) {
- print "<tr>";
+
+ # Create some simple booleans to check the status
+ my $hasExpired;
+ my $expiresSoon;
+
+ # Fetch information about the certificate for non-N2N connections only
+ if ($confighash{$key}[3] ne 'net') {
+ my @cavalid = &General::system_output("/usr/bin/openssl", "x509", "-text",
+ "-in", "${General::swroot}/ovpn/certs/$confighash{$key}[1]cert.pem");
+
+ my $expiryDate = 0;
+
+ # Parse the certificate information
+ foreach my $line (@cavalid) {
+ if ($line =~ /Not After : (.*)[\n]/) {
+ $expiryDate = &Date::Parse::str2time($1);
+ last;
+ }
+ }
+
+ # Calculate the remaining time
+ my $remainingTime = $expiryDate - time();
+
+ # Determine whether the certificate has already expired, or will so soon
+ $hasExpired = ($remainingTime <= 0);
+ $expiresSoon = ($remainingTime <= 30 * 24 * 3600);
+
+ } else {
+ # Populate booleans with dummy values for N2N connections (#13066)
+ $hasExpired = 0;
+ $expiresSoon = 0;
+ }
+
+ print "<tr>";
+
+ if ($hasExpired || $expiresSoon) {
+ $col="bgcolor='$color{'color14'}'";
+ } elsif ($id % 2) {
$col="bgcolor='$color{'color20'}'";
} else {
- print "<tr>";
$col="bgcolor='$color{'color22'}'";
}
- print "<td align='center' nowrap='nowrap' $col>$confighash{$key}[1]</td>";
- print "<td align='center' nowrap='nowrap' $col>" . $Lang::tr{"$confighash{$key}[3]"} . " (" . $Lang::tr{"$confighash{$key}[4]"} . ")</td>";
- #if ($confighash{$key}[4] eq 'cert') {
- #print "<td align='left' nowrap='nowrap'>$confighash{$key}[2]</td>";
- #} else {
- #print "<td align='left'> </td>";
- #}
- my @cavalid = &General::system_output("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$confighash{$key}[1]cert.pem");
- my $cavalid;
-
- foreach my $line (@cavalid) {
- if ($line =~ /Not After : (.*)[\n]/) {
- $cavalid = $1;
-
- last;
- }
+ print "<td align='center' nowrap='nowrap' $col>$confighash{$key}[1]";
+ if ($hasExpired) {
+ print " ($Lang::tr{'openvpn cert has expired'})";
+ } elsif ($expiresSoon) {
+ print " ($Lang::tr{'openvpn cert expires soon'})";
}
-
+ print "</td>";
+ print "<td align='center' nowrap='nowrap' $col>" . $Lang::tr{"$confighash{$key}[3]"} . " (" . $Lang::tr{"$confighash{$key}[4]"} . ")</td>";
print "<td align='center' $col>$confighash{$key}[25]</td>";
$col1="bgcolor='${Header::colourred}'";
my $active = "<b><font color='#FFFFFF'>$Lang::tr{'capsclosed'}</font></b>";
if ($match[1] ne "Common Name") {
$cn = $match[1];
}
- $cn =~ s/[_]/ /g;
if ($cn eq "$confighash{$key}[2]") {
$col1="bgcolor='${Header::colourgreen}'";
$active = "<b><font color='#FFFFFF'>$Lang::tr{'capsopen'}</font></b>";
}
- print <<END;
- <td align='center' $col1>$active</td>
+ if ($confighash{$key}[41] eq "pass") {
+ print <<END;
+ <td align='center' $col1>$active</td>
- <form method='post' name='frm${key}a'><td align='center' $col>
- <input type='image' name='$Lang::tr{'dl client arch'}' src='/images/openvpn.png' alt='$Lang::tr{'dl client arch'}' title='$Lang::tr{'dl client arch'}' border='0' />
- <input type='hidden' name='ACTION' value='$Lang::tr{'dl client arch'}' />
- <input type='hidden' name='KEY' value='$key' />
- </td></form>
+ <form method='post' name='frm${key}a'><td align='center' $col>
+ <input type='image' name='$Lang::tr{'dl client arch'}' src='/images/openvpn_encrypted.png'
+ alt='$Lang::tr{'dl client arch'}' title='$Lang::tr{'dl client arch'}' border='0' />
+ <input type='hidden' name='ACTION' value='$Lang::tr{'dl client arch'}' />
+ <input type='hidden' name='MODE' value='secure' />
+ <input type='hidden' name='KEY' value='$key' />
+ </td></form>
END
- ;
- if ($confighash{$key}[41] eq "no-pass") {
+ ; } elsif ($confighash{$key}[41] eq "no-pass") {
print <<END;
- <form method='post' name='frm${key}g'><td align='center' $col>
+ <td align='center' $col1>$active</td>
+
+ <form method='post' name='frm${key}a'><td align='center' $col>
<input type='image' name='$Lang::tr{'dl client arch insecure'}' src='/images/openvpn.png'
alt='$Lang::tr{'dl client arch insecure'}' title='$Lang::tr{'dl client arch insecure'}' border='0' />
<input type='hidden' name='ACTION' value='$Lang::tr{'dl client arch'}' />
<input type='hidden' name='KEY' value='$key' />
</td></form>
END
- } else {
+ ; } else {
print "<td $col> </td>";
}
# If the config file contains entries, print Key to action icons
if ( $id ) {
print <<END;
- <table border='0'>
- <tr>
+ <table width='85%' border='0'>
+ <tr>
<td class='boldbase'> <b>$Lang::tr{'legend'}:</b></td>
- <td> <img src='/images/on.gif' alt='$Lang::tr{'click to disable'}' /></td>
- <td class='base'>$Lang::tr{'click to disable'}</td>
+ <td> <img src='/images/openvpn.png' alt='?RELOAD'/></td>
+ <td class='base'>$Lang::tr{'dl client arch insecure'}</td>
+ <td> <img src='/images/openvpn_encrypted.png' alt='?RELOAD'/></td>
+ <td class='base'>$Lang::tr{'dl client arch'}</td>
<td> <img src='/images/info.gif' alt='$Lang::tr{'show certificate'}' /></td>
<td class='base'>$Lang::tr{'show certificate'}</td>
+ <td> <img src='/images/qr-code.png' alt='$Lang::tr{'show otp qrcode'}'/></td>
+ <td class='base'>$Lang::tr{'show otp qrcode'}</td>
+ </tr>
+ <tr>
+ <td> </td>
+ <td> <img src='/images/media-floppy.png' alt='?FLOPPY' /></td>
+ <td class='base'>$Lang::tr{'download certificate'}</td>
+ <td> <img src='/images/off.gif' alt='?OFF' /></td>
+ <td class='base'>$Lang::tr{'click to enable'}</td>
+ <td> <img src='/images/on.gif' alt='$Lang::tr{'click to disable'}' /></td>
+ <td class='base'>$Lang::tr{'click to disable'}</td>
+
<td> <img src='/images/edit.gif' alt='$Lang::tr{'edit'}' /></td>
<td class='base'>$Lang::tr{'edit'}</td>
<td> <img src='/images/delete.gif' alt='$Lang::tr{'remove'}' /></td>
<td class='base'>$Lang::tr{'remove'}</td>
- </tr>
- <tr>
- <td> </td>
- <td> <img src='/images/off.gif' alt='?OFF' /></td>
- <td class='base'>$Lang::tr{'click to enable'}</td>
- <td> <img src='/images/media-floppy.png' alt='?FLOPPY' /></td>
- <td class='base'>$Lang::tr{'download certificate'}</td>
- <td> <img src='/images/openvpn.png' alt='?RELOAD'/></td>
- <td class='base'>$Lang::tr{'dl client arch'}</td>
- <td> <img src='/images/qr-code.png' alt='$Lang::tr{'show otp qrcode'}'/></td>
- <td class='base'>$Lang::tr{'show otp qrcode'}</td>
- </tr>
- </table><br>
+ </tr>
+ </table><br>
END
;
}
# Nothing
print <<END;
<tr>
- <td width='25%' class='base' $col3>$Lang::tr{'dh parameter'}:</td>
+ <td width='25%' class='base' $col3>$Lang::tr{'dh'}:</td>
<td class='base' $col3>$Lang::tr{'not present'}</td>
</td><td colspan='3' $col3> </td>
</tr>