Commit e29b7ef5 authored by Timothy Smith's avatar Timothy Smith

Bug#48031: mysql_secure_installation -- bash bug regarding passwords with

  special chars

This script failed when the user tried passwords with multiple spaces, \, # or
' characters.  Now proper escaping and quoting is used in all contexts.

This problem occurs in the Perl version of this script, too, so fix it in both
places.
parent d31e4636
...@@ -108,6 +108,23 @@ sub prepare { ...@@ -108,6 +108,23 @@ sub prepare {
} }
} }
# Simple escape mechanism (\-escape any ' and \), suitable for two contexts:
# - single-quoted SQL strings
# - single-quoted option values on the right hand side of = in my.cnf
#
# These two contexts don't handle escapes identically. SQL strings allow
# quoting any character (\C => C, for any C), but my.cnf parsing allows
# quoting only \, ' or ". For example, password='a\b' quotes a 3-character
# string in my.cnf, but a 2-character string in SQL.
#
# This simple escape works correctly in both places.
sub basic_single_escape {
my ($str) = @_;
# Inside a character class, \ is not special; this escapes both \ and '
$str =~ s/([\'])/\\$1/g;
return $str;
}
sub do_query { sub do_query {
my $query = shift; my $query = shift;
write_file($command, $query); write_file($command, $query);
...@@ -119,11 +136,12 @@ sub do_query { ...@@ -119,11 +136,12 @@ sub do_query {
sub make_config { sub make_config {
my $password = shift; my $password = shift;
my $esc_pass = basic_single_escape($rootpass);
write_file($config, write_file($config,
"# mysql_secure_installation config file", "# mysql_secure_installation config file",
"[mysql]", "[mysql]",
"user=root", "user=root",
"password=$rootpass"); "password='$esc_pass'");
} }
sub get_root_password { sub get_root_password {
...@@ -165,8 +183,8 @@ sub set_root_password { ...@@ -165,8 +183,8 @@ sub set_root_password {
last; last;
} }
# FIXME: Quote password1 properly for SQL my $esc_pass = basic_single_escape($password1);
do_query("UPDATE mysql.user SET Password=PASSWORD('$password1') WHERE User='root';") do_query("UPDATE mysql.user SET Password=PASSWORD('$esc_pass') WHERE User='root';")
or die "Password update failed!\n"; or die "Password update failed!\n";
print "Password updated successfully!\n"; print "Password updated successfully!\n";
......
...@@ -38,16 +38,39 @@ prepare() { ...@@ -38,16 +38,39 @@ prepare() {
} }
do_query() { do_query() {
echo $1 >$command echo "$1" >$command
#sed 's,^,> ,' < $command # Debugging
mysql --defaults-file=$config <$command mysql --defaults-file=$config <$command
return $? return $?
} }
# Simple escape mechanism (\-escape any ' and \), suitable for two contexts:
# - single-quoted SQL strings
# - single-quoted option values on the right hand side of = in my.cnf
#
# These two contexts don't handle escapes identically. SQL strings allow
# quoting any character (\C => C, for any C), but my.cnf parsing allows
# quoting only \, ' or ". For example, password='a\b' quotes a 3-character
# string in my.cnf, but a 2-character string in SQL.
#
# This simple escape works correctly in both places.
basic_single_escape () {
# The quoting on this sed command is a bit complex. Single-quoted strings
# don't allow *any* escape mechanism, so they cannot contain a single
# quote. The string sed gets (as argv[1]) is: s/\(['\]\)/\\\1/g
#
# Inside a character class, \ and ' are not special, so the ['\] character
# class is balanced and contains two characters.
echo "$1" | sed 's/\(['"'"'\]\)/\\\1/g'
}
make_config() { make_config() {
echo "# mysql_secure_installation config file" >$config echo "# mysql_secure_installation config file" >$config
echo "[mysql]" >>$config echo "[mysql]" >>$config
echo "user=root" >>$config echo "user=root" >>$config
echo "password=$rootpass" >>$config esc_pass=`basic_single_escape "$rootpass"`
echo "password='$esc_pass'" >>$config
#sed 's,^,> ,' < $config # Debugging
} }
get_root_password() { get_root_password() {
...@@ -94,7 +117,8 @@ set_root_password() { ...@@ -94,7 +117,8 @@ set_root_password() {
return 1 return 1
fi fi
do_query "UPDATE mysql.user SET Password=PASSWORD('$password1') WHERE User='root';" esc_pass=`basic_single_escape "$password1"`
do_query "UPDATE mysql.user SET Password=PASSWORD('$esc_pass') WHERE User='root';"
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "Password updated successfully!" echo "Password updated successfully!"
echo "Reloading privilege tables.." echo "Reloading privilege tables.."
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment