summaryrefslogtreecommitdiff
path: root/hugo/libraries/ip_allow_deny.lib.php
diff options
context:
space:
mode:
Diffstat (limited to 'hugo/libraries/ip_allow_deny.lib.php')
-rw-r--r--hugo/libraries/ip_allow_deny.lib.php327
1 files changed, 327 insertions, 0 deletions
diff --git a/hugo/libraries/ip_allow_deny.lib.php b/hugo/libraries/ip_allow_deny.lib.php
new file mode 100644
index 0000000..f253e37
--- /dev/null
+++ b/hugo/libraries/ip_allow_deny.lib.php
@@ -0,0 +1,327 @@
+<?php
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+/**
+ * This library is used with the server IP allow/deny host authentication
+ * feature
+ *
+ * @package PhpMyAdmin
+ */
+if (! defined('PHPMYADMIN')) {
+ exit;
+}
+
+/**
+ * Gets the "true" IP address of the current user
+ *
+ * @return string the ip of the user
+ *
+ * @access private
+ */
+function PMA_getIp()
+{
+ /* Get the address of user */
+ if (!empty($_SERVER['REMOTE_ADDR'])) {
+ $direct_ip = $_SERVER['REMOTE_ADDR'];
+ } else {
+ /* We do not know remote IP */
+ return false;
+ }
+
+ /* Do we trust this IP as a proxy? If yes we will use it's header. */
+ if (isset($GLOBALS['cfg']['TrustedProxies'][$direct_ip])) {
+ $trusted_header_value
+ = PMA_getenv($GLOBALS['cfg']['TrustedProxies'][$direct_ip]);
+ $matches = array();
+ // the $ checks that the header contains only one IP address,
+ // ?: makes sure the () don't capture
+ $is_ip = preg_match(
+ '|^(?:[0-9]{1,3}\.){3,3}[0-9]{1,3}$|',
+ $trusted_header_value, $matches
+ );
+ if ($is_ip && (count($matches) == 1)) {
+ // True IP behind a proxy
+ return $matches[0];
+ }
+ }
+
+ /* Return true IP */
+ return $direct_ip;
+} // end of the 'PMA_getIp()' function
+
+
+/**
+ * Matches for IPv4 or IPv6 addresses
+ *
+ * @param string $testRange string of IP range to match
+ * @param string $ipToTest string of IP to test against range
+ *
+ * @return boolean whether the IP mask matches
+ *
+ * @access public
+ */
+function PMA_ipMaskTest($testRange, $ipToTest)
+{
+ $result = true;
+
+ if (strpos($testRange, ':') > -1 || strpos($ipToTest, ':') > -1) {
+ // assume IPv6
+ $result = PMA_ipv6MaskTest($testRange, $ipToTest);
+ } else {
+ $result = PMA_ipv4MaskTest($testRange, $ipToTest);
+ }
+
+ return $result;
+} // end of the "PMA_ipMaskTest()" 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 for phpMyAdmin
+ *
+ * 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 $testRange string of IP range to match
+ * @param string $ipToTest string of IP to test against range
+ *
+ * @return boolean whether the IP mask matches
+ *
+ * @access public
+ */
+function PMA_ipv4MaskTest($testRange, $ipToTest)
+{
+ $result = true;
+ $match = preg_match(
+ '|([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/([0-9]+)|',
+ $testRange,
+ $regs
+ );
+ if ($match) {
+ // 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 + PMA_Util::pow(2, (30 - $i));
+ } // end if
+ } // end for
+
+ if (($maskl & $rangel) == ($maskl & $ipl)) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ // range based
+ $maskocts = explode('.', $testRange);
+ $ipocts = explode('.', $ipToTest);
+
+ // perform a range match
+ for ($i = 0; $i < 4; $i++) {
+ if (preg_match('|\[([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_ipv4MaskTest()" function
+
+
+/**
+ * IPv6 matcher
+ * CIDR section taken from http://stackoverflow.com/a/10086404
+ * Modified for phpMyAdmin
+ *
+ * Matches:
+ * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx (exact)
+ * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:[yyyy-zzzz] (range, only at end of IP - no subnets)
+ * xxxx:xxxx:xxxx:xxxx/nn (CIDR)
+ *
+ * Does not match:
+ * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xx[yyy-zzz] (range, partial octets not supported)
+ *
+ * @param string $test_range string of IP range to match
+ * @param string $ip_to_test string of IP to test against range
+ *
+ * @return boolean whether the IP mask matches
+ *
+ * @access public
+ */
+function PMA_ipv6MaskTest($test_range, $ip_to_test)
+{
+ $result = true;
+
+ // convert to lowercase for easier comparison
+ $test_range = strtolower($test_range);
+ $ip_to_test = strtolower($ip_to_test);
+
+ $is_cidr = strpos($test_range, '/') > -1;
+ $is_range = strpos($test_range, '[') > -1;
+ $is_single = ! $is_cidr && ! $is_range;
+
+ $ip_hex = bin2hex(inet_pton($ip_to_test));
+
+ if ($is_single) {
+ $range_hex = bin2hex(inet_pton($test_range));
+ $result = $ip_hex === $range_hex;
+ } elseif ($is_range) {
+ // what range do we operate on?
+ $range_match = array();
+ if (preg_match('/\[([0-9a-f]+)\-([0-9a-f]+)\]/', $test_range, $range_match)) {
+ $range_start = $range_match[1];
+ $range_end = $range_match[2];
+
+ // get the first and last allowed IPs
+ $first_ip = str_replace($range_match[0], $range_start, $test_range);
+ $first_hex = bin2hex(inet_pton($first_ip));
+ $last_ip = str_replace($range_match[0], $range_end, $test_range);
+ $last_hex = bin2hex(inet_pton($last_ip));
+
+ // check if the IP to test is within the range
+ $result = ($ip_hex >= $first_hex && $ip_hex <= $last_hex);
+ }
+ } elseif ($is_cidr) {
+ // Split in address and prefix length
+ list($first_ip, $subnet) = explode('/', $test_range);
+
+ // Parse the address into a binary string
+ $first_bin = inet_pton($first_ip);
+ $first_hex = bin2hex($first_bin);
+
+ // Overwriting first address string to make sure notation is optimal
+ $first_ip = inet_ntop($first_bin);
+
+ $flexbits = 128 - $subnet;
+
+ // Build the hexadecimal string of the last address
+ $last_hex = $first_hex;
+
+ $pos = 31;
+ while ($flexbits > 0) {
+ // Get the character at this position
+ $orig = substr($last_hex, $pos, 1);
+
+ // Convert it to an integer
+ $origval = hexdec($orig);
+
+ // OR it with (2^flexbits)-1, with flexbits limited to 4 at a time
+ $newval = $origval | (pow(2, min(4, $flexbits)) - 1);
+
+ // Convert it back to a hexadecimal character
+ $new = dechex($newval);
+
+ // And put that character back in the string
+ $last_hex = substr_replace($last_hex, $new, $pos, 1);
+
+ // We processed one nibble, move to previous position
+ $flexbits -= 4;
+ $pos -= 1;
+ }
+
+ // check if the IP to test is within the range
+ $result = ($ip_hex >= $first_hex && $ip_hex <= $last_hex);
+ }
+
+ return $result;
+} // end of the "PMA_ipv6MaskTest()" function
+
+
+/**
+ * Runs through IP Allow/Deny rules the use of it below for more information
+ *
+ * @param string $type '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'
+ );
+
+ // Provide some useful shortcuts if server gives us address:
+ if (PMA_getenv('SERVER_ADDR')) {
+ $shortcuts['localnetA'] = PMA_getenv('SERVER_ADDR') . '/8';
+ $shortcuts['localnetB'] = PMA_getenv('SERVER_ADDR') . '/16';
+ $shortcuts['localnetC'] = PMA_getenv('SERVER_ADDR') . '/24';
+ }
+
+ foreach ($rules as $rule) {
+ // 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
+ 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
+
+?>