diff --git a/db_operations.php b/db_operations.php index 19744a7075..63d0123bbf 100644 --- a/db_operations.php +++ b/db_operations.php @@ -28,7 +28,7 @@ require_once 'libraries/common.inc.php'; /** * functions implementation for this script */ -require_once 'libraries/check_user_privileges.lib.php'; +require_once 'libraries/check_user_privileges.inc.php'; // add a javascript file for jQuery functions to handle Ajax actions $response = Response::getInstance(); diff --git a/db_routines.php b/db_routines.php index 7e5c3ba093..5740c35aee 100644 --- a/db_routines.php +++ b/db_routines.php @@ -14,7 +14,7 @@ require_once 'libraries/common.inc.php'; /** * Include all other files */ -require_once 'libraries/check_user_privileges.lib.php'; +require_once 'libraries/check_user_privileges.inc.php'; /** * Do the magic diff --git a/index.php b/index.php index b67f5402fa..bb14dce20f 100644 --- a/index.php +++ b/index.php @@ -192,7 +192,7 @@ if ($server > 0 || count($cfg['Servers']) > 1 * Displays the mysql server related links */ if ($server > 0) { - include_once 'libraries/check_user_privileges.lib.php'; + include_once 'libraries/check_user_privileges.inc.php'; // Logout for advanced authentication if ($cfg['Server']['auth_type'] != 'config') { diff --git a/libraries/check_user_privileges.inc.php b/libraries/check_user_privileges.inc.php new file mode 100644 index 0000000000..976776676c --- /dev/null +++ b/libraries/check_user_privileges.inc.php @@ -0,0 +1,29 @@ +isSuperuser(); + +list($username, $hostname) = $GLOBALS['dbi']->getCurrentUserAndHost(); +if ($username === '') { // MySQL is started with --skip-grant-tables + $GLOBALS['is_create_db_priv'] = true; + $GLOBALS['is_reload_priv'] = true; + $GLOBALS['db_to_create'] = ''; + $GLOBALS['dbs_where_create_table_allowed'] = array('*'); + $GLOBALS['dbs_to_test'] = false; + $GLOBALS['db_priv'] = true; + $GLOBALS['col_priv'] = true; + $GLOBALS['table_priv'] = true; + $GLOBALS['proc_priv'] = true; +} else { + CheckUserPrivileges::analyseShowGrant(); +} diff --git a/libraries/check_user_privileges.lib.php b/libraries/check_user_privileges.lib.php deleted file mode 100644 index e2e4afa517..0000000000 --- a/libraries/check_user_privileges.lib.php +++ /dev/null @@ -1,322 +0,0 @@ -isSuperuser(); - -/** - * Extracts details from a result row of a SHOW GRANT query - * - * @param string $row grant row - * - * @return array - */ -function PMA_getItemsFromShowGrantsRow($row) -{ - $db_name_offset = mb_strpos($row, ' ON ') + 4; - $show_grants_dbname = mb_substr( - $row, $db_name_offset, - mb_strpos($row, '.', $db_name_offset) - $db_name_offset - ); - - $show_grants_dbname = PhpMyAdmin\Util::unQuote($show_grants_dbname, '`'); - - $show_grants_str = mb_substr( - $row, - 6, - (mb_strpos($row, ' ON ') - 6) - ); - - // extrac table from GRANT sytax - $tblname_start_offset = mb_strpos($row, '.') + 1; - $tblname_end_offset = mb_strpos($row, ' TO '); - - $show_grants_tblname = mb_substr( - $row, $tblname_start_offset, - $tblname_end_offset - $tblname_start_offset - ); - $show_grants_tblname = PhpMyAdmin\Util::unQuote($show_grants_tblname, '`'); - - return array( - $show_grants_str, - $show_grants_dbname, - $show_grants_tblname - ); -} - -/** - * Check if user has required privileges for - * performing 'Adjust privileges' operations - * - * @param string $show_grants_str string containing grants for user - * @param string $show_grants_dbname name of db extracted from grant string - * @param string $show_grants_tblname name of table extracted from grant string - * - * @return void - */ -function PMA_checkRequiredPrivilegesForAdjust( - $show_grants_str, - $show_grants_dbname, - $show_grants_tblname -) { - // '... ALL PRIVILEGES ON *.* ...' OR '... ALL PRIVILEGES ON `mysql`.* ..' - // OR - // SELECT, INSERT, UPDATE, DELETE .... ON *.* OR `mysql`.* - if ($show_grants_str == 'ALL' - || $show_grants_str == 'ALL PRIVILEGES' - || (mb_strpos( - $show_grants_str, 'SELECT, INSERT, UPDATE, DELETE' - ) !== false) - ) { - if ($show_grants_dbname == '*' - && $show_grants_tblname == '*' - ) { - $GLOBALS['col_priv'] = true; - $GLOBALS['db_priv'] = true; - $GLOBALS['proc_priv'] = true; - $GLOBALS['table_priv'] = true; - - if ($show_grants_str == 'ALL PRIVILEGES' - || $show_grants_str == 'ALL' - ) { - $GLOBALS['is_reload_priv'] = true; - } - } - - // check for specific tables in `mysql` db - // Ex. '... ALL PRIVILEGES on `mysql`.`columns_priv` .. ' - if ($show_grants_dbname == 'mysql') { - switch ($show_grants_tblname) { - case "columns_priv": - $GLOBALS['col_priv'] = true; - break; - case "db": - $GLOBALS['db_priv'] = true; - break; - case "procs_priv": - $GLOBALS['proc_priv'] = true; - break; - case "tables_priv": - $GLOBALS['table_priv'] = true; - break; - case "*": - $GLOBALS['col_priv'] = true; - $GLOBALS['db_priv'] = true; - $GLOBALS['proc_priv'] = true; - $GLOBALS['table_priv'] = true; - break; - default: - } - } - } -} - -/** - * sets privilege information extracted from SHOW GRANTS result - * - * Detection for some CREATE privilege. - * - * Since MySQL 4.1.2, we can easily detect current user's grants using $userlink - * (no control user needed) and we don't have to try any other method for - * detection - * - * @todo fix to get really all privileges, not only explicitly defined for this user - * from MySQL manual: (https://dev.mysql.com/doc/refman/5.0/en/show-grants.html) - * SHOW GRANTS displays only the privileges granted explicitly to the named - * account. Other privileges might be available to the account, but they are not - * displayed. For example, if an anonymous account exists, the named account - * might be able to use its privileges, but SHOW GRANTS will not display them. - * - * @return void - */ -function PMA_analyseShowGrant() -{ - if (PhpMyAdmin\Util::cacheExists('is_create_db_priv')) { - $GLOBALS['is_create_db_priv'] = PhpMyAdmin\Util::cacheGet( - 'is_create_db_priv' - ); - $GLOBALS['is_reload_priv'] = PhpMyAdmin\Util::cacheGet( - 'is_reload_priv' - ); - $GLOBALS['db_to_create'] = PhpMyAdmin\Util::cacheGet( - 'db_to_create' - ); - $GLOBALS['dbs_where_create_table_allowed'] = PhpMyAdmin\Util::cacheGet( - 'dbs_where_create_table_allowed' - ); - $GLOBALS['dbs_to_test'] = PhpMyAdmin\Util::cacheGet( - 'dbs_to_test' - ); - - $GLOBALS['db_priv'] = PhpMyAdmin\Util::cacheGet( - 'db_priv' - ); - $GLOBALS['col_priv'] = PhpMyAdmin\Util::cacheGet( - 'col_priv' - ); - $GLOBALS['table_priv'] = PhpMyAdmin\Util::cacheGet( - 'table_priv' - ); - $GLOBALS['proc_priv'] = PhpMyAdmin\Util::cacheGet( - 'proc_priv' - ); - - return; - } - - // defaults - $GLOBALS['is_create_db_priv'] = false; - $GLOBALS['is_reload_priv'] = false; - $GLOBALS['db_to_create'] = ''; - $GLOBALS['dbs_where_create_table_allowed'] = array(); - $GLOBALS['dbs_to_test'] = $GLOBALS['dbi']->getSystemSchemas(); - $GLOBALS['proc_priv'] = false; - $GLOBALS['db_priv'] = false; - $GLOBALS['col_priv'] = false; - $GLOBALS['table_priv'] = false; - - $rs_usr = $GLOBALS['dbi']->tryQuery('SHOW GRANTS'); - - if (! $rs_usr) { - return; - } - - $re0 = '(^|(\\\\\\\\)+|[^\\\\])'; // non-escaped wildcards - $re1 = '(^|[^\\\\])(\\\)+'; // escaped wildcards - - while ($row = $GLOBALS['dbi']->fetchRow($rs_usr)) { - list( - $show_grants_str, - $show_grants_dbname, - $show_grants_tblname - ) = PMA_getItemsFromShowGrantsRow($row[0]); - - if ($show_grants_dbname == '*') { - if ($show_grants_str != 'USAGE') { - $GLOBALS['dbs_to_test'] = false; - } - } elseif ($GLOBALS['dbs_to_test'] !== false) { - $GLOBALS['dbs_to_test'][] = $show_grants_dbname; - } - - if ( - mb_strpos($show_grants_str,'RELOAD') !== false - ) { - $GLOBALS['is_reload_priv'] = true; - } - - // check for the required privileges for adjust - PMA_checkRequiredPrivilegesForAdjust( - $show_grants_str, - $show_grants_dbname, - $show_grants_tblname - ); - - /** - * @todo if we find CREATE VIEW but not CREATE, do not offer - * the create database dialog box - */ - if ($show_grants_str == 'ALL' - || $show_grants_str == 'ALL PRIVILEGES' - || $show_grants_str == 'CREATE' - || strpos($show_grants_str, 'CREATE,') !== false - ) { - if ($show_grants_dbname == '*') { - // a global CREATE privilege - $GLOBALS['is_create_db_priv'] = true; - $GLOBALS['is_reload_priv'] = true; - $GLOBALS['db_to_create'] = ''; - $GLOBALS['dbs_where_create_table_allowed'][] = '*'; - // @todo we should not break here, cause GRANT ALL *.* - // could be revoked by a later rule like GRANT SELECT ON db.* - break; - } else { - // this array may contain wildcards - $GLOBALS['dbs_where_create_table_allowed'][] = $show_grants_dbname; - - $dbname_to_test = PhpMyAdmin\Util::backquote($show_grants_dbname); - - if ($GLOBALS['is_create_db_priv']) { - // no need for any more tests if we already know this - continue; - } - - // does this db exist? - if ((preg_match('/' . $re0 . '%|_/', $show_grants_dbname) - && ! preg_match('/\\\\%|\\\\_/', $show_grants_dbname)) - || (! $GLOBALS['dbi']->tryQuery( - 'USE ' . preg_replace( - '/' . $re1 . '(%|_)/', '\\1\\3', $dbname_to_test - ) - ) - && mb_substr($GLOBALS['dbi']->getError(), 1, 4) != 1044) - ) { - /** - * Do not handle the underscore wildcard - * (this case must be rare anyway) - */ - $GLOBALS['db_to_create'] = preg_replace( - '/' . $re0 . '%/', '\\1', - $show_grants_dbname - ); - $GLOBALS['db_to_create'] = preg_replace( - '/' . $re1 . '(%|_)/', '\\1\\3', - $GLOBALS['db_to_create'] - ); - $GLOBALS['is_create_db_priv'] = true; - - /** - * @todo collect $GLOBALS['db_to_create'] into an array, - * to display a drop-down in the "Create database" dialog - */ - // we don't break, we want all possible databases - //break; - } // end if - } // end elseif - } // end if - - } // end while - - $GLOBALS['dbi']->freeResult($rs_usr); - - // must also cacheUnset() them in - // PhpMyAdmin\Plugins\Auth\AuthenticationCookie - PhpMyAdmin\Util::cacheSet('is_create_db_priv', $GLOBALS['is_create_db_priv']); - PhpMyAdmin\Util::cacheSet('is_reload_priv', $GLOBALS['is_reload_priv']); - PhpMyAdmin\Util::cacheSet('db_to_create', $GLOBALS['db_to_create']); - PhpMyAdmin\Util::cacheSet( - 'dbs_where_create_table_allowed', - $GLOBALS['dbs_where_create_table_allowed'] - ); - PhpMyAdmin\Util::cacheSet('dbs_to_test', $GLOBALS['dbs_to_test']); - - PhpMyAdmin\Util::cacheSet('proc_priv', $GLOBALS['proc_priv']); - PhpMyAdmin\Util::cacheSet('table_priv', $GLOBALS['table_priv']); - PhpMyAdmin\Util::cacheSet('col_priv', $GLOBALS['col_priv']); - PhpMyAdmin\Util::cacheSet('db_priv', $GLOBALS['db_priv']); -} // end function - -list($username, $hostname) = $GLOBALS['dbi']->getCurrentUserAndHost(); -if ($username === '') { // MySQL is started with --skip-grant-tables - $GLOBALS['is_create_db_priv'] = true; - $GLOBALS['is_reload_priv'] = true; - $GLOBALS['db_to_create'] = ''; - $GLOBALS['dbs_where_create_table_allowed'] = array('*'); - $GLOBALS['dbs_to_test'] = false; - $GLOBALS['db_priv'] = true; - $GLOBALS['col_priv'] = true; - $GLOBALS['table_priv'] = true; - $GLOBALS['proc_priv'] = true; -} else { - PMA_analyseShowGrant(); -} diff --git a/libraries/classes/CheckUserPrivileges.php b/libraries/classes/CheckUserPrivileges.php new file mode 100644 index 0000000000..732e892f47 --- /dev/null +++ b/libraries/classes/CheckUserPrivileges.php @@ -0,0 +1,310 @@ +getSystemSchemas(); + $GLOBALS['proc_priv'] = false; + $GLOBALS['db_priv'] = false; + $GLOBALS['col_priv'] = false; + $GLOBALS['table_priv'] = false; + + $rs_usr = $GLOBALS['dbi']->tryQuery('SHOW GRANTS'); + + if (! $rs_usr) { + return; + } + + $re0 = '(^|(\\\\\\\\)+|[^\\\\])'; // non-escaped wildcards + $re1 = '(^|[^\\\\])(\\\)+'; // escaped wildcards + + while ($row = $GLOBALS['dbi']->fetchRow($rs_usr)) { + list( + $show_grants_str, + $show_grants_dbname, + $show_grants_tblname + ) = self::getItemsFromShowGrantsRow($row[0]); + + if ($show_grants_dbname == '*') { + if ($show_grants_str != 'USAGE') { + $GLOBALS['dbs_to_test'] = false; + } + } elseif ($GLOBALS['dbs_to_test'] !== false) { + $GLOBALS['dbs_to_test'][] = $show_grants_dbname; + } + + if ( + mb_strpos($show_grants_str,'RELOAD') !== false + ) { + $GLOBALS['is_reload_priv'] = true; + } + + // check for the required privileges for adjust + self::checkRequiredPrivilegesForAdjust( + $show_grants_str, + $show_grants_dbname, + $show_grants_tblname + ); + + /** + * @todo if we find CREATE VIEW but not CREATE, do not offer + * the create database dialog box + */ + if ($show_grants_str == 'ALL' + || $show_grants_str == 'ALL PRIVILEGES' + || $show_grants_str == 'CREATE' + || strpos($show_grants_str, 'CREATE,') !== false + ) { + if ($show_grants_dbname == '*') { + // a global CREATE privilege + $GLOBALS['is_create_db_priv'] = true; + $GLOBALS['is_reload_priv'] = true; + $GLOBALS['db_to_create'] = ''; + $GLOBALS['dbs_where_create_table_allowed'][] = '*'; + // @todo we should not break here, cause GRANT ALL *.* + // could be revoked by a later rule like GRANT SELECT ON db.* + break; + } else { + // this array may contain wildcards + $GLOBALS['dbs_where_create_table_allowed'][] = $show_grants_dbname; + + $dbname_to_test = Util::backquote($show_grants_dbname); + + if ($GLOBALS['is_create_db_priv']) { + // no need for any more tests if we already know this + continue; + } + + // does this db exist? + if ((preg_match('/' . $re0 . '%|_/', $show_grants_dbname) + && ! preg_match('/\\\\%|\\\\_/', $show_grants_dbname)) + || (! $GLOBALS['dbi']->tryQuery( + 'USE ' . preg_replace( + '/' . $re1 . '(%|_)/', '\\1\\3', $dbname_to_test + ) + ) + && mb_substr($GLOBALS['dbi']->getError(), 1, 4) != 1044) + ) { + /** + * Do not handle the underscore wildcard + * (this case must be rare anyway) + */ + $GLOBALS['db_to_create'] = preg_replace( + '/' . $re0 . '%/', '\\1', + $show_grants_dbname + ); + $GLOBALS['db_to_create'] = preg_replace( + '/' . $re1 . '(%|_)/', '\\1\\3', + $GLOBALS['db_to_create'] + ); + $GLOBALS['is_create_db_priv'] = true; + + /** + * @todo collect $GLOBALS['db_to_create'] into an array, + * to display a drop-down in the "Create database" dialog + */ + // we don't break, we want all possible databases + //break; + } // end if + } // end elseif + } // end if + + } // end while + + $GLOBALS['dbi']->freeResult($rs_usr); + + // must also cacheUnset() them in + // PhpMyAdmin\Plugins\Auth\AuthenticationCookie + Util::cacheSet('is_create_db_priv', $GLOBALS['is_create_db_priv']); + Util::cacheSet('is_reload_priv', $GLOBALS['is_reload_priv']); + Util::cacheSet('db_to_create', $GLOBALS['db_to_create']); + Util::cacheSet( + 'dbs_where_create_table_allowed', + $GLOBALS['dbs_where_create_table_allowed'] + ); + Util::cacheSet('dbs_to_test', $GLOBALS['dbs_to_test']); + + Util::cacheSet('proc_priv', $GLOBALS['proc_priv']); + Util::cacheSet('table_priv', $GLOBALS['table_priv']); + Util::cacheSet('col_priv', $GLOBALS['col_priv']); + Util::cacheSet('db_priv', $GLOBALS['db_priv']); + } // end function +} diff --git a/libraries/classes/Controllers/Server/ServerDatabasesController.php b/libraries/classes/Controllers/Server/ServerDatabasesController.php index 456b29fbae..97f6fd7ffd 100644 --- a/libraries/classes/Controllers/Server/ServerDatabasesController.php +++ b/libraries/classes/Controllers/Server/ServerDatabasesController.php @@ -57,7 +57,7 @@ class ServerDatabasesController extends Controller */ public function indexAction() { - include_once 'libraries/check_user_privileges.lib.php'; + include_once 'libraries/check_user_privileges.inc.php'; $response = Response::getInstance(); diff --git a/libraries/classes/Controllers/Table/TableStructureController.php b/libraries/classes/Controllers/Table/TableStructureController.php index 95438221df..e5110a78ad 100644 --- a/libraries/classes/Controllers/Table/TableStructureController.php +++ b/libraries/classes/Controllers/Table/TableStructureController.php @@ -112,7 +112,7 @@ class TableStructureController extends TableController /** * Function implementations for this script */ - include_once 'libraries/check_user_privileges.lib.php'; + include_once 'libraries/check_user_privileges.inc.php'; $this->response->getHeader()->getScripts()->addFiles( array( @@ -512,7 +512,7 @@ class TableStructureController extends TableController /** * Form for changing properties. */ - include_once 'libraries/check_user_privileges.lib.php'; + include_once 'libraries/check_user_privileges.inc.php'; include 'libraries/tbl_columns_definition_form.inc.php'; } diff --git a/libraries/classes/Display/CreateTable.php b/libraries/classes/Display/CreateTable.php index 649083b44b..5114d6292c 100644 --- a/libraries/classes/Display/CreateTable.php +++ b/libraries/classes/Display/CreateTable.php @@ -28,7 +28,7 @@ namespace PhpMyAdmin\Display; use PhpMyAdmin\Template; -require_once './libraries/check_user_privileges.lib.php'; +require_once './libraries/check_user_privileges.inc.php'; /** * PhpMyAdmin\Display\CreateTable class diff --git a/libraries/classes/Import.php b/libraries/classes/Import.php index fad14cdf00..579836a956 100644 --- a/libraries/classes/Import.php +++ b/libraries/classes/Import.php @@ -24,7 +24,7 @@ use PhpMyAdmin\Util; * We need to know something about user */ $GLOBALS['cfg']['Server']['DisableIS'] = false; -require_once './libraries/check_user_privileges.lib.php'; +require_once './libraries/check_user_privileges.inc.php'; /** * PhpMyAdmin\Import class diff --git a/libraries/classes/ListDatabase.php b/libraries/classes/ListDatabase.php index dc2d36b2ca..1cf8520ed8 100644 --- a/libraries/classes/ListDatabase.php +++ b/libraries/classes/ListDatabase.php @@ -10,7 +10,7 @@ namespace PhpMyAdmin; use PhpMyAdmin\ListAbstract; use PhpMyAdmin\Util; -require_once './libraries/check_user_privileges.lib.php'; +require_once './libraries/check_user_privileges.inc.php'; /** * handles database lists diff --git a/libraries/classes/Navigation/NavigationTree.php b/libraries/classes/Navigation/NavigationTree.php index e1aa71fb7d..3bd55539af 100644 --- a/libraries/classes/Navigation/NavigationTree.php +++ b/libraries/classes/Navigation/NavigationTree.php @@ -17,7 +17,7 @@ use PhpMyAdmin\Response; use PhpMyAdmin\Util; use PhpMyAdmin\Url; -require_once 'libraries/check_user_privileges.lib.php'; +require_once 'libraries/check_user_privileges.inc.php'; /** * Displays a collapsible of database objects in the navigation frame diff --git a/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php b/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php index d5a08d9a85..fd6859a839 100644 --- a/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php +++ b/libraries/classes/Navigation/Nodes/NodeDatabaseContainer.php @@ -10,7 +10,7 @@ namespace PhpMyAdmin\Navigation\Nodes; use PhpMyAdmin\Navigation\NodeFactory; use PhpMyAdmin\Util; -require_once './libraries/check_user_privileges.lib.php'; +require_once './libraries/check_user_privileges.inc.php'; /** * Represents a container for database nodes in the navigation tree diff --git a/server_privileges.php b/server_privileges.php index 767a2b21f8..7643365c08 100644 --- a/server_privileges.php +++ b/server_privileges.php @@ -22,7 +22,7 @@ require_once 'libraries/common.inc.php'; /** * functions implementation for this script */ -require_once 'libraries/check_user_privileges.lib.php'; +require_once 'libraries/check_user_privileges.inc.php'; $cfgRelation = Relation::getRelationsParam(); diff --git a/sql.php b/sql.php index 685dc5e2ec..7867577f52 100644 --- a/sql.php +++ b/sql.php @@ -17,7 +17,7 @@ use PhpMyAdmin\Util; * Gets some core libraries */ require_once 'libraries/common.inc.php'; -require_once 'libraries/check_user_privileges.lib.php'; +require_once 'libraries/check_user_privileges.inc.php'; PageSettings::showGroup('Browse'); diff --git a/tbl_operations.php b/tbl_operations.php index 9738fb262d..36f6868239 100644 --- a/tbl_operations.php +++ b/tbl_operations.php @@ -22,7 +22,7 @@ require_once 'libraries/common.inc.php'; /** * functions implementation for this script */ -require_once 'libraries/check_user_privileges.lib.php'; +require_once 'libraries/check_user_privileges.inc.php'; $pma_table = new Table($GLOBALS['table'], $GLOBALS['db']); diff --git a/test/libraries/PMA_check_user_privileges_test.php b/test/classes/CheckUserPrivilegesTest.php similarity index 86% rename from test/libraries/PMA_check_user_privileges_test.php rename to test/classes/CheckUserPrivilegesTest.php index 0c6d827ce8..d7bc41cbfb 100644 --- a/test/libraries/PMA_check_user_privileges_test.php +++ b/test/classes/CheckUserPrivilegesTest.php @@ -1,27 +1,27 @@