LDAPAccountManager/lam/lib/security.inc

815 lines
24 KiB
PHP
Raw Normal View History

2006-03-26 11:36:43 +00:00
<?php
/*
2009-10-27 18:47:12 +00:00
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
2019-02-01 18:38:03 +00:00
Copyright (C) 2006 - 2019 Roland Gruber
2006-03-26 11:36:43 +00:00
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* This file includes functions to perform several security checks on each page load.
*
* @package lib
* @author Roland Gruber
*/
2006-04-18 10:57:16 +00:00
/** configuration options */
include_once('config.inc');
2006-04-23 16:33:25 +00:00
/** ldap connection */
include_once('ldap.inc');
/** common functions */
include_once('account.inc');
2006-04-18 10:57:16 +00:00
2006-04-25 11:25:07 +00:00
// check client IP address
checkClientIP();
2015-12-19 09:31:21 +00:00
setLAMHeaders();
2018-03-10 17:48:11 +00:00
/**
* Starts a session and sets the cookie options.
*/
function lam_start_session() {
$secureFlag = false;
if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) === 'on') {
$secureFlag = true;
}
session_set_cookie_params(0, '/', null, $secureFlag, true);
session_start();
}
2006-03-26 11:36:43 +00:00
/**
* Starts a session and checks the environment.
* The script is stopped if one of the checks fail (timeout redirection may be overriden).
2015-06-26 18:06:22 +00:00
*
* @param boolean $redirectToLogin redirect user to login page (default: true)
* @param boolean $initSecureData init verification data like session ID and client IP (default: false)
* @return boolean true if all ok, false if session expired
2006-03-26 11:36:43 +00:00
*/
function startSecureSession($redirectToLogin = true, $initSecureData = false) {
2006-03-26 11:36:43 +00:00
// start session
2018-12-29 08:51:51 +00:00
if (isset($_SESSION)) {
unset($_SESSION);
}
2009-07-08 18:03:28 +00:00
if (strtolower(session_module_name()) == 'files') {
2010-02-06 11:50:26 +00:00
$sessionDir = dirname(__FILE__) . "/../sess";
2009-07-08 18:03:28 +00:00
session_save_path($sessionDir);
// enable garbage collection (fix for Debian based systems)
if (@ini_get("session.gc_probability") == 0) {
@ini_set("session.gc_probability", 1);
}
2009-07-08 18:03:28 +00:00
}
2018-03-10 17:48:11 +00:00
lam_start_session();
// init secure data if needed
if ($initSecureData && !isset($_SESSION["sec_session_id"])) {
$_SESSION["sec_session_id"] = session_id();
$_SESSION["sec_client_ip"] = $_SERVER['REMOTE_ADDR'];
$_SESSION['sec_sessionTime'] = time();
$_SESSION['cfgMain'] = new LAMCfgMain();
}
// set error reporting
if (empty($_SESSION['cfgMain']) || ($_SESSION['cfgMain']->errorReporting == LAMCfgMain::ERROR_REPORTING_DEFAULT)) {
ini_set('error_reporting', 'E_ALL & ~E_NOTICE');
}
2014-04-21 10:52:46 +00:00
elseif ($_SESSION['cfgMain']->errorReporting == LAMCfgMain::ERROR_REPORTING_ALL) {
ini_set('error_reporting', E_ALL | E_STRICT);
ini_set('display_errors', 'On');
}
2006-03-26 11:36:43 +00:00
// check session id
if (! isset($_SESSION["sec_session_id"]) || ($_SESSION["sec_session_id"] != session_id())) {
// session id is invalid
logNewMessage(LOG_WARNING, "Invalid session ID, access denied (" . getClientIPForLogging() . ")");
if ($redirectToLogin) {
logoffAndBackToLoginPage();
}
else {
die();
}
2006-03-26 11:36:43 +00:00
}
// check if client IP has not changed
if (!isset($_SESSION["sec_client_ip"]) || ($_SESSION["sec_client_ip"] != $_SERVER['REMOTE_ADDR'])) {
// IP is invalid
logNewMessage(LOG_WARNING, "Client IP changed, access denied (" . getClientIPForLogging() . ")");
2006-03-26 11:36:43 +00:00
die();
}
// check if session time has not expired
2006-04-18 10:57:16 +00:00
if (($_SESSION['sec_sessionTime'] + (60 * $_SESSION['cfgMain']->sessionTimeout)) > time()) {
// ok, update time
$_SESSION['sec_sessionTime'] = time();
}
elseif ($redirectToLogin) {
2006-04-18 10:57:16 +00:00
// session expired, logoff user
logoffAndBackToLoginPage();
}
else {
return false;
}
setSSLCaCert();
return true;
2006-03-26 11:36:43 +00:00
}
/**
* Checks if the client's IP address is on the list of allowed IPs.
* The script is stopped if the host is not valid.
*
*/
function checkClientIP() {
2018-12-29 08:51:51 +00:00
if (isset($_SESSION['cfgMain'])) {
$cfg = $_SESSION['cfgMain'];
}
else {
$cfg = new LAMCfgMain();
}
2006-04-25 11:25:07 +00:00
$allowedHosts = $cfg->allowedHosts;
$url = getCallingURL();
if ((strpos($url, '/selfService/selfService') !== false) || ((strpos($url, '/misc/ajax.php?') !== false) && strpos($url, 'selfservice=1') !== false)) {
// self service pages have separate IP list
$allowedHosts = $cfg->allowedHostsSelfService;
}
2006-04-25 11:25:07 +00:00
// skip test if no hosts are defined
2015-10-30 19:09:55 +00:00
if (empty($allowedHosts) || empty($_SERVER['REMOTE_ADDR'])) {
return;
}
2006-04-25 11:25:07 +00:00
$allowedHosts = explode(",", $allowedHosts);
$grantAccess = false;
for ($i = 0; $i < sizeof($allowedHosts); $i++) {
$host = $allowedHosts[$i];
2012-03-13 21:02:37 +00:00
$ipRegex = '/^[0-9a-z\\.:\\*]+$/i';
2018-12-29 08:51:51 +00:00
if (!preg_match($ipRegex, $host)) {
continue;
}
2006-04-25 11:25:07 +00:00
$hostRegex = str_replace(".", "\\.", $host);
2009-08-13 18:57:26 +00:00
$hostRegex = '/^' . str_replace("*", ".*", $hostRegex) . '$/';
2006-04-25 11:25:07 +00:00
$clientIP = $_SERVER['REMOTE_ADDR'];
2009-08-13 18:57:26 +00:00
if (preg_match($hostRegex, $clientIP)) {
2006-04-25 11:25:07 +00:00
// client is allowed to access LAM
$grantAccess = true;
}
}
// stop script is client may not access LAM
2008-08-06 19:01:03 +00:00
if (!$grantAccess) {
logNewMessage(LOG_WARNING, "Invalid client IP, access denied (" . getClientIPForLogging() . ")");
2008-08-06 19:01:03 +00:00
die();
}
2006-03-26 11:36:43 +00:00
}
2006-04-18 10:57:16 +00:00
/**
* Logs off the user and displays the login page.
*
*/
function logoffAndBackToLoginPage() {
2006-04-23 16:33:25 +00:00
// log message
if (isset($_SESSION['ldap'])) {
2019-08-05 19:56:06 +00:00
$ldapUser = $_SESSION['ldap']->getUserName();
logNewMessage(LOG_WARNING, 'Session of user ' . $ldapUser . ' expired.');
// close LDAP connection
@$_SESSION["ldap"]->destroy();
}
elseif (isset($_SESSION['selfService_clientDN']) || (strpos($_SERVER['REQUEST_URI'], '/selfService/') !== false)) {
logNewMessage(LOG_WARNING, 'Self service session of DN ' . lamDecrypt($_SESSION['selfService_clientDN'], 'SelfService') . ' expired.');
}
2006-04-18 10:57:16 +00:00
// delete key and iv in cookie
2017-04-02 17:37:06 +00:00
if (function_exists('openssl_random_pseudo_bytes')) {
2015-12-19 09:12:47 +00:00
setcookie("Key", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 0, "/", null, null, true);
setcookie("IV", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 0, "/", null, null, true);
2006-04-18 10:57:16 +00:00
}
// link back to login page
2013-03-01 18:22:40 +00:00
$paths = array('./', '../', '../../', '../../../', '../../../../');
$page = 'login.php';
$pageSuffix = '?expired=yes';
if (isset($_SESSION['selfService_clientDN']) || (strpos($_SERVER['REQUEST_URI'], '/selfService/') !== false)) {
$scope = $_GET['scope'];
$name = $_GET['name'];
if (!preg_match('/^[0-9a-zA-Z _-]+$/', $scope) || !preg_match('/^[0-9a-zA-Z _-]+$/', $name)) {
logNewMessage(LOG_ERR, 'GET parameters invalid: ' . $name . ' ' . $scope);
die();
}
2013-03-01 18:22:40 +00:00
$page = 'selfServiceLogin.php';
$pageSuffix = '?expired=yes&scope=' . $scope . '&name=' . $name;
}
2006-04-18 10:57:16 +00:00
for ($i = 0; $i < sizeof($paths); $i++) {
if (file_exists($paths[$i] . $page)) {
$page = $paths[$i] . $page;
break;
}
}
2013-03-01 18:22:40 +00:00
$page .= $pageSuffix;
2006-04-18 10:57:16 +00:00
echo $_SESSION['header'];
echo "<title></title>\n";
echo "</head>\n";
echo "<body>\n";
// print JavaScript refresh
echo "<script type=\"text/javascript\">\n";
echo "top.location.href = \"" . $page . "\";\n";
echo "</script>\n";
// print link if refresh does not work
echo "<p>\n";
echo "<a target=\"_top\" href=\"" . $page . "\">" . _("Your session expired, click here to go back to the login page.") . "</a>\n";
echo "</p>\n";
echo "</body>\n";
echo "</html>\n";
// destroy session
session_destroy();
unset($_SESSION);
die();
}
2017-10-29 10:33:07 +00:00
/**
* Returns if debug messages are to be logged.
*
* @return boolean debug enabled
*/
function isDebugLoggingEnabled() {
2018-12-29 08:51:51 +00:00
if (isset($_SESSION['cfgMain'])) {
$cfg = $_SESSION['cfgMain'];
}
else {
$cfg = new LAMCfgMain();
}
2017-10-29 10:33:07 +00:00
return $cfg->logLevel >= LOG_DEBUG;
}
2006-04-23 16:33:25 +00:00
/**
* Puts a new message in the log file.
*
2010-01-25 16:38:36 +00:00
* @param string $level log level (LOG_DEBUG, LOG_NOTICE, LOG_WARNING, LOG_ERR)
2006-04-23 16:33:25 +00:00
* @param string $message log message
*/
function logNewMessage($level, $message) {
2019-02-23 18:44:10 +00:00
$possibleLevels = array(
LOG_DEBUG => 'DEBUG',
LOG_NOTICE => 'NOTICE',
LOG_WARNING => 'WARNING',
LOG_ERR => 'ERROR');
2018-12-29 08:51:51 +00:00
if (!in_array($level, array_keys($possibleLevels))) {
StatusMessage('ERROR', 'Invalid log level!', $level);
}
if (isset($_SESSION['cfgMain'])) {
$cfg = $_SESSION['cfgMain'];
}
else {
$cfg = new LAMCfgMain();
}
2006-04-23 16:33:25 +00:00
// check if logging is disabled
2018-12-29 08:51:51 +00:00
if (($cfg->logDestination == 'NONE')
// check if log level is high enough
|| ($cfg->logLevel < $level)) {
return;
}
2006-04-23 16:33:25 +00:00
// ok to log, build log message
2019-07-31 19:19:42 +00:00
$prefix = "LDAP Account Manager (" . session_id() . ' - ' . getClientIPForLogging() . ' - ' . getLamLdapUser() . ") - " . $possibleLevels[$level] . ": ";
2006-04-23 16:33:25 +00:00
$message = $prefix . $message;
// Syslog logging
if ($cfg->logDestination == 'SYSLOG') {
syslog($level, $message);
}
2019-02-23 18:44:10 +00:00
// remote logging
2019-03-01 17:28:14 +00:00
elseif (strpos($cfg->logDestination, 'REMOTE') === 0) {
2019-02-23 18:44:10 +00:00
lamLogRemoteMessage($level, $message, $cfg);
}
2006-04-23 16:33:25 +00:00
// log to file
else {
2008-05-16 17:32:02 +00:00
@touch($cfg->logDestination);
2006-04-23 16:33:25 +00:00
if (is_writable($cfg->logDestination)) {
$file = fopen($cfg->logDestination, 'a');
if ($file) {
2015-08-23 08:18:30 +00:00
$timeZone = 'UTC';
$sysTimeZone = @date_default_timezone_get();
if (!empty($sysTimeZone)) {
$timeZone = $sysTimeZone;
}
$time = new DateTime(null, new DateTimeZone($timeZone));
fwrite($file, $time->format('Y-m-d H:i:s') . ': ' . $message . "\n");
2006-04-23 16:33:25 +00:00
fclose($file);
}
}
else {
StatusMessage('ERROR', 'Unable to write to log file!', $cfg->logDestination);
}
}
}
2007-12-30 12:32:48 +00:00
/**
* Checks if write access to LDAP is allowed.
*
* @param String $scope account type (e.g. user)
2007-12-30 12:32:48 +00:00
* @return boolean true, if allowed
*/
function checkIfWriteAccessIsAllowed($scope = null) {
2007-12-30 12:32:48 +00:00
if (!isset($_SESSION['config'])) {
return false;
}
if ($_SESSION['config']->getAccessLevel() >= LAMConfig::ACCESS_ALL) {
$typeSettings = $_SESSION['config']->get_typeSettings();
2018-12-29 08:51:51 +00:00
if (($scope == null)
// check if write for this type is allowed
|| !isset($typeSettings['readOnly_' . $scope])
|| !$typeSettings['readOnly_' . $scope]) {
return true;
}
2007-12-30 12:32:48 +00:00
}
return false;
}
/**
* Checks if passwords may be changed.
*
* @return boolean true, if allowed
*/
function checkIfPasswordChangeIsAllowed() {
if (!isset($_SESSION['config'])) {
return false;
}
if ($_SESSION['config']->getAccessLevel() >= LAMConfig::ACCESS_PASSWORD_CHANGE) {
return true;
}
return false;
}
/**
* Checks if it is allowed to create new LDAP entries of the given type.
* This also checks if general write access is enabled.
2015-06-26 18:06:22 +00:00
*
* @param String $scope account type (e.g. 'user')
* @return boolean true, if new entries are allowed
*/
function checkIfNewEntriesAreAllowed($scope) {
if (!isLAMProVersion()) {
return true;
}
if (!isset($_SESSION['config']) || empty($scope)) {
return false;
}
$typeSettings = $_SESSION['config']->get_typeSettings();
if (isset($typeSettings['hideNewButton_' . $scope]) && $typeSettings['hideNewButton_' . $scope]) {
return false;
}
return checkIfWriteAccessIsAllowed();
}
/**
* Checks if it is allowed to delete LDAP entries of the given type.
2015-06-26 18:06:22 +00:00
*
* @param String $scope account type (e.g. 'user')
* @return boolean true, if entries may be deleted
*/
function checkIfDeleteEntriesIsAllowed($scope) {
if (!isLAMProVersion()) {
return true;
}
if (!isset($_SESSION['config']) || empty($scope)) {
return false;
}
$typeSettings = $_SESSION['config']->get_typeSettings();
if (isset($typeSettings['hideDeleteButton_' . $scope]) && $typeSettings['hideDeleteButton_' . $scope]) {
return false;
}
return checkIfWriteAccessIsAllowed();
}
2008-02-14 17:37:02 +00:00
/**
* Checks if the password fulfills the password policies.
2015-06-26 18:06:22 +00:00
*
2014-04-05 18:42:46 +00:00
* @param String $password password
* @param String $userName user name
2015-06-26 18:06:22 +00:00
* @param array $otherUserAttrs user's first/last name
2008-02-14 17:37:02 +00:00
* @return mixed true if ok, string with error message if not valid
*/
2014-04-05 18:42:46 +00:00
function checkPasswordStrength($password, $userName, $otherUserAttrs) {
2008-02-14 17:37:02 +00:00
if ($password == null) {
$password = "";
}
2018-12-29 08:51:51 +00:00
if (isset($_SESSION['cfgMain'])) {
$cfg = $_SESSION['cfgMain'];
}
else {
$cfg = new LAMCfgMain();
}
2008-02-14 17:37:02 +00:00
// check length
if (strlen($password) < $cfg->passwordMinLength) {
return sprintf(_('The password is too short. You have to enter at least %s characters.'), $cfg->passwordMinLength);
}
// get number of characers per character class
$lower = 0;
$upper = 0;
$numeric = 0;
$symbols = 0;
for ($i = 0; $i < strlen($password); $i++) {
2009-08-13 18:57:26 +00:00
if (preg_match("/[a-z]/", $password[$i])) {
2008-02-14 17:37:02 +00:00
$lower++;
}
2009-08-13 18:57:26 +00:00
if (preg_match("/[A-Z]/", $password[$i])) {
2008-02-14 17:37:02 +00:00
$upper++;
}
2009-08-13 18:57:26 +00:00
if (preg_match("/[0-9]/", $password[$i])) {
2008-02-14 17:37:02 +00:00
$numeric++;
}
2009-08-13 18:57:26 +00:00
if (preg_match("/[^a-z0-9]/i", $password[$i])) {
2008-02-14 17:37:02 +00:00
$symbols++;
}
}
2014-04-05 18:42:46 +00:00
$rulesMatched = 0;
$rulesFailed = 0;
2008-02-14 17:37:02 +00:00
// check lower case
2014-04-05 18:42:46 +00:00
if (($cfg->checkedRulesCount == -1) && ($lower < $cfg->passwordMinLower)) {
2008-02-14 17:37:02 +00:00
return sprintf(_('The password is too weak. You have to enter at least %s lower case characters.'), $cfg->passwordMinLower);
}
2014-04-05 18:42:46 +00:00
if ($lower < $cfg->passwordMinLower) {
$rulesFailed++;
}
else {
$rulesMatched++;
}
2008-02-14 17:37:02 +00:00
// check upper case
2014-04-05 18:42:46 +00:00
if (($cfg->checkedRulesCount == -1) && ($upper < $cfg->passwordMinUpper)) {
2008-02-14 17:37:02 +00:00
return sprintf(_('The password is too weak. You have to enter at least %s upper case characters.'), $cfg->passwordMinUpper);
}
2014-04-05 18:42:46 +00:00
if ($upper < $cfg->passwordMinUpper) {
$rulesFailed++;
}
else {
$rulesMatched++;
}
2008-02-14 17:37:02 +00:00
// check numeric
2014-04-05 18:42:46 +00:00
if (($cfg->checkedRulesCount == -1) && ($numeric < $cfg->passwordMinNumeric)) {
2008-02-14 17:37:02 +00:00
return sprintf(_('The password is too weak. You have to enter at least %s numeric characters.'), $cfg->passwordMinNumeric);
}
2014-04-05 18:42:46 +00:00
if ($numeric < $cfg->passwordMinNumeric) {
$rulesFailed++;
}
else {
$rulesMatched++;
}
2008-02-14 17:37:02 +00:00
// check symbols
2014-04-05 18:42:46 +00:00
if (($cfg->checkedRulesCount == -1) && ($symbols < $cfg->passwordMinSymbol)) {
2008-02-14 17:37:02 +00:00
return sprintf(_('The password is too weak. You have to enter at least %s symbolic characters.'), $cfg->passwordMinSymbol);
}
2014-04-05 18:42:46 +00:00
if ($symbols < $cfg->passwordMinSymbol) {
$rulesFailed++;
}
else {
$rulesMatched++;
}
2008-02-14 17:37:02 +00:00
// check classes
$classes = 0;
if ($lower > 0) {
$classes++;
}
if ($upper > 0) {
$classes++;
}
if ($numeric > 0) {
$classes++;
}
if ($symbols > 0) {
$classes++;
}
2014-04-05 18:42:46 +00:00
if (($cfg->checkedRulesCount == -1) && ($classes < $cfg->passwordMinClasses)) {
2008-02-14 17:37:02 +00:00
return sprintf(_('The password is too weak. You have to enter at least %s different character classes (upper/lower case, numbers and symbols).'), $cfg->passwordMinClasses);
}
2014-04-05 18:42:46 +00:00
if ($classes < $cfg->passwordMinClasses) {
$rulesFailed++;
}
else {
$rulesMatched++;
}
// check rules count
if (($cfg->checkedRulesCount != -1) && ($rulesMatched < $cfg->checkedRulesCount)) {
return sprintf(_('The password is too weak. It needs to match at least %s password complexity rules.'), $cfg->checkedRulesCount);
}
// check user name
if (($cfg->passwordMustNotContainUser == 'true') && !empty($userName)) {
$pwdLow = strtolower($password);
$userLow = strtolower($userName);
if (strpos($pwdLow, $userLow) !== false) {
return _('The password is too weak. You may not use the user name as part of the password.');
}
}
// check part of user name and additional attributes
if (($cfg->passwordMustNotContain3Chars == 'true') && (!empty($userName) || !empty($otherUserAttrs))) {
$pwdLow = strtolower($password);
// check if contains part of user name
if (!empty($userName) && (strlen($userName) > 2)) {
$userLow = strtolower($userName);
for ($i = 0; $i < strlen($userLow) - 3; $i++) {
$part = substr($userLow, 0, 3);
if (strpos($pwdLow, $part) !== false) {
return _('The password is too weak. You may not use parts of the user name for the password.');
}
}
}
// check other attributes
foreach ($otherUserAttrs as $other) {
$low = strtolower($other);
for ($i = 0; $i < strlen($low) - 3; $i++) {
$part = substr($low, 0, 3);
if (strpos($pwdLow, $part) !== false) {
return _('The password is too weak. You may not use parts of user attributes for the password.');
}
}
}
}
2018-04-10 19:32:26 +00:00
// check external password service
if (!checkPwdWithExternalPasswordService($cfg, $password)) {
return _('Your selected password is known to be insecure.');
}
return true;
}
/**
* Checks the password against the external password service.
*
* @param LAMCfgMain $cfg main configuration
* @param string $password password
* @return boolean password accepted as secure
*/
function checkPwdWithExternalPasswordService($cfg, $password) {
if (!function_exists('curl_init') || empty($cfg->externalPwdCheckUrl)) {
return true;
}
$sha1 = sha1($password);
$sha1Prefix = substr($sha1, 0, 5);
$sha1Suffix = substr($sha1, 5);
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$url = $cfg->externalPwdCheckUrl;
$url = str_replace('{SHA1PREFIX}', $sha1Prefix, $url);
curl_setopt($curl, CURLOPT_URL, $url);
$results = curl_exec($curl);
$code = curl_errno($curl);
if ($code) {
logNewMessage(LOG_ERR, 'Error calling the external password service at ' . $url
. '. ' . curl_error($curl));
return true;
}
curl_close($curl);
if (empty($results)) {
return true;
}
$results = explode("\n", $results);
foreach ($results as $result) {
if (stripos($result, $sha1Suffix . ':') !== false) {
return false;
}
}
2008-02-14 17:37:02 +00:00
return true;
}
2012-07-22 10:37:01 +00:00
/**
* Checks if the given tool is active.
* Otherwise, an error message is logged and the execution is stopped (die()).
2015-06-26 18:06:22 +00:00
*
2012-07-22 10:37:01 +00:00
* @param String $tool tool class name (e.g. toolFileUpload)
*/
function checkIfToolIsActive($tool) {
$toolSettings = $_SESSION['config']->getToolSettings();
// check if hidden by config
if (isset($toolSettings['tool_hide_' . $tool]) && ($toolSettings['tool_hide_' . $tool] == 'true')) {
logNewMessage(LOG_ERR, 'Unauthorized access to tool ' . $tool . ' denied.');
die();
}
}
2014-10-25 19:17:53 +00:00
/**
* Returns if the user is logged in.
2015-06-26 18:06:22 +00:00
*
2014-10-25 19:17:53 +00:00
* @return boolean is logged in
*/
function isLoggedIn() {
return (isset($_SESSION['loggedIn']) && ($_SESSION['loggedIn'] === true));
}
/**
* Returns the client IP and comma separated proxy IPs if any (HTTP_X_FORWARDED_FOR, HTTP_X_REAL_IP).
2015-06-26 18:06:22 +00:00
*
* @return String client IP (e.g. 10.10.10.10,11.11.11.11)
*/
function getClientIPForLogging() {
2015-06-26 18:06:22 +00:00
$ip = empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR'];
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && (strlen($_SERVER['HTTP_X_FORWARDED_FOR']) < 100)) {
$ip .= ',' . $_SERVER['HTTP_X_FORWARDED_FOR'];
}
if (!empty($_SERVER['HTTP_X_REAL_IP']) && (strlen($_SERVER['HTTP_X_REAL_IP']) < 100)) {
$ip .= ',' . $_SERVER['HTTP_X_REAL_IP'];
}
return $ip;
}
2019-07-31 19:19:42 +00:00
/**
* Returns the login dn of the current user.
*
* @return string user DN
*/
function getLamLdapUser() {
if (isset($_SESSION['ldap'])) {
return $_SESSION['ldap']->getUserName();
}
elseif (isset($_SESSION['selfService_clientDN'])) {
return lamDecrypt($_SESSION['selfService_clientDN'], 'SelfService');
}
return '';
}
2015-05-14 09:18:45 +00:00
/**
* Adds a security token to the session to prevent CSRF attacks.
2017-10-07 07:58:05 +00:00
*
* @param boolean $overwrite overwrite existing token
2015-05-14 09:18:45 +00:00
*/
2017-10-07 07:58:05 +00:00
function addSecurityTokenToSession($overwrite = true) {
if (!empty($_SESSION[getSecurityTokenName()]) && !$overwrite) {
return;
}
2015-05-14 09:18:45 +00:00
$_SESSION[getSecurityTokenName()] = getRandomNumber();
}
/**
* Checks if the security token from SESSION matches POST data.
*/
function validateSecurityToken() {
if (empty($_POST)) {
2015-05-14 09:18:45 +00:00
return;
}
if (empty($_POST[getSecurityTokenName()]) || ($_POST[getSecurityTokenName()] != $_SESSION[getSecurityTokenName()])) {
logNewMessage(LOG_ERR, 'Security token does not match POST data.');
2015-05-14 09:18:45 +00:00
die();
}
}
/**
* Adds a hidden input field to the given meta HTML table.
* Should be used to add token at the end of table.
2015-06-26 18:06:22 +00:00
*
2018-01-13 18:58:55 +00:00
* @param htmlTable|htmlGroup|htmlResponsiveRow $container table
2015-05-14 09:18:45 +00:00
*/
function addSecurityTokenToMetaHTML(&$container) {
2017-01-31 19:50:51 +00:00
$token = new htmlHiddenInput(getSecurityTokenName(), $_SESSION[getSecurityTokenName()]);
2018-01-13 18:58:55 +00:00
if ($container instanceof htmlResponsiveRow) {
$container->add($token, 12);
return;
}
2017-01-31 19:50:51 +00:00
$container->addElement($token, true);
2015-05-14 09:18:45 +00:00
}
/**
* Returns the name of the security token parameter.
2015-06-26 18:06:22 +00:00
*
2015-05-14 09:18:45 +00:00
* @return String name
*/
function getSecurityTokenName() {
return 'sec_token';
}
/**
* Returns the value of the security token parameter.
2015-06-26 18:06:22 +00:00
*
2015-05-14 09:18:45 +00:00
* @return String value
*/
function getSecurityTokenValue() {
return $_SESSION[getSecurityTokenName()];
}
2015-12-19 09:31:21 +00:00
/**
* Sets the X-Frame-Options and Content-Security-Policy header to prevent clickjacking.
*/
function setLAMHeaders() {
if (!headers_sent()) {
header('X-Frame-Options: sameorigin');
2019-08-13 15:03:30 +00:00
header('Content-Security-Policy: frame-ancestors \'self\'; form-action \'self\'; base-uri \'none\'; object-src \'none\'; frame-src \'self\' https://*.duosecurity.com; worker-src \'self\'');
2019-02-01 18:38:03 +00:00
header('X-Content-Type-Options: nosniff');
header('X-XSS-Protection: 1; mode=block');
2015-12-19 09:31:21 +00:00
}
}
/**
* Encrypts a string
*
* @param string $data string to encrypt
* @param string $prefix prefix for cookie names
* @return object encrypted string
*/
function lamEncrypt($data, $prefix='') {
2017-04-02 17:37:06 +00:00
// use OpenSSL if available
if (function_exists('openssl_random_pseudo_bytes')) {
// OpenSSL may have been enabled in a running session
2018-12-29 08:51:51 +00:00
if (!isset($_COOKIE[$prefix . "IV"])
|| ($_COOKIE[$prefix . "IV"] == '')
|| ($_COOKIE[$prefix . "IV"] == "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) {
return $data;
}
// read key and iv from cookie
$iv = base64_decode($_COOKIE[$prefix . "IV"]);
$key = base64_decode($_COOKIE[$prefix . "Key"]);
// encrypt string
2017-04-02 17:37:06 +00:00
return openssl_encrypt(base64_encode($data), lamEncryptionAlgo(), $key, 0, $iv);
}
// otherwise do not encrypt
else {
return $data;
}
}
/**
* Decrypts a string
*
* @param object $data string to decrypt
* @param string $prefix prefix for cookie names
* @return string decrypted string
*/
function lamDecrypt($data, $prefix='') {
2017-04-02 17:37:06 +00:00
// use OpenSSL if available
if (function_exists('openssl_random_pseudo_bytes')) {
// OpenSSL may have been enabled in a running session
2018-12-29 08:51:51 +00:00
if (!isset($_COOKIE[$prefix . "IV"])
|| ($_COOKIE[$prefix . "IV"] == '')
|| ($_COOKIE[$prefix . "IV"] == "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) {
return $data;
}
// read key and iv from cookie
$iv = base64_decode($_COOKIE[$prefix . "IV"]);
$key = base64_decode($_COOKIE[$prefix . "Key"]);
// decrypt string
2017-04-02 17:37:06 +00:00
$ret = openssl_decrypt($data, lamEncryptionAlgo(), $key, 0, $iv);
2018-12-29 08:51:51 +00:00
return base64_decode(str_replace(chr(00), "", $ret));
}
// otherwise do not decrypt
else {
return $data;
}
}
2017-04-02 17:37:06 +00:00
/**
* Returns the encryption algorithm to use.
*
* @return string algorithm name
*/
function lamEncryptionAlgo() {
$possibleAlgos = openssl_get_cipher_methods();
if (in_array('AES-256-CTR', $possibleAlgos)) {
return 'AES-256-CTR';
}
elseif (in_array('AES-256-CBC', $possibleAlgos)) {
return 'AES-256-CBC';
}
return 'AES256';
}
2019-02-23 18:44:10 +00:00
/**
* Logs a message to a remote logging service.
*
* @param int $level log level
* @param string $message log message
* @param LAMCfgMain $cfgMain main configuration
*/
function lamLogRemoteMessage($level, $message, $cfgMain) {
2019-02-23 19:29:45 +00:00
include_once __DIR__ . '/3rdParty/Psr/Log/InvalidArgumentException.php';
include_once __DIR__ . '/3rdParty/Psr/Log/LoggerInterface.php';
include_once __DIR__ . '/3rdParty/Monolog/ResettableInterface.php';
2019-02-23 18:44:10 +00:00
include_once __DIR__ . '/3rdParty/Monolog/Logger.php';
2019-02-23 19:29:45 +00:00
include_once __DIR__ . '/3rdParty/Monolog/Formatter/FormatterInterface.php';
include_once __DIR__ . '/3rdParty/Monolog/Formatter/NormalizerFormatter.php';
2019-02-23 18:44:10 +00:00
include_once __DIR__ . '/3rdParty/Monolog/Formatter/LineFormatter.php';
2019-02-23 19:29:45 +00:00
include_once __DIR__ . '/3rdParty/Monolog/Handler/HandlerInterface.php';
include_once __DIR__ . '/3rdParty/Monolog/Handler/AbstractHandler.php';
include_once __DIR__ . '/3rdParty/Monolog/Handler/AbstractProcessingHandler.php';
include_once __DIR__ . '/3rdParty/Monolog/Handler/AbstractSyslogHandler.php';
include_once __DIR__ . '/3rdParty/Monolog/Handler/SyslogUdp/UdpSocket.php';
2019-02-23 18:44:10 +00:00
include_once __DIR__ . '/3rdParty/Monolog/Handler/SyslogUdpHandler.php';
$remoteParts = explode(':', $cfgMain->logDestination);
2019-02-23 19:29:45 +00:00
$server = $remoteParts[1];
$port = intval($remoteParts[2]);
2019-02-23 18:44:10 +00:00
$output = "%channel%.%level_name%: %message%";
$formatter = new Monolog\Formatter\LineFormatter($output);
$logger = new Monolog\Logger('lam');
$syslogHandler = new Monolog\Handler\SyslogUdpHandler($server, $port);
$syslogHandler->setFormatter($formatter);
$logger->pushHandler($syslogHandler);
switch ($level) {
case LOG_DEBUG:
$logger->addDebug($message);
break;
case LOG_NOTICE:
$logger->addNotice($message);
break;
case LOG_WARNING:
$logger->addWarning($message);
break;
case LOG_ERR:
$logger->addError($message);
break;
}
}
2006-03-26 11:36:43 +00:00
?>