From f8ea67f2bc59d46290b85b2e578c649655f000e7 Mon Sep 17 00:00:00 2001 From: Deven Bansod Date: Fri, 16 Sep 2016 13:51:34 +0530 Subject: [PATCH 1/6] Fix #12530: Show enabled links for Edit and Execute after proper priv checks Signed-off-by: Deven Bansod --- ChangeLog | 1 + js/messages.php | 2 ++ js/rte.js | 6 +++++ libraries/DatabaseInterface.php | 5 ++-- libraries/rte/rte_export.lib.php | 26 +++++++++++++----- libraries/rte/rte_list.lib.php | 42 +++++++++++++++++++++++------- libraries/rte/rte_routines.lib.php | 41 ++++++++++++++++++++--------- libraries/rte/rte_words.lib.php | 6 +++++ 8 files changed, 97 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index 703d330f71..beea941cc0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,7 @@ phpMyAdmin - ChangeLog - issue #12473 Code can throw unhandled exception - issue #12550 Do not try to keep alive session even after expiry - issue #12512 Fixed rendering BBCode links in setup +- issue #12530 "Edit routine" crashes when the current user is not the definer, even if privileges are adequate 4.6.4 (2016-08-16) - issue [security] Weaknesses with cookie encryption, see PMASA-2016-29 diff --git a/js/messages.php b/js/messages.php index 9b8ecf2b33..c79629dd1c 100644 --- a/js/messages.php +++ b/js/messages.php @@ -385,6 +385,8 @@ $js_messages['strDeleting'] = __('Deleting'); $js_messages['MissingReturn'] = __('The definition of a stored function must contain a RETURN statement!'); $js_messages['strExport'] = __('Export'); +$js_messages['NoExportable'] + = __('No routine is exportable. Required privileges may be lacking.'); /* For ENUM/SET editor*/ $js_messages['enum_editor'] = __('ENUM/SET editor'); diff --git a/js/rte.js b/js/rte.js index ca2f6d4d6c..9a189aeae3 100644 --- a/js/rte.js +++ b/js/rte.js @@ -128,6 +128,11 @@ RTE.COMMON = { var count = export_anchors.length; var returnCount = 0; + // No routine is exportable (due to privilege issues) + if (count === 0) { + PMA_ajaxShowMessage(PMA_messages.NoExportable); + } + export_anchors.each(function () { $.get($(this).attr('href'), {'ajax_request': true}, function (data) { returnCount++; @@ -149,6 +154,7 @@ RTE.COMMON = { } else { $.get($this.attr('href'), {'ajax_request': true}, showExport); } + PMA_ajaxRemoveMessage($msg); function showExport(data) { if (data.success === true) { diff --git a/libraries/DatabaseInterface.php b/libraries/DatabaseInterface.php index db86343fb3..72fd3e42c7 100644 --- a/libraries/DatabaseInterface.php +++ b/libraries/DatabaseInterface.php @@ -1824,10 +1824,11 @@ class DatabaseInterface * @param string $db db name * @param string $which PROCEDURE | FUNCTION | EVENT | VIEW * @param string $name the procedure|function|event|view name + * @param object $link MySQL link * * @return string the definition */ - public function getDefinition($db, $which, $name) + public function getDefinition($db, $which, $name, $link = null) { $returned_field = array( 'PROCEDURE' => 'Create Procedure', @@ -1838,7 +1839,7 @@ class DatabaseInterface $query = 'SHOW CREATE ' . $which . ' ' . Util::backquote($db) . '.' . Util::backquote($name); - return($this->fetchValue($query, 0, $returned_field[$which])); + return($this->fetchValue($query, 0, $returned_field[$which], $link)); } /** diff --git a/libraries/rte/rte_export.lib.php b/libraries/rte/rte_export.lib.php index 55f9c2da57..19fa6dd0fb 100644 --- a/libraries/rte/rte_export.lib.php +++ b/libraries/rte/rte_export.lib.php @@ -44,15 +44,17 @@ function PMA_RTE_handleExport($export_data) } else { $_db = htmlspecialchars(PMA\libraries\Util::backquote($db)); $message = __('Error in processing request:') . ' ' - . sprintf(PMA_RTE_getWord('not_found'), $item_name, $_db); - $response = Message::error($message); + . sprintf(PMA_RTE_getWord('not_found'), $item_name, $_db) + . ' OR ' . PMA_RTE_getWord('no_view'); + $message = Message::error($message); + if ($GLOBALS['is_ajax_request'] == true) { $response = PMA\libraries\Response::getInstance(); $response->setRequestStatus(false); $response->addJSON('message', $message); exit; } else { - $response->display(); + $message->display(); } } } // end PMA_RTE_handleExport() @@ -70,6 +72,9 @@ function PMA_EVN_handleExport() if (! empty($_GET['export_item']) && ! empty($_GET['item_name'])) { $item_name = $_GET['item_name']; $export_data = $GLOBALS['dbi']->getDefinition($db, 'EVENT', $item_name); + if (! $export_data) { + $export_data = false; + } PMA_RTE_handleExport($export_data); } } // end PMA_EVN_handleExport() @@ -89,13 +94,20 @@ function PMA_RTN_handleExport() && ! empty($_GET['item_type']) ) { if ($_GET['item_type'] == 'FUNCTION' || $_GET['item_type'] == 'PROCEDURE') { - $export_data = "DELIMITER $$\n" - . $GLOBALS['dbi']->getDefinition( + $rtn_definition + = $GLOBALS['dbi']->getDefinition( $db, $_GET['item_type'], $_GET['item_name'] - ) - . "$$\nDELIMITER ;\n"; + ); + if (! $rtn_definition) { + $export_data = false; + } else { + $export_data = "DELIMITER $$\n" + . $rtn_definition + . "$$\nDELIMITER ;\n"; + } + PMA_RTE_handleExport($export_data); } } diff --git a/libraries/rte/rte_list.lib.php b/libraries/rte/rte_list.lib.php index 7d08d984b7..85d27d6b54 100644 --- a/libraries/rte/rte_list.lib.php +++ b/libraries/rte/rte_list.lib.php @@ -196,9 +196,24 @@ function PMA_RTN_getRowForList($routine, $rowclass = '') $retval .= " \n"; $retval .= " \n"; $retval .= " \n"; + + // this is for our purpose to decide whether to + // show the edit link or not, so we need the DEFINER for the routine + $where = "ROUTINE_SCHEMA " . PMA\libraries\Util::getCollateForIS() . "=" + . "'" . PMA\libraries\Util::sqlAddSlashes($db) . "' " + . "AND SPECIFIC_NAME='" . PMA\libraries\Util::sqlAddSlashes($routine['name']) . "'" + . "AND ROUTINE_TYPE='" . PMA\libraries\Util::sqlAddSlashes($routine['type']) . "'"; + $query = "SELECT `DEFINER` FROM INFORMATION_SCHEMA.ROUTINES WHERE $where;"; + $routine_definer = $GLOBALS['dbi']->fetchValue($query, 0, 0, $GLOBALS['controllink']); + + $curr_user = $GLOBALS['dbi']->getCurrentUser(); + // Since editing a procedure involved dropping and recreating, check also for // CREATE ROUTINE privilege to avoid lost procedures. - if (PMA\libraries\Util::currentUserHasPrivilege('CREATE ROUTINE', $db)) { + if ((PMA\libraries\Util::currentUserHasPrivilege('CREATE ROUTINE', $db) + && $curr_user == $routine_definer) + || $GLOBALS['is_superuser'] + ) { $retval .= ' \n"; $retval .= " \n"; - $retval .= ' ' . $titles['Export'] . "\n"; + if ((PMA\libraries\Util::currentUserHasPrivilege('CREATE ROUTINE', $db) + && $curr_user == $routine_definer) + || $GLOBALS['is_superuser'] + ) { + $retval .= ' ' . $titles['Export'] . "\n"; + } else { + $retval .= " {$titles['NoExport']}\n"; + } $retval .= " \n"; $retval .= " \n"; $retval .= ' fetchSingleRow($query); + $routine = $GLOBALS['dbi']->fetchSingleRow($query, 'ASSOC', $link); if (! $routine) { return false; @@ -595,13 +604,19 @@ function PMA_RTN_getDataFromName($name, $type, $all = true) $retval['item_name'] = $routine['SPECIFIC_NAME']; $retval['item_type'] = $routine['ROUTINE_TYPE']; - $parser = new SqlParser\Parser( - $GLOBALS['dbi']->getDefinition( + $definition + = $GLOBALS['dbi']->getDefinition( $db, $routine['ROUTINE_TYPE'], - $routine['SPECIFIC_NAME'] - ) - ); + $routine['SPECIFIC_NAME'], + $link + ); + + if ($definition == NULL) { + return false; + } + + $parser = new SqlParser\Parser($definition); /** * @var CreateStatement $stmt @@ -1283,7 +1298,7 @@ function PMA_RTN_handleExecute() if (! empty($_REQUEST['execute_routine']) && ! empty($_REQUEST['item_name'])) { // Build the queries $routine = PMA_RTN_getDataFromName( - $_REQUEST['item_name'], $_REQUEST['item_type'], false + $_REQUEST['item_name'], $_REQUEST['item_type'], false, true ); if ($routine === false) { $message = __('Error in processing request:') . ' '; @@ -1481,7 +1496,7 @@ function PMA_RTN_handleExecute() * Display the execute form for a routine. */ $routine = PMA_RTN_getDataFromName( - $_GET['item_name'], $_GET['item_type'], true + $_GET['item_name'], $_GET['item_type'], true, true ); if ($routine !== false) { $form = PMA_RTN_getExecuteForm($routine); diff --git a/libraries/rte/rte_words.lib.php b/libraries/rte/rte_words.lib.php index 18d757d252..ff301874df 100644 --- a/libraries/rte/rte_words.lib.php +++ b/libraries/rte/rte_words.lib.php @@ -31,6 +31,12 @@ function PMA_RTE_getWord($index) 'no_create' => __( 'You do not have the necessary privileges to create a routine' ), + 'no_edit' => __( + 'You do not have the necessary privileges to edit this routine' + ), + 'no_view' => __( + 'You do not have the necessary privileges to view/export this routine' + ), 'not_found' => __('No routine with name %1$s found in database %2$s'), 'nothing' => __('There are no routines to display.'), 'title' => __('Routines'), From 815bf44584f104d1616ca1d05a2aaba34580a418 Mon Sep 17 00:00:00 2001 From: Deven Bansod Date: Thu, 8 Sep 2016 10:39:19 +0530 Subject: [PATCH 2/6] Fix error messages to suit better localization Signed-off-by: Deven Bansod --- libraries/rte/rte_export.lib.php | 3 +-- libraries/rte/rte_routines.lib.php | 3 +-- libraries/rte/rte_words.lib.php | 6 ++++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/rte/rte_export.lib.php b/libraries/rte/rte_export.lib.php index 19fa6dd0fb..94b59ff5aa 100644 --- a/libraries/rte/rte_export.lib.php +++ b/libraries/rte/rte_export.lib.php @@ -44,8 +44,7 @@ function PMA_RTE_handleExport($export_data) } else { $_db = htmlspecialchars(PMA\libraries\Util::backquote($db)); $message = __('Error in processing request:') . ' ' - . sprintf(PMA_RTE_getWord('not_found'), $item_name, $_db) - . ' OR ' . PMA_RTE_getWord('no_view'); + . sprintf(PMA_RTE_getWord('no_view'), $item_name, $_db); $message = Message::error($message); if ($GLOBALS['is_ajax_request'] == true) { diff --git a/libraries/rte/rte_routines.lib.php b/libraries/rte/rte_routines.lib.php index 21eb9bf9db..2db6fcf79c 100644 --- a/libraries/rte/rte_routines.lib.php +++ b/libraries/rte/rte_routines.lib.php @@ -155,13 +155,12 @@ function PMA_RTN_handleEditor() } else { $message = __('Error in processing request:') . ' '; $message .= sprintf( - PMA_RTE_getWord('not_found'), + PMA_RTE_getWord('no_edit'), htmlspecialchars( PMA\libraries\Util::backquote($_REQUEST['item_name']) ), htmlspecialchars(PMA\libraries\Util::backquote($db)) ); - $message .= ' OR ' . PMA_RTE_getWord('no_edit'); $message = Message::error($message); if ($GLOBALS['is_ajax_request']) { diff --git a/libraries/rte/rte_words.lib.php b/libraries/rte/rte_words.lib.php index ff301874df..3205c2e7fb 100644 --- a/libraries/rte/rte_words.lib.php +++ b/libraries/rte/rte_words.lib.php @@ -32,10 +32,12 @@ function PMA_RTE_getWord($index) 'You do not have the necessary privileges to create a routine' ), 'no_edit' => __( - 'You do not have the necessary privileges to edit this routine' + 'No routine with name %1$s found in database %2$s. ' + . 'You might be lacking the necessary privileges to edit this routine' ), 'no_view' => __( - 'You do not have the necessary privileges to view/export this routine' + 'No routine with name %1$s found in database %2$s. ' + . 'You might be lacking the necessary privileges to view/export this routine' ), 'not_found' => __('No routine with name %1$s found in database %2$s'), 'nothing' => __('There are no routines to display.'), From b054aa70ef443929484f087f459d4d856fcabaa5 Mon Sep 17 00:00:00 2001 From: Deven Bansod Date: Thu, 15 Sep 2016 12:10:17 +0530 Subject: [PATCH 3/6] Uncheck the Add CREATE PROCEDURE / FUNCTION etc. checkbox for a selective export User can always check it if he/she wants to export the procs,funcs etc. too Signed-off-by: Deven Bansod --- js/export.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/js/export.js b/js/export.js index 762ba4166e..09fedd2af0 100644 --- a/js/export.js +++ b/js/export.js @@ -540,6 +540,16 @@ function toggle_table_select(row) { } } +function handleAddProcCheckbox() { + if ($('#table_structure_all').is(':checked') === true + && $('#table_data_all').is(':checked') === true + ) { + $('#checkbox_sql_procedure_function').prop('checked', true); + } else { + $('#checkbox_sql_procedure_function').prop('checked', false); + } +} + AJAX.registerOnload('export.js', function () { /** * For SQL plugin, if "CREATE TABLE options" is checked/unchecked, check/uncheck each of its sub-options @@ -579,26 +589,31 @@ AJAX.registerOnload('export.js', function () { $('input[name="table_select[]"]').on('change', function() { toggle_table_select($(this).closest('tr')); check_table_select_all(); + handleAddProcCheckbox(); }); $('input[name="table_structure[]"]').on('change', function() { check_table_selected($(this).closest('tr')); check_table_select_all(); + handleAddProcCheckbox(); }); $('input[name="table_data[]"]').on('change', function() { check_table_selected($(this).closest('tr')); check_table_select_all(); + handleAddProcCheckbox(); }); $('#table_structure_all').on('change', function() { toggle_table_select_all_str(); check_selected_tables(); + handleAddProcCheckbox(); }); $('#table_data_all').on('change', function() { toggle_table_select_all_data(); check_selected_tables(); + handleAddProcCheckbox(); }); if ($("input[name='export_type']").val() == 'database') { @@ -805,6 +820,8 @@ AJAX.registerOnload('export.js', function () { toggle_quick_or_custom(); toggle_structure_data_opts(); toggle_sql_include_comments(); + check_table_select_all(); + handleAddProcCheckbox(); /** * Initially disables the "Dump some row(s)" sub-options From 4f1432eb2fe6a25efbf740c9f712d4454e109969 Mon Sep 17 00:00:00 2001 From: Deven Bansod Date: Fri, 16 Sep 2016 13:57:26 +0530 Subject: [PATCH 4/6] ChangeLog entry for #12300 Signed-off-by: Deven Bansod Conflicts: ChangeLog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 703d330f71..e5e32418c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,7 @@ phpMyAdmin - ChangeLog - issue #12473 Code can throw unhandled exception - issue #12550 Do not try to keep alive session even after expiry - issue #12512 Fixed rendering BBCode links in setup +- issue #12300 Export selective tables by-default dumps Events also 4.6.4 (2016-08-16) - issue [security] Weaknesses with cookie encryption, see PMASA-2016-29 From e8d07e3783f0a1b7140ba3ee6a3b2e472e210b65 Mon Sep 17 00:00:00 2001 From: Deven Bansod Date: Thu, 15 Sep 2016 00:52:14 +0530 Subject: [PATCH 5/6] Allow vertical scrolling to read longer text values in grid editing Fix #12554 Signed-off-by: Deven Bansod --- themes/original/css/common.css.php | 3 ++- themes/pmahomme/css/common.css.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/themes/original/css/common.css.php b/themes/original/css/common.css.php index 2b17bcd491..13b4b3debc 100644 --- a/themes/original/css/common.css.php +++ b/themes/original/css/common.css.php @@ -2321,7 +2321,8 @@ fieldset .disabled-field td { } .cEdit .edit_box { - overflow: hidden; + overflow-x: hidden; + overflow-y: scroll; padding: 0; } diff --git a/themes/pmahomme/css/common.css.php b/themes/pmahomme/css/common.css.php index 50f6d22a86..a4177400f3 100644 --- a/themes/pmahomme/css/common.css.php +++ b/themes/pmahomme/css/common.css.php @@ -2873,7 +2873,8 @@ fieldset .disabled-field td { } .cEdit .edit_box { - overflow: hidden; + overflow-x: hidden; + overflow-y: scroll; padding: 0; margin: 0; } From b6952bbe55a9fa727482a47533cc066c5e36f189 Mon Sep 17 00:00:00 2001 From: Deven Bansod Date: Fri, 16 Sep 2016 13:59:00 +0530 Subject: [PATCH 6/6] ChangeLog entry for #12554 Signed-off-by: Deven Bansod Conflicts: ChangeLog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 703d330f71..b2c4eec55f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,7 @@ phpMyAdmin - ChangeLog - issue #12473 Code can throw unhandled exception - issue #12550 Do not try to keep alive session even after expiry - issue #12512 Fixed rendering BBCode links in setup +- issue #12554 Absence of scrolling makes it impossible to read longer text values in grid editing 4.6.4 (2016-08-16) - issue [security] Weaknesses with cookie encryption, see PMASA-2016-29