allow to specify SSL CA certificates in LAM main configuration

This commit is contained in:
Roland Gruber 2013-08-10 12:43:01 +00:00
parent 442c3f5cc6
commit 90e01cbcaa
11 changed files with 448 additions and 28 deletions

View File

@ -1,4 +1,5 @@
September 2013 4.3
- Custom SSL CA certificates can be setup in LAM main configuration
- LAM Pro:
-> PPolicy: check password history for password reuse
-> Custom fields: read-only fields for admin interface and file upload for binary data

View File

@ -80,6 +80,8 @@ $helpArray = array (
_("Example").
":</b><br><br>".
_("dc=yourcompany,dc=com")),
"204" => array ("Headline" => _("SSL certificate"),
"Text" => _("This is only needed for TLS/SSL connections. By default, LAM will use the certificate authorities installed on your system. If you have a private CA in your company you can upload your CA certificates here and override the system certificates.")),
"206" => array ("Headline" => _("List attributes"),
"Text" => _("This is the list of attributes to show in the account list. The entries can either be predefined values, \"#attribute\", or individual ones, \"attribute:description\". Several entries are separated by semicolons.") .
"<br><br><br><big><b>" .

View File

@ -1077,4 +1077,39 @@ function getRandomNumber() {
return mt_rand();
}
/**
* Connects to the LDAP server and extracts the certificates.
*
* @param String $server server name
* @param String $port server port
* @return mixed false on error and certificate if extracted successfully
*/
function getLDAPSSLCertificate($server, $port) {
$stream = @stream_context_create(array("ssl" => array("capture_peer_cert_chain" => true)));
if (!$stream) {
return false;
}
$client = @stream_socket_client('ssl://' . $server . ':' . $port, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $stream);
if (!$client) {
return false;
}
$context = stream_context_get_params($client);
if (!isset($context['options']['ssl']['peer_certificate_chain'])) {
return false;
}
$finalPEM = '';
for ($i = 0; $i < sizeof($context['options']['ssl']['peer_certificate_chain']); $i++) {
$cert = $context['options']['ssl']['peer_certificate_chain'][$i];
$pemData = null;
$pemResult = @openssl_x509_export($cert, $pemData);
if ($pemResult) {
$finalPEM .= $pemData;
}
else {
return false;
}
}
return $finalPEM;
}
?>

View File

@ -70,6 +70,10 @@ if (! function_exists('ldap_search')) {
if (! function_exists('gettext') || !function_exists('_')) {
$criticalErrors[] = array("ERROR", "Your PHP has no gettext support!", "Please install gettext for PHP.");
}
// check if PHP has openssl support
if (! function_exists('openssl_x509_parse')) {
$criticalErrors[] = array("ERROR", "Your PHP has no openssl support!", "Please install openssl for PHP.");
}
// check if PHP has XML support
if (! function_exists('utf8_decode')) {
$criticalErrors[] = array("ERROR", "Your PHP has no XML support!", "Please install the XML extension for PHP.");

View File

@ -37,6 +37,20 @@ include_once("modules.inc");
/** Used to get type information. */
include_once("types.inc");
/**
* Sets the environment variables for custom SSL CA certificates.
*/
function setSSLCaCert() {
// set SSL certificate if set
if (isset($_SESSION['cfgMain'])) {
$sslCaPath = $_SESSION['cfgMain']->getSSLCaCertPath();
if ($sslCaPath != null) {
putenv('LDAPTLS_CACERT=' . $sslCaPath);
putenv('TLS_CACERT=' . $sslCaPath);
}
}
}
/**
* Sets language settings for automatic translation
*/
@ -545,15 +559,16 @@ class LAMConfig {
}
}
$file = @fopen($conffile, "w");
$saveResult = LAMConfig::SAVE_OK;
if ($file) {
for ($i = 0; $i < sizeof($file_array); $i++) fputs($file, $file_array[$i]);
fclose($file);
@chmod($conffile, 0600);
return LAMConfig::SAVE_OK;
}
else {
return LAMConfig::SAVE_FAIL;
$saveResult = LAMConfig::SAVE_FAIL;
}
return $saveResult;
}
}
@ -1376,6 +1391,12 @@ class LAMCfgMain {
/** path to config file */
private $conffile;
/** uploaded SSL certificate that is stored to disk on save() */
private $uploadedSSLCaCert = null;
/** SSL certificate should be deleted on save() */
private $delSSLCaCert = false;
/** list of data fields to save in config file */
private $settings = array("password", "default", "sessionTimeout",
"logLevel", "logDestination", "allowedHosts", "passwordMinLength",
@ -1473,6 +1494,27 @@ class LAMCfgMain {
else {
StatusMessage("ERROR", "", _("Cannot open config file!") . " (" . $this->conffile . ")");
}
// store SSL certificate
if ($this->uploadedSSLCaCert != null) {
$sslPath = $this->getInternalSSLCaCertFileName();
$file = @fopen($sslPath, "w");
if ($file) {
fputs($file, $this->uploadedSSLCaCert);
fclose($file);
@chmod($sslPath, 0600);
}
else {
StatusMessage("ERROR", _("Cannot write certificate file. Please check the permissions of config/serverCerts.pem."));
}
}
// delete SSL certificate
if ($this->delSSLCaCert === true) {
$sslPath = $this->getInternalSSLCaCertFileName();
$result = @unlink($sslPath);
if (!$result) {
StatusMessage("ERROR", _("Cannot write certificate file. Please check the permissions of config/serverCerts.pem."));
}
}
}
/**
@ -1537,6 +1579,187 @@ class LAMCfgMain {
return file_exists($this->conffile);
}
/**
* Returns the path to the SSL CA certificate file that overrides the system certificates.
*
* @return String path to certificate file or null if certificate is not overridden
*/
public function getSSLCaCertPath() {
$path = $this->getInternalSSLCaCertFileName();
if (file_exists($path)) {
return $path;
}
return null;
}
/**
* Returns the file name that will be used internally to store the CA file.
*
* @return String file name
*/
private function getInternalSSLCaCertFileName() {
return dirname(__FILE__) . '/../config/serverCerts.pem';
}
/**
* Uploads a new SSL CA cert.
*
* @param String $cert file content in DER/PEM format
* @return mixed TRUE if format is correct, error message if file is not accepted
*/
public function uploadSSLCaCert($cert) {
if (strpos($cert, '-----BEGIN CERTIFICATE-----') !== 0) {
$pem = @chunk_split(@base64_encode($cert), 64, "\n");
$cert = "-----BEGIN CERTIFICATE-----\n" . $pem . "-----END CERTIFICATE-----\n";
}
$pemData = @openssl_x509_parse($cert);
if ($pemData === false) {
return _('Please provide a file in DER or PEM format.');
}
$existingCerts = $this->getSSLCaCertificateContent();
if (!empty($existingCerts)) {
// merge with existing certificates
$existingList = $this->splitSSLCaCertificateContent($existingCerts);
$newList = $this->splitSSLCaCertificateContent($cert);
$this->uploadedSSLCaCert = implode("\n", array_unique(array_merge($existingList, $newList)));
}
else {
$this->uploadedSSLCaCert = $cert;
}
$this->delSSLCaCert = false;
return true;
}
/**
* Returns the name of a temporary file in tmp that contains the SSL certificate.
* The file contains either the stored data in serverCerts or the uploaded data.
*
* @return String file name or null if no certificate was set
*/
public function getSSLCaCertTempFileName() {
if ($this->delSSLCaCert) {
return null;
}
// get certificate data
$content = $this->getSSLCaCertificateContent();
if ($content == null) {
return null;
}
// write to temp file
$fileName = time() . getRandomNumber() . '.pem';
$path = dirname(__FILE__) . '/../tmp/' . $fileName;
$handle = @fopen($path, "wb");
@chmod($path, 0600);
if ($handle) {
$content = fputs($handle, $content);
fclose($handle);
}
else {
return null;
}
return $fileName;
}
/**
* Marks a single or all SSL CA certificate files for deletion.
* The changes take effect on save().
*
* @param int $index certificate index, null deletes all certificates (default: null)
*/
public function deleteSSLCaCert($index = null) {
if ($index == null) {
// delete all
$this->delSSLCaCert = true;
return;
}
$content = $this->getSSLCaCertificateContent();
$list = $this->splitSSLCaCertificateContent($content);
unset($list[$index]);
if (sizeof($list) < 1) {
$this->delSSLCaCert = true;
$this->uploadedSSLCaCert = null;
}
else {
$this->uploadedSSLCaCert = implode("\n", $list);
}
}
/**
* Returns a list of all CA certificates.
*
* @return array list of certificates as output of openssl_x509_parse()
*/
public function getSSLCaCertificates() {
if ($this->delSSLCaCert) {
return array();
}
$content = $this->getSSLCaCertificateContent();
if (empty($content)) {
return array();
}
$list = $this->splitSSLCaCertificateContent($content);
for ($i = 0; $i < sizeof($list); $i++) {
$list[$i] = @openssl_x509_parse($list[$i]);
}
return $list;
}
/**
* Returns the content of the certificate file or uploaded data.
*
* @return String null or certificate content
*/
private function getSSLCaCertificateContent() {
$content = null;
if ($this->delSSLCaCert) {
return null;
}
if ($this->uploadedSSLCaCert != null) {
$content = $this->uploadedSSLCaCert;
}
elseif ($this->getSSLCaCertPath() != null) {
$path = $this->getSSLCaCertPath();
$handle = @fopen($path, "r");
if ($handle) {
$content = fread($handle, 10000000);
fclose($handle);
}
}
return $content;
}
/**
* Splits the certificate content into single PEM data chunks.
*
* @param String $content PEM file content
* @return array one element for each certificate chunk
*/
private function splitSSLCaCertificateContent($content) {
if (empty($content)) {
return array();
}
$content = str_replace("\n\n", "\n", $content);
if (empty($content)) {
return array();
}
if (!(strpos($content, '-----BEGIN CERTIFICATE-----') === 0)) {
return array();
}
$lines = explode("\n", $content);
$list = array();
$pos = -1;
foreach ($lines as $line) {
if (strpos($line, '-----BEGIN CERTIFICATE-----') === 0) {
$pos++;
}
if (!isset($list[$pos])) {
$list[$pos] = '';
}
$list[$pos] .= $line . "\n";
}
return $list;
}
}
?>

View File

@ -2261,7 +2261,9 @@ class inetOrgPerson extends baseModule implements passwordService {
$table->colspan = 10;
for ($i = 0; $i < sizeof($this->attributes['userCertificate;binary']); $i++) {
$filename = 'userCertificate' . getRandomNumber() . '.der';
$out = @fopen(dirname(__FILE__) . '/../../tmp/' . $filename, "wb");
$pathOut = dirname(__FILE__) . '/../../tmp/' . $filename;
$out = @fopen($pathOut, "wb");
@chmod($pathOut, 0600);
fwrite($out, $this->attributes['userCertificate;binary'][$i]);
fclose ($out);
$path = '../../tmp/' . $filename;

View File

@ -87,6 +87,7 @@ function startSecureSession($redirectToLogin = true, $initSecureData = false) {
else {
return false;
}
setSSLCaCert();
return true;
}

View File

@ -186,7 +186,7 @@ if (sizeof($errorsToDisplay) > 0) {
}
// display formular
echo ("<form action=\"confmain.php\" method=\"post\" autocomplete=\"off\">\n");
echo ("<form enctype=\"multipart/form-data\" action=\"confmain.php\" method=\"post\" autocomplete=\"off\">\n");
// hidden submit buttons which are clicked by tabs
echo "<div style=\"display: none;\">\n";
@ -264,6 +264,7 @@ if (isLAMProVersion()) {
$accessSelect->setHasDescriptiveElements(true);
$serverSettingsContent->addElement($accessSelect, true);
}
$serverSettings = new htmlFieldset($serverSettingsContent, _("Server settings"), '../../graphics/profiles.png');
$container->addElement($serverSettings, true);
$container->addElement(new htmlSpacer(null, '10px'), true);

View File

@ -46,7 +46,9 @@ setlanguage();
// remove settings from session
if (isset($_SESSION["mainconf_password"])) unset($_SESSION["mainconf_password"]);
if (isset($_SESSION['cfgMain'])) {
unset($_SESSION['cfgMain']);
}
$cfgMain = new LAMCfgMain();
// check if user entered a password
if (isset($_POST['passwd'])) {

View File

@ -43,7 +43,11 @@ if (strtolower(session_module_name()) == 'files') {
setlanguage();
if (!isset($_SESSION['cfgMain'])) {
$cfg = new LAMCfgMain();
$_SESSION['cfgMain'] = $cfg;
}
$cfg = &$_SESSION['cfgMain'];
// check if user is logged in
if (!isset($_SESSION["mainconf_password"]) || (!$cfg->checkPassword($_SESSION["mainconf_password"]))) {
@ -58,8 +62,9 @@ if (isset($_POST['cancel'])) {
}
$errors = array();
$messages = array();
// check if submit button was pressed
if (isset($_POST['submit'])) {
if (isset($_POST['submitFormData'])) {
// remove double slashes if magic quotes are on
if (get_magic_quotes_gpc() == 1) {
$postKeys = array_keys($_POST);
@ -117,13 +122,63 @@ if (isset($_POST['submit'])) {
$cfg->passwordMinNumeric = $_POST['passwordMinNumeric'];
$cfg->passwordMinSymbol = $_POST['passwordMinSymbol'];
$cfg->passwordMinClasses = $_POST['passwordMinClasses'];
if (isset($_POST['sslCaCertUpload'])) {
if (!isset($_FILES['sslCaCert']) || ($_FILES['sslCaCert']['size'] == 0)) {
$errors[] = _('No file selected.');
}
else {
$handle = fopen($_FILES['sslCaCert']['tmp_name'], "r");
$data = fread($handle, 10000000);
fclose($handle);
$sslReturn = $cfg->uploadSSLCaCert($data);
if ($sslReturn !== true) {
$errors[] = $sslReturn;
}
else {
$messages[] = _('You might need to restart your webserver for changes to take effect.');
}
}
}
if (isset($_POST['sslCaCertDelete'])) {
$cfg->deleteSSLCaCert();
$messages[] = _('You might need to restart your webserver for changes to take effect.');
}
if (isset($_POST['sslCaCertImport'])) {
$matches = array();
if (preg_match('/^([a-zA-Z0-9_\\.-]+)(:([0-9]+))?$/', $_POST['serverurl'], $matches)) {
$port = '636';
if (isset($matches[3]) && !empty($matches[3])) {
$port = $matches[3];
}
$pemResult = getLDAPSSLCertificate($matches[1], $port);
if ($pemResult !== false) {
$messages[] = _('Imported certificate from server.');
$messages[] = _('You might need to restart your webserver for changes to take effect.');
$cfg->uploadSSLCaCert($pemResult);
}
else {
$errors[] = _('Unable to import server certificate. Please use the upload function.');
}
}
else {
$errors[] = _('Invalid server name. Please enter "server" or "server:port".');
}
}
foreach ($_POST as $key => $value) {
if (strpos($key, 'deleteCert_') === 0) {
$index = substr($key, strlen('deleteCert_'));
$cfg->deleteSSLCaCert($index);
}
}
// save settings
if (isset($_POST['submit'])) {
$cfg->save();
if (sizeof($errors) == 0) {
metaRefresh('../login.php?confMainSavedOk=1');
exit();
}
}
}
echo $_SESSION['header'];
@ -166,7 +221,7 @@ echo $_SESSION['header'];
</table>
<br>
<!-- form for adding/renaming/deleting profiles -->
<form action="mainmanage.php" method="post">
<form enctype="multipart/form-data" action="mainmanage.php" method="post">
<?php
// include all JavaScript files
@ -188,23 +243,97 @@ $container = new htmlTable();
for ($i = 0; $i < sizeof($errors); $i++) {
$container->addElement(new htmlStatusMessage("ERROR", $errors[$i]), true);
}
for ($i = 0; $i < sizeof($messages); $i++) {
$container->addElement(new htmlStatusMessage("INFO", $messages[$i]), true);
}
// check if config file is writable
if (!$cfg->isWritable()) {
$container->addElement(new htmlStatusMessage('WARN', 'The config file is not writable.', 'Your changes cannot be saved until you make the file writable for the webserver user.'), true);
}
$container->addElement(new htmlSpacer(null, '20px'), true);
// security settings
$container->addElement(new htmlSubTitle(_("Security settings")), true);
$securityTable = new htmlTable();
$options = array(5, 10, 20, 30, 60, 90, 120, 240);
$securityTable->addElement(new htmlTableExtendedSelect('sessionTimeout', $options, array($cfg->sessionTimeout), _("Session timeout"), '238'), true);
$securityTable->addElement(new htmlTableExtendedInputTextarea('allowedHosts', implode("\n", explode(",", $cfg->allowedHosts)), '30', '7', _("Allowed hosts"), '241'), true);
$securityField = new htmlFieldset($securityTable, _("Security settings"));
$container->addElement($securityField, true);
// SSL certificate
$securityTable->addElement(new htmlOutputText(_('SSL certificates')));
$sslMethod = _('use system certificates');
$sslFileName = $cfg->getSSLCaCertTempFileName();
if ($sslFileName != null) {
$sslMethod = _('use custom CA certificate');
}
$sslDelSaveGroup = new htmlGroup();
$sslDelSaveGroup->addElement(new htmlOutputText($sslMethod));
$sslDelSaveGroup->addElement(new htmlSpacer('5px', null));
// delete+download button
if ($sslFileName != null) {
$sslDownloadBtn = new htmlLink('', '../../tmp/' . $sslFileName, '../../graphics/save.png');
$sslDownloadBtn->setTargetWindow('_blank');
$sslDownloadBtn->setTitle(_('Download CA certificates'));
$sslDelSaveGroup->addElement($sslDownloadBtn);
$sslDeleteBtn = new htmlButton('sslCaCertDelete', 'delete.png', true);
$sslDeleteBtn->setTitle(_('Delete all CA certificates'));
$sslDelSaveGroup->addElement($sslDeleteBtn);
}
$securityTable->addElement($sslDelSaveGroup);
$securityTable->addElement(new htmlHelpLink('204'));
$securityTable->addElement(new htmlSpacer('250px', null), true);
$securityTable->addElement(new htmlOutputText(''));
$sslButtonTable = new htmlTable();
$sslButtonTable->colspan = 3;
$sslButtonTable->addElement(new htmlInputFileUpload('sslCaCert'));
$sslUploadBtn = new htmlButton('sslCaCertUpload', _('Upload'));
$sslUploadBtn->setIconClass('upButton');
$sslUploadBtn->setTitle(_('Upload CA certificate'));
$sslButtonTable->addElement($sslUploadBtn, true);
if (function_exists('stream_socket_client')) {
$sslImportGroup = new htmlGroup();
$sslImportGroup->addElement(new htmlOutputText('ldaps://'));
$sslImportServerUrl = !empty($_POST['serverurl']) ? $_POST['serverurl'] : '';
$sslImportGroup->addElement(new htmlInputField('serverurl'));
$sslButtonTable->addElement($sslImportGroup);
$sslImportBtn = new htmlButton('sslCaCertImport', _('Import from server'));
$sslImportBtn->setIconClass('downButton');
$sslImportBtn->setTitle(_('Imports the certificate directly from your LDAP server.'));
$sslImportBtn->setCSSClasses(array('nowrap'));
$sslButtonTable->addElement($sslImportBtn);
$sslButtonTable->addElement(new htmlEqualWidth(array('btn_sslCaCertUpload', 'btn_sslCaCertImport')));
}
$securityTable->addElement($sslButtonTable, true);
$sslCerts = $cfg->getSSLCaCertificates();
if (sizeof($sslCerts) > 0) {
$certTable = new htmlTable();
$certTable->colspan = 3;
$certSpace = new htmlSpacer('5px', null);
$certTable->addElement(new htmlOutputText(''));
$certTable->addElement(new htmlOutputText(_('Serial number')));
$certTable->addElement($certSpace);
$certTable->addElement(new htmlOutputText(_('Valid to')));
$certTable->addElement($certSpace);
$certTable->addElement(new htmlOutputText(_('Common name')), true);
for ($i = 0; $i < sizeof($sslCerts); $i++) {
$serial = isset($sslCerts[$i]['serialNumber']) ? $sslCerts[$i]['serialNumber'] : '';
$validTo = isset($sslCerts[$i]['validTo_time_t']) ? $sslCerts[$i]['validTo_time_t'] : '';
$cn = isset($sslCerts[$i]['subject']['CN']) ? $sslCerts[$i]['subject']['CN'] : '';
$certTable->addElement(new htmlButton('deleteCert_' . $i, 'delete.png', true));
$certTable->addElement(new htmlOutputText($serial));
$certTable->addElement($certSpace);
$certTable->addElement(new htmlOutputText(formatSSLTimestamp($validTo)));
$certTable->addElement($certSpace);
$certTable->addElement(new htmlOutputText($cn), true);
}
$securityTable->addElement(new htmlOutputText(''));
$securityTable->addElement($certTable, true);
}
$container->addElement($securityTable, true);
$container->addElement(new htmlSpacer(null, '10px'), true);
// password policy
$container->addElement(new htmlSubTitle(_("Password policy")), true);
$policyTable = new htmlTable();
$options20 = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
$options4 = array(0, 1, 2, 3, 4);
@ -214,11 +343,11 @@ $policyTable->addElement(new htmlTableExtendedSelect('passwordMinUpper', $option
$policyTable->addElement(new htmlTableExtendedSelect('passwordMinNumeric', $options20, array($cfg->passwordMinNumeric), _('Minimum numeric characters'), '242'), true);
$policyTable->addElement(new htmlTableExtendedSelect('passwordMinSymbol', $options20, array($cfg->passwordMinSymbol), _('Minimum symbolic characters'), '242'), true);
$policyTable->addElement(new htmlTableExtendedSelect('passwordMinClasses', $options4, array($cfg->passwordMinClasses), _('Minimum character classes'), '242'), true);
$policyField = new htmlFieldset($policyTable, _("Password policy"));
$container->addElement($policyField, true);
$container->addElement($policyTable, true);
$container->addElement(new htmlSpacer(null, '10px'), true);
// logging
$container->addElement(new htmlSubTitle(_("Logging")), true);
$loggingTable = new htmlTable();
$levelOptions = array(_("Debug") => LOG_DEBUG, _("Notice") => LOG_NOTICE, _("Warning") => LOG_WARNING, _("Error") => LOG_ERR);
$levelSelect = new htmlTableExtendedSelect('logLevel', $levelOptions, array($cfg->logLevel), _("Log level"), '239');
@ -238,11 +367,11 @@ elseif ($cfg->logDestination == 'SYSLOG') {
$loggingTable->addElement(new htmlTableExtendedRadio(_("Log destination"), 'logDestination', $destinationOptions, $destinationSelected, '240'), true);
$loggingTable->addElement(new htmlOutputText(''));
$loggingTable->addElement(new htmlInputField('logFile', $destinationPath), true);
$loggingField = new htmlFieldset($loggingTable, _("Logging"));
$container->addElement($loggingField, true);
$container->addElement($loggingTable, true);
$container->addElement(new htmlSpacer(null, '10px'), true);
// change master password
$container->addElement(new htmlSubTitle(_("Change master password")), true);
$passwordTable = new htmlTable();
$pwd1 = new htmlTableExtendedInputField(_("New master password"), 'masterpassword', '', '235');
$pwd1->setIsPassword(true);
@ -250,8 +379,7 @@ $passwordTable->addElement($pwd1, true);
$pwd2 = new htmlTableExtendedInputField(_("Reenter password"), 'masterpassword2', '');
$pwd2->setIsPassword(true);
$passwordTable->addElement($pwd2, true);
$passwordField = new htmlFieldset($passwordTable, _("Change master password"));
$container->addElement($passwordField, true);
$container->addElement($passwordTable, true);
$container->addElement(new htmlSpacer(null, '20px'), true);
// buttons
@ -259,11 +387,31 @@ if ($cfg->isWritable()) {
$buttonTable = new htmlTable();
$buttonTable->addElement(new htmlButton('submit', _("Ok")));
$buttonTable->addElement(new htmlButton('cancel', _("Cancel")));
$container->addElement($buttonTable);
$container->addElement($buttonTable, true);
}
$container->addElement(new htmlHiddenInput('submitFormData', '1'), true);
$tabindex = 1;
parseHtml(null, $container, array(), false, $tabindex, 'user');
$globalFieldset = new htmlFieldset($container, _('General settings'));
parseHtml(null, $globalFieldset, array(), false, $tabindex, 'user');
/**
* Formats an LDAP time string (e.g. from createTimestamp).
*
* @param String $time LDAP time value
* @return String formated time
*/
function formatSSLTimestamp($time) {
$matches = array();
if (!empty($time)) {
return date('d.m.Y', $time);
}
return '';
}
?>
</form>

View File

@ -523,6 +523,7 @@ if(!empty($_POST['checklogin'])) {
include_once("../lib/ldap.inc"); // Include ldap.php which provides Ldap class
$_SESSION['ldap'] = new Ldap($_SESSION['config']); // Create new Ldap object
setSSLCaCert();
$clientSource = $_SERVER['REMOTE_ADDR'];
if (isset($_SERVER['REMOTE_HOST'])) {