...
 
Commits (10)
......@@ -40,6 +40,7 @@ header('X-Frame-Options: deny');
session::start();
if (isset($_REQUEST['signout']) && $_REQUEST['signout']) {
$reason = '';
if (session::is_set('connected')) {
$config = session::get('config');
if ($config->get_cfg_value('casActivated') == 'TRUE') {
......@@ -57,8 +58,23 @@ if (isset($_REQUEST['signout']) && $_REQUEST['signout']) {
phpCAS::setCasServerCACert($config->get_cfg_value('casServerCaCertPath'));
phpCas::logout();
}
$reason = 'Sign out';
if (isset($_REQUEST['message'])) {
switch ($_REQUEST['message']) {
case 'expired':
$reason = 'Session expired';
break;
case 'invalidparameter':
$reason = sprintf('Invalid plugin parameter "%s"!', $_REQUEST['plug']);
break;
case 'nosession':
$reason = 'No session found';
break;
default:
}
}
}
session::destroy();
session::destroy($reason);
session::start();
}
......@@ -90,6 +106,9 @@ $config = new config(CONFIG_DIR.'/'.CONFIG_FILE, $BASE_DIR);
session::set('config', $config);
session::set('DEBUGLEVEL', $config->get_cfg_value('DEBUGLEVEL'));
@DEBUG(DEBUG_CONFIG, __LINE__, __FUNCTION__, __FILE__, $config->data, 'config');
/* Configuration was reloaded, so plist needs to be as well */
session::un_set('plist');
unset($plist);
/* Set template compile directory */
$smarty->compile_dir = $config->get_cfg_value('templateCompileDirectory', SPOOL_DIR);
......
......@@ -46,7 +46,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
/* Logged in? Simple security check */
if (!session::is_set('connected')) {
logging::log('security', 'login', '', [], 'main.php called without session - logging out');
session::destroy('main.php called without session');
header('Location: index.php?message=nosession');
exit;
}
......@@ -77,8 +77,7 @@ if (session::get('_LAST_PAGE_REQUEST') != '') {
* kill session
*/
if ($request_time > $max_life) {
session::destroy();
logging::log('security', 'login', '', [], 'main.php called with expired session - logging out');
session::destroy('main.php called with expired session');
header('Location: index.php?signout=1&message=expired');
exit;
}
......
......@@ -70,6 +70,8 @@ class logging
];
if (isset($ui->dn) && !empty($ui->dn)) {
$entry['user'] = $ui->dn;
} elseif (isset($_SERVER['REMOTE_ADDR'])) {
$entry['user'] = $_SERVER['REMOTE_ADDR'];
} else {
$entry['user'] = 'unknown';
}
......
......@@ -177,8 +177,35 @@ class session
/*!
* \brief Destroy a session
*/
public static function destroy ()
public static function destroy (string $reason = '')
{
global $ui;
if (!isset($ui)) {
$ui = static::get('ui');
}
try {
if (isset($ui)) {
logging::log(
'security',
'logout',
$ui->uid,
[],
sprintf('Logged out (%s)', $reason)
);
} elseif (!empty($reason)) {
logging::log(
'security',
'session',
'',
[],
sprintf('Session destroyed (%s)', $reason)
);
}
} catch (Exception $e) {
/* Ignore exceptions here */
}
@session_destroy();
}
}
......@@ -45,8 +45,8 @@ class LoginHTTPAuth extends LoginMethod
$success = static::runSteps([
'validateUserInput',
'ldapLoginUser',
'checkForLockingBranch',
'ldapLoginUser',
'loginAndCheckExpired',
'runSchemaCheck',
]);
......
......@@ -98,11 +98,9 @@ class LoginMethod
try {
$ui = userinfo::loginUser(static::$username, static::$password);
} catch (LoginFailureException $e) {
if (isset($_SERVER['REMOTE_ADDR'])) {
logging::log('security', 'login', '', [], 'Authentication failed for user "'.static::$username.'" [from '.$_SERVER['REMOTE_ADDR'].']: '.$e->getMessage());
} else {
logging::log('security', 'login', '', [], 'Authentication failed for user "'.static::$username.'": '.$e->getMessage());
}
/* Load plist to be able to log */
pluglist::load();
logging::log('security', 'login failure', static::$username, [], 'Authentication failed: '.$e->getMessage());
/* Show the same message whether the user exists or not to avoid information leak */
$message = $e->getMessage();
$smarty->assign('focusfield', 'password');
......@@ -115,6 +113,7 @@ class LoginMethod
static function loginAndCheckExpired ()
{
global $ui, $config, $plist, $message, $smarty;
/* Remove all locks of this user */
del_user_locks($ui->dn);
......@@ -137,7 +136,7 @@ class LoginMethod
$expired = $ui->expired_status();
if ($expired == POSIX_ACCOUNT_EXPIRED) {
logging::log('security', 'login', '', [], 'Account for user "'.static::$username.'" has expired');
logging::log('security', 'account', $ui->dn, [], 'Account for user "'.static::$username.'" has expired');
$message = _('Account locked. Please contact your system administrator!');
$smarty->assign('focusfield', 'username');
return FALSE;
......@@ -149,9 +148,10 @@ class LoginMethod
/*! \brief Final step of successful login: redirect to main.php */
static function redirect ()
{
global $config;
global $config, $ui;
/* Not account expired or password forced change go to main page */
logging::log('security', 'login', '', [], 'User "'.static::$username.'" logged in successfully.');
logging::log('security', 'login', static::$username, [], 'Logged in successfully');
session::set('connected', 1);
session::set('DEBUGLEVEL', $config->get_cfg_value('DEBUGLEVEL'));
header('Location: main.php');
......@@ -176,7 +176,8 @@ class LoginMethod
/*! \brief All login steps in the right order */
static function loginProcess ()
{
global $config;
global $config, $smarty;
$method = $config->get_cfg_value('LoginMethod', '');
if (empty($method)) {
// Try to detect configurations from FD<1.4
......@@ -190,7 +191,27 @@ class LoginMethod
$method = 'LoginPost';
}
}
$method::loginProcess();
try {
$method::loginProcess();
} catch (Exception $e) {
$display = '<h1>'._('An unrecoverable error occurred. Please contact your administator.').'</h1><p>';
if (ini_get('display_errors') == 1) {
$display .= nl2br(htmlentities((string)$e, ENT_COMPAT, 'UTF-8'));
} else {
$display .= 'Error detail display is turned off.';
}
$display .= '</p>'."\n";
$smarty->assign('headline', _('Fatal error!'));
$smarty->assign('headline_image', 'geticon.php?context=status&icon=dialog-error&size=32');
$smarty->assign('usePrototype', 'false');
$smarty->assign('date', date('l, dS F Y H:i:s O'));
$smarty->assign('lang', preg_replace('/_.*$/', '', $lang));
$smarty->assign('rtl', Language::isRTL($lang));
$smarty->display(get_template_path('headers.tpl'));
echo $display;
exit();
}
}
/*! \brief Displayed name for each login method. Returning FALSE disables a method */
......
......@@ -44,8 +44,8 @@ class LoginPost extends LoginMethod
$success = static::runSteps([
'validateUserInput',
'ldapLoginUser',
'checkForLockingBranch',
'ldapLoginUser',
'loginAndCheckExpired',
'runSchemaCheck',
]);
......
<?php
/*
This code is part of FusionDirectory (http://www.fusiondirectory.org/)
Copyright (C) 2017-2019 FusionDirectory
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
class CheckBoxesFilterElement extends FilterElement
{
protected $items;
protected $name;
protected $operator;
/*!
* \brief __construct
*
* \param managementFilter $parent
* \param string $name Name of the filter element
* \param array $items Associative array of items with keys: name, ?desc, filter, ?icon
*/
public function __construct (managementFilter $parent, string $name, array $items, string $operator = '&')
{
global $config;
parent::__construct($parent);
$this->name = $name;
$this->items = $items;
$this->operator = $operator;
foreach ($this->items as &$item) {
$item['checked'] = FALSE;
}
unset($item);
}
public function update ()
{
foreach ($this->items as $key => &$item) {
$item['checked'] = isset($_POST['filter_item_'.$key]);
}
unset($item);
}
public function render (): string
{
if (empty($this->items)) {
return '';
}
$inputs = [];
foreach ($this->items as $key => $item) {
$inputs['filter_item_'.$key] = [
'name' => ($item['name'] ?? $key),
'desc' => ($item['desc'] ?? $item['name'] ?? $key).' '.$item['filter'],
'icon' => ($item['icon'] ?? NULL),
'checked' => $item['checked'],
];
}
$smarty = get_smarty();
$smarty->assign('NAME', $this->name);
$smarty->assign('INPUTS', $inputs);
return $smarty->fetch(get_template_path('management/filter-element.tpl'));
}
public function getFilters (string $type, array &$filters): bool
{
if ($this->operator == '&') {
foreach ($this->items as $item) {
if ($item['checked']) {
$filters[] = $item['filter'];
}
}
} else {
$subfilters = [];
foreach ($this->items as $item) {
if ($item['checked']) {
$subfilters[] = $item['filter'];
}
}
if (!empty($subfilters)) {
$filter = new ldapFilter($this->operator, $subfilters);
$filters[] = (string)$filter;
}
}
return FALSE;
}
}
......@@ -146,8 +146,13 @@ class managementListing
'sortable' => $column->isSortable(),
'label' => $column->getLabel(),
];
if (($index == $this->sortColumn) && $column->isSortable()) {
$this->header[$index]['sortdirection'] = $this->sortDirection[$index];
if ($index == $this->sortColumn) {
if ($column->isSortable()) {
$this->header[$index]['sortdirection'] = $this->sortDirection[$index];
} elseif ($sortInit) {
/* sortColumn is not sortable, try next one */
$this->sortColumn++;
}
}
}
}
......@@ -257,13 +262,7 @@ class managementListing
if (isset($_GET['act'])) {
$key = validate($_GET['act']);
if (preg_match('/^SORT_([0-9]+)$/', $key, $match)) {
// Switch to new column or invert search order?
$column = $match[1];
if ($this->sortColumn != $column) {
$this->sortColumn = $column;
} else {
$this->sortDirection[$column] = !$this->sortDirection[$column];
}
$this->setSortColumn($match[1]);
// Allow header to update itself according to the new sort settings
$this->renderHeader();
......@@ -589,6 +588,22 @@ class managementListing
return NULL;
}
/*!
* \brief Set sort column
*
* \param int $column Index of column to sort by
* \param bool $direction Whether to sort up or down
*/
public function setSortColumn (int $column, bool $direction = NULL)
{
if ($direction === NULL) {
// Switch to new column or invert search order?
$direction = (($this->sortColumn == $column) && !$this->sortDirection[$column]);
}
$this->sortColumn = $column;
$this->sortDirection[$column] = $direction;
}
function fillSearchedAttributes (string $type, array &$attrs)
{
global $ui;
......
......@@ -262,7 +262,7 @@ function gosaRaiseError ($errno, $errstr, $errfile, $errline)
/* Flush in case of fatal errors */
if (preg_match('/^fatal/i', $errstr) || (PHP_ERROR_FATAL == 'TRUE')) {
session::destroy();
session::destroy('Fatal error');
if (PHP_ERROR_FATAL == 'TRUE') {
$error_collector = str_replace('display: none;', '', $error_collector);
}
......
......@@ -502,8 +502,9 @@ class OrderedArrayAttribute extends SetAttribute
}
list ($img, $nbicons) = $this->genRowIcons($key, $value);
$fields[] = ["html" => $img, "attach" => 'style="border:0px;width:'.($nbicons * 20).'px;"'];
if ($nbicons > 0) {
$fields[] = ['html' => $img, 'attach' => 'style="border:0px;width:'.($nbicons * 20).'px;"'];
}
$div->addEntry($fields);
}
$smarty->assign("div_$id", $div->drawList());
......
......@@ -436,7 +436,7 @@ class simpleTabs
}
}
if (empty($errors) && ($this->dn == $ui->dn)) {
if (empty($errors) && isset($ui->dn) && ($this->dn == $ui->dn)) {
/* If the logged in user was edited, update his information */
$ui->loadLDAPInfo();
}
......
......@@ -51,9 +51,9 @@ class setup
$this->i_steps = count($this->o_steps);
/* Ensure that setup is not reachable if fusiondirectory.conf exist (CONFIG_FILE) */
if (file_exists(CONFIG_DIR."/".CONFIG_FILE)) {
session::destroy();
header("Location: index.php");
if (file_exists(CONFIG_DIR.'/'.CONFIG_FILE)) {
session::destroy('Invalid setup.php call');
header('Location: index.php');
exit();
}
}
......