2006-03-26 11:36:43 +00:00
< ? php
/*
$Id $
This code is part of LDAP Account Manager ( http :// www . sourceforge . net / projects / lam )
Copyright ( C ) 2006 Roland Gruber
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' );
2006-04-18 10:57:16 +00:00
2006-04-25 11:25:07 +00:00
// check client IP address
checkClientIP ();
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 .
*/
function startSecureSession () {
// start session
if ( isset ( $_SESSION )) unset ( $_SESSION );
2009-07-08 18:03:28 +00:00
if ( strtolower ( session_module_name ()) == 'files' ) {
$sessionDir = substr ( __FILE__ , 0 , strlen ( __FILE__ ) - 17 ) . " /sess " ;
session_save_path ( $sessionDir );
}
2006-03-26 11:36:43 +00:00
@ session_start ();
// check session id
if ( ! isset ( $_SESSION [ " sec_session_id " ]) || ( $_SESSION [ " sec_session_id " ] != session_id ())) {
// session id is invalid
2008-08-06 19:01:03 +00:00
logNewMessage ( LOG_WARNING , " Invalid session ID, access denied ( " . $_SERVER [ 'REMOTE_ADDR' ] . " ) " );
2006-09-24 14:19:50 +00:00
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
2008-08-06 19:01:03 +00:00
logNewMessage ( LOG_WARNING , " Client IP changed, access denied ( " . $_SERVER [ 'REMOTE_ADDR' ] . " ) " );
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 ();
}
else {
// session expired, logoff user
logoffAndBackToLoginPage ();
}
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 () {
2007-07-08 19:23:07 +00:00
if ( isset ( $_SESSION [ 'cfgMain' ])) $cfg = $_SESSION [ 'cfgMain' ];
else $cfg = new LAMCfgMain ();
2006-04-25 11:25:07 +00:00
$allowedHosts = $cfg -> allowedHosts ;
// skip test if no hosts are defined
if ( $allowedHosts == " " ) return ;
$allowedHosts = explode ( " , " , $allowedHosts );
$grantAccess = false ;
for ( $i = 0 ; $i < sizeof ( $allowedHosts ); $i ++ ) {
$host = $allowedHosts [ $i ];
2009-08-13 18:57:26 +00:00
$ipRegex = '/^[0-9\\.\\*]+$/' ;
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 ( " . $_SERVER [ 'REMOTE_ADDR' ] . " ) " );
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
$ldapUser = $_SESSION [ 'ldap' ] -> decrypt_login ();
logNewMessage ( LOG_WARNING , 'Session of user ' . $ldapUser [ 0 ] . ' expired.' );
2006-04-18 10:57:16 +00:00
// delete key and iv in cookie
if ( function_exists ( 'mcrypt_create_iv' )) {
setcookie ( " Key " , " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx " , 0 , " / " );
setcookie ( " IV " , " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx " , 0 , " / " );
}
// close LDAP connection
@ $_SESSION [ " ldap " ] -> destroy ();
// link back to login page
$paths = array ( './' , '../' , '../../' , '../../../' );
$page = 'login.php' ;
for ( $i = 0 ; $i < sizeof ( $paths ); $i ++ ) {
if ( file_exists ( $paths [ $i ] . $page )) {
$page = $paths [ $i ] . $page ;
break ;
}
}
2006-05-01 08:56:40 +00:00
$page .= " ?expired=yes " ;
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 ();
}
2006-04-23 16:33:25 +00:00
/**
* Puts a new message in the log file .
*
* @ param string $level log level ( LOG_NOTICE , LOG_WARNING , LOG_ERR )
* @ param string $message log message
*/
function logNewMessage ( $level , $message ) {
$possibleLevels = array ( LOG_NOTICE => 'NOTICE' , LOG_WARNING => 'WARNING' , LOG_ERR => 'ERROR' );
if ( ! in_array ( $level , array_keys ( $possibleLevels ))) StatusMessage ( 'ERROR' , 'Invalid log level!' , $level );
if ( isset ( $_SESSION [ 'cfgMain' ])) $cfg = $_SESSION [ 'cfgMain' ];
2006-09-24 14:19:50 +00:00
else $cfg = new LAMCfgMain ();
2006-04-23 16:33:25 +00:00
// check if logging is disabled
if ( $cfg -> logDestination == 'NONE' ) return ;
// check if log level is high enough
elseif ( $cfg -> logLevel < $level ) return ;
// ok to log, build log message
2007-12-28 10:36:07 +00:00
$prefix = " LDAP Account Manager ( " . session_id () . " ) - " . $possibleLevels [ $level ] . " : " ;
2006-04-23 16:33:25 +00:00
$message = $prefix . $message ;
// Syslog logging
if ( $cfg -> logDestination == 'SYSLOG' ) {
syslog ( $level , $message );
}
// 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 ) {
2009-05-21 16:19:12 +00:00
fwrite ( $file , date ( '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 .
*
* @ return boolean true , if allowed
*/
function checkIfWriteAccessIsAllowed () {
if ( ! isset ( $_SESSION [ 'config' ])) {
return false ;
}
if ( $_SESSION [ 'config' ] -> getAccessLevel () >= LAMConfig :: ACCESS_ALL ) {
return true ;
}
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 ;
}
2008-02-14 17:37:02 +00:00
/**
* Checks if the password fulfills the password policies .
*
* @ param string $password password
* @ return mixed true if ok , string with error message if not valid
*/
function checkPasswordStrength ( $password ) {
if ( $password == null ) {
$password = " " ;
}
if ( isset ( $_SESSION [ 'cfgMain' ])) $cfg = $_SESSION [ 'cfgMain' ];
else $cfg = new LAMCfgMain ();
// 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 ++ ;
}
}
// check lower case
if ( $lower < $cfg -> passwordMinLower ) {
return sprintf ( _ ( 'The password is too weak. You have to enter at least %s lower case characters.' ), $cfg -> passwordMinLower );
}
// check upper case
if ( $upper < $cfg -> passwordMinUpper ) {
return sprintf ( _ ( 'The password is too weak. You have to enter at least %s upper case characters.' ), $cfg -> passwordMinUpper );
}
// check numeric
if ( $numeric < $cfg -> passwordMinNumeric ) {
return sprintf ( _ ( 'The password is too weak. You have to enter at least %s numeric characters.' ), $cfg -> passwordMinNumeric );
}
// check symbols
if ( $symbols < $cfg -> passwordMinSymbol ) {
return sprintf ( _ ( 'The password is too weak. You have to enter at least %s symbolic characters.' ), $cfg -> passwordMinSymbol );
}
// check classes
$classes = 0 ;
if ( $lower > 0 ) {
$classes ++ ;
}
if ( $upper > 0 ) {
$classes ++ ;
}
if ( $numeric > 0 ) {
$classes ++ ;
}
if ( $symbols > 0 ) {
$classes ++ ;
}
if ( $classes < $cfg -> passwordMinClasses ) {
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 );
}
return true ;
}
2006-03-26 11:36:43 +00:00
?>