Commit 4da30b3e authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

MDEV-221 - Properly escape command line when starting mysql_install_db

since password characters can contain quotes or spaces.

The proper quoting method for command line arguments used here was  extracted from
http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx

Additionally, mysql_install_db.exe now passes root password to "mysqld.exe --bootstrap"
 in hexadecimal form, to handle potential special chars inside password string literal.
parent e638e605
......@@ -316,9 +316,9 @@ static int create_myini()
static const char update_root_passwd_part1[]=
"UPDATE mysql.user SET Password = PASSWORD('";
"UPDATE mysql.user SET Password = PASSWORD(";
static const char update_root_passwd_part2[]=
"') where User='root';\n";
") where User='root';\n";
static const char remove_default_user_cmd[]=
"DELETE FROM mysql.user where User='';\n";
static const char allow_remote_root_access_cmd[]=
......@@ -589,11 +589,19 @@ static int create_db_instance()
}
/* Change root password if requested. */
if (opt_password)
if (opt_password && opt_password[0])
{
verbose("Changing root password",remove_default_user_cmd);
verbose("Setting root password",remove_default_user_cmd);
fputs(update_root_passwd_part1, in);
fputs(opt_password, in);
/* Use hex encoding for password, to avoid escaping problems.*/
fputc('0', in);
fputc('x', in);
for(int i= 0; opt_password[i]; i++)
{
fprintf(in,"%02x",opt_password[i]);
}
fputs(update_root_passwd_part2, in);
fflush(in);
}
......
......@@ -71,6 +71,82 @@ LExit:
return WcaFinalize(er);
}
/*
Escape command line parameter fpr pass to CreateProcess().
We assume out has enough space to include encoded string
2*wcslen(in) is enough.
It is assumed that called will add double quotation marks before and after
the string.
*/
static void EscapeCommandLine(const wchar_t *in, wchar_t *out)
{
const wchar_t special_chars[]=L" \t\n\v\"";
bool needs_escaping= false;
size_t pos;
for(int i=0; i< sizeof(special_chars) -1; i++)
{
if (wcschr(in, special_chars[i]))
{
needs_escaping = true;
break;
}
}
if(!needs_escaping)
{
wcscpy(out, in);
return;
}
pos= 0;
for(int i = 0 ; ; i++)
{
size_t n_backslashes = 0;
wchar_t c;
while (in[i] == L'\\')
{
i++;
n_backslashes++;
}
c= in[i];
if (c == 0)
{
/*
Escape all backslashes, but let the terminating double quotation mark
that caller adds be interpreted as a metacharacter.
*/
for(int j= 0; j < 2*n_backslashes;j++)
{
out[pos++]=L'\\';
}
break;
}
else if (c == L'"')
{
/*
Escape all backslashes and the following double quotation mark.
*/
for(int j= 0; j < 2*n_backslashes + 1; j++)
{
out[pos++]=L'\\';
}
out[pos++]= L'"';
}
else
{
/* Backslashes aren't special here. */
for (int j=0; j < n_backslashes; j++)
out[pos++] = L'\\';
out[pos++]= c;
}
}
out[pos++]= 0;
}
/*
Check for if directory is empty during install,
sets "<PROPERTY>_NOT_EMPTY" otherise
......@@ -460,6 +536,8 @@ unsigned long long GetMaxBufferSize(unsigned long long totalPhys)
return totalPhys;
#endif
}
/*
Checks SERVICENAME, PORT and BUFFERSIZE parameters
*/
......@@ -468,6 +546,8 @@ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall)
wchar_t ServiceName[MAX_PATH]={0};
wchar_t SkipNetworking[MAX_PATH]={0};
wchar_t QuickConfig[MAX_PATH]={0};
wchar_t Password[MAX_PATH]={0};
wchar_t EscapedPassword[2*MAX_PATH+2];
wchar_t Port[6];
wchar_t BufferPoolSize[16];
DWORD PortLen=6;
......@@ -510,8 +590,12 @@ extern "C" UINT __stdcall CheckDatabaseProperties (MSIHANDLE hInstall)
}
}
DWORD SkipNetworkingLen= MAX_PATH;
DWORD PasswordLen= MAX_PATH;
MsiGetPropertyW (hInstall, L"PASSWORD", Password, &PasswordLen);
EscapeCommandLine(Password, EscapedPassword);
MsiSetPropertyW(hInstall,L"ESCAPEDPASSWORD",EscapedPassword);
DWORD SkipNetworkingLen= MAX_PATH;
MsiGetPropertyW(hInstall, L"SKIPNETWORKING", SkipNetworking,
&SkipNetworkingLen);
MsiGetPropertyW(hInstall, L"PORT", Port, &PortLen);
......
......@@ -34,6 +34,7 @@
<!-- Root password -->
<Property Id="PASSWORD" Hidden="yes" Secure="yes" />
<Property Id="ESCAPEDPASSWORD" Hidden="yes" Secure="yes" />
<!-- Database port -->
<Property Id="PORT" Value="3306" Secure="yes"/>
<!-- Whether to allow remote access for root user -->
......@@ -668,7 +669,7 @@
<CustomAction Id='PresetDatabaseProperties' BinaryKey='wixca.dll' DllEntry='PresetDatabaseProperties' />
<CustomAction Id="CreateDatabaseCommand" Property="CreateDatabase"
Value=
"&quot;[#F.bin.mysql_install_db.exe]&quot; &quot;--service=[SERVICENAME]&quot; --port=[PORT] &quot;--password=[PASSWORD]&quot; &quot;--datadir=[DATADIR]\&quot; [SKIPNETWORKING] [ALLOWREMOTEROOTACCESS] [DEFAULTUSER]"
"&quot;[#F.bin.mysql_install_db.exe]&quot; &quot;--service=[SERVICENAME]&quot; --port=[PORT] &quot;--password=[ESCAPEDPASSWORD]&quot; &quot;--datadir=[DATADIR]\&quot; [SKIPNETWORKING] [ALLOWREMOTEROOTACCESS] [DEFAULTUSER]"
Execute="immediate"
HideTarget="yes"
/>
......@@ -703,7 +704,7 @@
<![CDATA[&DBInstance=3 AND NOT !DBInstance=3 AND OLDERVERSIONBEINGUPGRADED=""]]>
</Custom>
<Custom Action="ErrorDataDirNotEmpty" After="CheckDataDirectoryEmpty" >DATADIRNOTEMPTY</Custom>
<Custom Action="CheckDatabaseProperties" Before="CreateDatabaseCommand">SERVICENAME</Custom>
<Custom Action="CreateDatabaseCommand" After="CostFinalize" >
<![CDATA[&DBInstance=3 AND NOT !DBInstance=3 AND OLDERVERSIONBEINGUPGRADED=""]]>
</Custom>
......
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