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' );
2014-01-12 19:58:15 +00:00
/** 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 .
2013-02-28 19:04:27 +00:00
* The script is stopped if one of the checks fail ( timeout redirection may be overriden ) .
2015-06-26 18:06:22 +00:00
*
2013-07-28 17:49:20 +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 )
2013-02-28 19:04:27 +00:00
* @ return boolean true if all ok , false if session expired
2006-03-26 11:36:43 +00:00
*/
2013-07-28 17:49:20 +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 );
2010-05-28 08:01:54 +00:00
// 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 ();
2013-07-28 17:49:20 +00:00
// 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 ();
}
2013-10-18 17:43:09 +00:00
// 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
2015-02-17 18:31:52 +00:00
logNewMessage ( LOG_WARNING , " Invalid session ID, access denied ( " . getClientIPForLogging () . " ) " );
2017-02-27 18:25:47 +00:00
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
2015-02-17 18:31:52 +00:00
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 ();
}
2013-02-28 19:04:27 +00:00
elseif ( $redirectToLogin ) {
2006-04-18 10:57:16 +00:00
// session expired, logoff user
logoffAndBackToLoginPage ();
}
2013-02-28 19:04:27 +00:00
else {
return false ;
}
2013-08-10 12:43:01 +00:00
setSSLCaCert ();
2013-02-28 19:04:27 +00:00
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 ;
2014-01-12 19:58:15 +00:00
$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 ) {
2015-02-17 18:31:52 +00:00
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
2013-02-28 17:42:09 +00:00
if ( isset ( $_SESSION [ 'ldap' ])) {
2019-08-05 19:56:06 +00:00
$ldapUser = $_SESSION [ 'ldap' ] -> getUserName ();
logNewMessage ( LOG_WARNING , 'Session of user ' . $ldapUser . ' expired.' );
2013-02-28 17:42:09 +00:00
// close LDAP connection
@ $_SESSION [ " ldap " ] -> destroy ();
}
2013-07-28 17:49:20 +00:00
elseif ( isset ( $_SESSION [ 'selfService_clientDN' ]) || ( strpos ( $_SERVER [ 'REQUEST_URI' ], '/selfService/' ) !== false )) {
2016-08-07 08:40:36 +00:00
logNewMessage ( LOG_WARNING , 'Self service session of DN ' . lamDecrypt ( $_SESSION [ 'selfService_clientDN' ], 'SelfService' ) . ' expired.' );
2013-02-28 17:42:09 +00:00
}
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' ;
2013-07-28 17:49:20 +00:00
if ( isset ( $_SESSION [ 'selfService_clientDN' ]) || ( strpos ( $_SERVER [ 'REQUEST_URI' ], '/selfService/' ) !== false )) {
2013-02-28 17:42:09 +00:00
$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 ;
2013-02-28 17:42:09 +00:00
}
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 .
*
2014-01-15 20:48:52 +00:00
* @ param String $scope account type ( e . g . user )
2007-12-30 12:32:48 +00:00
* @ return boolean true , if allowed
*/
2014-01-15 20:48:52 +00:00
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 ) {
2014-01-15 20:48:52 +00:00
$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 ]) {
2014-01-15 20:48:52 +00:00
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 ;
}
2013-05-01 12:36:17 +00:00
/**
* 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
*
2013-05-01 12:36:17 +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
*
2013-05-01 12:36:17 +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 ));
}
2015-02-17 18:31:52 +00:00
/**
* 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
*
2015-02-17 18:31:52 +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' ];
2015-02-17 18:31:52 +00:00
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 .
*/
2018-03-14 19:06:09 +00:00
function validateSecurityToken () {
if ( empty ( $_POST )) {
2015-05-14 09:18:45 +00:00
return ;
}
2018-03-14 19:06:09 +00:00
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
}
}
2016-08-07 08:40:36 +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 " )) {
2016-08-07 08:40:36 +00:00
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 );
2016-08-07 08:40:36 +00:00
}
// 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 " )) {
2016-08-07 08:40:36 +00:00
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 ));
2016-08-07 08:40:36 +00:00
}
// 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
?>