shell32: Have SHELL_ArgifyW respect the length of the buffer passed in and report a needed buffer size.

This commit is contained in:
Aric Stewart 2006-11-03 10:24:19 -06:00 committed by Alexandre Julliard
parent 3490cb81ed
commit 3f9a168f47
1 changed files with 112 additions and 29 deletions

View File

@ -75,17 +75,15 @@ static const WCHAR wszEmpty[] = {0};
* %S ??? * %S ???
* %* all following parameters (see batfile) * %* all following parameters (see batfile)
* *
* FIXME: use 'len'
* FIXME: Careful of going over string boundaries. No checking is done to 'res'...
*/ */
static BOOL SHELL_ArgifyW(WCHAR* out, int len, const WCHAR* fmt, const WCHAR* lpFile, LPITEMIDLIST pidl, LPCWSTR args) static BOOL SHELL_ArgifyW(WCHAR* out, int len, const WCHAR* fmt, const WCHAR* lpFile, LPITEMIDLIST pidl, LPCWSTR args, DWORD* out_len)
{ {
WCHAR xlpFile[1024]; WCHAR xlpFile[1024];
BOOL done = FALSE; BOOL done = FALSE;
BOOL found_p1 = FALSE; BOOL found_p1 = FALSE;
PWSTR res = out; PWSTR res = out;
PCWSTR cmd; PCWSTR cmd;
LPVOID pv; DWORD used = 0;
TRACE("%p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt), TRACE("%p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt),
debugstr_w(lpFile), pidl, args); debugstr_w(lpFile), pidl, args);
@ -98,7 +96,9 @@ static BOOL SHELL_ArgifyW(WCHAR* out, int len, const WCHAR* fmt, const WCHAR* lp
{ {
case '\0': case '\0':
case '%': case '%':
*res++ = '%'; used++;
if (used < len)
*res++ = '%';
break; break;
case '2': case '2':
@ -115,15 +115,31 @@ static BOOL SHELL_ArgifyW(WCHAR* out, int len, const WCHAR* fmt, const WCHAR* lp
{ {
if (*fmt == '*') if (*fmt == '*')
{ {
*res++ = '"'; used++;
if (used < len)
*res++ = '"';
while(*args) while(*args)
*res++ = *args++; {
*res++ = '"'; used++;
if (used < len)
*res++ = *args++;
else
args++;
}
used++;
if (used < len)
*res++ = '"';
} }
else else
{ {
while(*args && !isspace(*args)) while(*args && !isspace(*args))
*res++ = *args++; {
used++;
if (used < len)
*res++ = *args++;
else
args++;
}
while(isspace(*args)) while(isspace(*args))
++args; ++args;
@ -145,15 +161,27 @@ static BOOL SHELL_ArgifyW(WCHAR* out, int len, const WCHAR* fmt, const WCHAR* lp
enclosed in double quotation marks */ enclosed in double quotation marks */
if ((res == out || *(fmt + 1) != '"') && *cmd != '"') if ((res == out || *(fmt + 1) != '"') && *cmd != '"')
{ {
*res++ = '"'; used++;
strcpyW(res, cmd); if (used < len)
res += strlenW(cmd); *res++ = '"';
*res++ = '"'; used += strlenW(cmd);
if (used < len)
{
strcpyW(res, cmd);
res += strlenW(cmd);
}
used++;
if (used < len)
*res++ = '"';
} }
else else
{ {
strcpyW(res, cmd); used += strlenW(cmd);
res += strlenW(cmd); if (used < len)
{
strcpyW(res, cmd);
res += strlenW(cmd);
}
} }
} }
found_p1 = TRUE; found_p1 = TRUE;
@ -167,18 +195,35 @@ static BOOL SHELL_ArgifyW(WCHAR* out, int len, const WCHAR* fmt, const WCHAR* lp
case 'l': case 'l':
case 'L': case 'L':
if (lpFile) { if (lpFile) {
strcpyW(res, lpFile); used += strlenW(lpFile);
res += strlenW(lpFile); if (used < len)
{
strcpyW(res, lpFile);
res += strlenW(lpFile);
}
} }
found_p1 = TRUE; found_p1 = TRUE;
break; break;
case 'i': case 'i':
case 'I': case 'I':
if (pidl) { if (pidl) {
INT chars = 0;
/* %p should not exceed 8, maybe 16 when looking foward to 64bit.
* allowing a buffer of 100 should more than exceed all needs */
WCHAR buf[100];
LPVOID pv;
HGLOBAL hmem = SHAllocShared(pidl, ILGetSize(pidl), 0); HGLOBAL hmem = SHAllocShared(pidl, ILGetSize(pidl), 0);
pv = SHLockShared(hmem, 0); pv = SHLockShared(hmem, 0);
res += sprintfW(res, wszILPtr, pv); chars = sprintfW(buf, wszILPtr, pv);
if (chars >= sizeof(buf)/sizeof(WCHAR))
ERR("pidl format buffer too small!");
used += chars;
if (used < len)
{
strcpyW(res,buf);
res += chars;
}
SHUnlockShared(pv); SHUnlockShared(pv);
} }
found_p1 = TRUE; found_p1 = TRUE;
@ -205,10 +250,23 @@ static BOOL SHELL_ArgifyW(WCHAR* out, int len, const WCHAR* fmt, const WCHAR* lp
envRet = GetEnvironmentVariableW(tmpBuffer, tmpEnvBuff, MAX_PATH); envRet = GetEnvironmentVariableW(tmpBuffer, tmpEnvBuff, MAX_PATH);
if (envRet == 0 || envRet > MAX_PATH) if (envRet == 0 || envRet > MAX_PATH)
strcpyW( res, tmpBuffer ); {
used += strlenW(tmpBuffer);
if (used < len)
{
strcpyW( res, tmpBuffer );
res += strlenW(tmpBuffer);
}
}
else else
strcpyW( res, tmpEnvBuff ); {
res += strlenW(res); used += strlenW(tmpEnvBuff);
if (used < len)
{
strcpyW( res, tmpEnvBuff );
res += strlenW(tmpEnvBuff);
}
}
} }
done = TRUE; done = TRUE;
break; break;
@ -220,10 +278,19 @@ static BOOL SHELL_ArgifyW(WCHAR* out, int len, const WCHAR* fmt, const WCHAR* lp
} }
} }
else else
*res++ = *fmt++; {
used ++;
if (used < len)
*res++ = *fmt++;
else
fmt++;
}
} }
*res = '\0'; *res = '\0';
TRACE("used %i of %i space\n",used,len);
if (out_len)
*out_len = used;
return found_p1; return found_p1;
} }
@ -621,7 +688,10 @@ UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation,
if (retval > 32) if (retval > 32)
{ {
SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args); DWORD finishedLen;
SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args, &finishedLen);
if (finishedLen > resultLen)
ERR("Argify buffer not large enough.. truncated\n");
/* Remove double quotation marks and command line arguments */ /* Remove double quotation marks and command line arguments */
if (*lpResult == '"') if (*lpResult == '"')
@ -703,6 +773,7 @@ static unsigned dde_connect(WCHAR* key, const WCHAR* start, WCHAR* ddeexec,
WCHAR * exec; WCHAR * exec;
DWORD ddeInst = 0; DWORD ddeInst = 0;
DWORD tid; DWORD tid;
DWORD resultLen;
HSZ hszApp, hszTopic; HSZ hszApp, hszTopic;
HCONV hConv; HCONV hConv;
HDDEDATA hDdeData; HDDEDATA hDdeData;
@ -767,7 +838,9 @@ static unsigned dde_connect(WCHAR* key, const WCHAR* start, WCHAR* ddeexec,
} }
} }
SHELL_ArgifyW(res, sizeof(res)/sizeof(WCHAR), exec, lpFile, pidl, szCommandline); SHELL_ArgifyW(res, sizeof(res)/sizeof(WCHAR), exec, lpFile, pidl, szCommandline, &resultLen);
if (resultLen > sizeof(res)/sizeof(WCHAR))
ERR("Argify buffer not large enough, truncated\n");
TRACE("%s %s => %s\n", debugstr_w(exec), debugstr_w(lpFile), debugstr_w(res)); TRACE("%s %s => %s\n", debugstr_w(exec), debugstr_w(lpFile), debugstr_w(res));
/* It's documented in the KB 330337 that IE has a bug and returns /* It's documented in the KB 330337 that IE has a bug and returns
@ -820,6 +893,7 @@ static UINT_PTR execute_from_key(LPWSTR key, LPCWSTR lpFile, WCHAR *env, LPCWSTR
if (RegQueryValueW(HKEY_CLASSES_ROOT, key, cmd, &cmdlen) == ERROR_SUCCESS) if (RegQueryValueW(HKEY_CLASSES_ROOT, key, cmd, &cmdlen) == ERROR_SUCCESS)
{ {
WCHAR param[1024]; WCHAR param[1024];
DWORD resultLen;
TRACE("got cmd: %s\n", debugstr_w(cmd)); TRACE("got cmd: %s\n", debugstr_w(cmd));
@ -828,13 +902,16 @@ static UINT_PTR execute_from_key(LPWSTR key, LPCWSTR lpFile, WCHAR *env, LPCWSTR
/* Is there a replace() function anywhere? */ /* Is there a replace() function anywhere? */
cmdlen /= sizeof(WCHAR); cmdlen /= sizeof(WCHAR);
cmd[cmdlen] = '\0'; cmd[cmdlen] = '\0';
if (!SHELL_ArgifyW(param, sizeof(param)/sizeof(WCHAR), cmd, lpFile, psei->lpIDList, szCommandline)) if (!SHELL_ArgifyW(param, sizeof(param)/sizeof(WCHAR), cmd, lpFile, psei->lpIDList, szCommandline, &resultLen))
{ {
/* looks like there is no %1 param in the cmd, add one */ /* looks like there is no %1 param in the cmd, add one */
static const WCHAR oneW[] = { ' ','\"','%','1','\"',0 }; static const WCHAR oneW[] = { ' ','\"','%','1','\"',0 };
strcatW(cmd, oneW); strcatW(cmd, oneW);
SHELL_ArgifyW(param, sizeof(param)/sizeof(WCHAR), cmd, lpFile, psei->lpIDList, szCommandline); SHELL_ArgifyW(param, sizeof(param)/sizeof(WCHAR), cmd, lpFile, psei->lpIDList, szCommandline, &resultLen);
} }
if (resultLen > sizeof(param)/sizeof(WCHAR))
ERR("Argify buffer not large enough, truncating\n");
TRACE("executing: %s\n", debugstr_w(param)); TRACE("executing: %s\n", debugstr_w(param));
retval = execfunc(param, env, FALSE, psei, psei_out); retval = execfunc(param, env, FALSE, psei, psei_out);
} }
@ -1299,6 +1376,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
/* the Commandline contains 'c:\Path\wordpad.exe "%1"' */ /* the Commandline contains 'c:\Path\wordpad.exe "%1"' */
/* FIXME: szCommandline should not be of a fixed size. Fixed to 1024, MAX_PATH is way too short! */ /* FIXME: szCommandline should not be of a fixed size. Fixed to 1024, MAX_PATH is way too short! */
ULONG cmask=(sei_tmp.fMask & SEE_MASK_CLASSALL); ULONG cmask=(sei_tmp.fMask & SEE_MASK_CLASSALL);
DWORD resultLen;
HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? sei_tmp.hkeyClass : NULL, HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? sei_tmp.hkeyClass : NULL,
(cmask == SEE_MASK_CLASSNAME) ? sei_tmp.lpClass: NULL, (cmask == SEE_MASK_CLASSNAME) ? sei_tmp.lpClass: NULL,
sei_tmp.lpVerb, sei_tmp.lpVerb,
@ -1308,12 +1386,14 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
TRACE("SEE_MASK_CLASSNAME->'%s', doc->'%s'\n", debugstr_w(wszParameters), debugstr_w(wszApplicationName)); TRACE("SEE_MASK_CLASSNAME->'%s', doc->'%s'\n", debugstr_w(wszParameters), debugstr_w(wszApplicationName));
wcmd[0] = '\0'; wcmd[0] = '\0';
done = SHELL_ArgifyW(wcmd, sizeof(wcmd)/sizeof(WCHAR), wszParameters, wszApplicationName, sei_tmp.lpIDList, NULL); done = SHELL_ArgifyW(wcmd, sizeof(wcmd)/sizeof(WCHAR), wszParameters, wszApplicationName, sei_tmp.lpIDList, NULL, &resultLen);
if (!done && wszApplicationName[0]) if (!done && wszApplicationName[0])
{ {
strcatW(wcmd, wSpace); strcatW(wcmd, wSpace);
strcatW(wcmd, wszApplicationName); strcatW(wcmd, wszApplicationName);
} }
if (resultLen > sizeof(wcmd)/sizeof(WCHAR))
ERR("Argify buffer not large enough... truncating\n");
retval = execfunc(wcmd, NULL, FALSE, &sei_tmp, sei); retval = execfunc(wcmd, NULL, FALSE, &sei_tmp, sei);
HeapFree(GetProcessHeap(), 0, wszApplicationName); HeapFree(GetProcessHeap(), 0, wszApplicationName);
@ -1334,6 +1414,7 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
} else { } else {
WCHAR target[MAX_PATH]; WCHAR target[MAX_PATH];
DWORD attribs; DWORD attribs;
DWORD resultLen;
/* Check if we're executing a directory and if so use the /* Check if we're executing a directory and if so use the
handler for the Folder class */ handler for the Folder class */
strcpyW(target, buffer); strcpyW(target, buffer);
@ -1344,7 +1425,9 @@ BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
sei_tmp.lpVerb, sei_tmp.lpVerb,
buffer, sizeof(buffer))) { buffer, sizeof(buffer))) {
SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen, SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen,
buffer, target, sei_tmp.lpIDList, NULL); buffer, target, sei_tmp.lpIDList, NULL, &resultLen);
if (resultLen > dwApplicationNameLen)
ERR("Argify buffer not large enough... truncating\n");
} }
sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST; sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST;
} }