MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Timothy Smith Date:November 3 2009 8:53pm
Subject:bzr commit into mysql-5.0-bugteam branch (timothy.smith:2836) Bug#48031
View as plain text  
#At file:///home/tsmith/m/bzr/bugteam/50-bugfix/ based on revid:timothy.smith@stripped

 2836 Timothy Smith	2009-11-03
      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.

    modified:
      scripts/mysql_secure_installation.pl.in
      scripts/mysql_secure_installation.sh
=== modified file 'scripts/mysql_secure_installation.pl.in'
--- a/scripts/mysql_secure_installation.pl.in	2009-10-30 20:28:33 +0000
+++ b/scripts/mysql_secure_installation.pl.in	2009-11-03 20:50:28 +0000
@@ -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 {
   my $query   = shift;
   write_file($command, $query);
@@ -119,11 +136,12 @@ sub do_query {
 sub make_config {
   my $password = shift;
 
+  my $esc_pass = basic_single_escape($rootpass);
   write_file($config,
              "# mysql_secure_installation config file",
              "[mysql]",
              "user=root",
-             "password=$rootpass");
+             "password='$esc_pass'");
 }
 
 sub get_root_password {
@@ -165,8 +183,8 @@ sub set_root_password {
     last;
   }
 
-  # FIXME: Quote password1 properly for SQL
-  do_query("UPDATE mysql.user SET Password=PASSWORD('$password1') WHERE User='root';")
+  my $esc_pass = basic_single_escape($password1);
+  do_query("UPDATE mysql.user SET Password=PASSWORD('$esc_pass') WHERE User='root';")
     or die "Password update failed!\n";
 
   print "Password updated successfully!\n";

=== modified file 'scripts/mysql_secure_installation.sh'
--- a/scripts/mysql_secure_installation.sh	2009-11-03 20:32:12 +0000
+++ b/scripts/mysql_secure_installation.sh	2009-11-03 20:50:28 +0000
@@ -38,16 +38,39 @@ prepare() {
 }
 
 do_query() {
-    echo $1 >$command
+    echo "$1" >$command
+    #sed 's,^,> ,' < $command  # Debugging
     mysql --defaults-file=$config <$command
     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() {
     echo "# mysql_secure_installation config file" >$config
     echo "[mysql]" >>$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() {
@@ -94,7 +117,8 @@ set_root_password() {
 	return 1
     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
 	echo "Password updated successfully!"
 	echo "Reloading privilege tables.."


Attachment: [text/bzr-bundle] bzr/timothy.smith@sun.com-20091103205028-afmvdk2r26eltv12.bundle
Thread
bzr commit into mysql-5.0-bugteam branch (timothy.smith:2836) Bug#48031Timothy Smith3 Nov