From 841ddb2edcb7e6549d4e9d31466f3a51968e975d Mon Sep 17 00:00:00 2001 From: Sveta Smirnova Date: Wed, 10 Apr 2024 23:31:20 +0300 Subject: [PATCH] PT-2327 - pt-mysql-summary fails to connect if password has a single quote character - Implemented the fix - Added test case - Run update-modules --- bin/pt-ioprofile | 4 +- bin/pt-mext | 4 +- bin/pt-mysql-summary | 4 +- bin/pt-pmp | 4 +- bin/pt-sift | 4 +- bin/pt-stalk | 4 +- bin/pt-summary | 4 +- lib/bash/parse_options.sh | 4 +- t/pt-mysql-summary/pt-2327.t | 77 ++++++++++++++++++++++++++++++++++++ 9 files changed, 93 insertions(+), 16 deletions(-) create mode 100644 t/pt-mysql-summary/pt-2327.t diff --git a/bin/pt-ioprofile b/bin/pt-ioprofile index 785e7dfb..ae4f3698 100755 --- a/bin/pt-ioprofile +++ b/bin/pt-ioprofile @@ -408,7 +408,7 @@ _parse_command_line() { fi if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then - val="$(echo $opt | awk -F= '{print $2}')" + val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')" opt="$(echo $opt | awk -F= '{print $1}')" fi @@ -453,7 +453,7 @@ _parse_command_line() { val=$(size_to_bytes $val) fi - eval "OPT_$opt"="'$val'" + eval "OPT_$opt"='$val' opt="" val="" diff --git a/bin/pt-mext b/bin/pt-mext index df068aab..42d6f787 100755 --- a/bin/pt-mext +++ b/bin/pt-mext @@ -449,7 +449,7 @@ _parse_command_line() { fi if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then - val="$(echo $opt | awk -F= '{print $2}')" + val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')" opt="$(echo $opt | awk -F= '{print $1}')" fi @@ -494,7 +494,7 @@ _parse_command_line() { val=$(size_to_bytes $val) fi - eval "OPT_$opt"="'$val'" + eval "OPT_$opt"='$val' opt="" val="" diff --git a/bin/pt-mysql-summary b/bin/pt-mysql-summary index 681b153f..8d8bbd54 100755 --- a/bin/pt-mysql-summary +++ b/bin/pt-mysql-summary @@ -410,7 +410,7 @@ _parse_command_line() { fi if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then - val="$(echo $opt | awk -F= '{print $2}')" + val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')" opt="$(echo $opt | awk -F= '{print $1}')" fi @@ -455,7 +455,7 @@ _parse_command_line() { val=$(size_to_bytes $val) fi - eval "OPT_$opt"="'$val'" + eval "OPT_$opt"='$val' opt="" val="" diff --git a/bin/pt-pmp b/bin/pt-pmp index 0aacb473..8a8b7e0e 100755 --- a/bin/pt-pmp +++ b/bin/pt-pmp @@ -451,7 +451,7 @@ _parse_command_line() { fi if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then - val="$(echo $opt | awk -F= '{print $2}')" + val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')" opt="$(echo $opt | awk -F= '{print $1}')" fi @@ -496,7 +496,7 @@ _parse_command_line() { val=$(size_to_bytes $val) fi - eval "OPT_$opt"="'$val'" + eval "OPT_$opt"='$val' opt="" val="" diff --git a/bin/pt-sift b/bin/pt-sift index bbf077cf..9e0c02fe 100755 --- a/bin/pt-sift +++ b/bin/pt-sift @@ -449,7 +449,7 @@ _parse_command_line() { fi if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then - val="$(echo $opt | awk -F= '{print $2}')" + val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')" opt="$(echo $opt | awk -F= '{print $1}')" fi @@ -494,7 +494,7 @@ _parse_command_line() { val=$(size_to_bytes $val) fi - eval "OPT_$opt"="'$val'" + eval "OPT_$opt"='$val' opt="" val="" diff --git a/bin/pt-stalk b/bin/pt-stalk index 9f8d86a6..e83228d4 100755 --- a/bin/pt-stalk +++ b/bin/pt-stalk @@ -462,7 +462,7 @@ _parse_command_line() { fi if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then - val="$(echo $opt | awk -F= '{print $2}')" + val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')" opt="$(echo $opt | awk -F= '{print $1}')" fi @@ -507,7 +507,7 @@ _parse_command_line() { val=$(size_to_bytes $val) fi - eval "OPT_$opt"="'$val'" + eval "OPT_$opt"='$val' opt="" val="" diff --git a/bin/pt-summary b/bin/pt-summary index cf000117..983df245 100755 --- a/bin/pt-summary +++ b/bin/pt-summary @@ -417,7 +417,7 @@ _parse_command_line() { fi if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then - val="$(echo $opt | awk -F= '{print $2}')" + val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')" opt="$(echo $opt | awk -F= '{print $1}')" fi @@ -462,7 +462,7 @@ _parse_command_line() { val=$(size_to_bytes $val) fi - eval "OPT_$opt"="'$val'" + eval "OPT_$opt"='$val' opt="" val="" diff --git a/lib/bash/parse_options.sh b/lib/bash/parse_options.sh index 97fe0c4e..1fee5c6b 100644 --- a/lib/bash/parse_options.sh +++ b/lib/bash/parse_options.sh @@ -475,7 +475,7 @@ _parse_command_line() { # Split opt=val pair. if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then - val="$(echo $opt | awk -F= '{print $2}')" + val="$(echo "$opt" | awk '{ st = index($0,"="); print substr($0, st+1)}')" opt="$(echo $opt | awk -F= '{print $1}')" fi @@ -533,7 +533,7 @@ _parse_command_line() { fi # Re-eval the option to update its global variable value. - eval "OPT_$opt"="'$val'" + eval "OPT_$opt"='$val' opt="" val="" diff --git a/t/pt-mysql-summary/pt-2327.t b/t/pt-mysql-summary/pt-2327.t new file mode 100644 index 00000000..69c68021 --- /dev/null +++ b/t/pt-mysql-summary/pt-2327.t @@ -0,0 +1,77 @@ +#!/usr/bin/env perl + +BEGIN { + die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n" + unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH}; + unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib"; +}; + +use strict; +use warnings FATAL => 'all'; +use English qw(-no_match_vars); +use PerconaTest; +use Sandbox; +use DSNParser; +require VersionParser; +use Test::More; + +local $ENV{PTDEBUG} = ""; + +my $dp = new DSNParser(opts=>$dsn_opts); +my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp); +my $dbh = $sb->get_dbh_for('master'); +my $cnf = '/tmp/12345/my.sandbox.cnf'; +my $output; + +if ( !$dbh ) { + plan skip_all => 'Cannot connect to sandbox master'; +} +else { + plan tests => 5; +} + +$sb->do_as_root("master", q/create user pt2302 identified by "root_'f<=*password"/); +$sb->do_as_root("master", q/grant all on *.* to pt2302/); + +my $cmd = "$trunk/bin/pt-mysql-summary --sleep 1 -- --defaults-file=$cnf --user=pt2302 --password=\"root_'f<=*password\""; + +$output = `$cmd 2>&1`; + +unlike( + $output, + qr/eval: Syntax error: Unterminated quoted string/s, + "pt-mysql-summary does not stop with password containing an apostrophe" +); + +unlike( + $output, + qr/Access denied for user/s, + "pt-mysql-summary works fine with password containing an apostrophe" +); + +$sb->do_as_root("master", q/drop user pt2302/); +$sb->do_as_root("master", q/create user pt2302 identified by 'root_"f<=*password'/); +$sb->do_as_root("master", q/grant all on *.* to pt2302/); + +$cmd = "$trunk/bin/pt-mysql-summary --sleep 1 -- --defaults-file=$cnf --user=pt2302 --password='root_\"f<=*password'"; + +$output = `$cmd 2>&1`; + +unlike( + $output, + qr/eval: Syntax error: Unterminated quoted string/s, + "pt-mysql-summary does not stop with password containing a quote" +); + +unlike( + $output, + qr/Access denied for user/s, + "pt-mysql-summary works fine with password containing a quote" +); +# ############################################################################# +# Done. +# ############################################################################# +$sb->do_as_root("master", q/drop user pt2302/); +$sb->wipe_clean($dbh); +ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); +exit;