diff --git a/db_operations.php b/db_operations.php index 7099be344e..12b2e1d5d3 100644 --- a/db_operations.php +++ b/db_operations.php @@ -21,6 +21,7 @@ require_once 'libraries/mysql_charsets.inc.php'; /** * functions implementation for this script */ +require_once 'libraries/check_user_privileges.lib.php'; require_once 'libraries/operations.lib.php'; // add a javascript file for jQuery functions to handle Ajax actions diff --git a/db_routines.php b/db_routines.php index c273b7b291..be7791c649 100644 --- a/db_routines.php +++ b/db_routines.php @@ -16,6 +16,7 @@ require_once 'libraries/mysql_charsets.inc.php'; /** * Include all other files */ +require_once 'libraries/check_user_privileges.lib.php'; require_once 'libraries/rte/rte_routines.lib.php'; /** diff --git a/doc/faq.rst b/doc/faq.rst index 48649158d9..5909f6807f 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -2065,6 +2065,13 @@ Notes: *column-related privileges* for the columns inside the table are also adjusted to the table's new name. +* While adjusting privileges, the user performing the operation **must** have the following + privileges: + + * SELECT, INSERT, UPDATE, DELETE privileges on following tables: + `mysql`.`db`, `mysql`.`columns_priv`, `mysql`.`tables_priv`, `mysql`.`procs_priv` + * FLUSH privilege (GLOBAL) + Thus, if you want to replicate the database/table/column/procedure as it is while renaming/copying/moving these objects, make sure you have checked this option. diff --git a/libraries/check_user_privileges.lib.php b/libraries/check_user_privileges.lib.php index aa118617e2..d03bb34c31 100644 --- a/libraries/check_user_privileges.lib.php +++ b/libraries/check_user_privileges.lib.php @@ -14,6 +14,208 @@ if (! defined('PHPMYADMIN')) { */ $GLOBALS['is_superuser'] = $GLOBALS['dbi']->isSuperuser(); +/** + * Check if user has required privileges for + * performing 'FLUSH PRIVILEGES' operation + * + * @return void + */ +function PMA_checkRequiredPrivilegesForFlushing() +{ + + $res = $GLOBALS['dbi']->tryQuery( + 'FLUSH PRIVILEGES' + ); + + // Save the value + $GLOBALS['flush_priv'] = $res; +} + +/** + * Check if user has required privileges for + * performing 'Adjust Privileges' operations + * + * @return void + */ +function PMA_checkRequiredPrivilgesForAdjust() +{ + $privs_available = true; + // FOR DB PRIVS + $select_privs_available = $GLOBALS['dbi']->tryQuery( + 'SELECT * FROM `mysql`.`db` LIMIT 1' + ); + + $privs_available = $select_privs_available && $privs_available; + + if ($privs_available) { + $delete_privs_available = $GLOBALS['dbi']->tryQuery( + 'DELETE FROM `mysql`.`db` WHERE `host` = "" AND ' + . '`Db` = "" AND `User` = "" LIMIT 1;' + ); + $privs_available = $delete_privs_available && $privs_available; + } + + if ($privs_available) { + $insert_privs_available = $GLOBALS['dbi']->tryQuery( + 'INSERT INTO `mysql`.`db`(`host`, `Db`, `User`) VALUES("pma_test_host", ' + . '"mysql", "pma_test_user");' + ); + // If successful test insert, delete the test row + if ($insert_privs_available) { + $GLOBALS['dbi']->tryQuery( + 'DELETE FROM `mysql`.`db` WHERE host = "pma_test_host" AND ' + . 'Db = "mysql" AND User = "pma_test_user" LIMIT 1;' + ); + } + $privs_available = $insert_privs_available && $privs_available; + } + + if ($privs_available) { + $update_privs_available = $GLOBALS['dbi']->tryQuery( + 'UPDATE `mysql`.`db` SET `host` = "" WHERE `host` = "" AND ' + . '`Db` = "" AND `User` = "" LIMIT 1;' + ); + $privs_available = $update_privs_available && $privs_available; + } + // save the value + $GLOBALS['db_priv'] = $privs_available; + // reset the value + $privs_available = true; + + // FOR COLUMNS_PRIV + $select_privs_available = $GLOBALS['dbi']->tryQuery( + 'SELECT * FROM `mysql`.`columns_priv` LIMIT 1' + ); + + $privs_available = $select_privs_available && $privs_available; + + if ($privs_available) { + $delete_privs_available = $GLOBALS['dbi']->tryQuery( + 'DELETE FROM `mysql`.`columns_priv` WHERE `host` = "" AND ' + . '`Db` = "" AND `User` = "" LIMIT 1;' + ); + $privs_available = $delete_privs_available && $privs_available; + } + + if ($privs_available) { + $insert_privs_available = $GLOBALS['dbi']->tryQuery( + 'INSERT INTO `mysql`.`columns_priv`(`host`, `Db`, `User`, `Table_name`,' + . ' `Column_name`) VALUES("pma_test_host", ' + . '"mysql", "pma_test_user", "", "")' + ); + // If successful test insert, delete the test row + if ($insert_privs_available) { + $GLOBALS['dbi']->tryQuery( + 'DELETE FROM `mysql`.`columns_priv` WHERE host = "pma_test_host" AND ' + . 'Db = "mysql" AND User = "pma_test_user" AND Table_name = ""' + . ' AND Column_name = "" LIMIT 1;' + ); + } + $privs_available = $insert_privs_available && $privs_available; + } + + if ($privs_available) { + $update_privs_available = $GLOBALS['dbi']->tryQuery( + 'UPDATE `mysql`.`columns_priv` SET `host` = "" WHERE `host` = "" AND ' + . '`Db` = "" AND `User` = "" AND Column_name = "" AND Table_name = "" LIMIT 1;' + ); + $privs_available = $update_privs_available && $privs_available; + + } + // Save the value + $GLOBALS['col_priv'] = $privs_available; + // Reset the value + $privs_available = true; + + // FOR TABLES_PRIV + $select_privs_available = $GLOBALS['dbi']->tryQuery( + 'SELECT * FROM `mysql`.`tables_priv` LIMIT 1' + ); + + $privs_available = $select_privs_available && $privs_available; + + if ($privs_available) { + $delete_privs_available = $GLOBALS['dbi']->tryQuery( + 'DELETE FROM `mysql`.`tables_priv` WHERE `host` = "" AND ' + . '`Db` = "" AND `User` = "" AND Table_name = "" LIMIT 1;' + ); + $privs_available = $delete_privs_available && $privs_available; + } + + if ($privs_available) { + $insert_privs_available = $GLOBALS['dbi']->tryQuery( + 'INSERT INTO `mysql`.`tables_priv`(`host`, `Db`, `User`, `Table_name`' + . ') VALUES("pma_test_host", ' + . '"mysql", "pma_test_user", "")' + ); + // If successful test insert, delete the test row + if ($insert_privs_available) { + $GLOBALS['dbi']->tryQuery( + 'DELETE FROM `mysql`.`tables_priv` WHERE host = "pma_test_host" AND ' + . 'Db = "mysql" AND User = "pma_test_user" AND Table_name = "" LIMIT 1;' + ); + } + $privs_available = $insert_privs_available && $privs_available; + } + + if ($privs_available) { + $update_privs_available = $GLOBALS['dbi']->tryQuery( + 'UPDATE `mysql`.`tables_priv` SET `host` = "" WHERE `host` = "" AND ' + . '`Db` = "" AND `User` = "" AND Table_name = "" LIMIT 1;' + ); + $privs_available = $update_privs_available && $privs_available; + + } + // Save the value + $GLOBALS['table_priv'] = $privs_available; + // Reset the value + $privs_available = true; + + // FOR PROCS_PRIV + $select_privs_available = $GLOBALS['dbi']->tryQuery( + 'SELECT * FROM `mysql`.`procs_priv` LIMIT 1' + ); + + $privs_available = $select_privs_available && $privs_available; + + if ($privs_available) { + $delete_privs_available = $GLOBALS['dbi']->tryQuery( + 'DELETE FROM `mysql`.`procs_priv` WHERE `host` = "" AND ' + . '`Db` = "" AND `User` = "" AND `Routine_name` = ""' + . ' AND `Routine_type` = "" LIMIT 1;' + ); + $privs_available = $delete_privs_available && $privs_available; + } + + if ($privs_available) { + $insert_privs_available = $GLOBALS['dbi']->tryQuery( + 'INSERT INTO `mysql`.`procs_priv`(`host`, `Db`, `User`, `Routine_name`,' + . ' `Routine_type`) VALUES("pma_test_host", ' + . '"mysql", "pma_test_user", "", "PROCEDURE")' + ); + // If successful test insert, delete the test row + if ($insert_privs_available) { + $GLOBALS['dbi']->tryQuery( + 'DELETE FROM `mysql`.`procs_priv` WHERE `host` = "pma_test_host" AND ' + . '`Db` = "mysql" AND `User` = "pma_test_user" AND `Routine_name` = ""' + . ' AND `Routine_type` = "PROCEDURE" LIMIT 1;' + ); + } + $privs_available = $insert_privs_available && $privs_available; + } + + if ($privs_available) { + $update_privs_available = $GLOBALS['dbi']->tryQuery( + 'UPDATE `mysql`.`procs_priv` SET `host` = "" WHERE `host` = "" AND ' + . '`Db` = "" AND `User` = "" AND `Routine_name` = "" LIMIT 1;' + ); + $privs_available = $update_privs_available && $privs_available; + } + // Save the value + $GLOBALS['proc_priv'] = $privs_available; + +} + /** * sets privilege information extracted from SHOW GRANTS result * @@ -185,6 +387,13 @@ if (!PMA_DRIZZLE) { } else { PMA_analyseShowGrant(); } + + // Check if privileges to 'mysql'.col_privs, 'mysql'.db, + // 'mysql'.table_privs, 'mysql'.proc_privs and privileges for + // flushing the privileges are available + PMA_checkRequiredPrivilegesForFlushing(); + PMA_checkRequiredPrivilgesForAdjust(); + } else { // todo: for simple_user_policy only database with user's login can be created // (unless logged in as root) diff --git a/libraries/dbi/DBIDummy.class.php b/libraries/dbi/DBIDummy.class.php index 10323afe6d..7ac4c44155 100644 --- a/libraries/dbi/DBIDummy.class.php +++ b/libraries/dbi/DBIDummy.class.php @@ -559,6 +559,26 @@ $GLOBALS['dummy_queries'] = array( array( 'query' => "SHOW EVENTS FROM `default`", 'result' => array() + ), + array( + 'query' => "FLUSH PRIVILEGES", + 'result' => array() + ), + array( + 'query' => "SELECT * FROM `mysql`.`db` LIMIT 1", + 'result' => array() + ), + array( + 'query' => "SELECT * FROM `mysql`.`columns_priv` LIMIT 1", + 'result' => array() + ), + array( + 'query' => "SELECT * FROM `mysql`.`tables_priv` LIMIT 1", + 'result' => array() + ), + array( + 'query' => "SELECT * FROM `mysql`.`procs_priv` LIMIT 1", + 'result' => array() ) ); /** diff --git a/libraries/operations.lib.php b/libraries/operations.lib.php index 9b938e3c48..306e770755 100644 --- a/libraries/operations.lib.php +++ b/libraries/operations.lib.php @@ -77,11 +77,26 @@ function PMA_getHtmlForRenameDatabase($db) $html_output .= ''; - $html_output .= ''; + + if (isset($GLOBALS['db_priv']) && $GLOBALS['db_priv'] + && isset($GLOBALS['flush_priv']) && $GLOBALS['flush_priv'] + ) { + $html_output .= ''; + } else { + $html_output .= ''; + } + $html_output .= '
'; + . __('Adjust Privileges') . PMA_Util::showDocu('faq', 'faq6-39') + . '
'; + $html_output .= '' . '' . '
' @@ -205,11 +220,25 @@ function PMA_getHtmlForCopyDatabase($db) $html_output .= '
'; $html_output .= '
'; - $html_output .= ''; + + if (isset($GLOBALS['db_priv']) && $GLOBALS['db_priv'] + && isset($GLOBALS['flush_priv']) && $GLOBALS['flush_priv'] + ) { + $html_output .= ''; + } else { + $html_output .= ''; + } $html_output .= '
'; + $html_output .= '' . '
' - . '' - . '
'; + + if (isset($GLOBALS['table_priv']) && $GLOBALS['table_priv'] + && isset($GLOBALS['flush_priv']) && $GLOBALS['flush_priv'] + ) { + $html_output .= ''; + } else { + $html_output .= ''; + } + + $html_output .= '
' . '
'; @@ -868,10 +911,23 @@ function PMA_getHtmlForRenameTable() . 'value="' . htmlspecialchars($GLOBALS['table']) . '" required="required" />' . '' - . '' - . '' - . '