From 9f3823a6bc986e911b52b41338881ff35dccc37c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Thu, 30 Jun 2016 09:49:37 +0200 Subject: [PATCH 001/101] Sent CSP headers for phpinfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- phpinfo.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phpinfo.php b/phpinfo.php index 55ff9d27b4..6ac84c7ea4 100644 --- a/phpinfo.php +++ b/phpinfo.php @@ -10,7 +10,9 @@ * Gets core libraries and defines some variables */ require_once 'libraries/common.inc.php'; -PMA\libraries\Response::getInstance()->disable(); +$response = PMA\libraries\Response::getInstance(); +$response->disable(); +$response->getHeader()->sendHttpHeaders(); /** * Displays PHP information From 4183bab696c68ef8ee5cb2d58cb8fb2795b0e802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Thu, 30 Jun 2016 09:50:17 +0200 Subject: [PATCH 002/101] Send CSP headers on changelog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- changelog.php | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.php b/changelog.php index 95da01d4a5..b71e29e35b 100644 --- a/changelog.php +++ b/changelog.php @@ -13,6 +13,7 @@ require 'libraries/common.inc.php'; $response = PMA\libraries\Response::getInstance(); $response->disable(); +$response->getHeader()->sendHttpHeaders(); $filename = CHANGELOG_FILE; From 5491d67fb545ef9878b59e05a10f814f7a92a7ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Thu, 30 Jun 2016 10:04:46 +0200 Subject: [PATCH 003/101] Avoid possible path traversal using MySQL username MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/Util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/Util.php b/libraries/Util.php index 8606f4de91..bcef4f8819 100644 --- a/libraries/Util.php +++ b/libraries/Util.php @@ -2692,7 +2692,7 @@ class Util $dir .= '/'; } - return str_replace('%u', $GLOBALS['cfg']['Server']['user'], $dir); + return str_replace('%u', PMA_securePath($GLOBALS['cfg']['Server']['user']), $dir); } /** From a82835cf09c20b381b9c8a7bfe337a11ab904ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Thu, 30 Jun 2016 10:22:39 +0200 Subject: [PATCH 004/101] Generate valid PHP code even when table/database name contains PHP markup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/plugins/export/ExportPhparray.php | 25 ++++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/libraries/plugins/export/ExportPhparray.php b/libraries/plugins/export/ExportPhparray.php index 4a48f10e18..4fd224d310 100644 --- a/libraries/plugins/export/ExportPhparray.php +++ b/libraries/plugins/export/ExportPhparray.php @@ -65,6 +65,19 @@ class ExportPhparray extends ExportPlugin $this->properties = $exportPluginProperties; } + /** + * Removes end of comment from a string + * + * @param string $string String to replace + * + * @return string + */ + public function commentString($string) + { + return strtr($string, '*/', '-'); + } + + /** * Outputs export header * @@ -107,9 +120,9 @@ class ExportPhparray extends ExportPlugin $db_alias = $db; } PMA_exportOutputHandler( - '//' . $GLOBALS['crlf'] - . '// Database ' . PMA\libraries\Util::backquote($db_alias) - . $GLOBALS['crlf'] . '//' . $GLOBALS['crlf'] + '/**' . $GLOBALS['crlf'] + . ' * Database ' . $this->commentString(PMA\libraries\Util::backquote($db_alias)) + . $GLOBALS['crlf'] . ' */' . $GLOBALS['crlf'] ); return true; @@ -207,9 +220,9 @@ class ExportPhparray extends ExportPlugin $buffer = ''; $record_cnt = 0; // Output table name as comment - $buffer .= $crlf . '// ' - . PMA\libraries\Util::backquote($db_alias) . '.' - . PMA\libraries\Util::backquote($table_alias) . $crlf; + $buffer .= $crlf . '/* ' + . $this->commentString(PMA\libraries\Util::backquote($db_alias)) . '.' + . $this->commentString(PMA\libraries\Util::backquote($table_alias)) . ' */' . $crlf; $buffer .= '$' . $tablefixed . ' = array('; while ($record = $GLOBALS['dbi']->fetchRow($result)) { From 2b5915ce7b061df005373b3ebf5affe7345ef141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Thu, 30 Jun 2016 10:27:26 +0200 Subject: [PATCH 005/101] Use phpMyAdmin version in PHP export header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using fixed 0.2b really makes no sense. Signed-off-by: Michal Čihař --- libraries/plugins/export/ExportPhparray.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/plugins/export/ExportPhparray.php b/libraries/plugins/export/ExportPhparray.php index 4fd224d310..e959d6b67f 100644 --- a/libraries/plugins/export/ExportPhparray.php +++ b/libraries/plugins/export/ExportPhparray.php @@ -89,7 +89,7 @@ class ExportPhparray extends ExportPlugin ' Date: Thu, 30 Jun 2016 10:30:27 +0200 Subject: [PATCH 006/101] Fix PHP export tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- test/classes/plugin/export/ExportPhparrayTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/classes/plugin/export/ExportPhparrayTest.php b/test/classes/plugin/export/ExportPhparrayTest.php index cb5dee8f22..94d6c0bfd3 100644 --- a/test/classes/plugin/export/ExportPhparrayTest.php +++ b/test/classes/plugin/export/ExportPhparrayTest.php @@ -163,7 +163,7 @@ class ExportPhparrayTest extends PMATestCase */ public function testExportDBHeader() { - $GLOBALS['crlf'] = ' '; + $GLOBALS['crlf'] = "\n"; ob_start(); $this->assertTrue( @@ -172,7 +172,7 @@ class ExportPhparrayTest extends PMATestCase $result = ob_get_clean(); $this->assertContains( - '// Database `db` ', + "/**\n * Database `db`\n */", $result ); } @@ -253,7 +253,7 @@ class ExportPhparrayTest extends PMATestCase $result = ob_get_clean(); $this->assertEquals( - "\n" . '// `db`.`table`' . "\n" . + "\n" . '/* `db`.`table` */' . "\n" . '$table = array(' . "\n" . ' array(\'c1\' => 1,\'\' => \'a\')' . "\n" . ');' . "\n", From bd2080c40aa05b883109fbf9739ffb4c674af698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Thu, 30 Jun 2016 10:52:49 +0200 Subject: [PATCH 007/101] Adjust test to not use HTML escaping layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- test/classes/plugin/export/ExportXmlTest.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/classes/plugin/export/ExportXmlTest.php b/test/classes/plugin/export/ExportXmlTest.php index 887d201c50..e2034b5e73 100644 --- a/test/classes/plugin/export/ExportXmlTest.php +++ b/test/classes/plugin/export/ExportXmlTest.php @@ -529,6 +529,8 @@ class ExportXmlTest extends PMATestCase public function testExportData() { $GLOBALS['xml_export_contents'] = true; + $GLOBALS['asfile'] = true; + $GLOBALS['output_charset_conversion'] = false; $dbi = $this->getMockBuilder('PMA\libraries\DatabaseInterface') ->disableOriginalConstructor() @@ -587,33 +589,33 @@ class ExportXmlTest extends PMATestCase $result = ob_get_clean(); $this->assertContains( - "<!-- Table ta<ble -->", + "", $result ); $this->assertContains( - "<table name="ta&lt;ble">", + "", $result ); $this->assertContains( - "<column name="fName1">NULL</column>", + "NULL", $result ); $this->assertContains( - "<column name="fNa&quot;me2">&lt;a&gt;" . - "</column>", + "<a>" . + "", $result ); $this->assertContains( - "<column name="fName3">NULL</column>", + "NULL", $result ); $this->assertContains( - "</table>", + "
", $result ); } From 7de139b90ca6926d9ec06c2684ef8877a01b5ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Thu, 30 Jun 2016 10:54:05 +0200 Subject: [PATCH 008/101] Properly escape generated XML export MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many fields could contain XML markup, so we need to ensure the generated XML is valid. Signed-off-by: Michal Čihař --- libraries/plugins/export/ExportXml.php | 14 +++++++------- test/classes/plugin/export/ExportXmlTest.php | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/plugins/export/ExportXml.php b/libraries/plugins/export/ExportXml.php index 325e2e6e37..1ccffeee58 100644 --- a/libraries/plugins/export/ExportXml.php +++ b/libraries/plugins/export/ExportXml.php @@ -185,7 +185,7 @@ class ExportXml extends ExportPlugin if ($names) { foreach ($names as $name) { $head .= ' ' . $crlf; + . htmlspecialchars($name) . '">' . $crlf; // Do some formatting $sql = $GLOBALS['dbi']->getDefinition($db, $dbitype, $name); @@ -232,7 +232,7 @@ class ExportXml extends ExportPlugin . '- version ' . PMA_VERSION . $crlf . '- https://www.phpmyadmin.net' . $crlf . '-' . $crlf - . '- ' . __('Host:') . ' ' . $cfg['Server']['host']; + . '- ' . __('Host:') . ' ' . htmlspecialchars($cfg['Server']['host']); if (!empty($cfg['Server']['port'])) { $head .= ':' . $cfg['Server']['port']; } @@ -263,7 +263,7 @@ class ExportXml extends ExportPlugin $head .= ' -->' . $crlf; $head .= ' ' . $crlf; $head .= ' ' . $crlf; if (count($tables) == 0) { @@ -296,7 +296,7 @@ class ExportXml extends ExportPlugin continue; } - $head .= ' ' + $head .= ' ' . $crlf; $tbl = " " . htmlspecialchars($tbl); @@ -314,7 +314,7 @@ class ExportXml extends ExportPlugin foreach ($triggers as $trigger) { $code = $trigger['create']; $head .= ' ' . $crlf; + . htmlspecialchars($trigger['name']) . '">' . $crlf; // Do some formatting $code = mb_substr(rtrim($code), 0, -3); @@ -402,7 +402,7 @@ class ExportXml extends ExportPlugin ) { $head = ' ' . $crlf . ' ' . $crlf; @@ -491,7 +491,7 @@ class ExportXml extends ExportPlugin unset($i); $buffer = ' ' . $crlf; + . htmlspecialchars($table_alias) . ' -->' . $crlf; if (!PMA_exportOutputHandler($buffer)) { return false; } diff --git a/test/classes/plugin/export/ExportXmlTest.php b/test/classes/plugin/export/ExportXmlTest.php index e2034b5e73..e2dcefbf4b 100644 --- a/test/classes/plugin/export/ExportXmlTest.php +++ b/test/classes/plugin/export/ExportXmlTest.php @@ -589,7 +589,7 @@ class ExportXmlTest extends PMATestCase $result = ob_get_clean(); $this->assertContains( - "", + "", $result ); From a97be3a604cb9a56074b76905792479251e744a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Fri, 8 Jul 2016 17:15:09 +0200 Subject: [PATCH 009/101] Improve cookie encryption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - use MAC to validate content before decryption - create unique IV for every cookie Signed-off-by: Michal Čihař --- .../plugins/auth/AuthenticationCookie.php | 62 +++++++++++-------- .../plugin/auth/AuthenticationCookieTest.php | 5 +- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/libraries/plugins/auth/AuthenticationCookie.php b/libraries/plugins/auth/AuthenticationCookie.php index 8d753cd7a3..ce5f5b93d4 100644 --- a/libraries/plugins/auth/AuthenticationCookie.php +++ b/libraries/plugins/auth/AuthenticationCookie.php @@ -359,9 +359,7 @@ class AuthenticationCookie extends AuthenticationPlugin } // check cookies - if (empty($_COOKIE['pmaUser-' . $GLOBALS['server']]) - || empty($_COOKIE['pma_iv-' . $GLOBALS['server']]) - ) { + if (empty($_COOKIE['pmaUser-' . $GLOBALS['server']])) { return false; } @@ -485,8 +483,6 @@ class AuthenticationCookie extends AuthenticationPlugin { global $cfg; - $this->createIV(); - // Name and password cookies need to be refreshed each time // Duration = one month for username $this->storeUsernameCookie($cfg['Server']['user']); @@ -679,20 +675,28 @@ class AuthenticationCookie extends AuthenticationPlugin */ public function cookieEncrypt($data, $secret) { + $iv = $this->createIV(); if (self::useOpenSSL()) { - return openssl_encrypt( + $result = openssl_encrypt( $data, 'AES-128-CBC', $secret, 0, - $this->_cookie_iv + $iv ); } else { $cipher = new Crypt\AES(Crypt\Base::MODE_CBC); - $cipher->setIV($this->_cookie_iv); + $cipher->setIV($iv); $cipher->setKey($secret); - return base64_encode($cipher->encrypt($data)); + $result = base64_encode($cipher->encrypt($data)); } + return json_encode( + array( + 'iv' => base64_encode($iv), + 'mac' => sha1($result . $secret), + 'payload' => $result, + ) + ); } /** @@ -702,33 +706,35 @@ class AuthenticationCookie extends AuthenticationPlugin * @param string $encdata encrypted data * @param string $secret the secret * - * @return string original data + * @return string|bool original data, false on error */ public function cookieDecrypt($encdata, $secret) { - if (is_null($this->_cookie_iv)) { - $this->_cookie_iv = base64_decode( - $_COOKIE['pma_iv-' . $GLOBALS['server']], - true - ); + $data = json_decode($encdata, true); + + if (! is_array($data) || ! isset($data['mac']) || ! isset($data['iv']) || ! isset($data['payload'])) { + return false; } - if (mb_strlen($this->_cookie_iv, '8bit') < $this->getIVSize()) { - $this->createIV(); + + $newmac = sha1($data['payload'] . $secret); + + if (! hash_equals($data['mac'], $newmac)) { + return false; } if (self::useOpenSSL()) { return openssl_decrypt( - $encdata, + $data['payload'], 'AES-128-CBC', $secret, 0, - $this->_cookie_iv + base64_decode($data['iv']) ); } else { $cipher = new Crypt\AES(Crypt\Base::MODE_CBC); - $cipher->setIV($this->_cookie_iv); + $cipher->setIV(base64_decode($data['iv'])); $cipher->setKey($secret); - return $cipher->decrypt(base64_decode($encdata)); + return $cipher->decrypt(base64_decode($data['payload'])); } } @@ -756,24 +762,26 @@ class AuthenticationCookie extends AuthenticationPlugin */ public function createIV() { + /* Testsuite shortcut only to allow predictable IV */ + if (! is_null($this->_cookie_iv)) { + return $this->_cookie_iv; + } if (self::useOpenSSL()) { - $this->_cookie_iv = openssl_random_pseudo_bytes( + return openssl_random_pseudo_bytes( $this->getIVSize() ); } else { - $this->_cookie_iv = Crypt\Random::string( + return Crypt\Random::string( $this->getIVSize() ); } - $GLOBALS['PMA_Config']->setCookie( - 'pma_iv-' . $GLOBALS['server'], - base64_encode($this->_cookie_iv) - ); } /** * Sets encryption IV to use * + * This is for testing only! + * * @param string $vector The IV * * @return void diff --git a/test/classes/plugin/auth/AuthenticationCookieTest.php b/test/classes/plugin/auth/AuthenticationCookieTest.php index 2f979d99d9..d999336b75 100644 --- a/test/classes/plugin/auth/AuthenticationCookieTest.php +++ b/test/classes/plugin/auth/AuthenticationCookieTest.php @@ -1103,7 +1103,7 @@ class AuthenticationCookieTest extends PMATestCase $this->object->setIV('testiv09testiv09'); // works with the openssl extension active or inactive $this->assertEquals( - '+coP/up/ZBTBwbiEpCUVXQ==', + '{"iv":"dGVzdGl2MDl0ZXN0aXYwOQ==","mac":"a2749d5b5b8857adfb2dd0b28582a0c0388cb709","payload":"+coP\/up\/ZBTBwbiEpCUVXQ=="}', $this->object->cookieEncrypt('data123', 'sec321') ); } @@ -1115,12 +1115,11 @@ class AuthenticationCookieTest extends PMATestCase */ public function testCookieDecrypt() { - $this->object->setIV('testiv09testiv09'); // works with the openssl extension active or inactive $this->assertEquals( 'data123', $this->object->cookieDecrypt( - '+coP/up/ZBTBwbiEpCUVXQ==', + '{"iv":"dGVzdGl2MDl0ZXN0aXYwOQ==","mac":"a2749d5b5b8857adfb2dd0b28582a0c0388cb709","payload":"+coP\/up\/ZBTBwbiEpCUVXQ=="}', 'sec321' ) ); From c0b2d56ac0a94c371004f25a5ae3d0ec247516f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Sat, 9 Jul 2016 09:12:43 +0200 Subject: [PATCH 010/101] Use https for wiki links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- doc/other.rst | 2 +- js/tbl_structure.js | 2 +- libraries/import.lib.php | 4 ++-- libraries/plugins/import/README | 2 +- po/az.po | 2 +- po/bg.po | 8 ++++---- po/bn.po | 16 ++++++++-------- po/ca.po | 8 ++++---- po/cs.po | 16 ++++++++-------- po/da.po | 16 ++++++++-------- po/de.po | 8 ++++---- po/el.po | 8 ++++---- po/en_GB.po | 16 ++++++++-------- po/es.po | 12 ++++++------ po/et.po | 10 +++++----- po/fi.po | 18 +++++++++--------- po/fr.po | 8 ++++---- po/gl.po | 18 +++++++++--------- po/hi.po | 2 +- po/hu.po | 18 +++++++++--------- po/ia.po | 18 +++++++++--------- po/id.po | 12 ++++++------ po/it.po | 8 ++++---- po/ja.po | 16 ++++++++-------- po/ko.po | 10 +++++----- po/lt.po | 18 +++++++++--------- po/nb.po | 16 ++++++++-------- po/nl.po | 8 ++++---- po/pl.po | 16 ++++++++-------- po/pt.po | 18 +++++++++--------- po/pt_BR.po | 18 +++++++++--------- po/ro.po | 18 +++++++++--------- po/ru.po | 18 +++++++++--------- po/si.po | 16 ++++++++-------- po/sk.po | 18 +++++++++--------- po/sl.po | 8 ++++---- po/sq.po | 18 +++++++++--------- po/sv.po | 18 +++++++++--------- po/th.po | 4 ++-- po/tr.po | 8 ++++---- po/uk.po | 14 +++++++------- po/ur.po | 12 ++++++------ po/uz.po | 18 +++++++++--------- po/uz@latin.po | 18 +++++++++--------- po/vi.po | 16 ++++++++-------- po/zh_CN.po | 18 +++++++++--------- po/zh_TW.po | 8 ++++---- scripts/create-release.sh | 2 +- test/libraries/core/PMA_getLinks_test.php | 4 ++-- 49 files changed, 294 insertions(+), 294 deletions(-) diff --git a/doc/other.rst b/doc/other.rst index bb6de86dc8..61e83accbb 100644 --- a/doc/other.rst +++ b/doc/other.rst @@ -15,4 +15,4 @@ Tutorials Third party tutorials and articles are listed on our `wiki page`_. -.. _wiki page: http://wiki.phpmyadmin.net/pma/Articles +.. _wiki page: https://wiki.phpmyadmin.net/pma/Articles diff --git a/js/tbl_structure.js b/js/tbl_structure.js index 3dbfa32809..6dd5ce0ab6 100644 --- a/js/tbl_structure.js +++ b/js/tbl_structure.js @@ -173,7 +173,7 @@ AJAX.registerOnload('tbl_structure.js', function () { // If Collation is changed, Warn and Confirm if (checkIfConfirmRequired($form, field_cnt)){ var question = sprintf( - PMA_messages.strChangeColumnCollation, 'http://wiki.phpmyadmin.net/pma/Garbled_data' + PMA_messages.strChangeColumnCollation, 'https://wiki.phpmyadmin.net/pma/Garbled_data' ); $form.PMA_confirm(question, $form.attr('action'), function (url) { submitForm(); diff --git a/libraries/import.lib.php b/libraries/import.lib.php index f2d4515c5b..65f10071ba 100644 --- a/libraries/import.lib.php +++ b/libraries/import.lib.php @@ -870,7 +870,7 @@ function PMA_detectType($last_cumulative_type, $cell) * @return array array(array $types, array $sizes) * @access public * - * @link http://wiki.phpmyadmin.net/pma/Import + * @link https://wiki.phpmyadmin.net/pma/Import * * @todo Handle the error case more elegantly */ @@ -977,7 +977,7 @@ $import_notice = null; * @return void * @access public * - * @link http://wiki.phpmyadmin.net/pma/Import + * @link https://wiki.phpmyadmin.net/pma/Import */ function PMA_buildSQL($db_name, &$tables, &$analyses = null, &$additional_sql = null, $options = null, &$sql_data diff --git a/libraries/plugins/import/README b/libraries/plugins/import/README index 9ec4df7d50..a7e60dd132 100644 --- a/libraries/plugins/import/README +++ b/libraries/plugins/import/README @@ -1,6 +1,6 @@ This directory holds import plugins for phpMyAdmin. Any new plugin should basically follow the structure presented here. The messages must use our -gettext mechanism, see http://wiki.phpmyadmin.net/pma/Gettext_for_developers. +gettext mechanism, see https://wiki.phpmyadmin.net/pma/Gettext_for_developers. Date: Sat, 9 Jul 2016 09:14:26 +0200 Subject: [PATCH 011/101] Use https for wiki links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- doc/faq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/faq.rst b/doc/faq.rst index 9a9c44eb50..fc560c37ea 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -1831,7 +1831,7 @@ other. Not every table can be put to the chart. Only tables with one, two or three columns can be visualised as a chart. Moreover the table must be in a special format for chart script to understand it. Currently -supported formats can be found in the `wiki `_. +supported formats can be found in the `wiki `_. .. _faq6_30: From 1ed4007689ebbb6b6a08a242025382d0f8d347b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Sun, 10 Jul 2016 18:01:45 +0200 Subject: [PATCH 012/101] Properly escape MySQL status variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/replication_gui.lib.php | 8 ++++---- libraries/server_status_variables.lib.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/replication_gui.lib.php b/libraries/replication_gui.lib.php index d700bf4cb3..d0d5dd25b9 100644 --- a/libraries/replication_gui.lib.php +++ b/libraries/replication_gui.lib.php @@ -548,7 +548,7 @@ function PMA_getHtmlForReplicationStatusTable($type, $hidden = false, $title = t foreach (${"{$type}_variables"} as $variable) { $html .= ' '; $html .= ' '; - $html .= $variable; + $html .= htmlspecialchars($variable); $html .= ' '; $html .= ' '; @@ -571,13 +571,13 @@ function PMA_getHtmlForReplicationStatusTable($type, $hidden = false, $title = t 'Replicate_Do_Table', 'Replicate_Ignore_Table', 'Replicate_Wild_Do_Table', 'Replicate_Wild_Ignore_Table'); if (in_array($variable, $variables_wrap)) { - $html .= str_replace( + $html .= htmlspecialchars(str_replace( ',', ', ', ${"server_{$type}_replication"}[0][$variable] - ); + )); } else { - $html .= ${"server_{$type}_replication"}[0][$variable]; + $html .= htmlspecialchars(${"server_{$type}_replication"}[0][$variable]); } $html .= ''; diff --git a/libraries/server_status_variables.lib.php b/libraries/server_status_variables.lib.php index 98ab500f04..53b7ad4b95 100644 --- a/libraries/server_status_variables.lib.php +++ b/libraries/server_status_variables.lib.php @@ -284,7 +284,7 @@ function PMA_getHtmlForRenderVariables($ServerStatusData, $alerts, $strShowStatu $retval .= ''; } } - $retval .= $value; + $retval .= htmlspecialchars($value); if (isset($alerts[$name])) { $retval .= ''; } From c4a595357f8393915f8a2258f8997b5d1ba6f1f0 Mon Sep 17 00:00:00 2001 From: Isaac Bennetch Date: Sun, 10 Jul 2016 22:35:38 -0400 Subject: [PATCH 013/101] Add Secure and HttpOnly flags for session cookie setup in examples Signed-off-by: Isaac Bennetch --- examples/openid.php | 2 +- examples/signon.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/openid.php b/examples/openid.php index 8ef34e9ee3..67585c2e53 100644 --- a/examples/openid.php +++ b/examples/openid.php @@ -74,7 +74,7 @@ function Die_error($e) /* Need to have cookie visible from parent directory */ -session_set_cookie_params(0, '/', '', false); +session_set_cookie_params(0, '/', '', true, true); /* Create signon session */ $session_name = 'SignonSession'; session_name($session_name); diff --git a/examples/signon.php b/examples/signon.php index 4fc0f25c9a..4463c38707 100644 --- a/examples/signon.php +++ b/examples/signon.php @@ -12,7 +12,7 @@ */ /* Need to have cookie visible from parent directory */ -session_set_cookie_params(0, '/', '', false); +session_set_cookie_params(0, '/', '', true, true); /* Create signon session */ $session_name = 'SignonSession'; session_name($session_name); From 6aacd7dcfef8a04898393009dea11ddd07a3891d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Mon, 11 Jul 2016 08:07:19 +0200 Subject: [PATCH 014/101] Make proxy IP parsing aware of multiple proxies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/ip_allow_deny.lib.php | 19 ++++--- test/libraries/PMA_ip_allow_deny_test.php | 62 ++++++++++++++++------- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/libraries/ip_allow_deny.lib.php b/libraries/ip_allow_deny.lib.php index a9d434f74c..59b335a607 100644 --- a/libraries/ip_allow_deny.lib.php +++ b/libraries/ip_allow_deny.lib.php @@ -30,14 +30,21 @@ function PMA_getIp() return $direct_ip; } - $trusted_header_value - = PMA_getenv($GLOBALS['cfg']['TrustedProxies'][$direct_ip]); - $matches = array(); + /** + * Parse header in form: + * X-Forwarded-For: client, proxy1, proxy2 + */ + // Get header content + $value = PMA_getenv($GLOBALS['cfg']['TrustedProxies'][$direct_ip]); + // Grab first element what is client adddress + $value = explode(',', $value)[0]; + // Extract IP address // the $ checks that the header contains only one IP address, // ?: makes sure the () don't capture + $matches = array(); $is_ip = preg_match( '|^(?:[0-9]{1,3}\.){3,3}[0-9]{1,3}$|', - $trusted_header_value, $matches + $value, $matches ); if ($is_ip && (count($matches) == 1)) { @@ -45,8 +52,8 @@ function PMA_getIp() return $matches[0]; } - /* Return true IP */ - return $direct_ip; + // We could not parse header + return false; } // end of the 'PMA_getIp()' function diff --git a/test/libraries/PMA_ip_allow_deny_test.php b/test/libraries/PMA_ip_allow_deny_test.php index fdc384487f..f2d0a7c0a9 100644 --- a/test/libraries/PMA_ip_allow_deny_test.php +++ b/test/libraries/PMA_ip_allow_deny_test.php @@ -51,32 +51,58 @@ class PMA_Ip_Allow_Deny_Test extends PHPUnit_Framework_TestCase * Test for PMA_getIp * * @return void + * + * @dataProvider proxyIPs */ - public function testGetIp() + public function testGetIp($remote, $header, $expected, $proxyip = null) { - //$_SERVER['REMOTE_ADDR'] is empty + unset($_SERVER['REMOTE_ADDR']); + unset($_SERVER['TEST_FORWARDED_HEADER']); + $GLOBALS['cfg']['TrustedProxies'] = array(); + + if (!is_null($remote)) { + $_SERVER['REMOTE_ADDR'] = $remote; + } + + if (!is_null($header)) { + if (is_null($proxyip)) { + $proxyip = $remote; + } + $GLOBALS['cfg']['TrustedProxies'][$proxyip] = 'TEST_FORWARDED_HEADER'; + $_SERVER['TEST_FORWARDED_HEADER'] = $header; + } + $this->assertEquals( - false, + $expected, PMA_getIp() ); - $_SERVER['REMOTE_ADDR'] = "101.0.0.25"; - $this->assertEquals( - "101.0.0.25", - PMA_getIp() - ); + unset($_SERVER['REMOTE_ADDR']); + unset($_SERVER['TEST_FORWARDED_HEADER']); + $GLOBALS['cfg']['TrustedProxies'] = array(); + } - //proxy - $var_name = "direct_ip"; - $direct_ip = $_SERVER['REMOTE_ADDR']; - $GLOBALS['cfg']['TrustedProxies'][$direct_ip] = $var_name; - $_SERVER[$var_name] = "192.168.0.1"; - $this->assertEquals( - "192.168.0.1", - PMA_getIp() + /** + * Data provider for PMA_getIp tests + * + * @return array + */ + public function proxyIPs() + { + return array( + // Nothing set + array(null, null, false), + // Remote IP set + array('101.0.0.25', null, '101.0.0.25'), + // Proxy + array('101.0.0.25', '192.168.10.10', '192.168.10.10'), + // Several proxies + array('101.0.0.25', '192.168.10.1, 192.168.100.100', '192.168.10.1'), + // Invalid proxy + array('101.0.0.25', 'invalid', false), + // Direct IP with proxy enabled + array('101.0.0.25', '192.168.10.10', '101.0.0.25', '10.10.10.10'), ); - unset($_SERVER[$var_name]); - unset($GLOBALS['cfg']['TrustedProxies'][$direct_ip]); } /** From 08864ebc8c66f2e1971342472b7527985bc52794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Mon, 11 Jul 2016 08:36:04 +0200 Subject: [PATCH 015/101] Remove not needed include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- test/libraries/PMA_ip_allow_deny_test.php | 1 - 1 file changed, 1 deletion(-) diff --git a/test/libraries/PMA_ip_allow_deny_test.php b/test/libraries/PMA_ip_allow_deny_test.php index f2d0a7c0a9..9cc07ac0ef 100644 --- a/test/libraries/PMA_ip_allow_deny_test.php +++ b/test/libraries/PMA_ip_allow_deny_test.php @@ -44,7 +44,6 @@ class PMA_Ip_Allow_Deny_Test extends PHPUnit_Framework_TestCase $GLOBALS['cfg']['Server']['AllowDeny']['rules'][] = "deny % 255.255.0.0/8"; $GLOBALS['cfg']['Server']['AllowDeny']['rules'][] = "deny % from 255.255.0.0/8"; - include_once 'libraries/ip_allow_deny.lib.php'; } /** From 23c011df36c6cc9c977beba3faf3b3f665159319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Mon, 11 Jul 2016 08:36:55 +0200 Subject: [PATCH 016/101] Move PMA_getIp to core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/core.lib.php | 50 +++++++++++++++++++++++++++++++++ libraries/ip_allow_deny.lib.php | 50 --------------------------------- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/libraries/core.lib.php b/libraries/core.lib.php index 2cd93f076b..dc5d35ee12 100644 --- a/libraries/core.lib.php +++ b/libraries/core.lib.php @@ -963,6 +963,56 @@ function PMA_checkExtensions() } } +/** + * 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'])) { + /* We do not know remote IP */ + return false; + } + + $direct_ip = $_SERVER['REMOTE_ADDR']; + + /* Do we trust this IP as a proxy? If yes we will use it's header. */ + if (!isset($GLOBALS['cfg']['TrustedProxies'][$direct_ip])) { + /* Return true IP */ + return $direct_ip; + } + + /** + * Parse header in form: + * X-Forwarded-For: client, proxy1, proxy2 + */ + // Get header content + $value = PMA_getenv($GLOBALS['cfg']['TrustedProxies'][$direct_ip]); + // Grab first element what is client adddress + $value = explode(',', $value)[0]; + // Extract IP address + // the $ checks that the header contains only one IP address, + // ?: makes sure the () don't capture + $matches = array(); + $is_ip = preg_match( + '|^(?:[0-9]{1,3}\.){3,3}[0-9]{1,3}$|', + $value, $matches + ); + + if ($is_ip && (count($matches) == 1)) { + // True IP behind a proxy + return $matches[0]; + } + + // We could not parse header + return false; +} // end of the 'PMA_getIp()' function + + /* Compatibility with PHP < 5.6 */ if(! function_exists('hash_equals')) { diff --git a/libraries/ip_allow_deny.lib.php b/libraries/ip_allow_deny.lib.php index 77c23bd0b8..078e290dba 100644 --- a/libraries/ip_allow_deny.lib.php +++ b/libraries/ip_allow_deny.lib.php @@ -7,56 +7,6 @@ * @package PhpMyAdmin */ -/** - * 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'])) { - /* We do not know remote IP */ - return false; - } - - $direct_ip = $_SERVER['REMOTE_ADDR']; - - /* Do we trust this IP as a proxy? If yes we will use it's header. */ - if (!isset($GLOBALS['cfg']['TrustedProxies'][$direct_ip])) { - /* Return true IP */ - return $direct_ip; - } - - /** - * Parse header in form: - * X-Forwarded-For: client, proxy1, proxy2 - */ - // Get header content - $value = PMA_getenv($GLOBALS['cfg']['TrustedProxies'][$direct_ip]); - // Grab first element what is client adddress - $value = explode(',', $value)[0]; - // Extract IP address - // the $ checks that the header contains only one IP address, - // ?: makes sure the () don't capture - $matches = array(); - $is_ip = preg_match( - '|^(?:[0-9]{1,3}\.){3,3}[0-9]{1,3}$|', - $value, $matches - ); - - if ($is_ip && (count($matches) == 1)) { - // True IP behind a proxy - return $matches[0]; - } - - // We could not parse header - return false; -} // end of the 'PMA_getIp()' function - - /** * Matches for IPv4 or IPv6 addresses * From 2b59fa3bf9692f59eff802c6e761bdd22f5db86f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Mon, 11 Jul 2016 08:37:43 +0200 Subject: [PATCH 017/101] Use PMA_getIp instead of REMOTE_ADDR to get user address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/Logging.php | 2 +- libraries/plugins/auth/AuthenticationCookie.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/Logging.php b/libraries/Logging.php index b12c376b41..d8d018028e 100644 --- a/libraries/Logging.php +++ b/libraries/Logging.php @@ -35,7 +35,7 @@ class Logging @syslog( LOG_WARNING, 'user denied: ' . $user . ' (' . $status . ') from ' . - $_SERVER['REMOTE_ADDR'] + PMA_getIp() ); } } diff --git a/libraries/plugins/auth/AuthenticationCookie.php b/libraries/plugins/auth/AuthenticationCookie.php index 558fdd8519..6a394e1d1c 100644 --- a/libraries/plugins/auth/AuthenticationCookie.php +++ b/libraries/plugins/auth/AuthenticationCookie.php @@ -286,7 +286,7 @@ class AuthenticationCookie extends AuthenticationPlugin // verify captcha status. $resp = $reCaptcha->verify( $_POST["g-recaptcha-response"], - $_SERVER["REMOTE_ADDR"] + PMA_getIp() ); // Check if the captcha entered is valid, if not stop the login. From fc6ef261eb4469f764d1e305a4ac617d26ca1864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Mon, 11 Jul 2016 09:02:58 +0200 Subject: [PATCH 018/101] Remove Swekey support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is buggy and their servers are no longer working. Signed-off-by: Michal Čihař --- .scrutinizer.yml | 2 +- build.xml | 6 +- config.sample.inc.php | 2 - doc/config.rst | 9 - doc/setup.rst | 34 -- examples/swekey.sample.conf | 44 -- libraries/config.default.php | 8 - libraries/config/messages.inc.php | 6 - libraries/config/setup.forms.php | 3 - .../plugins/auth/AuthenticationCookie.php | 15 - .../auth/swekey/authentication.inc.php | 176 ------ libraries/plugins/auth/swekey/musbe-ca.crt | 25 - .../plugins/auth/swekey/swekey.auth.lib.php | 315 ---------- libraries/plugins/auth/swekey/swekey.php | 536 ------------------ phpunit.xml.dist | 1 - .../plugin/auth/AuthenticationCookieTest.php | 25 - 16 files changed, 3 insertions(+), 1204 deletions(-) delete mode 100644 examples/swekey.sample.conf delete mode 100644 libraries/plugins/auth/swekey/authentication.inc.php delete mode 100644 libraries/plugins/auth/swekey/musbe-ca.crt delete mode 100644 libraries/plugins/auth/swekey/swekey.auth.lib.php delete mode 100644 libraries/plugins/auth/swekey/swekey.php diff --git a/.scrutinizer.yml b/.scrutinizer.yml index dd98975248..9a84f5469a 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -3,7 +3,7 @@ imports: - javascript - php filter: - excluded_paths: [libraries/php-gettext/*, libraries/tcpdf/*, libraries/bfShapeFiles/*, libraries/phpseclib/*, libraries/plugins/auth/recaptchalib.php, libraries/plugins/auth/swekey/swekey.php, libraries/sql-formatter/*, js/jquery/*, js/jqplot/*, js/openlayers/*, js/codemirror/*, js/canvg/*, js/tracekit/*, js/OpenStreetMap.js, js/sprintf.js, test/libraries/php-gettext/*, test/libraries/sql-formatter/*] + excluded_paths: [libraries/php-gettext/*, libraries/tcpdf/*, libraries/bfShapeFiles/*, libraries/phpseclib/*, libraries/plugins/auth/recaptchalib.php, libraries/sql-formatter/*, js/jquery/*, js/jqplot/*, js/openlayers/*, js/codemirror/*, js/canvg/*, js/tracekit/*, js/OpenStreetMap.js, js/sprintf.js, test/libraries/php-gettext/*, test/libraries/sql-formatter/*] tools: php_code_sniffer: config: diff --git a/build.xml b/build.xml index 445084cc57..53f883123c 100644 --- a/build.xml +++ b/build.xml @@ -55,7 +55,7 @@ @@ -71,7 +71,6 @@ --exclude libraries/bfShapeFiles --exclude libraries/phpseclib --exclude libraries/plugins/auth/recaptcha/recaptchalib.php - --exclude libraries/plugins/auth/swekey/swekey.php --exclude libraries/sql-parser ${source}" /> @@ -88,7 +87,6 @@ --exclude libraries/bfShapeFiles --exclude libraries/phpseclib --exclude libraries/plugins/auth/recaptcha/recaptchalib.php - --exclude libraries/plugins/auth/swekey/swekey.php --exclude libraries/sql-parser ${source}" /> @@ -103,7 +101,7 @@ `_ -since this link provides funding for phpMyAdmin. - -A self documented sample file is provided in the -file :file:`examples/swekey.sample.conf`: - -.. literalinclude:: ../examples/swekey.sample.conf - :language: sh - -.. seealso:: :config:option:`$cfg['Servers'][$i]['auth_swekey_config']` - Securing your phpMyAdmin installation +++++++++++++++++++++++++++++++++++++ diff --git a/examples/swekey.sample.conf b/examples/swekey.sample.conf deleted file mode 100644 index 49392bd94c..0000000000 --- a/examples/swekey.sample.conf +++ /dev/null @@ -1,44 +0,0 @@ -# This is a typical file used to enable Swekey hardware authentication. -# -# To activate the Swekey authentication add the following line to your config.inc.php file. -# $cfg['Servers'][$i]['auth_swekey_config'] = '/etc/swekey-pma.conf'; -# Then rename this file "swekey-pma.conf" and copy it to the /etc directory. -# Add all the Swekey ids you want to grant access to in the file. -# After each Swekey id put the corresponding user name. -# -# If you don't know the id of a Swekey just visit http://www.swekey.com?sel=support -# while your Swekey is connected. -# -# If you need to purchase a Swekey please visit https://www.phpmyadmin.net/auth_key/ -# since this link provides funding to PhpMyAdmin. -# - -0000000000000000000000000000763A:root -000000000000000000000000000089E4:steve -0000000000000000000000000000231E:scott - -# -# It is recommended to include the following lines to contact the -# authentication servers in SSL mode. -# - -SERVER_CHECK=https://auth-check-ssl.musbe.net -SERVER_RNDTOKEN=https://auth-rnd-gen-ssl.musbe.net -SERVER_STATUS=https://auth-status-ssl.musbe.net - -# -# The path of the root certificate file used to ensure a secure -# communication with the authentication servers in SSL mode. -# If not specified, will use musbe-ca.crt found in your -# phpMyAdmin/libraries/auth/swekey. -# - -#CA_FILE=/var/http-root/phpmyadmin/libraries/auth/swekey/musbe-ca.crt - -# -# If your server receives many login requests, you can enable the random -# token caching to accelerate the authentication process. -# Token caching is enabled by default. -# - -#ENABLE_TOKEN_CACHE=0 diff --git a/libraries/config.default.php b/libraries/config.default.php index 022623c5f8..0288fae742 100644 --- a/libraries/config.default.php +++ b/libraries/config.default.php @@ -236,14 +236,6 @@ $cfg['Servers'][$i]['auth_type'] = 'cookie'; */ $cfg['Servers'][$i]['auth_http_realm'] = ''; -/** - * File containing Swekey ids and login names (see /contrib); - * leave empty to deactivate Swekey hardware authentication - * - * @global string $cfg['Servers'][$i]['auth_swekey_config'] - */ -$cfg['Servers'][$i]['auth_swekey_config'] = ''; - /** * MySQL user * diff --git a/libraries/config/messages.inc.php b/libraries/config/messages.inc.php index d20822e3a7..57ec672898 100644 --- a/libraries/config/messages.inc.php +++ b/libraries/config/messages.inc.php @@ -632,12 +632,6 @@ $strConfigServers_SessionTimeZone_desc = __( $strConfigServers_auth_http_realm_desc = __('HTTP Basic Auth Realm name to display when doing HTTP Auth.'); $strConfigServers_auth_http_realm_name = __('HTTP Realm'); -$strConfigServers_auth_swekey_config_desc = __( - 'The path for the config file for SweKey hardware ' - . 'authentication (not located in your document root; suggested: ' - . '/etc/swekey.conf).' -); -$strConfigServers_auth_swekey_config_name = __('SweKey config file'); $strConfigServers_auth_type_desc = __('Authentication method to use.'); $strConfigServers_auth_type_name = __('Authentication type'); $strConfigServers_bookmarktable_desc = __( diff --git a/libraries/config/setup.forms.php b/libraries/config/setup.forms.php index 275181974a..cfffe9d5d1 100644 --- a/libraries/config/setup.forms.php +++ b/libraries/config/setup.forms.php @@ -41,9 +41,6 @@ $forms['Servers']['Server_auth'] = array('Servers' => array(1 => array( 'user', 'password', ':group:end', - ':group:' . __('Cookie authentication'), - 'auth_swekey_config' => './swekey.conf', - ':group:end', ':group:' . __('HTTP authentication'), 'auth_http_realm', ':group:end', diff --git a/libraries/plugins/auth/AuthenticationCookie.php b/libraries/plugins/auth/AuthenticationCookie.php index ce5f5b93d4..eedcb0b9f4 100644 --- a/libraries/plugins/auth/AuthenticationCookie.php +++ b/libraries/plugins/auth/AuthenticationCookie.php @@ -27,11 +27,6 @@ if (! empty($_REQUEST['target'])) { $GLOBALS['target'] = basename(PMA_getenv('SCRIPT_NAME')); } -/** - * Swekey authentication functions. - */ -require './libraries/plugins/auth/swekey/swekey.auth.lib.php'; - /** * Handles the cookie authentication method * @@ -229,10 +224,6 @@ class AuthenticationCookie extends AuthenticationPlugin echo ' '; - // BEGIN Swekey Integration - Swekey_login('input_username', 'input_go'); - // END Swekey Integration - if ($GLOBALS['error_handler']->hasDisplayErrors()) { echo '
'; $GLOBALS['error_handler']->dispErrors(); @@ -279,12 +270,6 @@ class AuthenticationCookie extends AuthenticationPlugin $GLOBALS['PHP_AUTH_USER'] = $GLOBALS['PHP_AUTH_PW'] = ''; $GLOBALS['from_cookie'] = false; - // BEGIN Swekey Integration - if (! Swekey_Auth_check()) { - return false; - } - // END Swekey Integration - if (! empty($_REQUEST['pma_username'])) { // Verify Captcha if it is required. diff --git a/libraries/plugins/auth/swekey/authentication.inc.php b/libraries/plugins/auth/swekey/authentication.inc.php deleted file mode 100644 index 1d42e2c3e0..0000000000 --- a/libraries/plugins/auth/swekey/authentication.inc.php +++ /dev/null @@ -1,176 +0,0 @@ - - - diff --git a/libraries/plugins/auth/swekey/musbe-ca.crt b/libraries/plugins/auth/swekey/musbe-ca.crt deleted file mode 100644 index 2a31ad18f9..0000000000 --- a/libraries/plugins/auth/swekey/musbe-ca.crt +++ /dev/null @@ -1,25 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIJAMjw7QcLWCd6MA0GCSqGSIb3DQEBBQUAMGsxCzAJBgNV -BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQKEwtNdXNiZSwgSW5j -LjESMBAGA1UEAxMJbXVzYmUuY29tMR0wGwYJKoZIhvcNAQkBFg5pbmZvQG11c2Jl -LmNvbTAeFw0wODA5MDQxNDE2MTNaFw0zNzEyMjExNDE2MTNaMGsxCzAJBgNVBAYT -AlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQKEwtNdXNiZSwgSW5jLjES -MBAGA1UEAxMJbXVzYmUuY29tMR0wGwYJKoZIhvcNAQkBFg5pbmZvQG11c2JlLmNv -bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOBhOljxVzQfK4gted2I -d3BemcjW4abAUOzn3KYWXpPO5xIfVeXNDGkDbyH+X+7fo94sX25/ewuKNFDSOcvo -tXHq7uQenTHB35r+a+LY81KceUHgW90a3XsqPAkwAjyYcgo3zmM2DtLvw+5Yod8T -wAHk9m3qavnQ1uk99jBTwL7RZ9jIZHh9pFCL93uJc2obtd8O96Iycbn2q0w/AWbb -+eUVWIHzvLtfPvROeL3lJzr/Uz5LjKapxJ3qyqASflfHpnj9pU8l6g2TQ6Hg5KT5 -tLFkRe7uGhOfRtOQ/+NjaWrEuNCFnpyN4Q5Fv+5qA1Ip1IpH0200sWbAf/k2u0Qp -Sx0CAwEAAaOB0DCBzTAdBgNVHQ4EFgQUczJrQ7hCvtsnzcqiDIZ/GSn/CiwwgZ0G -A1UdIwSBlTCBkoAUczJrQ7hCvtsnzcqiDIZ/GSn/Ciyhb6RtMGsxCzAJBgNVBAYT -AlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQKEwtNdXNiZSwgSW5jLjES -MBAGA1UEAxMJbXVzYmUuY29tMR0wGwYJKoZIhvcNAQkBFg5pbmZvQG11c2JlLmNv -bYIJAMjw7QcLWCd6MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGxk -8xzIljeBDQWWVRr0NEALVSv3i09V4jAKkyEOfmZ8lKMKJi0atwbtjrXTzLnNYj+Q -pyUbyY/8ItWvV7pnVxMiF9qcer7e9X4vw358GZuMVE/da1nWxz+CwzTm5oO30RzA -antM9bISFFr9lJq69bDWOnCUi1IG8DSL3TxtlABso7S4vqiZ+sB33l6k1K4a/Njb -QkU9UejKhKkVVZTsOrumfnOJ4MCmPfX8Y/AY2o670y5HnzpxerIYziCVzApPVrW7 -sKH0tuVGturMfQOKgstYe4/m9glBTeTLMkjD+6MJC2ONBD7GAiOO95gNl5M1fzJQ -FEe5CJ7DCYl0GdmLXXw= ------END CERTIFICATE----- diff --git a/libraries/plugins/auth/swekey/swekey.auth.lib.php b/libraries/plugins/auth/swekey/swekey.auth.lib.php deleted file mode 100644 index 78d90099d6..0000000000 --- a/libraries/plugins/auth/swekey/swekey.auth.lib.php +++ /dev/null @@ -1,315 +0,0 @@ - - - \n"; - // if (file_exists($caFile)) - // echo "\n"; - } - - if (@file_exists($caFile)) { - Swekey_SetCAFile($caFile); - } elseif (! empty($caFile) - && (substr($_SESSION['SWEKEY']['CONF_SERVER_CHECK'], 0, 8) == "https://") - ) { - return "Internal Error: CA File $caFile not found"; - } - - $result = null; - $swekey_id = $_GET['swekey_id']; - $swekey_otp = $_GET['swekey_otp']; - - if (isset($swekey_id)) { - unset($_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY']); - if (! isset($_SESSION['SWEKEY']['RND_TOKEN'])) { - unset($swekey_id); - } else { - if (strlen($swekey_id) == 32) { - $res = Swekey_CheckOtp( - $swekey_id, $_SESSION['SWEKEY']['RND_TOKEN'], $swekey_otp - ); - unset($_SESSION['SWEKEY']['RND_TOKEN']); - if (! $res) { - $result = __('Hardware authentication failed!') . ' (' . Swekey_GetLastError() . ')'; - } else { - $_SESSION['SWEKEY']['AUTHENTICATED_SWEKEY'] = $swekey_id; - $_SESSION['SWEKEY']['FORCE_USER'] - = $_SESSION['SWEKEY']['VALID_SWEKEYS'][$swekey_id]; - return null; - } - } else { - $result = __('No valid authentication key plugged'); - if ($_SESSION['SWEKEY']['CONF_DEBUG']) { - $result .= "
" . htmlspecialchars($swekey_id); - } - unset($_SESSION['SWEKEY']['CONF_LOADED']); // reload the conf file - } - } - } else { - unset($_SESSION['SWEKEY']); - } - - $_SESSION['SWEKEY']['RND_TOKEN'] = Swekey_GetFastRndToken(); - if (strlen($_SESSION['SWEKEY']['RND_TOKEN']) != 64) { - $result = __('Hardware authentication failed!') . ' (' . Swekey_GetLastError() . ')'; - unset($_SESSION['SWEKEY']['CONF_LOADED']); // reload the conf file - } - - if (! isset($swekey_id)) { - ?> - - display(); - if ($GLOBALS['error_handler']->hasDisplayErrors()) { - echo '
'; - $GLOBALS['error_handler']->dispErrors(); - echo '
'; - } - } - - if (isset($_SESSION['SWEKEY']) && $_SESSION['SWEKEY']['ENABLED']) { - echo ''; - } -} - -if (!empty($_GET['session_to_unset'])) { - session_write_close(); - session_id($_GET['session_to_unset']); - session_start(); - $_SESSION = array(); - session_write_close(); - session_destroy(); - exit; -} - -if (isset($_GET['swekey_reset'])) { - unset($_SESSION['SWEKEY']); -} - diff --git a/libraries/plugins/auth/swekey/swekey.php b/libraries/plugins/auth/swekey/swekey.php deleted file mode 100644 index baba5ee696..0000000000 --- a/libraries/plugins/auth/swekey/swekey.php +++ /dev/null @@ -1,536 +0,0 @@ -"; - -/** - * Servers addresses - * Use the Swekey_SetXxxServer($server) functions to set them - */ - -global $gSwekeyCheckServer; -if (! isset($gSwekeyCheckServer)) { - $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER; -} - -global $gSwekeyRndTokenServer; -if (! isset($gSwekeyRndTokenServer)) { - $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER; -} - -global $gSwekeyStatusServer; -if (! isset($gSwekeyStatusServer)) { - $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER; -} - -global $gSwekeyCA; - -global $gSwekeyTokenCacheEnabled; -if (! isset($gSwekeyTokenCacheEnabled)) { - $gSwekeyTokenCacheEnabled = true; -} - -/** - * Change the address of the Check server. - * If $server is empty the default value 'http://auth-check.musbe.net' will be used - * - * @param int $server The protocol and hostname to use - * - * @access public - */ -function Swekey_SetCheckServer($server) -{ - global $gSwekeyCheckServer; - if (empty($server)) { - $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER; - } else { - $gSwekeyCheckServer = $server; - } -} - -/** - * Change the address of the Random Token Generator server. - * If $server is empty the default value 'http://auth-rnd-gen.musbe.net' will be used - * - * @param int $server The protocol and hostname to use - * - * @access public - */ -function Swekey_SetRndTokenServer($server) -{ - global $gSwekeyRndTokenServer; - if (empty($server)) { - $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER; - } else { - $gSwekeyRndTokenServer = $server; - } -} - -/** - * Change the address of the Satus server. - * If $server is empty the default value 'http://auth-status.musbe.net' will be used - * - * @param int $server The protocol and hostname to use - * - * @access public - */ -function Swekey_SetStatusServer($server) -{ - global $gSwekeyStatusServer; - if (empty($server)) { - $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER; - } else { - $gSwekeyStatusServer = $server; - } -} - -/** - * Change the certificat file in case of the the severs use https instead of http - * - * @param string $cafile The path of the crt file to use - * - * @access public - */ -function Swekey_SetCAFile($cafile) -{ - global $gSwekeyCA; - $gSwekeyCA = $cafile; -} - -/** - * Enable or disable the random token caching - * Because everybody has full access to the cache file, it can be a DOS vulnerability - * So disable it if you are running in a non secure enviromnement - * - * @param $enable - * - * @access public - */ -function Swekey_EnableTokenCache($enable) -{ - global $gSwekeyTokenCacheEnabled; - $gSwekeyTokenCacheEnabled = ! empty($enable); -} - - -/** - * Return the last error. - * - * @return string The Last Error - * @access public - */ -function Swekey_GetLastError() -{ - global $gSwekeyLastError; - return $gSwekeyLastError; -} - -/** - * Return the last result. - * - * @return string The Last Error - * @access public - */ -function Swekey_GetLastResult() -{ - global $gSwekeyLastResult; - return $gSwekeyLastResult; -} - -/** - * Send a synchronous request to the server. - * This function manages timeout then will not block if one of the server is down - * - * @param string $url The url to get - * @param string $response_code The response code - * - * @return string The body of the response or "" in case of error - * @access private - */ -function Swekey_HttpGet($url, &$response_code) -{ - global $gSwekeyLastError; - $gSwekeyLastError = 0; - global $gSwekeyLastResult; - $gSwekeyLastResult = ""; - - // use curl if available - if (function_exists('curl_init')) { - $sess = curl_init($url); - if (substr($url, 0, 8) == "https://") { - global $gSwekeyCA; - - if (! empty($gSwekeyCA)) { - if (file_exists($gSwekeyCA)) { - if (! curl_setopt($sess, CURLOPT_CAINFO, $gSwekeyCA)) { - error_log( - "SWEKEY_ERROR:Could not set CA file : ".curl_error($sess) - ); - } else { - $caFileOk = true; - } - } else { - error_log( - "SWEKEY_ERROR:Could not find CA file $gSwekeyCA getting $url" - ); - } - } - - curl_setopt($sess, CURLOPT_SSL_VERIFYHOST, '2'); - curl_setopt($sess, CURLOPT_SSL_VERIFYPEER, '1'); - curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '20'); - curl_setopt($sess, CURLOPT_TIMEOUT, '20'); - } else { - curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '3'); - curl_setopt($sess, CURLOPT_TIMEOUT, '5'); - } - - curl_setopt($sess, CURLOPT_RETURNTRANSFER, '1'); - $res=curl_exec($sess); - $response_code = curl_getinfo($sess, CURLINFO_HTTP_CODE); - $curlerr = curl_error($sess); - curl_close($sess); - - if ($response_code == 200) { - $gSwekeyLastResult = $res; - return $res; - } - - if (! empty($response_code)) { - $gSwekeyLastError = $response_code; - error_log( - "SWEKEY_ERROR:Error $gSwekeyLastError ($curlerr) getting $url" - ); - return ""; - } - - $response_code = 408; // Request Timeout - $gSwekeyLastError = $response_code; - error_log("SWEKEY_ERROR:Error $curlerr getting $url"); - return ""; - } - - // use pecl_http if available - if (class_exists('HttpRequest')) { - // retry if one of the server is down - for ($num=1; $num <= 3; $num++ ) { - $r = new HttpRequest($url); - $options = array('timeout' => '3'); - - if (substr($url, 0, 6) == "https:") { - $sslOptions = array(); - $sslOptions['verifypeer'] = true; - $sslOptions['verifyhost'] = true; - - $capath = __FILE__; - $name = strrchr($capath, '/'); - // windows - if (empty($name)) { - $name = strrchr($capath, '\\'); - } - $capath = substr($capath, 0, strlen($capath) - strlen($name) + 1) - . 'musbe-ca.crt'; - - if (! empty($gSwekeyCA)) { - $sslOptions['cainfo'] = $gSwekeyCA; - } - - $options['ssl'] = $sslOptions; - } - - $r->setOptions($options); - - /* - try - { - */ - $reply = $r->send(); - $res = $reply->getBody(); - $info = $r->getResponseInfo(); - $response_code = $info['response_code']; - if ($response_code != 200) { - $gSwekeyLastError = $response_code; - error_log( - "SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url - ); - return ""; - } - - - $gSwekeyLastResult = $res; - return $res; - /* - } - catch (HttpException $e) - { - error_log("SWEKEY_WARNING:HttpException ".$e." getting ".$url); - } - */ - } - - $response_code = 408; // Request Timeout - $gSwekeyLastError = $response_code; - error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url); - return ""; - } - - global $http_response_header; - $res = @file_get_contents($url); - $response_code = substr($http_response_header[0], 9, 3); //HTTP/1.0 - if ($response_code == 200) { - $gSwekeyLastResult = $res; - return $res; - } - - $gSwekeyLastError = $response_code; - error_log("SWEKEY_ERROR:Error ".$response_code." getting ".$url); - return ""; -} - -/** - * Get a Random Token from a Token Server - * The RT is a 64 vhars hexadecimal value - * You should better use Swekey_GetFastRndToken() for performance - * @access public - */ -function Swekey_GetRndToken() -{ - global $gSwekeyRndTokenServer; - return Swekey_HttpGet($gSwekeyRndTokenServer.'/FULL-RND-TOKEN', $response_code); -} - -/** - * Get a Half Random Token from a Token Server - * The RT is a 64 vhars hexadecimal value - * Use this value if you want to make your own Swekey_GetFastRndToken() - * @access public - */ -function Swekey_GetHalfRndToken() -{ - global $gSwekeyRndTokenServer; - return Swekey_HttpGet($gSwekeyRndTokenServer.'/HALF-RND-TOKEN', $response_code); -} - -/** - * Get a Half Random Token - * The RT is a 64 vhars hexadecimal value - * This function get a new random token and reuse it. - * Token are refetched from the server only once every 30 seconds. - * You should always use this function to get half random token. - * @access public - */ -function Swekey_GetFastHalfRndToken() -{ - global $gSwekeyTokenCacheEnabled; - - $res = ""; - $cachefile = ""; - - // We check if we have a valid RT is the session - if (isset($_SESSION['rnd-token-date'])) { - if (time() - $_SESSION['rnd-token-date'] < 30) { - $res = $_SESSION['rnd-token']; - } - } - - // If not we try to get it from a temp file (PHP >= 5.2.1 only) - if (strlen($res) != 32 && $gSwekeyTokenCacheEnabled) { - if (function_exists('sys_get_temp_dir')) { - $tempdir = sys_get_temp_dir(); - $cachefile = $tempdir."/swekey-rnd-token-".get_current_user(); - $modif = filemtime($cachefile); - if ($modif != false) { - if (time() - $modif < 30) { - $res = @file_get_contents($cachefile); - if (strlen($res) != 32) { - $res = ""; - } else { - $_SESSION['rnd-token'] = $res; - $_SESSION['rnd-token-date'] = $modif; - } - } - } - } - } - - // If we don't have a valid RT here we have to get it from the server - if (strlen($res) != 32) { - $res = substr(Swekey_GetHalfRndToken(), 0, 32); - $_SESSION['rnd-token'] = $res; - $_SESSION['rnd-token-date'] = time(); - if (! empty($cachefile)) { - // we unlink the file so no possible tempfile race attack - unlink($cachefile); - $file = fopen($cachefile, "x"); - if ($file != false) { - @fwrite($file, $res); - @fclose($file); - } - } - } - - return $res."00000000000000000000000000000000"; -} - -/** - * Get a Random Token - * The RT is a 64 vhars hexadecimal value - * This function generates a unique random token for each call but call the - * server only once every 30 seconds. - * You should always use this function to get random token. - * @access public - */ -function Swekey_GetFastRndToken() -{ - $res = Swekey_GetFastHalfRndToken(); - if (strlen($res) == 64) { - return substr($res, 0, 32).strtoupper(md5("Musbe Authentication Key" . mt_rand() . date(DATE_ATOM))); - } - return ""; -} - - -/** - * Checks that an OTP generated by a Swekey is valid - * - * @param mixed $id The id of the swekey - * @param mixed $rt The random token used to generate the otp - * @param mixed $otp The otp generated by the swekey - * - * @return boolean Success - * @access public - */ -function Swekey_CheckOtp($id, $rt, $otp) -{ - global $gSwekeyCheckServer; - $res = Swekey_HttpGet( - $gSwekeyCheckServer.'/CHECK-OTP/'.$id.'/'.$rt.'/'.$otp, - $response_code - ); - return $response_code == 200 && $res == "OK"; -} - -/** - * Values that are associated with a key. - * The following values can be returned by the Swekey_GetStatus() function - */ -define("SWEKEY_STATUS_OK", 0); -define("SWEKEY_STATUS_NOT_FOUND", 1); // The key does not exist in the db -define("SWEKEY_STATUS_INACTIVE", 2); // The key has never been activated -define("SWEKEY_STATUS_LOST", 3); // The user has lost his key -define("SWEKEY_STATUS_STOLEN", 4); // The key was stolen -define("SWEKEY_STATUS_FEE_DUE", 5); // The annual fee was not paid -define("SWEKEY_STATUS_OBSOLETE", 6); // The hardware is no longer supported -define("SWEKEY_STATUS_UNKOWN", 201); // We could not connect to the authentication server - -/** - * Values that are associated with a key. - * The Javascript Api can also return the following values - */ -define("SWEKEY_STATUS_REPLACED", 100); // This key has been replaced by a backup key -define("SWEKEY_STATUS_BACKUP_KEY", 101); // This key is a backup key that is not activated yet -define("SWEKEY_STATUS_NOTPLUGGED", 200); // This key is not plugged in the computer - - -/** - * Return the text corresponding to the integer status of a key - * - * @param int $status The status - * - * @return string The text corresponding to the status - * @access public - */ -function Swekey_GetStatusStr($status) -{ - switch($status) - { - case SWEKEY_STATUS_OK : - return 'OK'; - case SWEKEY_STATUS_NOT_FOUND : - return 'Key does not exist in the db'; - case SWEKEY_STATUS_INACTIVE : - return 'Key not activated'; - case SWEKEY_STATUS_LOST : - return 'Key was lost'; - case SWEKEY_STATUS_STOLEN : - return 'Key was stolen'; - case SWEKEY_STATUS_FEE_DUE : - return 'The annual fee was not paid'; - case SWEKEY_STATUS_OBSOLETE : - return 'Key no longer supported'; - case SWEKEY_STATUS_REPLACED : - return 'This key has been replaced by a backup key'; - case SWEKEY_STATUS_BACKUP_KEY : - return 'This key is a backup key that is not activated yet'; - case SWEKEY_STATUS_NOTPLUGGED : - return 'This key is not plugged in the computer'; - case SWEKEY_STATUS_UNKOWN : - return 'Unknow Status, could not connect to the authentication server'; - } - return 'unknown status '.$status; -} - -/** - * If your web site requires a key to login you should check that the key - * is still valid (has not been lost or stolen) before requiring it. - * A key can be authenticated only if its status is SWEKEY_STATUS_OK - * - * @param mixed $id The id of the swekey - * - * @return int The status of the swekey - * @access public - */ -function Swekey_GetStatus($id) -{ - global $gSwekeyStatusServer; - $res = Swekey_HttpGet($gSwekeyStatusServer.'/GET-STATUS/'.$id, $response_code); - if ($response_code == 200) { - return intval($res); - } - return SWEKEY_STATUS_UNKOWN; -} diff --git a/phpunit.xml.dist b/phpunit.xml.dist index efcc2aed56..2e2d1d226f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -48,7 +48,6 @@ libraries/bfShapeFiles libraries/php-gettext libraries/phpseclib - libraries/plugins/auth/swekey/ libraries/sql-parser libraries/tcpdf diff --git a/test/classes/plugin/auth/AuthenticationCookieTest.php b/test/classes/plugin/auth/AuthenticationCookieTest.php index d999336b75..e4d2e87840 100644 --- a/test/classes/plugin/auth/AuthenticationCookieTest.php +++ b/test/classes/plugin/auth/AuthenticationCookieTest.php @@ -404,22 +404,6 @@ class AuthenticationCookieTest extends PMATestCase $attrInstance->setValue($restoreInstance); } - /** - * Test for PMA\libraries\plugins\auth\AuthenticationConfig::authCheck - * - * @return void - */ - public function testAuthCheckSwekey() - { - $GLOBALS['cfg']['Server']['auth_swekey_config'] = 'testConfigSwekey'; - - file_put_contents('testConfigSwekey', ''); - $this->assertFalse( - $this->object->authCheck() - ); - @unlink('testConfigSwekey'); - } - /** * Test for PMA\libraries\plugins\auth\AuthenticationConfig::authCheck * @@ -427,7 +411,6 @@ class AuthenticationCookieTest extends PMATestCase */ public function testAuthCheckCaptcha() { - $GLOBALS['cfg']['Server']['auth_swekey_config'] = ''; $GLOBALS['cfg']['CaptchaLoginPrivateKey'] = 'testprivkey'; $GLOBALS['cfg']['CaptchaLoginPublicKey'] = 'testpubkey'; $_POST["g-recaptcha-response"] = ''; @@ -470,7 +453,6 @@ class AuthenticationCookieTest extends PMATestCase $attrInstance->setAccessible(true); $attrInstance->setValue($mockResponse); - $GLOBALS['cfg']['Server']['auth_swekey_config'] = ''; $GLOBALS['cfg']['CaptchaLoginPrivateKey'] = ''; $GLOBALS['cfg']['CaptchaLoginPublicKey'] = ''; $GLOBALS['cfg']['LoginCookieDeleteAll'] = true; @@ -512,7 +494,6 @@ class AuthenticationCookieTest extends PMATestCase $attrInstance = new ReflectionProperty('PMA\libraries\Response', '_instance'); $attrInstance->setAccessible(true); $attrInstance->setValue($mockResponse); - $GLOBALS['cfg']['Server']['auth_swekey_config'] = ''; $GLOBALS['cfg']['CaptchaLoginPrivateKey'] = ''; $GLOBALS['cfg']['CaptchaLoginPublicKey'] = ''; $GLOBALS['cfg']['LoginCookieDeleteAll'] = false; @@ -536,7 +517,6 @@ class AuthenticationCookieTest extends PMATestCase */ public function testAuthCheckArbitrary() { - $GLOBALS['cfg']['Server']['auth_swekey_config'] = ''; $GLOBALS['cfg']['CaptchaLoginPrivateKey'] = ''; $GLOBALS['cfg']['CaptchaLoginPublicKey'] = ''; $_REQUEST['old_usr'] = ''; @@ -577,7 +557,6 @@ class AuthenticationCookieTest extends PMATestCase public function testAuthCheckIV() { $GLOBALS['cfg']['AllowArbitraryServer'] = true; - $GLOBALS['cfg']['Server']['auth_swekey_config'] = ''; $_REQUEST['pma_servername'] = 'testPMAServer'; $_REQUEST['pma_password'] = 'testPMAPSWD'; $_REQUEST['pma_username'] = ''; @@ -603,7 +582,6 @@ class AuthenticationCookieTest extends PMATestCase */ public function testAuthCheckExpires() { - $GLOBALS['cfg']['Server']['auth_swekey_config'] = ''; $GLOBALS['server'] = 1; $_COOKIE['pmaServer-1'] = 'pmaServ1'; $_COOKIE['pmaUser-1'] = 'pmaUser1'; @@ -625,7 +603,6 @@ class AuthenticationCookieTest extends PMATestCase */ public function testAuthCheckDecryptUser() { - $GLOBALS['cfg']['Server']['auth_swekey_config'] = 'testConfigSwekey'; $GLOBALS['server'] = 1; $_REQUEST['old_usr'] = ''; $_REQUEST['pma_username'] = ''; @@ -664,7 +641,6 @@ class AuthenticationCookieTest extends PMATestCase */ public function testAuthCheckDecryptPassword() { - $GLOBALS['cfg']['Server']['auth_swekey_config'] = 'testConfigSwekey'; $GLOBALS['server'] = 1; $_REQUEST['old_usr'] = ''; $_REQUEST['pma_username'] = ''; @@ -710,7 +686,6 @@ class AuthenticationCookieTest extends PMATestCase */ public function testAuthCheckAuthFails() { - $GLOBALS['cfg']['Server']['auth_swekey_config'] = 'testConfigSwekey'; $GLOBALS['server'] = 1; $_REQUEST['old_usr'] = ''; $_REQUEST['pma_username'] = ''; From de3181277e747a94fb0b0213f3d11576458b72cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Mon, 11 Jul 2016 09:18:19 +0200 Subject: [PATCH 019/101] Include only relative path in backtrace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/Error.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/Error.php b/libraries/Error.php index 5caec03852..6548877c60 100644 --- a/libraries/Error.php +++ b/libraries/Error.php @@ -117,12 +117,17 @@ class Error extends Message { $result = array(); - $members = array('file', 'line', 'function', 'class', 'type'); + $members = array('line', 'function', 'class', 'type'); foreach ($backtrace as $idx => $step) { /* Create new backtrace entry */ $result[$idx] = array(); + /* Make path relative */ + if (isset($step['file'])) { + $result[$idx]['file'] = Error::relPath($step['file']); + } + /* Store members we want */ foreach ($members as $name) { if (isset($step[$name])) { From 660e3a177f4933018c94ba1270a61b2437aa1163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Mon, 11 Jul 2016 09:31:55 +0200 Subject: [PATCH 020/101] Remove debugging code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/core.lib.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libraries/core.lib.php b/libraries/core.lib.php index 037227d797..093141341f 100644 --- a/libraries/core.lib.php +++ b/libraries/core.lib.php @@ -520,11 +520,6 @@ function PMA_sendHeaderLocation($uri, $use_refresh = false) session_write_close(); if ($response->headersSent()) { - if (function_exists('debug_print_backtrace')) { - echo '
';
-            debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
-            echo '
'; - } trigger_error( 'PMA_sendHeaderLocation called when headers are already sent!', E_USER_ERROR From cc7d01daa7fe3c525718c7ef19f82d13e51cc080 Mon Sep 17 00:00:00 2001 From: Madhura Jayaratne Date: Tue, 12 Jul 2016 11:27:36 +1000 Subject: [PATCH 021/101] Fix XSS in tbl_gis_visualization.php Signed-off-by: Madhura Jayaratne --- templates/table/gis_visualization/gis_visualization.phtml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/table/gis_visualization/gis_visualization.phtml b/templates/table/gis_visualization/gis_visualization.phtml index d62c46b00c..b6b956be85 100644 --- a/templates/table/gis_visualization/gis_visualization.phtml +++ b/templates/table/gis_visualization/gis_visualization.phtml @@ -10,8 +10,8 @@ @@ -20,8 +20,8 @@ From cbba4f4fdb18ad071e3d515a0e96067939d3352b Mon Sep 17 00:00:00 2001 From: Madhura Jayaratne Date: Tue, 12 Jul 2016 11:49:53 +1000 Subject: [PATCH 022/101] Fix XSS in server_replication.php Signed-off-by: Madhura Jayaratne --- libraries/replication_gui.lib.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/replication_gui.lib.php b/libraries/replication_gui.lib.php index d0d5dd25b9..3cda3498ec 100644 --- a/libraries/replication_gui.lib.php +++ b/libraries/replication_gui.lib.php @@ -806,7 +806,7 @@ function PMA_getHtmlForAddUserLoginForm($username_length) . (empty($_REQUEST['username']) ? '' : ' value="' . (isset($GLOBALS['new_username']) ? $GLOBALS['new_username'] - : $_REQUEST['username']) . '"') + : htmlspecialchars($_REQUEST['username'])) . '"') . ' />' . '
'; @@ -836,7 +836,7 @@ function PMA_getHtmlForTableInfoForm($hostname_length) . '' . '' . PMA\libraries\Util::showHint( From 0bf21ebf720a552c8e727a6cca1c653e20c3160a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 10:36:33 +0200 Subject: [PATCH 023/101] Use whitelist rather than blacklist for URL filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- .../transformations/abs/TextImageLinkTransformationsPlugin.php | 2 +- .../transformations/abs/TextLinkTransformationsPlugin.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/plugins/transformations/abs/TextImageLinkTransformationsPlugin.php b/libraries/plugins/transformations/abs/TextImageLinkTransformationsPlugin.php index d341f59da9..800a76e12b 100644 --- a/libraries/plugins/transformations/abs/TextImageLinkTransformationsPlugin.php +++ b/libraries/plugins/transformations/abs/TextImageLinkTransformationsPlugin.php @@ -49,7 +49,7 @@ abstract class TextImageLinkTransformationsPlugin extends TransformationsPlugin $url = (isset($options[0]) ? $options[0] : '') . $buffer; $parsed = parse_url($url); /* Do not allow javascript links */ - if (isset($parsed['scheme']) && $parsed['scheme'] == 'javascript') { + if (! isset($parsed['scheme']) || ! in_array(strtolower($parsed['scheme']), array('http', 'https', 'ftp', 'mailto'))) { return htmlspecialchars($url); } return ' Date: Tue, 12 Jul 2016 10:38:25 +0200 Subject: [PATCH 024/101] Fix wrong merge resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- po/sq.po | 1 - 1 file changed, 1 deletion(-) diff --git a/po/sq.po b/po/sq.po index 1f158cd0e3..58ab57ba42 100644 --- a/po/sq.po +++ b/po/sq.po @@ -7208,7 +7208,6 @@ msgid "" "tables]pmadb[/doc] for complete information. Leave blank for no support. " "Suggested: [kbd]phpmyadmin[/kbd]." msgstr "" -<<<<<<< "Databaza e përdorur për relacione, faqeruajtës dhe tiparet PDF. Shiko [doc" "@linked-tables][/doc][/doc]pmadb[/doc] për informacion më të plotë. Lëre të " "zbrazët për mos mbështetje. Sugjerohet: [kbd]phpmyadmin[/kbd]." From 3c06eede3fda803fb2b931598e26d61563a4502b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 10:57:23 +0200 Subject: [PATCH 025/101] Add rel="noopener noreferrer" to all target="_blank" links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- changelog.php | 1 + libraries/display_git_revision.lib.php | 4 ++-- libraries/engines/Pbxt.php | 2 +- .../transformations/abs/InlineTransformationsPlugin.php | 2 +- .../abs/TextImageLinkTransformationsPlugin.php | 2 +- libraries/sanitizing.lib.php | 3 +++ templates/list/item.phtml | 4 ++++ themes.php | 2 +- 8 files changed, 14 insertions(+), 6 deletions(-) diff --git a/changelog.php b/changelog.php index b71e29e35b..c19bcf53d5 100644 --- a/changelog.php +++ b/changelog.php @@ -155,6 +155,7 @@ echo ''; var links = document.getElementsByTagName("a"); for(var i = 0; i < links.length; i++) { links[i].target = "_blank"; + links[i].rel = "noopener noreferrer"; } diff --git a/libraries/display_git_revision.lib.php b/libraries/display_git_revision.lib.php index bd179973dc..38506c8889 100644 --- a/libraries/display_git_revision.lib.php +++ b/libraries/display_git_revision.lib.php @@ -37,7 +37,7 @@ function PMA_printGitRevision() 'https://github.com/phpmyadmin/phpmyadmin/commit/' . $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_COMMITHASH') ) - . '" target="_blank">' . $commit_hash . ''; + . '" rel="noopener noreferrer" target="_blank">' . $commit_hash . ''; } $branch = $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_BRANCH'); @@ -47,7 +47,7 @@ function PMA_printGitRevision() 'https://github.com/phpmyadmin/phpmyadmin/tree/' . $GLOBALS['PMA_Config']->get('PMA_VERSION_GIT_BRANCH') ) - . '" target="_blank">' . $branch . ''; + . '" rel="noopener noreferrer" target="_blank">' . $branch . ''; } if ($branch !== false) { $branch = sprintf(__('%1$s from %2$s branch'), $commit_hash, $branch); diff --git a/libraries/engines/Pbxt.php b/libraries/engines/Pbxt.php index 1922ea42a7..68af617199 100644 --- a/libraries/engines/Pbxt.php +++ b/libraries/engines/Pbxt.php @@ -182,7 +182,7 @@ class Pbxt extends StorageEngine . ' can be found on the %sPrimeBase XT Home Page%s.' ), '', + . '" rel="noopener noreferrer" target="_blank">', '' ) . '

' . "\n"; diff --git a/libraries/plugins/transformations/abs/InlineTransformationsPlugin.php b/libraries/plugins/transformations/abs/InlineTransformationsPlugin.php index 9d2a12f59f..4e21e88ae8 100644 --- a/libraries/plugins/transformations/abs/InlineTransformationsPlugin.php +++ b/libraries/plugins/transformations/abs/InlineTransformationsPlugin.php @@ -51,7 +51,7 @@ abstract class InlineTransformationsPlugin extends TransformationsPlugin if (PMA_IS_GD2) { return '' . htmlspecialchars($buffer) . ''; diff --git a/libraries/sanitizing.lib.php b/libraries/sanitizing.lib.php index 0094430e55..f5ff998e45 100644 --- a/libraries/sanitizing.lib.php +++ b/libraries/sanitizing.lib.php @@ -56,6 +56,9 @@ function PMA_replaceBBLink($found) $target = ''; if (! empty($found[3])) { $target = ' target="' . $found[3] . '"'; + if ($found[3] == '_blank') { + $target .= ' rel="noopener noreferrer"'; + } } /* Construct url */ diff --git a/templates/list/item.phtml b/templates/list/item.phtml index 099a211d86..c3efdde8e0 100644 --- a/templates/list/item.phtml +++ b/templates/list/item.phtml @@ -21,6 +21,10 @@ ? ' target="' . $url['target'] . '"' : null; ?> + phpMyAdmin - ' . __('Theme') . ''; $output .= '

'; -$output .= ''; +$output .= ''; $output .= __('Get more themes!'); $output .= ''; $output .= '

'; From 3b0115a32159608a930e03a4d3a8830cb3520c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 11:15:48 +0200 Subject: [PATCH 026/101] Adjust tests to recent changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- test/classes/DisplayResultsTest.php | 4 +- test/classes/engines/PbxtTest.php | 2 +- .../TransformationPluginsTest.php | 46 ++++++++++++++++--- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/test/classes/DisplayResultsTest.php b/test/classes/DisplayResultsTest.php index ae0a85063d..404c4886a5 100644 --- a/test/classes/DisplayResultsTest.php +++ b/test/classes/DisplayResultsTest.php @@ -1385,7 +1385,7 @@ class DisplayResultsTest extends PMATestCase $meta, $url_params, null, - '1001' + '1001' ), array( false, @@ -1514,7 +1514,7 @@ class DisplayResultsTest extends PMATestCase 0, 'binary', '' - . '1001' + . '1001' ), array( 'noblob', diff --git a/test/classes/engines/PbxtTest.php b/test/classes/engines/PbxtTest.php index 5ac3e025ad..110a63200a 100644 --- a/test/classes/engines/PbxtTest.php +++ b/test/classes/engines/PbxtTest.php @@ -252,7 +252,7 @@ class PbxtTest extends PMATestCase . ' can be found on the %sPrimeBase XT Home Page%s.' ), '', + . '" rel="noopener noreferrer" target="_blank">', '' ) . '

' . "\n" diff --git a/test/classes/plugin/transformations/TransformationPluginsTest.php b/test/classes/plugin/transformations/TransformationPluginsTest.php index 872adb352c..afd692124a 100644 --- a/test/classes/plugin/transformations/TransformationPluginsTest.php +++ b/test/classes/plugin/transformations/TransformationPluginsTest.php @@ -778,7 +778,7 @@ class TransformationPluginsTest extends PMATestCase array("./image/", "200", "wrapper_link"=>"PMA_wrapper_link") ), '[PMA_JPEG_Inline]' ), @@ -799,7 +799,7 @@ class TransformationPluginsTest extends PMATestCase array("./image/", "200", "wrapper_link"=>"PMA_wrapper_link") ), '' @@ -868,15 +868,23 @@ class TransformationPluginsTest extends PMATestCase ), "PMA_BUFFER" ), + array( + new Text_Plain_Imagelink(), + array( + 'PMA_IMAGE', + array("http://image/", "200") + ), + '' + . 'PMA_IMAGE' + ), array( new Text_Plain_Imagelink(), array( 'PMA_IMAGE', array("./image/", "200") ), - '' - . 'PMA_IMAGE' + './image/PMA_IMAGE' ), array( new Text_Plain_Sql(), @@ -894,8 +902,32 @@ class TransformationPluginsTest extends PMATestCase 'PMA_TXT_LINK', array("./php/", "text_name") ), - 'text_name' + './php/PMA_TXT_LINK' + ), + array( + new Text_Plain_Link(), + array( + 'PMA_TXT_LINK', + array(), + ), + 'PMA_TXT_LINK' + ), + array( + new Text_Plain_Link(), + array( + 'https://example.com/PMA_TXT_LINK', + array(), + ), + 'https://example.com/PMA_TXT_LINK' + ), + array( + new Text_Plain_Link(), + array( + 'PMA_TXT_LINK', + array("./php/", "text_name") + ), + './php/PMA_TXT_LINK' ), array( new Text_Plain_Longtoipv4(), From 2ea0b722d7cb7affbfa3f02c9442f0b6f0833306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 11:20:16 +0200 Subject: [PATCH 027/101] Use _blank target instead of invalid _new MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- .../transformations/abs/ImageLinkTransformationsPlugin.php | 2 +- .../transformations/abs/TextLinkTransformationsPlugin.php | 2 +- .../plugin/transformations/TransformationPluginsTest.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/plugins/transformations/abs/ImageLinkTransformationsPlugin.php b/libraries/plugins/transformations/abs/ImageLinkTransformationsPlugin.php index 5246fb2e5f..429b5cfdb8 100644 --- a/libraries/plugins/transformations/abs/ImageLinkTransformationsPlugin.php +++ b/libraries/plugins/transformations/abs/ImageLinkTransformationsPlugin.php @@ -49,7 +49,7 @@ abstract class ImageLinkTransformationsPlugin extends TransformationsPlugin { // must disable the page loader, see // https://wiki.phpmyadmin.net/pma/Page_loader#Bypassing_the_page_loader - return '[BLOB]'; } diff --git a/libraries/plugins/transformations/abs/TextLinkTransformationsPlugin.php b/libraries/plugins/transformations/abs/TextLinkTransformationsPlugin.php index 14e3fda8c6..776a219da2 100644 --- a/libraries/plugins/transformations/abs/TextLinkTransformationsPlugin.php +++ b/libraries/plugins/transformations/abs/TextLinkTransformationsPlugin.php @@ -56,7 +56,7 @@ abstract class TextLinkTransformationsPlugin extends TransformationsPlugin . htmlspecialchars($url) . '" title="' . htmlspecialchars(isset($options[1]) ? $options[1] : '') - . '" target="_new">' + . '" target="_blank" rel="noopener noreferrer">' . htmlspecialchars(isset($options[1]) ? $options[1] : $buffer) . ''; } diff --git a/test/classes/plugin/transformations/TransformationPluginsTest.php b/test/classes/plugin/transformations/TransformationPluginsTest.php index afd692124a..275800f297 100644 --- a/test/classes/plugin/transformations/TransformationPluginsTest.php +++ b/test/classes/plugin/transformations/TransformationPluginsTest.php @@ -788,7 +788,7 @@ class TransformationPluginsTest extends PMATestCase 'PMA_IMAGE_LINK', array("./image/", "200", "wrapper_link"=>"PMA_wrapper_link") ), - '[BLOB]' ), @@ -919,7 +919,7 @@ class TransformationPluginsTest extends PMATestCase array(), ), 'https://example.com/PMA_TXT_LINK' + . ' target="_blank" rel="noopener noreferrer">https://example.com/PMA_TXT_LINK' ), array( new Text_Plain_Link(), From 6da13e2a1cbcd204617ab140ab70e08258473e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 12:29:35 +0200 Subject: [PATCH 028/101] Escape HTML in Mediawiki comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/plugins/export/ExportMediawiki.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/plugins/export/ExportMediawiki.php b/libraries/plugins/export/ExportMediawiki.php index 085b956cd0..810198bbe4 100644 --- a/libraries/plugins/export/ExportMediawiki.php +++ b/libraries/plugins/export/ExportMediawiki.php @@ -360,7 +360,7 @@ class ExportMediawiki extends ExportPlugin // see http://www.mediawiki.org/wiki/Help:Formatting $comment = $this->_exportCRLF(); $comment .= '' . str_repeat($this->_exportCRLF(), 2); return $comment; From 78bed3c4441bc8ea1b4bf380eb51d100e39841ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 12:33:53 +0200 Subject: [PATCH 029/101] Ensure last version is numeric MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/tracking.lib.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/tracking.lib.php b/libraries/tracking.lib.php index 6fc9f4253b..bc478e1c17 100644 --- a/libraries/tracking.lib.php +++ b/libraries/tracking.lib.php @@ -388,9 +388,7 @@ function PMA_getHtmlForTableVersionDetails( function PMA_getTableLastVersionNumber($sql_result) { $maxversion = $GLOBALS['dbi']->fetchArray($sql_result); - $last_version = $maxversion['version']; - - return $last_version; + return intval($maxversion['version']); } /** From 8095b837faec8508201e500b7c7ff25fe2269fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 12:37:19 +0200 Subject: [PATCH 030/101] Hide session error messages to avoid FPD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- examples/openid.php | 2 +- examples/signon.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/openid.php b/examples/openid.php index 67585c2e53..0db0a466b8 100644 --- a/examples/openid.php +++ b/examples/openid.php @@ -78,7 +78,7 @@ session_set_cookie_params(0, '/', '', true, true); /* Create signon session */ $session_name = 'SignonSession'; session_name($session_name); -session_start(); +@session_start(); // Determine realm and return_to $base = 'http'; diff --git a/examples/signon.php b/examples/signon.php index 4463c38707..da9fadfabc 100644 --- a/examples/signon.php +++ b/examples/signon.php @@ -18,7 +18,7 @@ $session_name = 'SignonSession'; session_name($session_name); // Uncomment and change the following line to match your $cfg['SessionSavePath'] //session_save_path('/foobar'); -session_start(); +@session_start(); /* Was data posted? */ if (isset($_POST['user'])) { @@ -31,7 +31,7 @@ if (isset($_POST['user'])) { $_SESSION['PMA_single_signon_cfgupdate'] = array('verbose' => 'Signon test'); $id = session_id(); /* Close that session */ - session_write_close(); + @session_write_close(); /* Redirect to phpMyAdmin (should use absolute URL here!) */ header('Location: ../index.php'); } else { From 0d57c09bd582f6f138bb4583374a83b673520fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 12:47:35 +0200 Subject: [PATCH 031/101] Do not allow symlinks in UploadDir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- import.php | 9 +++++++++ libraries/File.php | 5 +++++ libraries/file_listing.lib.php | 1 + 3 files changed, 15 insertions(+) diff --git a/import.php b/import.php index ae0eaef802..a43eff6b63 100644 --- a/import.php +++ b/import.php @@ -435,6 +435,15 @@ if (! empty($local_import_file) && ! empty($cfg['UploadDir'])) { $import_file = PMA\libraries\Util::userDir($cfg['UploadDir']) . $local_import_file; + /* + * Do not allow symlinks to avoid security issues + * (user can create symlink to file he can not access, + * but phpMyAdmin can). + */ + if (@is_link($import_file)) { + $import_file = 'none'; + } + } elseif (empty($import_file) || ! is_uploaded_file($import_file)) { $import_file = 'none'; } diff --git a/libraries/File.php b/libraries/File.php index b456fb2727..4d71dc3f63 100644 --- a/libraries/File.php +++ b/libraries/File.php @@ -420,6 +420,11 @@ class File $this->setName( Util::userDir($GLOBALS['cfg']['UploadDir']) . PMA_securePath($name) ); + if (@is_link($this->getName())) { + $this->_error_message = __('File is a symbolic link'); + $this->setName(null); + return false; + } if (! $this->isReadable()) { $this->_error_message = __('File could not be read!'); $this->setName(null); diff --git a/libraries/file_listing.lib.php b/libraries/file_listing.lib.php index 64f7230634..64b469b014 100644 --- a/libraries/file_listing.lib.php +++ b/libraries/file_listing.lib.php @@ -26,6 +26,7 @@ function PMA_getDirContent($dir, $expression = '') } while ($file = @readdir($handle)) { if (@is_file($dir . $file) + && ! @is_link($dir . $file) && ($expression == '' || preg_match($expression, $file)) ) { $result[] = $file; From 2f79bacefab46fc43cedd70917c50800caaa417a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 14:02:26 +0200 Subject: [PATCH 032/101] Use phpseclib's Crypt module to generate encryption keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/config/ServerConfigChecks.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/config/ServerConfigChecks.php b/libraries/config/ServerConfigChecks.php index ae57be2fc6..39f7b092f2 100644 --- a/libraries/config/ServerConfigChecks.php +++ b/libraries/config/ServerConfigChecks.php @@ -214,7 +214,12 @@ class ServerConfigChecks $blowfishSecret, $cookieAuthServer, $blowfishSecretSet ) { if ($cookieAuthServer && $blowfishSecret === null) { - $blowfishSecret = uniqid('', true); + if (! function_exists('openssl_random_pseudo_bytes')) { + $blowfishSecret = bin2hex(phpseclib\Crypt\Random::string(16)); + } else { + $blowfishSecret = bin2hex(openssl_random_pseudo_bytes(16)); + } + $blowfishSecretSet = true; $this->cfg->set('blowfish_secret', $blowfishSecret); return array($blowfishSecret, $blowfishSecretSet); From 2ef4fe3d842f25e1ad0551e7ca4781b5fc7a4e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 14:11:45 +0200 Subject: [PATCH 033/101] Use iframe sandbox for rendering HTML in transformation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- .../abs/FormattedTransformationsPlugin.php | 4 +++- .../transformations/TransformationPluginsTest.php | 10 +++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/plugins/transformations/abs/FormattedTransformationsPlugin.php b/libraries/plugins/transformations/abs/FormattedTransformationsPlugin.php index 798dc539e4..d71842af36 100644 --- a/libraries/plugins/transformations/abs/FormattedTransformationsPlugin.php +++ b/libraries/plugins/transformations/abs/FormattedTransformationsPlugin.php @@ -42,7 +42,9 @@ abstract class FormattedTransformationsPlugin extends TransformationsPlugin */ public function applyTransformation($buffer, $options = array(), $meta = '') { - return $buffer; + return ''; } diff --git a/test/classes/plugin/transformations/TransformationPluginsTest.php b/test/classes/plugin/transformations/TransformationPluginsTest.php index 275800f297..60b995b952 100644 --- a/test/classes/plugin/transformations/TransformationPluginsTest.php +++ b/test/classes/plugin/transformations/TransformationPluginsTest.php @@ -866,7 +866,15 @@ class TransformationPluginsTest extends PMATestCase "PMA_BUFFER", array("option1", "option2") ), - "PMA_BUFFER" + "" + ), + array( + new Text_Plain_Formatted(), + array( + "PMA_BUFFER", + array("option1", "option2") + ), + "" ), array( new Text_Plain_Imagelink(), From e749214b1681ce6af31df169f57b0c23d2a40232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 14:32:31 +0200 Subject: [PATCH 034/101] Prefer curl over file_get_contents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Curl is better in SSL certificate verification. Signed-off-by: Michal Čihař --- libraries/VersionInformation.php | 34 +++++++++++++-------------- libraries/error_report.lib.php | 40 +++++++++++++++----------------- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/libraries/VersionInformation.php b/libraries/VersionInformation.php index 49e5e4ce4d..e7f229cc73 100644 --- a/libraries/VersionInformation.php +++ b/libraries/VersionInformation.php @@ -48,23 +48,7 @@ class VersionInformation } else { $save = true; $file = 'https://www.phpmyadmin.net/home_page/version.json'; - if (ini_get('allow_url_fopen')) { - $context = array( - 'http' => array( - 'request_fulluri' => true, - 'timeout' => $connection_timeout, - ) - ); - $context = Util::handleContext($context); - if (! defined('TESTSUITE')) { - session_write_close(); - } - $response = file_get_contents( - $file, - false, - stream_context_create($context) - ); - } else if (function_exists('curl_init')) { + if (function_exists('curl_init')) { $curl_handle = curl_init($file); if ($curl_handle === false) { return null; @@ -89,6 +73,22 @@ class VersionInformation session_write_close(); } $response = curl_exec($curl_handle); + } else if (ini_get('allow_url_fopen')) { + $context = array( + 'http' => array( + 'request_fulluri' => true, + 'timeout' => $connection_timeout, + ) + ); + $context = Util::handleContext($context); + if (! defined('TESTSUITE')) { + session_write_close(); + } + $response = file_get_contents( + $file, + false, + stream_context_create($context) + ); } } diff --git a/libraries/error_report.lib.php b/libraries/error_report.lib.php index 856425606f..91dadaaf95 100644 --- a/libraries/error_report.lib.php +++ b/libraries/error_report.lib.php @@ -178,7 +178,24 @@ function PMA_sanitizeUrl($url) function PMA_sendErrorReport($report) { $data_string = json_encode($report); - if (ini_get('allow_url_fopen')) { + if (function_exists('curl_init')) { + $curl_handle = curl_init(SUBMISSION_URL); + if ($curl_handle === false) { + return null; + } + $curl_handle = PMA\libraries\Util::configureCurl($curl_handle); + curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, "POST"); + curl_setopt( + $curl_handle, CURLOPT_HTTPHEADER, + array('Expect:', 'Content-Type: application/json') + ); + curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $data_string); + curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1); + $response = curl_exec($curl_handle); + curl_close($curl_handle); + + return $response; + } else if (ini_get('allow_url_fopen')) { $context = array("http" => array( 'method' => 'POST', @@ -195,26 +212,7 @@ function PMA_sendErrorReport($report) return $response; } - if (!function_exists('curl_init')) { - return null; - } - - $curl_handle = curl_init(SUBMISSION_URL); - if ($curl_handle === false) { - return null; - } - $curl_handle = PMA\libraries\Util::configureCurl($curl_handle); - curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, "POST"); - curl_setopt( - $curl_handle, CURLOPT_HTTPHEADER, - array('Expect:', 'Content-Type: application/json') - ); - curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $data_string); - curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1); - $response = curl_exec($curl_handle); - curl_close($curl_handle); - - return $response; + return null; } /** From 767195e197e1b75609875330602aa203782e8671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 15:04:45 +0200 Subject: [PATCH 035/101] Sanitize MySQL host name before connecting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It can contain p: prefix which we don't want to honor. Signed-off-by: Michal Čihař --- libraries/config/Validator.php | 1 + libraries/core.lib.php | 18 +++++++ .../plugins/auth/AuthenticationCookie.php | 2 +- libraries/replication.inc.php | 2 +- .../core/PMA_sanitizeMySQLHost_test.php | 48 +++++++++++++++++++ 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 test/libraries/core/PMA_sanitizeMySQLHost_test.php diff --git a/libraries/config/Validator.php b/libraries/config/Validator.php index b7973ce9a7..042103172b 100644 --- a/libraries/config/Validator.php +++ b/libraries/config/Validator.php @@ -227,6 +227,7 @@ class Validator ) { // static::testPHPErrorMsg(); $error = null; + $host = PMA_sanitizeMySQLHost($host); if (DatabaseInterface::checkDbExtension('mysqli')) { $socket = empty($socket) || $connect_type == 'tcp' ? null : $socket; diff --git a/libraries/core.lib.php b/libraries/core.lib.php index 093141341f..aed72ffc76 100644 --- a/libraries/core.lib.php +++ b/libraries/core.lib.php @@ -990,3 +990,21 @@ if(! function_exists('hash_equals')) { return ! $ret; } } + +/** + * Sanitizes MySQL hostname + * + * * strips p: prefix + * + * @param string $name User given hostname + * + * @return string + */ +function PMA_sanitizeMySQLHost($name) +{ + if (strtolower(substr($name, 0, 2)) == 'p:') { + return substr($name, 2); + } + + return $name; +} diff --git a/libraries/plugins/auth/AuthenticationCookie.php b/libraries/plugins/auth/AuthenticationCookie.php index eedcb0b9f4..18be5a76b5 100644 --- a/libraries/plugins/auth/AuthenticationCookie.php +++ b/libraries/plugins/auth/AuthenticationCookie.php @@ -326,7 +326,7 @@ class AuthenticationCookie extends AuthenticationPlugin return false; } } - $GLOBALS['pma_auth_server'] = $_REQUEST['pma_servername']; + $GLOBALS['pma_auth_server'] = PMA_sanitizeMySQLHost($_REQUEST['pma_servername']); } PMA_secureSession(); return true; diff --git a/libraries/replication.inc.php b/libraries/replication.inc.php index f4a4cd4aa4..9f2179ba14 100644 --- a/libraries/replication.inc.php +++ b/libraries/replication.inc.php @@ -299,7 +299,7 @@ function PMA_Replication_connectToMaster( // 5th parameter set to true means that it's an auxiliary connection // and we must not go back to login page if it fails - return $GLOBALS['dbi']->connect($user, $password, false, $server, true); + return PMA_DBI_connect($user, $password, false, PMA_sanitizeMySQLHost($server), true); } /** * Fetches position and file of current binary log on master diff --git a/test/libraries/core/PMA_sanitizeMySQLHost_test.php b/test/libraries/core/PMA_sanitizeMySQLHost_test.php new file mode 100644 index 0000000000..1b4404732a --- /dev/null +++ b/test/libraries/core/PMA_sanitizeMySQLHost_test.php @@ -0,0 +1,48 @@ +assertEquals( + $expected, + PMA_sanitizeMySQLHost($host) + ); + } + + /** + * Test data provider + * + * @return array + */ + function provideMySQLHosts() + { + return array( + array('p:foo.bar', 'foo.bar'), + array('bar.baz', 'bar.baz'), + array('P:example.com', 'example.com'), + ); + } + +} From ba072e42dc15123bdd61185ccce85e384ca452b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 15:04:45 +0200 Subject: [PATCH 036/101] Validate serialized data before unserializing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need only strings, integers or arrays, so there is no need to unserialize strings containing any complex types. Signed-off-by: Michal Čihař --- libraries/core.lib.php | 88 +++++++++++++++++++ libraries/tracking.lib.php | 5 +- .../core/PMA_safeUnserialize_test.php | 55 ++++++++++++ 3 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 test/libraries/core/PMA_safeUnserialize_test.php diff --git a/libraries/core.lib.php b/libraries/core.lib.php index aed72ffc76..7aa04f9ebb 100644 --- a/libraries/core.lib.php +++ b/libraries/core.lib.php @@ -1008,3 +1008,91 @@ function PMA_sanitizeMySQLHost($name) return $name; } + +/** + * Safe unserializer wrapper + * + * It does not unserialize data containing objects + * + * @param string $data Data to unserialize + * + * @return mixed + */ +function PMA_safeUnserialize($data) +{ + if (! is_string($data)) { + return null; + } + + /* validate serialized data */ + $length = strlen($data); + $depth = 0; + for ($i = 0; $i < $length; $i++) { + $value = $data[$i]; + + switch ($value) + { + case '}': + /* end of array */ + if ($depth <= 0) { + return null; + } + $depth--; + break; + case 's': + /* string */ + // parse sting length + $strlen = intval($data[$i + 2]); + // string start + $i = strpos($data, ':', $i + 2); + if ($i === false) { + return null; + } + // skip string, quotes and ; + $i += 2 + $strlen + 1; + if ($data[$i] != ';') { + return null; + } + break; + + case 'b': + case 'i': + case 'd': + /* bool, integer or double */ + // skip value to sepearator + $i = strpos($data, ';', $i); + if ($i === false) { + return null; + } + break; + case 'a': + /* array */ + // find array start + $i = strpos($data, '{', $i); + if ($i === false) { + return null; + } + // remember nesting + $depth++; + break; + case 'N': + /* null */ + // skip to end + $i = strpos($data, ';', $i); + if ($i === false) { + return null; + } + break; + default: + /* any other elements are not wanted */ + return null; + } + } + + // check unterminated arrays + if ($depth > 0) { + return null; + } + + return unserialize($data); +} diff --git a/libraries/tracking.lib.php b/libraries/tracking.lib.php index bc478e1c17..7687cc7365 100644 --- a/libraries/tracking.lib.php +++ b/libraries/tracking.lib.php @@ -860,7 +860,10 @@ function PMA_getHtmlForSchemaSnapshot($url_query) ); // Unserialize snapshot - $temp = unserialize($data['schema_snapshot']); + $temp = PMA_safeUnserialize($data['schema_snapshot']); + if ($temp === null) { + $temp = array('COLUMNS' => array(), 'INDEXES' => array()); + } $columns = $temp['COLUMNS']; $indexes = $temp['INDEXES']; $html .= PMA_getHtmlForColumns($columns); diff --git a/test/libraries/core/PMA_safeUnserialize_test.php b/test/libraries/core/PMA_safeUnserialize_test.php new file mode 100644 index 0000000000..f2710c0792 --- /dev/null +++ b/test/libraries/core/PMA_safeUnserialize_test.php @@ -0,0 +1,55 @@ +assertEquals( + $expected, + PMA_safeUnserialize($data) + ); + } + + /** + * Test data provider + * + * @return array + */ + function provideMySQLHosts() + { + return array( + array('s:6:"foobar";', 'foobar'), + array('foobar', null), + array('b:0;', false), + array('O:1:"a":1:{s:5:"value";s:3:"100";}', null), + array('O:8:"stdClass":1:{s:5:"field";O:8:"stdClass":0:{}}', null), + array(serialize(array(1, 2, 3)), array(1, 2, 3)), + array(serialize('string""'), 'string""'), + array(serialize(array('foo' => 'bar')), array('foo' => 'bar')), + array(serialize(array('1', new stdClass(), '2')), null), + ); + } + +} + From bde4ef735b0620f8b11deb21f29a79d9942a98ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 16:40:36 +0200 Subject: [PATCH 037/101] Escape suggested database name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- templates/server/databases/create.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/server/databases/create.phtml b/templates/server/databases/create.phtml index 90355aefd7..a8b71d7f0e 100644 --- a/templates/server/databases/create.phtml +++ b/templates/server/databases/create.phtml @@ -15,7 +15,7 @@ - @@ -33,4 +33,4 @@ - \ No newline at end of file + From 80b03a4f1629957c4b3f22288147e5ed8495856b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 16:47:50 +0200 Subject: [PATCH 038/101] Ensure page number is integer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even if somebody decides to change configuration storage structure. Signed-off-by: Michal Čihař --- libraries/db_designer.lib.php | 2 +- libraries/plugins/export/ExportSql.php | 2 +- libraries/plugins/schema/ExportRelationSchema.php | 2 +- libraries/pmd_common.php | 12 ++++++------ libraries/relation.lib.php | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/db_designer.lib.php b/libraries/db_designer.lib.php index 34e2028d13..bf52111d59 100644 --- a/libraries/db_designer.lib.php +++ b/libraries/db_designer.lib.php @@ -90,7 +90,7 @@ function PMA_getPageIdsAndNames($db) $result = array(); while ($curr_page = $GLOBALS['dbi']->fetchAssoc($page_rs)) { - $result[$curr_page['page_nr']] = $curr_page['page_descr']; + $result[intval($curr_page['page_nr'])] = $curr_page['page_descr']; } return $result; } diff --git a/libraries/plugins/export/ExportSql.php b/libraries/plugins/export/ExportSql.php index 7812c7c732..20a8cfaafb 100644 --- a/libraries/plugins/export/ExportSql.php +++ b/libraries/plugins/export/ExportSql.php @@ -1112,7 +1112,7 @@ class ExportSql extends ExportPlugin $dbNameColumn ) . " = '" . Util::sqlAddSlashes($db) . "'" - . " AND `page_nr` = '" . $page . "'"; + . " AND `page_nr` = '" . intval($page) . "'"; if (!$this->exportData( $cfgRelation['db'], diff --git a/libraries/plugins/schema/ExportRelationSchema.php b/libraries/plugins/schema/ExportRelationSchema.php index 4ca5503487..228af6c655 100644 --- a/libraries/plugins/schema/ExportRelationSchema.php +++ b/libraries/plugins/schema/ExportRelationSchema.php @@ -53,7 +53,7 @@ class ExportRelationSchema */ public function setPageNumber($value) { - $this->pageNumber = $value; + $this->pageNumber = intval($value); } /** diff --git a/libraries/pmd_common.php b/libraries/pmd_common.php index 5b84015bf1..03e018c5cc 100644 --- a/libraries/pmd_common.php +++ b/libraries/pmd_common.php @@ -261,7 +261,7 @@ function PMA_getTablePositions($pg) 1 AS `H` FROM " . PMA\libraries\Util::backquote($cfgRelation['db']) . "." . PMA\libraries\Util::backquote($cfgRelation['table_coords']) . " - WHERE pdf_page_number = " . $pg; + WHERE pdf_page_number = " . intval($pg); $tab_pos = $GLOBALS['dbi']->fetchResult( $query, @@ -290,7 +290,7 @@ function PMA_getPageName($pg) $query = "SELECT `page_descr`" . " FROM " . PMA\libraries\Util::backquote($cfgRelation['db']) . "." . PMA\libraries\Util::backquote($cfgRelation['pdf_pages']) - . " WHERE " . PMA\libraries\Util::backquote('page_nr') . " = " . $pg; + . " WHERE " . PMA\libraries\Util::backquote('page_nr') . " = " . intval($pg); $page_name = $GLOBALS['dbi']->fetchResult( $query, null, @@ -317,7 +317,7 @@ function PMA_deletePage($pg) $query = "DELETE FROM " . PMA\libraries\Util::backquote($cfgRelation['db']) . "." . PMA\libraries\Util::backquote($cfgRelation['table_coords']) - . " WHERE " . PMA\libraries\Util::backquote('pdf_page_number') . " = " . $pg; + . " WHERE " . PMA\libraries\Util::backquote('pdf_page_number') . " = " . intval($pg); $success = PMA_queryAsControlUser( $query, true, PMA\libraries\DatabaseInterface::QUERY_STORE ); @@ -325,7 +325,7 @@ function PMA_deletePage($pg) if ($success) { $query = "DELETE FROM " . PMA\libraries\Util::backquote($cfgRelation['db']) . "." . PMA\libraries\Util::backquote($cfgRelation['pdf_pages']) - . " WHERE " . PMA\libraries\Util::backquote('page_nr') . " = " . $pg; + . " WHERE " . PMA\libraries\Util::backquote('page_nr') . " = " . intval($pg); $success = PMA_queryAsControlUser( $query, true, PMA\libraries\DatabaseInterface::QUERY_STORE ); @@ -364,7 +364,7 @@ function PMA_getDefaultPage($db) ); if (count($default_page_no)) { - return $default_page_no[0]; + return intval($default_page_no[0]); } return -1; } @@ -406,7 +406,7 @@ function PMA_getLoadingPage($db) $page_no = $min_page_no[0]; } } - return $page_no; + return intval($page_no); } /** diff --git a/libraries/relation.lib.php b/libraries/relation.lib.php index 19c21cbdef..e99cd9a56b 100644 --- a/libraries/relation.lib.php +++ b/libraries/relation.lib.php @@ -1665,7 +1665,7 @@ function PMA_REL_renameTable($source_db, $target_db, $source_table, $target_tabl * @param array $cfgRelation Relation configuration * @param string $db database name * - * @return string $pdf_page_number + * @return int $pdf_page_number */ function PMA_REL_createPage($newpage, $cfgRelation, $db) { From 7ef96c5cdc2adc16f4d8530ad90c76715825d471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 17:35:56 +0200 Subject: [PATCH 039/101] Correctly escape MySQL username in queries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/RecentFavoriteTable.php | 4 ++-- libraries/Table.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/RecentFavoriteTable.php b/libraries/RecentFavoriteTable.php index 6d766607fb..6063b75e7f 100644 --- a/libraries/RecentFavoriteTable.php +++ b/libraries/RecentFavoriteTable.php @@ -96,7 +96,7 @@ class RecentFavoriteTable // Read from phpMyAdmin database, if recent tables is not in session $sql_query = " SELECT `tables` FROM " . $this->_getPmaTable() . - " WHERE `username` = '" . $GLOBALS['cfg']['Server']['user'] . "'"; + " WHERE `username` = '" . Util::sqlAddSlashes($GLOBALS['cfg']['Server']['user']) . "'"; $return = array(); $result = PMA_queryAsControlUser($sql_query, false); @@ -119,7 +119,7 @@ class RecentFavoriteTable $username = $GLOBALS['cfg']['Server']['user']; $sql_query = " REPLACE INTO " . $this->_getPmaTable() . " (`username`, `tables`)" . - " VALUES ('" . $username . "', '" + " VALUES ('" . Util::sqlAddSlashes($username) . "', '" . Util::sqlAddSlashes( json_encode($this->_tables) ) . "')"; diff --git a/libraries/Table.php b/libraries/Table.php index 7e4a9addf6..cddb1d9422 100644 --- a/libraries/Table.php +++ b/libraries/Table.php @@ -1494,7 +1494,7 @@ class Table // Read from phpMyAdmin database $sql_query = " SELECT `prefs` FROM " . $pma_table - . " WHERE `username` = '" . $GLOBALS['cfg']['Server']['user'] . "'" + . " WHERE `username` = '" . Util::sqlAddSlashes($GLOBALS['cfg']['Server']['user']) . "'" . " AND `db_name` = '" . Util::sqlAddSlashes($this->_db_name) . "'" . " AND `table_name` = '" . Util::sqlAddSlashes($this->_name) . "'"; @@ -1522,7 +1522,7 @@ class Table $username = $GLOBALS['cfg']['Server']['user']; $sql_query = " REPLACE INTO " . $pma_table . " (username, db_name, table_name, prefs) VALUES ('" - . $username . "', '" . $secureDbName + . Util::sqlAddSlashes($username) . "', '" . $secureDbName . "', '" . Util::sqlAddSlashes($this->_name) . "', '" . Util::sqlAddSlashes(json_encode($this->uiprefs)) . "')"; From 1290f9895bbcda839d0ae0b150114b9d43ab33f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Tue, 12 Jul 2016 20:33:54 +0200 Subject: [PATCH 040/101] Fix merge error in po file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- po/ko.po | 1 - 1 file changed, 1 deletion(-) diff --git a/po/ko.po b/po/ko.po index 0b0ea6b0e4..a36635cc83 100644 --- a/po/ko.po +++ b/po/ko.po @@ -7118,7 +7118,6 @@ msgstr "연관된 테이블" #| "types[/a] for an example." msgid "" "See [doc@authentication-modes]authentication types[/doc] for an example." -<<<<<<< msgstr "[doc@authentication-modes]인증 타입[/doc] 예제를 참조하세요." #: libraries/config/messages.inc.php:755 From 551031da09f461a8cef3f6e5883bd0baf1a872dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 09:37:24 +0200 Subject: [PATCH 041/101] Validate image scaling dimensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure we pass only integers and they are not too big. Signed-off-by: Michal Čihař --- transformation_wrapper.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/transformation_wrapper.php b/transformation_wrapper.php index f55d8f9935..8240a06845 100644 --- a/transformation_wrapper.php +++ b/transformation_wrapper.php @@ -34,9 +34,20 @@ $request_params = array( 'transform_key', 'where_clause' ); +$size_params = array( + 'newHeight', + 'newWidth', +); foreach ($request_params as $one_request_param) { if (isset($_REQUEST[$one_request_param])) { - $GLOBALS[$one_request_param] = $_REQUEST[$one_request_param]; + if (in_array($one_request_param, $size_params)) { + $GLOBALS[$one_request_param] = intval($_REQUEST[$one_request_param]); + if ($GLOBALS[$one_request_param] > 2000) { + $GLOBALS[$one_request_param] = 2000; + } + } else { + $GLOBALS[$one_request_param] = $_REQUEST[$one_request_param]; + } } } From ceeef537488b348a9ec4c485159e7f097f71bea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 09:43:07 +0200 Subject: [PATCH 042/101] Add missing escaping to the export type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/display_export.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/display_export.lib.php b/libraries/display_export.lib.php index 5d14369822..1032a6a239 100644 --- a/libraries/display_export.lib.php +++ b/libraries/display_export.lib.php @@ -250,7 +250,7 @@ function PMA_getOptionsForExportTemplates($export_type) . PMA\libraries\Util::backquote($cfgRelation['export_templates']) . " WHERE `username` = " . "'" . PMA\libraries\Util::sqlAddSlashes($GLOBALS['cfg']['Server']['user']) - . "' AND `export_type` = '" . $export_type . "'" + . "' AND `export_type` = '" . PMA\libraries\Util::sqlAddSlashes($export_type) . "'" . " ORDER BY `template_name`;"; $result = PMA_queryAsControlUser($query); From dd732134f27abc6fc41d4ec52a9e02914ca8fdf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 09:47:09 +0200 Subject: [PATCH 043/101] Do not try to create non existing classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/plugin_interface.lib.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/plugin_interface.lib.php b/libraries/plugin_interface.lib.php index 1d165a1bf3..b9fd1b6512 100644 --- a/libraries/plugin_interface.lib.php +++ b/libraries/plugin_interface.lib.php @@ -37,7 +37,10 @@ function PMA_getPlugin( if (is_file($plugins_dir . $file)) { //include_once $plugins_dir . $file; $fqnClass = 'PMA\\' . str_replace('/', '\\', $plugins_dir) . $class_name; - return new $fqnClass; + // check if class exists, could be caused by skip_import + if (class_exists($fqnClass)) { + return new $fqnClass; + } } return null; From dc52930bbab226ce7b7555c3f8714b3fd31d0499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 09:57:49 +0200 Subject: [PATCH 044/101] Properly handle newlines in SQL comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/plugins/export/ExportSql.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/plugins/export/ExportSql.php b/libraries/plugins/export/ExportSql.php index 20a8cfaafb..769334a766 100644 --- a/libraries/plugins/export/ExportSql.php +++ b/libraries/plugins/export/ExportSql.php @@ -595,7 +595,14 @@ class ExportSql extends ExportPlugin && $GLOBALS['sql_include_comments'] ) { // see https://dev.mysql.com/doc/refman/5.0/en/ansi-diff-comments.html - return '--' . (empty($text) ? '' : ' ') . $text . $GLOBALS['crlf']; + if (empty($text)) { + return '--' . $GLOBALS['crlf']; + } else { + $lines = preg_split("/\\r\\n|\\r|\\n/", $text); + foreach ($lines as $line) { + return '-- ' . $line . $GLOBALS['crlf']; + } + } } else { return ''; } From 7e510e8e92b33493aded0086c0b87d8ed7bdec78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 10:21:24 +0200 Subject: [PATCH 045/101] Properly escape partition removal query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- templates/table/structure/display_structure.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/table/structure/display_structure.phtml b/templates/table/structure/display_structure.phtml index ceece39f02..1cb33919bb 100644 --- a/templates/table/structure/display_structure.phtml +++ b/templates/table/structure/display_structure.phtml @@ -186,7 +186,7 @@ $rownum = 0; $odd_row = true; ?> $tmp_partition_description = $firstPartition->getDescription(); $removeSQL = "ALTER TABLE " . Util::backquote($table) . " REMOVE PARTITIONING"; - $removeUrl = 'sql.php' . $url_query . '&sql_query=' . urldecode($removeSQL); + $removeUrl = 'sql.php' . $url_query . '&sql_query=' . urlencode($removeSQL); echo Template::get('table/structure/display_partitions')->render( array( @@ -222,4 +222,4 @@ $rownum = 0; $odd_row = true; ?> -
\ No newline at end of file +
From 9e3492730ebf6d60dafd0283f605c6ad09f8271a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 10:27:43 +0200 Subject: [PATCH 046/101] Do not use empty MIME type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will turn on content sniffing in browser leading to unwanted results. Signed-off-by: Michal Čihař --- transformation_wrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transformation_wrapper.php b/transformation_wrapper.php index 8240a06845..48ae3a03d8 100644 --- a/transformation_wrapper.php +++ b/transformation_wrapper.php @@ -102,7 +102,7 @@ $response->getHeader()->sendHttpHeaders(); if (isset($ct) && ! empty($ct)) { $mime_type = $ct; } else { - $mime_type = (isset($mime_map[$transform_key]['mimetype']) + $mime_type = (!empty($mime_map[$transform_key]['mimetype']) ? str_replace('_', '/', $mime_map[$transform_key]['mimetype']) : $default_ct) . (isset($mime_options['charset']) ? $mime_options['charset'] : ''); From c3a3531b61bb0c886d4d6838356c32f655a1123c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 10:32:55 +0200 Subject: [PATCH 047/101] Escape HTML markup in transformation wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...in case content type is html. Signed-off-by: Michal Čihař --- transformation_wrapper.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/transformation_wrapper.php b/transformation_wrapper.php index 48ae3a03d8..8a8e3caac7 100644 --- a/transformation_wrapper.php +++ b/transformation_wrapper.php @@ -111,7 +111,11 @@ if (isset($ct) && ! empty($ct)) { PMA_downloadHeader($cn, $mime_type); if (! isset($_REQUEST['resize'])) { - echo $row[$transform_key]; + if (stripos($mime_type, 'html') === false) { + echo $row[$transform_key]; + } else { + echo htmlspecialchars($row[$transform_key]); + } } else { // if image_*__inline.inc.php finds that we can resize, // it sets the resize parameter to jpeg or png From 9f11a0e81198ef39664453de8531f9d627819c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 10:39:45 +0200 Subject: [PATCH 048/101] Add missing escaping in user group queries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/server_user_groups.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/server_user_groups.lib.php b/libraries/server_user_groups.lib.php index 32c85189e2..70368f0531 100644 --- a/libraries/server_user_groups.lib.php +++ b/libraries/server_user_groups.lib.php @@ -351,7 +351,7 @@ function PMA_editUserGroup($userGroup, $new = false) } $tabName = $tabGroupName . '_' . $tab; $allowed = isset($_REQUEST[$tabName]) && $_REQUEST[$tabName] == 'Y'; - $sql_query .= "('" . $userGroup . "', '" . $tabName . "', '" + $sql_query .= "('" . PMA_Util::sqlAddSlashes($userGroup) . "', '" . $tabName . "', '" . ($allowed ? "Y" : "N") . "')"; $first = false; } From cc6853538cec697b67e03fbfef2e5f2c7ebc481f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 10:45:18 +0200 Subject: [PATCH 049/101] Properly escape error input in the message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- .../abs/RegexValidationTransformationsPlugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/plugins/transformations/abs/RegexValidationTransformationsPlugin.php b/libraries/plugins/transformations/abs/RegexValidationTransformationsPlugin.php index 63995e4a9f..caf540395c 100644 --- a/libraries/plugins/transformations/abs/RegexValidationTransformationsPlugin.php +++ b/libraries/plugins/transformations/abs/RegexValidationTransformationsPlugin.php @@ -50,7 +50,7 @@ abstract class RegexValidationTransformationsPlugin extends IOTransformationsPlu $this->success = false; $this->error = sprintf( __('Validation failed for the input string %s.'), - $buffer + htmlspecialchars($buffer) ); } From c3310536b2896a12dab3e0f7715c7e693221de25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 10:48:53 +0200 Subject: [PATCH 050/101] Ensure widht and height are integers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- .../transformations/abs/ImageUploadTransformationsPlugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/plugins/transformations/abs/ImageUploadTransformationsPlugin.php b/libraries/plugins/transformations/abs/ImageUploadTransformationsPlugin.php index a976ff62ac..446381616f 100644 --- a/libraries/plugins/transformations/abs/ImageUploadTransformationsPlugin.php +++ b/libraries/plugins/transformations/abs/ImageUploadTransformationsPlugin.php @@ -82,8 +82,8 @@ abstract class ImageUploadTransformationsPlugin extends IOTransformationsPlugin $src = 'transformation_wrapper.php' . $options['wrapper_link']; } $html .= ''
+            . (isset($options[0]) ? intval($options[0]) : '100') . ''; $html .= '
'; From dc899d8e7584b6bfb104d66668527e9609a80b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 10:51:53 +0200 Subject: [PATCH 051/101] Ensure widht and height are integers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- .../abs/TextImageLinkTransformationsPlugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/plugins/transformations/abs/TextImageLinkTransformationsPlugin.php b/libraries/plugins/transformations/abs/TextImageLinkTransformationsPlugin.php index 26ccf8e038..e768da4236 100644 --- a/libraries/plugins/transformations/abs/TextImageLinkTransformationsPlugin.php +++ b/libraries/plugins/transformations/abs/TextImageLinkTransformationsPlugin.php @@ -54,8 +54,8 @@ abstract class TextImageLinkTransformationsPlugin extends TransformationsPlugin } return '' + . '" border="0" width="' . (isset($options[1]) ? intval($options[1]) : 100) + . '" height="' . (isset($options[2]) ? intval($options[2]) : 50) . '" />' . htmlspecialchars($buffer) . ''; } From e4be768781a6c17ece9d2d3f34f9aa0f3e2e1056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 10:53:51 +0200 Subject: [PATCH 052/101] Ensure widht and height are integers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- .../transformations/abs/InlineTransformationsPlugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/plugins/transformations/abs/InlineTransformationsPlugin.php b/libraries/plugins/transformations/abs/InlineTransformationsPlugin.php index 4e21e88ae8..ac9134a3de 100644 --- a/libraries/plugins/transformations/abs/InlineTransformationsPlugin.php +++ b/libraries/plugins/transformations/abs/InlineTransformationsPlugin.php @@ -53,8 +53,8 @@ abstract class InlineTransformationsPlugin extends TransformationsPlugin . $options['wrapper_link'] . '" rel="noopener noreferrer" target="_blank">[' . htmlspecialchars($buffer) . ']'; } else { return '" + this + ""; + optionsAsString += ""; }); $dropdown.append($(optionsAsString)); } From 42c868b69171f7c6095a55ab3998481cb1674d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 13 Jul 2016 11:31:55 +0200 Subject: [PATCH 054/101] HML encode embedded JSON data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- templates/table/search/zoom_result_form.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/table/search/zoom_result_form.phtml b/templates/table/search/zoom_result_form.phtml index eb52de0057..83dd332acd 100644 --- a/templates/table/search/zoom_result_form.phtml +++ b/templates/table/search/zoom_result_form.phtml @@ -16,7 +16,7 @@