diff options
Diffstat (limited to 'srcs/phpmyadmin/libraries/classes/Server/Privileges.php')
| -rw-r--r-- | srcs/phpmyadmin/libraries/classes/Server/Privileges.php | 5649 |
1 files changed, 5649 insertions, 0 deletions
diff --git a/srcs/phpmyadmin/libraries/classes/Server/Privileges.php b/srcs/phpmyadmin/libraries/classes/Server/Privileges.php new file mode 100644 index 0000000..1e50fbb --- /dev/null +++ b/srcs/phpmyadmin/libraries/classes/Server/Privileges.php @@ -0,0 +1,5649 @@ +<?php +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * set of functions with the Privileges section in pma + * + * @package PhpMyAdmin + */ +declare(strict_types=1); + +namespace PhpMyAdmin\Server; + +use PhpMyAdmin\Core; +use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Display\ChangePassword; +use PhpMyAdmin\Message; +use PhpMyAdmin\Relation; +use PhpMyAdmin\RelationCleanup; +use PhpMyAdmin\Response; +use PhpMyAdmin\Template; +use PhpMyAdmin\Url; +use PhpMyAdmin\Util; + +/** + * Privileges class + * + * @package PhpMyAdmin + */ +class Privileges +{ + /** + * @var Template + */ + public $template; + + /** + * @var RelationCleanup + */ + private $relationCleanup; + + /** + * @var DatabaseInterface + */ + public $dbi; + + /** + * @var Relation + */ + public $relation; + + /** + * Privileges constructor. + * + * @param Template $template Template object + * @param DatabaseInterface $dbi DatabaseInterface object + * @param Relation $relation Relation object + * @param RelationCleanup $relationCleanup RelationCleanup object + */ + public function __construct( + Template $template, + $dbi, + Relation $relation, + RelationCleanup $relationCleanup + ) { + $this->template = $template; + $this->dbi = $dbi; + $this->relation = $relation; + $this->relationCleanup = $relationCleanup; + } + + /** + * Get Html for User Group Dialog + * + * @param string $username username + * @param bool $is_menuswork Is menuswork set in configuration + * + * @return string html + */ + public function getHtmlForUserGroupDialog($username, $is_menuswork) + { + $html = ''; + if (! empty($_GET['edit_user_group_dialog']) && $is_menuswork) { + $dialog = $this->getHtmlToChooseUserGroup($username); + $response = Response::getInstance(); + if ($response->isAjax()) { + $response->addJSON('message', $dialog); + exit; + } else { + $html .= $dialog; + } + } + + return $html; + } + + /** + * Escapes wildcard in a database+table specification + * before using it in a GRANT statement. + * + * Escaping a wildcard character in a GRANT is only accepted at the global + * or database level, not at table level; this is why I remove + * the escaping character. Internally, in mysql.tables_priv.Db there are + * no escaping (for example test_db) but in mysql.db you'll see test\_db + * for a db-specific privilege. + * + * @param string $dbname Database name + * @param string $tablename Table name + * + * @return string the escaped (if necessary) database.table + */ + public function wildcardEscapeForGrant($dbname, $tablename) + { + if (strlen($dbname) === 0) { + $db_and_table = '*.*'; + } else { + if (strlen($tablename) > 0) { + $db_and_table = Util::backquote( + Util::unescapeMysqlWildcards($dbname) + ) + . '.' . Util::backquote($tablename); + } else { + $db_and_table = Util::backquote($dbname) . '.*'; + } + } + return $db_and_table; + } + + /** + * Generates a condition on the user name + * + * @param string $initial the user's initial + * + * @return string the generated condition + */ + public function rangeOfUsers($initial = '') + { + // strtolower() is used because the User field + // might be BINARY, so LIKE would be case sensitive + if ($initial === null || $initial === '') { + return ''; + } + + $ret = " WHERE `User` LIKE '" + . $this->dbi->escapeString($initial) . "%'" + . " OR `User` LIKE '" + . $this->dbi->escapeString(mb_strtolower($initial)) + . "%'"; + return $ret; + } // end function + + /** + * Formats privilege name for a display + * + * @param array $privilege Privilege information + * @param boolean $html Whether to use HTML + * + * @return string + */ + public function formatPrivilege(array $privilege, $html) + { + if ($html) { + return '<dfn title="' . $privilege[2] . '">' + . $privilege[1] . '</dfn>'; + } + + return $privilege[1]; + } + + /** + * Parses privileges into an array, it modifies the array + * + * @param array $row Results row from + * + * @return void + */ + public function fillInTablePrivileges(array &$row) + { + $row1 = $this->dbi->fetchSingleRow( + 'SHOW COLUMNS FROM `mysql`.`tables_priv` LIKE \'Table_priv\';', + 'ASSOC' + ); + // note: in MySQL 5.0.3 we get "Create View', 'Show view'; + // the View for Create is spelled with uppercase V + // the view for Show is spelled with lowercase v + // and there is a space between the words + + $av_grants = explode( + '\',\'', + mb_substr( + $row1['Type'], + mb_strpos($row1['Type'], '(') + 2, + mb_strpos($row1['Type'], ')') + - mb_strpos($row1['Type'], '(') - 3 + ) + ); + + $users_grants = explode(',', $row['Table_priv']); + + foreach ($av_grants as $current_grant) { + $row[$current_grant . '_priv'] + = in_array($current_grant, $users_grants) ? 'Y' : 'N'; + } + unset($row['Table_priv']); + } + + + /** + * Extracts the privilege information of a priv table row + * + * @param array|null $row the row + * @param boolean $enableHTML add <dfn> tag with tooltips + * @param boolean $tablePrivs whether row contains table privileges + * + * @global resource $user_link the database connection + * + * @return array + */ + public function extractPrivInfo($row = null, $enableHTML = false, $tablePrivs = false) + { + if ($tablePrivs) { + $grants = $this->getTableGrantsArray(); + } else { + $grants = $this->getGrantsArray(); + } + + if ($row !== null && isset($row['Table_priv'])) { + $this->fillInTablePrivileges($row); + } + + $privs = []; + $allPrivileges = true; + foreach ($grants as $current_grant) { + if (($row !== null && isset($row[$current_grant[0]])) + || ($row === null && isset($GLOBALS[$current_grant[0]])) + ) { + if (($row !== null && $row[$current_grant[0]] == 'Y') + || ($row === null + && ($GLOBALS[$current_grant[0]] == 'Y' + || (is_array($GLOBALS[$current_grant[0]]) + && count($GLOBALS[$current_grant[0]]) == $_REQUEST['column_count'] + && empty($GLOBALS[$current_grant[0] . '_none'])))) + ) { + $privs[] = $this->formatPrivilege($current_grant, $enableHTML); + } elseif (! empty($GLOBALS[$current_grant[0]]) + && is_array($GLOBALS[$current_grant[0]]) + && empty($GLOBALS[$current_grant[0] . '_none']) + ) { + // Required for proper escaping of ` (backtick) in a column name + $grant_cols = array_map( + function ($val) { + return Util::backquote($val); + }, + $GLOBALS[$current_grant[0]] + ); + + $privs[] = $this->formatPrivilege($current_grant, $enableHTML) + . ' (' . implode(', ', $grant_cols) . ')'; + } else { + $allPrivileges = false; + } + } + } + if (empty($privs)) { + if ($enableHTML) { + $privs[] = '<dfn title="' . __('No privileges.') . '">USAGE</dfn>'; + } else { + $privs[] = 'USAGE'; + } + } elseif ($allPrivileges + && (! isset($_POST['grant_count']) || count($privs) == $_POST['grant_count']) + ) { + if ($enableHTML) { + $privs = ['<dfn title="' + . __('Includes all privileges except GRANT.') + . '">ALL PRIVILEGES</dfn>', + ]; + } else { + $privs = ['ALL PRIVILEGES']; + } + } + return $privs; + } + + /** + * Returns an array of table grants and their descriptions + * + * @return array array of table grants + */ + public function getTableGrantsArray() + { + return [ + [ + 'Delete', + 'DELETE', + $GLOBALS['strPrivDescDelete'], + ], + [ + 'Create', + 'CREATE', + $GLOBALS['strPrivDescCreateTbl'], + ], + [ + 'Drop', + 'DROP', + $GLOBALS['strPrivDescDropTbl'], + ], + [ + 'Index', + 'INDEX', + $GLOBALS['strPrivDescIndex'], + ], + [ + 'Alter', + 'ALTER', + $GLOBALS['strPrivDescAlter'], + ], + [ + 'Create View', + 'CREATE_VIEW', + $GLOBALS['strPrivDescCreateView'], + ], + [ + 'Show view', + 'SHOW_VIEW', + $GLOBALS['strPrivDescShowView'], + ], + [ + 'Trigger', + 'TRIGGER', + $GLOBALS['strPrivDescTrigger'], + ], + ]; + } + + /** + * Get the grants array which contains all the privilege types + * and relevant grant messages + * + * @return array + */ + public function getGrantsArray() + { + return [ + [ + 'Select_priv', + 'SELECT', + __('Allows reading data.'), + ], + [ + 'Insert_priv', + 'INSERT', + __('Allows inserting and replacing data.'), + ], + [ + 'Update_priv', + 'UPDATE', + __('Allows changing data.'), + ], + [ + 'Delete_priv', + 'DELETE', + __('Allows deleting data.'), + ], + [ + 'Create_priv', + 'CREATE', + __('Allows creating new databases and tables.'), + ], + [ + 'Drop_priv', + 'DROP', + __('Allows dropping databases and tables.'), + ], + [ + 'Reload_priv', + 'RELOAD', + __('Allows reloading server settings and flushing the server\'s caches.'), + ], + [ + 'Shutdown_priv', + 'SHUTDOWN', + __('Allows shutting down the server.'), + ], + [ + 'Process_priv', + 'PROCESS', + __('Allows viewing processes of all users.'), + ], + [ + 'File_priv', + 'FILE', + __('Allows importing data from and exporting data into files.'), + ], + [ + 'References_priv', + 'REFERENCES', + __('Has no effect in this MySQL version.'), + ], + [ + 'Index_priv', + 'INDEX', + __('Allows creating and dropping indexes.'), + ], + [ + 'Alter_priv', + 'ALTER', + __('Allows altering the structure of existing tables.'), + ], + [ + 'Show_db_priv', + 'SHOW DATABASES', + __('Gives access to the complete list of databases.'), + ], + [ + 'Super_priv', + 'SUPER', + __( + 'Allows connecting, even if maximum number of connections ' + . 'is reached; required for most administrative operations ' + . 'like setting global variables or killing threads of other users.' + ), + ], + [ + 'Create_tmp_table_priv', + 'CREATE TEMPORARY TABLES', + __('Allows creating temporary tables.'), + ], + [ + 'Lock_tables_priv', + 'LOCK TABLES', + __('Allows locking tables for the current thread.'), + ], + [ + 'Repl_slave_priv', + 'REPLICATION SLAVE', + __('Needed for the replication slaves.'), + ], + [ + 'Repl_client_priv', + 'REPLICATION CLIENT', + __('Allows the user to ask where the slaves / masters are.'), + ], + [ + 'Create_view_priv', + 'CREATE VIEW', + __('Allows creating new views.'), + ], + [ + 'Event_priv', + 'EVENT', + __('Allows to set up events for the event scheduler.'), + ], + [ + 'Trigger_priv', + 'TRIGGER', + __('Allows creating and dropping triggers.'), + ], + // for table privs: + [ + 'Create View_priv', + 'CREATE VIEW', + __('Allows creating new views.'), + ], + [ + 'Show_view_priv', + 'SHOW VIEW', + __('Allows performing SHOW CREATE VIEW queries.'), + ], + // for table privs: + [ + 'Show view_priv', + 'SHOW VIEW', + __('Allows performing SHOW CREATE VIEW queries.'), + ], + [ + 'Delete_history_priv', + 'DELETE HISTORY', + $GLOBALS['strPrivDescDeleteHistoricalRows'], + ], + [ + 'Delete versioning rows_priv', + 'DELETE HISTORY', + $GLOBALS['strPrivDescDeleteHistoricalRows'], + ], + [ + 'Create_routine_priv', + 'CREATE ROUTINE', + __('Allows creating stored routines.'), + ], + [ + 'Alter_routine_priv', + 'ALTER ROUTINE', + __('Allows altering and dropping stored routines.'), + ], + [ + 'Create_user_priv', + 'CREATE USER', + __('Allows creating, dropping and renaming user accounts.'), + ], + [ + 'Execute_priv', + 'EXECUTE', + __('Allows executing stored routines.'), + ], + ]; + } + + /** + * Displays on which column(s) a table-specific privilege is granted + * + * @param array $columns columns array + * @param array $row first row from result or boolean false + * @param string $name_for_select privilege types - Select_priv, Insert_priv + * Update_priv, References_priv + * @param string $priv_for_header privilege for header + * @param string $name privilege name: insert, select, update, references + * @param string $name_for_dfn name for dfn + * @param string $name_for_current name for current + * + * @return string html snippet + */ + public function getHtmlForColumnPrivileges( + array $columns, + array $row, + $name_for_select, + $priv_for_header, + $name, + $name_for_dfn, + $name_for_current + ) { + return $this->template->render('server/privileges/column_privileges', [ + 'columns' => $columns, + 'row' => $row, + 'name_for_select' => $name_for_select, + 'priv_for_header' => $priv_for_header, + 'name' => $name, + 'name_for_dfn' => $name_for_dfn, + 'name_for_current' => $name_for_current, + ]); + } + + /** + * Get sql query for display privileges table + * + * @param string $db the database + * @param string $table the table + * @param string $username username for database connection + * @param string $hostname hostname for database connection + * + * @return string sql query + */ + public function getSqlQueryForDisplayPrivTable($db, $table, $username, $hostname) + { + if ($db == '*') { + return "SELECT * FROM `mysql`.`user`" + . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" + . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "';"; + } elseif ($table == '*') { + return "SELECT * FROM `mysql`.`db`" + . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" + . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "'" + . " AND '" . $this->dbi->escapeString(Util::unescapeMysqlWildcards($db)) . "'" + . " LIKE `Db`;"; + } + return "SELECT `Table_priv`" + . " FROM `mysql`.`tables_priv`" + . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" + . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "'" + . " AND `Db` = '" . $this->dbi->escapeString(Util::unescapeMysqlWildcards($db)) . "'" + . " AND `Table_name` = '" . $this->dbi->escapeString($table) . "';"; + } + + /** + * Displays a dropdown to select the user group + * with menu items configured to each of them. + * + * @param string $username username + * + * @return string html to select the user group + */ + public function getHtmlToChooseUserGroup($username) + { + $cfgRelation = $this->relation->getRelationsParam(); + $groupTable = Util::backquote($cfgRelation['db']) + . "." . Util::backquote($cfgRelation['usergroups']); + $userTable = Util::backquote($cfgRelation['db']) + . "." . Util::backquote($cfgRelation['users']); + + $userGroup = ''; + if (isset($GLOBALS['username'])) { + $sql_query = "SELECT `usergroup` FROM " . $userTable + . " WHERE `username` = '" . $this->dbi->escapeString($username) . "'"; + $userGroup = $this->dbi->fetchValue( + $sql_query, + 0, + 0, + DatabaseInterface::CONNECT_CONTROL + ); + } + + $allUserGroups = ['' => '']; + $sql_query = "SELECT DISTINCT `usergroup` FROM " . $groupTable; + $result = $this->relation->queryAsControlUser($sql_query, false); + if ($result) { + while ($row = $this->dbi->fetchRow($result)) { + $allUserGroups[$row[0]] = $row[0]; + } + } + $this->dbi->freeResult($result); + + return $this->template->render('server/privileges/choose_user_group', [ + 'all_user_groups' => $allUserGroups, + 'user_group' => $userGroup, + 'params' => ['username' => $username], + ]); + } + + /** + * Sets the user group from request values + * + * @param string $username username + * @param string $userGroup user group to set + * + * @return void + */ + public function setUserGroup($username, $userGroup) + { + $userGroup = $userGroup === null ? '' : $userGroup; + $cfgRelation = $this->relation->getRelationsParam(); + if (empty($cfgRelation['db']) || empty($cfgRelation['users']) || empty($cfgRelation['usergroups'])) { + return; + } + + $userTable = Util::backquote($cfgRelation['db']) + . "." . Util::backquote($cfgRelation['users']); + + $sql_query = "SELECT `usergroup` FROM " . $userTable + . " WHERE `username` = '" . $this->dbi->escapeString($username) . "'"; + $oldUserGroup = $this->dbi->fetchValue( + $sql_query, + 0, + 0, + DatabaseInterface::CONNECT_CONTROL + ); + + if ($oldUserGroup === false) { + $upd_query = "INSERT INTO " . $userTable . "(`username`, `usergroup`)" + . " VALUES ('" . $this->dbi->escapeString($username) . "', " + . "'" . $this->dbi->escapeString($userGroup) . "')"; + } else { + if (empty($userGroup)) { + $upd_query = "DELETE FROM " . $userTable + . " WHERE `username`='" . $this->dbi->escapeString($username) . "'"; + } elseif ($oldUserGroup != $userGroup) { + $upd_query = "UPDATE " . $userTable + . " SET `usergroup`='" . $this->dbi->escapeString($userGroup) . "'" + . " WHERE `username`='" . $this->dbi->escapeString($username) . "'"; + } + } + if (isset($upd_query)) { + $this->relation->queryAsControlUser($upd_query); + } + } + + /** + * Displays the privileges form table + * + * @param string $db the database + * @param string $table the table + * @param boolean $submit whether to display the submit button or not + * + * @global array $cfg the phpMyAdmin configuration + * @global resource $user_link the database connection + * + * @return string html snippet + */ + public function getHtmlToDisplayPrivilegesTable( + $db = '*', + $table = '*', + $submit = true + ) { + $html_output = ''; + $sql_query = ''; + + if ($db == '*') { + $table = '*'; + } + $username = ''; + $hostname = ''; + if (isset($GLOBALS['username'])) { + $username = $GLOBALS['username']; + $hostname = $GLOBALS['hostname']; + $sql_query = $this->getSqlQueryForDisplayPrivTable( + $db, + $table, + $username, + $hostname + ); + $row = $this->dbi->fetchSingleRow($sql_query); + } + if (empty($row)) { + if ($table == '*' && $this->dbi->isSuperuser()) { + $row = []; + if ($db == '*') { + $sql_query = 'SHOW COLUMNS FROM `mysql`.`user`;'; + } elseif ($table == '*') { + $sql_query = 'SHOW COLUMNS FROM `mysql`.`db`;'; + } + $res = $this->dbi->query($sql_query); + while ($row1 = $this->dbi->fetchRow($res)) { + if (mb_substr($row1[0], 0, 4) == 'max_') { + $row[$row1[0]] = 0; + } elseif (mb_substr($row1[0], 0, 5) == 'x509_' + || mb_substr($row1[0], 0, 4) == 'ssl_' + ) { + $row[$row1[0]] = ''; + } else { + $row[$row1[0]] = 'N'; + } + } + $this->dbi->freeResult($res); + } elseif ($table == '*') { + $row = []; + } else { + $row = ['Table_priv' => '']; + } + } + if (isset($row['Table_priv'])) { + $this->fillInTablePrivileges($row); + + // get columns + $res = $this->dbi->tryQuery( + 'SHOW COLUMNS FROM ' + . Util::backquote( + Util::unescapeMysqlWildcards($db) + ) + . '.' . Util::backquote($table) . ';' + ); + $columns = []; + if ($res) { + while ($row1 = $this->dbi->fetchRow($res)) { + $columns[$row1[0]] = [ + 'Select' => false, + 'Insert' => false, + 'Update' => false, + 'References' => false, + ]; + } + $this->dbi->freeResult($res); + } + unset($res, $row1); + } + // table-specific privileges + if (! empty($columns)) { + $html_output .= $this->getHtmlForTableSpecificPrivileges( + $username, + $hostname, + $db, + $table, + $columns, + $row + ); + } else { + // global or db-specific + $html_output .= $this->getHtmlForGlobalOrDbSpecificPrivs($db, $table, $row); + } + $html_output .= '</fieldset>' . "\n"; + if ($submit) { + $html_output .= '<fieldset id="fieldset_user_privtable_footer" ' + . 'class="tblFooters">' . "\n" + . '<input type="hidden" name="update_privs" value="1">' . "\n" + . '<input class="btn btn-primary" type="submit" value="' . __('Go') . '">' . "\n" + . '</fieldset>' . "\n"; + } + return $html_output; + } // end of the 'PMA_displayPrivTable()' function + + /** + * Get HTML for "Require" + * + * @param array $row privilege array + * + * @return string html snippet + */ + public function getHtmlForRequires(array $row) + { + $specified = (isset($row['ssl_type']) && $row['ssl_type'] == 'SPECIFIED'); + $require_options = [ + [ + 'name' => 'ssl_type', + 'value' => 'NONE', + 'description' => __( + 'Does not require SSL-encrypted connections.' + ), + 'label' => 'REQUIRE NONE', + 'checked' => isset($row['ssl_type']) + && ($row['ssl_type'] == 'NONE' + || $row['ssl_type'] == '') + ? 'checked="checked"' + : '', + 'disabled' => false, + 'radio' => true, + ], + [ + 'name' => 'ssl_type', + 'value' => 'ANY', + 'description' => __( + 'Requires SSL-encrypted connections.' + ), + 'label' => 'REQUIRE SSL', + 'checked' => isset($row['ssl_type']) && ($row['ssl_type'] == 'ANY') + ? 'checked="checked"' + : '', + 'disabled' => false, + 'radio' => true, + ], + [ + 'name' => 'ssl_type', + 'value' => 'X509', + 'description' => __( + 'Requires a valid X509 certificate.' + ), + 'label' => 'REQUIRE X509', + 'checked' => isset($row['ssl_type']) && ($row['ssl_type'] == 'X509') + ? 'checked="checked"' + : '', + 'disabled' => false, + 'radio' => true, + ], + [ + 'name' => 'ssl_type', + 'value' => 'SPECIFIED', + 'description' => '', + 'label' => 'SPECIFIED', + 'checked' => $specified ? 'checked="checked"' : '', + 'disabled' => false, + 'radio' => true, + ], + [ + 'name' => 'ssl_cipher', + 'value' => isset($row['ssl_cipher']) + ? htmlspecialchars($row['ssl_cipher']) : '', + 'description' => __( + 'Requires that a specific cipher method be used for a connection.' + ), + 'label' => 'REQUIRE CIPHER', + 'checked' => '', + 'disabled' => ! $specified, + 'radio' => false, + ], + [ + 'name' => 'x509_issuer', + 'value' => isset($row['x509_issuer']) + ? htmlspecialchars($row['x509_issuer']) : '', + 'description' => __( + 'Requires that a valid X509 certificate issued by this CA be presented.' + ), + 'label' => 'REQUIRE ISSUER', + 'checked' => '', + 'disabled' => ! $specified, + 'radio' => false, + ], + [ + 'name' => 'x509_subject', + 'value' => isset($row['x509_subject']) + ? htmlspecialchars($row['x509_subject']) : '', + 'description' => __( + 'Requires that a valid X509 certificate with this subject be presented.' + ), + 'label' => 'REQUIRE SUBJECT', + 'checked' => '', + 'disabled' => ! $specified, + 'radio' => false, + ], + ]; + + return $this->template->render('server/privileges/require_options', [ + 'require_options' => $require_options, + ]); + } + + /** + * Get HTML for "Resource limits" + * + * @param array $row first row from result or boolean false + * + * @return string html snippet + */ + public function getHtmlForResourceLimits(array $row) + { + $limits = [ + [ + 'input_name' => 'max_questions', + 'name_main' => 'MAX QUERIES PER HOUR', + 'value' => isset($row['max_questions']) ? $row['max_questions'] : '0', + 'description' => __( + 'Limits the number of queries the user may send to the server per hour.' + ), + ], + [ + 'input_name' => 'max_updates', + 'name_main' => 'MAX UPDATES PER HOUR', + 'value' => isset($row['max_updates']) ? $row['max_updates'] : '0', + 'description' => __( + 'Limits the number of commands that change any table ' + . 'or database the user may execute per hour.' + ), + ], + [ + 'input_name' => 'max_connections', + 'name_main' => 'MAX CONNECTIONS PER HOUR', + 'value' => isset($row['max_connections']) ? $row['max_connections'] : '0', + 'description' => __( + 'Limits the number of new connections the user may open per hour.' + ), + ], + [ + 'input_name' => 'max_user_connections', + 'name_main' => 'MAX USER_CONNECTIONS', + 'value' => isset($row['max_user_connections']) ? + $row['max_user_connections'] : '0', + 'description' => __( + 'Limits the number of simultaneous connections ' + . 'the user may have.' + ), + ], + ]; + + return $this->template->render('server/privileges/resource_limits', [ + 'limits' => $limits, + ]); + } + + /** + * Get the HTML snippet for routine specific privileges + * + * @param string $username username for database connection + * @param string $hostname hostname for database connection + * @param string $db the database + * @param string $routine the routine + * @param string $url_dbname url encoded db name + * + * @return string + */ + public function getHtmlForRoutineSpecificPrivileges( + $username, + $hostname, + $db, + $routine, + $url_dbname + ) { + $header = $this->getHtmlHeaderForUserProperties( + false, + $url_dbname, + $db, + $username, + $hostname, + $routine, + 'routine' + ); + + $sql = "SELECT `Proc_priv`" + . " FROM `mysql`.`procs_priv`" + . " WHERE `User` = '" . $this->dbi->escapeString($username) . "'" + . " AND `Host` = '" . $this->dbi->escapeString($hostname) . "'" + . " AND `Db` = '" + . $this->dbi->escapeString(Util::unescapeMysqlWildcards($db)) . "'" + . " AND `Routine_name` LIKE '" . $this->dbi->escapeString($routine) . "';"; + $res = $this->dbi->fetchValue($sql); + + $privs = $this->parseProcPriv($res); + + $routineArray = [$this->getTriggerPrivilegeTable()]; + $privTableNames = [__('Routine')]; + $privCheckboxes = $this->getHtmlForGlobalPrivTableWithCheckboxes( + $routineArray, + $privTableNames, + $privs + ); + + return $this->template->render('server/privileges/edit_routine_privileges', [ + 'username' => $username, + 'hostname' => $hostname, + 'database' => $db, + 'routine' => $routine, + 'grant_count' => count($privs), + 'priv_checkboxes' => $privCheckboxes, + 'header' => $header, + ]); + } + + /** + * Get routine privilege table as an array + * + * @return array privilege type array + */ + public function getTriggerPrivilegeTable() + { + $routinePrivTable = [ + [ + 'Grant', + 'GRANT', + __( + 'Allows user to give to other users or remove from other users ' + . 'privileges that user possess on this routine.' + ), + ], + [ + 'Alter_routine', + 'ALTER ROUTINE', + __('Allows altering and dropping this routine.'), + ], + [ + 'Execute', + 'EXECUTE', + __('Allows executing this routine.'), + ], + ]; + return $routinePrivTable; + } + + /** + * Get the HTML snippet for table specific privileges + * + * @param string $username username for database c |
