From 9da7080d8d580093db303dd3943ad8a94f1fce65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Chapeaux?= Date: Sat, 18 May 2002 12:37:01 +0000 Subject: [PATCH] * exported the "IP-based Allow/Deny" code in a distinct library; * coding standards; * improved PHP3 compliance; * better ip checking. --- ChangeLog | 8 + libraries/common.lib.php3 | 211 ++++------------- libraries/ip_allow_deny.lib.php3 | 375 +++++++++++++++++++++++++++++++ 3 files changed, 422 insertions(+), 172 deletions(-) create mode 100644 libraries/ip_allow_deny.lib.php3 diff --git a/ChangeLog b/ChangeLog index 084998f2c..d7197e68e 100755 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,14 @@ phpMyAdmin - Changelog $Id$ $Source$ +2002-05-18 Loïc Chapeaux + * 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 * config.inc.php3, libraries/common.lib.php3: IP-based Allow/Deny code from feature #484158 diff --git a/libraries/common.lib.php3 b/libraries/common.lib.php3 index a21a1c89d..e2bb319e7 100644 --- a/libraries/common.lib.php3 +++ b/libraries/common.lib.php3 @@ -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 - * Found on - * Modified by Robbat2 - * - * 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'] != '') { diff --git a/libraries/ip_allow_deny.lib.php3 b/libraries/ip_allow_deny.lib.php3 new file mode 100644 index 000000000..92a2b3a74 --- /dev/null +++ b/libraries/ip_allow_deny.lib.php3 @@ -0,0 +1,375 @@ + + * + * @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 + * Found on + * Modified by Robbat2 + * + * 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__ +?> \ No newline at end of file