* exported the "IP-based Allow/Deny" code in a distinct library;

* coding standards;
* improved PHP3 compliance;
* better ip checking.
This commit is contained in:
Loïc Chapeaux
2002-05-18 12:37:01 +00:00
parent 99051ee709
commit 9da7080d8d
3 changed files with 422 additions and 172 deletions

View File

@@ -5,6 +5,14 @@ phpMyAdmin - Changelog
$Id$
$Source$
2002-05-18 Lo<4C>c Chapeaux <lolo@phpheaven.net>
* libraries/common.lib.php3; libraries/ip_allow_deny.lib.php3:
- exported the "IP-based Allow/Deny" code in a distinct library;
- coding standards;
- improved PHP3 compliance;
- better ip checking.
* Documentation.html: typos and line sizes.
2002-05-17 Robin Johnson <robbat2@users.sourceforge.net>
* config.inc.php3, libraries/common.lib.php3: IP-based Allow/Deny code
from feature #484158

View File

@@ -311,144 +311,6 @@ if (!defined('PMA_COMMON_LIB_INCLUDED')){
return true;
} // end of the 'PMA_setFontSizes()' function
/**
* Based on IP Pattern Matcher
* Originally by J.Adams <jna@retina.net>
* Found on <http://www.php.net/manual/en/function.ip2long.php>
* Modified by Robbat2 <robbat2@users.sourceforge.net>
*
* Matches:
* xxx.xxx.xxx.xxx (exact)
* xxx.xxx.xxx.[yyy-zzz] (range)
* xxx.xxx.xxx.xxx/nn (CIDR)
*
* Does not match:
* xxx.xxx.xxx.xx[yyy-zzz] (range, partial octets not supported)
*
* @param string string of IP range to match
* @param string string of IP to test against range
*
* @return boolean always true
*
* @access public
*/
function PMA_IPMaskTest($TestRange,$IPtoTest)
{
$result = TRUE;
if (ereg( "([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/([0-9]+)", $TestRange, $regs) ) {
//perform a mask match
$ipl = ip2long($IPtoTest);
$rangel = ip2long($regs[1].'.'.$regs[2].'.'.$regs[3].'.'.$regs[4]);
$maskl = 0;
for ($i = 0; $i< 31; $i++) {
if ($i < $regs[5]-1) {
$maskl = $maskl + pow(2,(30-$i));
} // end if
} // end for
if (($maskl & $rangel) == ($maskl & $ipl)) {
return TRUE;
} else {
return FALSE;
}
} else {
// range based
$maskocts = split("\.",$TestRange);
$ipocts = split("\.",$IPtoTest);
// perform a range match
for ($i=0; $i<4; $i++) {
if (ereg("\[([0-9]+)\-([0-9]+)\]",$maskocts[$i],$regs)) {
if ( ($ipocts[$i] > $regs[2])
|| ($ipocts[$i] < $regs[1])) {
$result = FALSE;
} // end if
} else {
if ($maskocts[$i] <> $ipocts[$i]) {
$result = FALSE;
} // end if
} // end if/else
} //end for
} //end if/else
return $result;
}
/**
* Runs through IP Allow/Deny rules the use of it below for more information
*
* @param string 'allow' | 'deny' type of rule to match
*
* @return bool Matched a rule ?
*
* @access public
*/
function PMA_AllowDeny($type)
{
global $cfg;
// grab IP of user
if (getenv("HTTP_X_FORWARDED_FOR")) {
// try to behave properly with proxies, as per
// http://www.php.net/manual/en/function.getenv.php
$remoteip = getenv("HTTP_X_FORWARDED_FOR");
} else {
// possibly does not work in ISAPI?
$remoteip = getenv("REMOTE_ADDR");
}
// copy username
$username = $cfg['Server']['user'];
// copy rule database
$rules = $cfg['Server']['AllowDeny']['rules'];
// lookup table for some name shortcuts
$shortcuts = array(
"all" => "0.0.0.0/0",
"localhost" => "127.0.0.1/8"
);
reset ($rules); // used instead of a foreach look for PHP3 support
while ( list(, $rule) = each ($rules) ) {
// extract rule data
$rule_data = explode(' ',$rule);
// check for rule type
if( $rule_data[0] != $type )
continue;
// check for username
if( ($rule_data[1] != '%' ) //wildcarded first
&& ($rule_data[1] != $username) )
continue;
// check if the config file has the full string with an extra 'from' in it
// if it does, just discard it
if( $rule_data[2] == 'from' )
$rule_data[2] = $rule_data[3];
// Handle shortcuts with above array
// DON'T use "array_key_exists" as it's only PHP 4.1 and newer.
if( isset($shortcuts[$rule_data[2]]) )
$rule_data[2] = $shortcuts[$rule_data[2]];
// Add code for host lookups here
// Excluded for the moment
// Do the actual matching now
if(PMA_IPMaskTest($rule_data[2],$remoteip))
return TRUE;
}
return FALSE;
}
/**
* $cfg['PmaAbsoluteUri'] is a required directive else cookies won't be
@@ -543,41 +405,46 @@ if (!defined('PMA_COMMON_LIB_INCLUDED')){
PMA_auth_set_user();
}
// Check IP-based Allow/Deny rules as soon as possible to reject the user
// Based on mod_access in Apache
// http://cvs.apache.org/viewcvs.cgi/httpd-2.0/modules/aaa/mod_access.c?rev=1.37&content-type=text/vnd.viewcvs-markup
// Look at: "static int check_dir_access(request_rec *r)"
// Robbat2 - May 10, 2002
// Check IP-based Allow/Deny rules as soon as possible to reject the
// user
// Based on mod_access in Apache:
// http://cvs.apache.org/viewcvs.cgi/httpd-2.0/modules/aaa/mod_access.c?rev=1.37&content-type=text/vnd.viewcvs-markup
// Look at: "static int check_dir_access(request_rec *r)"
// Robbat2 - May 10, 2002
if ($cfg['Server']['AllowDeny']['order']) {
include('./libraries/ip_allow_deny.lib.php3');
$AllowDeny_forbidden = FALSE; //default
if ( $cfg['Server']['AllowDeny']['order'] == 'allow,deny' ) {
$AllowDeny_forbidden = TRUE;
if( PMA_AllowDeny('allow') ) {
$AllowDeny_forbidden = FALSE;
}
if( PMA_AllowDeny('deny') ) {
$AllowDeny_forbidden = TRUE;
}
} else if ( $cfg['Server']['AllowDeny']['order'] == 'deny,allow' ) {
if( PMA_AllowDeny('deny') ) {
$AllowDeny_forbidden = TRUE;
}
if( PMA_AllowDeny('allow') ) {
$AllowDeny_forbidden = FALSE;
}
} else if ( $cfg['Server']['AllowDeny']['order'] == 'explicit' ) {
if( PMA_AllowDeny('allow')
&& !PMA_AllowDeny('deny') ) {
$AllowDeny_forbidden = FALSE;
} else {
$AllowDeny_forbidden = TRUE;
}
}
if($AllowDeny_forbidden) {
// eject the user if they are bad
PMA_auth_fails();
}
unset($AllowDeny_forbidden); //Clean up after you!
$allowDeny_forbidden = FALSE; //default
if ($cfg['Server']['AllowDeny']['order'] == 'allow,deny') {
$allowDeny_forbidden = TRUE;
if (PMA_allowDeny('allow')) {
$allowDeny_forbidden = FALSE;
}
if (PMA_allowDeny('deny')) {
$allowDeny_forbidden = TRUE;
}
} else if ($cfg['Server']['AllowDeny']['order'] == 'deny,allow') {
if (PMA_allowDeny('deny')) {
$allowDeny_forbidden = TRUE;
}
if (PMA_allowDeny('allow')) {
$allowDeny_forbidden = FALSE;
}
} else if ($cfg['Server']['AllowDeny']['order'] == 'explicit') {
if (PMA_allowDeny('allow')
&& !PMA_allowDeny('deny')) {
$allowDeny_forbidden = FALSE;
} else {
$allowDeny_forbidden = TRUE;
}
} // end if... else if... else if
// Ejects the user if banished
if ($allowDeny_forbidden) {
PMA_auth_fails();
}
unset($allowDeny_forbidden); //Clean up after you!
} // end if
// The user can work with only some databases
if (isset($cfg['Server']['only_db']) && $cfg['Server']['only_db'] != '') {

View File

@@ -0,0 +1,375 @@
<?php
/* $Id$ */
/**
* This library is used with the server IP allow/deny host authentication
* feature
*/
if (!defined('PMA_ALLOW_DENY_LIB_INCLUDED')) {
define('PMA_ALLOW_DENY_LIB_INCLUDED', 1);
if (PMA_PHP_INT_VERSION < 40000) {
/**
* Emulates the "ip2long" function under PHP3
*
* Based on a piece of code from
* richard lithvall <richard at lithvall dot nu>
*
* @param string an IP in Internet standard format
*
* @return string its IPv4 Internet network address
*
* @access private
*/
function ip2long($dotted)
{
$dotted = split('\.', $dotted);
$ip = (double)0;
$y = 0x1000000;
for ($i = 0; $i < 4; $i++) {
$ip += ($dotted[$i] * $y);
$y = ($y >> 8);
} // end for
return $ip;
} // end of the "ip2long" function
} // end if
/**
* Gets the "true" IP address of the current user
*
* @return string the ip of the user
*
* @access private
*/
function PMA_getIp()
{
global $REMOTE_ADDR;
global $HTTP_X_FORWARDED_FOR, $HTTP_X_FORWARDED, $HTTP_FORWARDED_FOR, $HTTP_FORWARDED;
global $HTTP_VIA, $HTTP_X_COMING_FROM, $HTTP_COMING_FROM;
global $HTTP_SERVER_VARS, $HTTP_ENV_VARS;
// Get some server/environment variables values
if (empty($REMOTE_ADDR)) {
if (!empty($_SERVER) && isset($_SERVER['REMOTE_ADDR'])) {
$REMOTE_ADDR = $_SERVER['REMOTE_ADDR'];
}
else if (!empty($_ENV) && isset($_ENV['REMOTE_ADDR'])) {
$REMOTE_ADDR = $_ENV['REMOTE_ADDR'];
}
else if (!empty($HTTP_SERVER_VARS) && isset($HTTP_SERVER_VARS['REMOTE_ADDR'])) {
$REMOTE_ADDR = $HTTP_SERVER_VARS['REMOTE_ADDR'];
}
else if (!empty($HTTP_ENV_VARS) && isset($HTTP_ENV_VARS['REMOTE_ADDR'])) {
$REMOTE_ADDR = $HTTP_ENV_VARS['REMOTE_ADDR'];
}
else if (@getenv('REMOTE_ADDR')) {
$REMOTE_ADDR = getenv('REMOTE_ADDR');
}
} // end if
if (empty($HTTP_X_FORWARDED_FOR)) {
if (!empty($_SERVER) && isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$HTTP_X_FORWARDED_FOR = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
else if (!empty($_ENV) && isset($_ENV['HTTP_X_FORWARDED_FOR'])) {
$HTTP_X_FORWARDED_FOR = $_ENV['HTTP_X_FORWARDED_FOR'];
}
else if (!empty($HTTP_SERVER_VARS) && isset($HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'])) {
$HTTP_X_FORWARDED_FOR = $HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'];
}
else if (!empty($HTTP_ENV_VARS) && isset($HTTP_ENV_VARS['HTTP_X_FORWARDED_FOR'])) {
$HTTP_X_FORWARDED_FOR = $HTTP_ENV_VARS['HTTP_X_FORWARDED_FOR'];
}
else if (@getenv('HTTP_X_FORWARDED_FOR')) {
$HTTP_X_FORWARDED_FOR = getenv('HTTP_X_FORWARDED_FOR');
}
} // end if
if (empty($HTTP_X_FORWARDED)) {
if (!empty($_SERVER) && isset($_SERVER['HTTP_X_FORWARDED'])) {
$HTTP_X_FORWARDED = $_SERVER['HTTP_X_FORWARDED'];
}
else if (!empty($_ENV) && isset($_ENV['HTTP_X_FORWARDED'])) {
$HTTP_X_FORWARDED = $_ENV['HTTP_X_FORWARDED'];
}
else if (!empty($HTTP_SERVER_VARS) && isset($HTTP_SERVER_VARS['HTTP_X_FORWARDED'])) {
$HTTP_X_FORWARDED = $HTTP_SERVER_VARS['HTTP_X_FORWARDED'];
}
else if (!empty($HTTP_ENV_VARS) && isset($HTTP_ENV_VARS['HTTP_X_FORWARDED'])) {
$HTTP_X_FORWARDED = $HTTP_ENV_VARS['HTTP_X_FORWARDED'];
}
else if (@getenv('HTTP_X_FORWARDED')) {
$HTTP_X_FORWARDED = getenv('HTTP_X_FORWARDED');
}
} // end if
if (empty($HTTP_FORWARDED_FOR)) {
if (!empty($_SERVER) && isset($_SERVER['HTTP_FORWARDED_FOR'])) {
$HTTP_FORWARDED_FOR = $_SERVER['HTTP_FORWARDED_FOR'];
}
else if (!empty($_ENV) && isset($_ENV['HTTP_FORWARDED_FOR'])) {
$HTTP_FORWARDED_FOR = $_ENV['HTTP_FORWARDED_FOR'];
}
else if (!empty($HTTP_SERVER_VARS) && isset($HTTP_SERVER_VARS['HTTP_FORWARDED_FOR'])) {
$HTTP_FORWARDED_FOR = $HTTP_SERVER_VARS['HTTP_FORWARDED_FOR'];
}
else if (!empty($HTTP_ENV_VARS) && isset($HTTP_ENV_VARS['HTTP_FORWARDED_FOR'])) {
$HTTP_FORWARDED_FOR = $HTTP_ENV_VARS['HTTP_FORWARDED_FOR'];
}
else if (@getenv('HTTP_FORWARDED_FOR')) {
$HTTP_FORWARDED_FOR = getenv('HTTP_FORWARDED_FOR');
}
} // end if
if (empty($HTTP_FORWARDED)) {
if (!empty($_SERVER) && isset($_SERVER['HTTP_FORWARDED'])) {
$HTTP_FORWARDED = $_SERVER['HTTP_FORWARDED'];
}
else if (!empty($_ENV) && isset($_ENV['HTTP_FORWARDED'])) {
$HTTP_FORWARDED = $_ENV['HTTP_FORWARDED'];
}
else if (!empty($HTTP_SERVER_VARS) && isset($HTTP_SERVER_VARS['HTTP_FORWARDED'])) {
$HTTP_FORWARDED = $HTTP_SERVER_VARS['HTTP_FORWARDED'];
}
else if (!empty($HTTP_ENV_VARS) && isset($HTTP_ENV_VARS['HTTP_FORWARDED'])) {
$HTTP_FORWARDED = $HTTP_ENV_VARS['HTTP_FORWARDED'];
}
else if (@getenv('HTTP_FORWARDED')) {
$HTTP_FORWARDED = getenv('HTTP_FORWARDED');
}
} // end if
if (empty($HTTP_VIA)) {
if (!empty($_SERVER) && isset($_SERVER['HTTP_VIA'])) {
$HTTP_VIA = $_SERVER['HTTP_VIA'];
}
else if (!empty($_ENV) && isset($_ENV['HTTP_VIA'])) {
$HTTP_VIA = $_ENV['HTTP_VIA'];
}
else if (!empty($HTTP_SERVER_VARS) && isset($HTTP_SERVER_VARS['HTTP_VIA'])) {
$HTTP_VIA = $HTTP_SERVER_VARS['HTTP_VIA'];
}
else if (!empty($HTTP_ENV_VARS) && isset($HTTP_ENV_VARS['HTTP_VIA'])) {
$HTTP_VIA = $HTTP_ENV_VARS['HTTP_VIA'];
}
else if (@getenv('HTTP_VIA')) {
$HTTP_VIA = getenv('HTTP_VIA');
}
} // end if
if (empty($HTTP_X_COMING_FROM)) {
if (!empty($_SERVER) && isset($_SERVER['HTTP_X_COMING_FROM'])) {
$HTTP_X_COMING_FROM = $_SERVER['HTTP_X_COMING_FROM'];
}
else if (!empty($_ENV) && isset($_ENV['HTTP_X_COMING_FROM'])) {
$HTTP_X_COMING_FROM = $_ENV['HTTP_X_COMING_FROM'];
}
else if (!empty($HTTP_SERVER_VARS) && isset($HTTP_SERVER_VARS['HTTP_X_COMING_FROM'])) {
$HTTP_X_COMING_FROM = $HTTP_SERVER_VARS['HTTP_X_COMING_FROM'];
}
else if (!empty($HTTP_ENV_VARS) && isset($HTTP_ENV_VARS['HTTP_X_COMING_FROM'])) {
$HTTP_X_COMING_FROM = $HTTP_ENV_VARS['HTTP_X_COMING_FROM'];
}
else if (@getenv('HTTP_X_COMING_FROM')) {
$HTTP_X_COMING_FROM = getenv('HTTP_X_COMING_FROM');
}
} // end if
if (empty($HTTP_COMING_FROM)) {
if (!empty($_SERVER) && isset($_SERVER['HTTP_COMING_FROM'])) {
$HTTP_COMING_FROM = $_SERVER['HTTP_COMING_FROM'];
}
else if (!empty($_ENV) && isset($_ENV['HTTP_COMING_FROM'])) {
$HTTP_COMING_FROM = $_ENV['HTTP_COMING_FROM'];
}
else if (!empty($HTTP_COMING_FROM) && isset($HTTP_SERVER_VARS['HTTP_COMING_FROM'])) {
$HTTP_COMING_FROM = $HTTP_SERVER_VARS['HTTP_COMING_FROM'];
}
else if (!empty($HTTP_ENV_VARS) && isset($HTTP_ENV_VARS['HTTP_COMING_FROM'])) {
$HTTP_COMING_FROM = $HTTP_ENV_VARS['HTTP_COMING_FROM'];
}
else if (@getenv('HTTP_COMING_FROM')) {
$HTTP_COMING_FROM = getenv('HTTP_COMING_FROM');
}
} // end if
// Gets the default ip sent by the user
if (!empty($REMOTE_ADDR)) {
$direct_ip = $REMOTE_ADDR;
}
// Gets the proxy ip sent by the user
$proxy_ip = '';
if (!empty($HTTP_X_FORWARDED_FOR)) {
$proxy_ip = $HTTP_X_FORWARDED_FOR;
} else if (!empty($HTTP_X_FORWARDED)) {
$proxy_ip = $HTTP_X_FORWARDED;
} else if (!empty($HTTP_FORWARDED_FOR)) {
$proxy_ip = $HTTP_FORWARDED_FOR;
} else if (!empty($HTTP_FORWARDED)) {
$proxy_ip = $HTTP_FORWARDED;
} else if (!empty($HTTP_VIA)) {
$proxy_ip = $HTTP_VIA;
} else if (!empty($HTTP_X_COMING_FROM)) {
$proxy_ip = $HTTP_X_COMING_FROM;
} else if (!empty($HTTP_COMING_FROM)) {
$proxy_ip = $HTTP_COMING_FROM;
} // end if... else if...
// Returns the true IP if it has been found, else FALSE
if (empty($proxy_ip)) {
// True IP without proxy
return $direct_ip;
} else {
$is_ip = ereg('^([0-9]{1,3}\.){3,3}[0-9]{1,3}', $direct_ip, $regs);
if ($is_ip && (count($regs) > 0)) {
// True IP behind a proxy
return $regs[0];
} else {
// Can't define IP: there is a proxy but we don't have
// information about the true IP
return FALSE;
}
} // end if... else...
} // end of the 'PMA_getIp()' function
/**
* Based on IP Pattern Matcher
* Originally by J.Adams <jna@retina.net>
* Found on <http://www.php.net/manual/en/function.ip2long.php>
* Modified by Robbat2 <robbat2@users.sourceforge.net>
*
* Matches:
* xxx.xxx.xxx.xxx (exact)
* xxx.xxx.xxx.[yyy-zzz] (range)
* xxx.xxx.xxx.xxx/nn (CIDR)
*
* Does not match:
* xxx.xxx.xxx.xx[yyy-zzz] (range, partial octets not supported)
*
* @param string string of IP range to match
* @param string string of IP to test against range
*
* @return boolean always true
*
* @access public
*/
function PMA_ipMaskTest($testRange, $ipToTest)
{
$result = TRUE;
if (ereg('([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/([0-9]+)', $testRange, $regs)) {
// performs a mask match
$ipl = ip2long($ipToTest);
$rangel = ip2long($regs[1] . '.' . $regs[2] . '.' . $regs[3] . '.' . $regs[4]);
$maskl = 0;
for ($i = 0; $i < 31; $i++) {
if ($i < $regs[5] - 1) {
$maskl = $maskl + pow(2, (30 - $i));
} // end if
} // end for
if (($maskl & $rangel) == ($maskl & $ipl)) {
return TRUE;
} else {
return FALSE;
}
} else {
// range based
$maskocts = split('\.', $testRange);
$ipocts = split('\.', $ipToTest);
// perform a range match
for ($i = 0; $i < 4; $i++) {
if (ereg('\[([0-9]+)\-([0-9]+)\]', $maskocts[$i], $regs)) {
if (($ipocts[$i] > $regs[2])
|| ($ipocts[$i] < $regs[1])) {
$result = FALSE;
} // end if
} else {
if ($maskocts[$i] <> $ipocts[$i]) {
$result = FALSE;
} // end if
} // end if/else
} //end for
} //end if/else
return $result;
} // end of the "PMA_IPMaskTest()" function
/**
* Runs through IP Allow/Deny rules the use of it below for more information
*
* @param string 'allow' | 'deny' type of rule to match
*
* @return bool Matched a rule ?
*
* @access public
*
* @see PMA_getIp()
*/
function PMA_allowDeny($type)
{
global $cfg;
// Grabs true IP of the user and returns if it can't be found
$remote_ip = PMA_getIp();
if (empty($remote_ip)) {
return FALSE;
}
// copy username
$username = $cfg['Server']['user'];
// copy rule database
$rules = $cfg['Server']['AllowDeny']['rules'];
// lookup table for some name shortcuts
$shortcuts = array(
'all' => '0.0.0.0/0',
'localhost' => '127.0.0.1/8'
);
reset($rules); // used instead of a foreach look for PHP3 support
while (list(, $rule) = each($rules)) {
// extract rule data
$rule_data = explode(' ', $rule);
// check for rule type
if ($rule_data[0] != $type) {
continue;
}
// check for username
if (($rule_data[1] != '%') //wildcarded first
&& ($rule_data[1] != $username)) {
continue;
}
// check if the config file has the full string with an extra
// 'from' in it and if it does, just discard it
if ($rule_data[2] == 'from') {
$rule_data[2] = $rule_data[3];
}
// Handle shortcuts with above array
// DON'T use "array_key_exists" as it's only PHP 4.1 and newer.
if (isset($shortcuts[$rule_data[2]])) {
$rule_data[2] = $shortcuts[$rule_data[2]];
}
// Add code for host lookups here
// Excluded for the moment
// Do the actual matching now
if (PMA_ipMaskTest($rule_data[2], $remote_ip)) {
return TRUE;
}
} // end while
return FALSE;
} // end of the "PMA_AllowDeny()" function
} // $__PMA_ALLOW_DENY_LIB__
?>