shlexec: Fixes for buffer overrun problems

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi, this is a cleanup of shell32/shlexec.c to remove potential buffer 
overruns. I've also tried to make parts of the code a little easier to 
follow, without affecting the functionality.

Index: dlls/shell32/shlexec.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shlexec.c,v
retrieving revision 1.23
diff -u -r1.23 shlexec.c
--- dlls/shell32/shlexec.c	26 Sep 2003 04:35:01 -0000	1.23
+++ dlls/shell32/shlexec.c	11 Dec 2003 17:30:27 -0000
@@ -53,6 +53,58 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(exec);
 
+
+/***********************************************************************
+ * Append the string 'append' onto the string 'appendTo'. 'appendTo' will be
+ * allocated from the heap, and will be automatically updated on reallocation.
+ * 'appendLen' can be used to constrain the length of 'append'. Set to -1 to
+ * append everything.
+ */
+static BOOL SHELL_heapStrAppend(char** appendTo, const char* append, int appendLen) {
+    char* tmp;
+    int len = 1; // need +1 for the null
+
+    // calculate length of data to append
+    if (*appendTo != NULL) {
+        len += strlen(*appendTo);
+    }
+
+    if (append != NULL) {
+        if (appendLen == -1) {
+            appendLen = strlen(append);
+        }
+        len += appendLen;
+    }
+
+    // allocate/reallocate the string
+    tmp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
+    if (tmp == NULL) {
+        return FALSE;
+    }
+
+    // update
+    if (*appendTo != NULL) {
+        strcpy(tmp, *appendTo);
+    }
+    HeapFree(GetProcessHeap(), 0, *appendTo);
+    *appendTo = tmp;
+
+    // concatenate the strings together
+    if (append != NULL) strncat(*appendTo, append, appendLen);
+
+    // success!
+    return TRUE;
+}
+
+/***********************************************************************
+ * Free a supplied heap-allocated string.
+ */
+static void SHELL_heapStrFree(char** appendTo) {
+    if ((!appendTo) || (!*appendTo)) return;
+    HeapFree(GetProcessHeap(), 0, *appendTo);
+    *appendTo = NULL;
+}
+
 /***********************************************************************
  * this function is supposed to expand the escape sequences found in the registry
  * some diving reported that the following were used:
@@ -65,58 +117,67 @@
  * %L seems to be %1 as long filename followed by the 8+3 variation
  * %S ???
  * %* all following parameters (see batfile)
+ *
+ * Returns: 0 for error, 1 if completed successfully, 2 if successful, AND lpFile was used
  */
-static BOOL argify(char* res, int len, const char* fmt, const char* lpFile)
+static int SHELL_argify(char** res, const char* fmt, const char* lpFile)
 {
     char        xlpFile[1024];
-    BOOL        done = FALSE;
+    int         result = 1;
 
     while (*fmt)
     {
-        if (*fmt == '%')
-        {
-            switch (*++fmt)
-            {
-            case '\0':
-            case '%':
-                *res++ = '%';
+        if (*fmt == '%') {
+            fmt++;
+
+            switch (*fmt) {
+            case '\0': // string ended with a single % - copy it across
+            case '%': // %% - i.e. a single % character
+                if (!SHELL_heapStrAppend(res, "%", -1)) return 0;
                 break;
+
             case '1':
             case '*':
-                if (!done || (*fmt == '1'))
-                {
-                    if (SearchPathA(NULL, lpFile, ".exe", sizeof(xlpFile), xlpFile, NULL))
-                    {
-                        strcpy(res, xlpFile);
-                        res += strlen(xlpFile);
-                    }
-                    else
-                    {
-                        strcpy(res, lpFile);
-                        res += strlen(lpFile);
+                if ((result == 1) || (*fmt == '1')) {
+                    if (SearchPathA(NULL, lpFile, ".exe", sizeof(xlpFile), xlpFile, NULL)) {
+                        if (!SHELL_heapStrAppend(res, xlpFile, -1)) return 0;
+                    } else {
+                        if (!SHELL_heapStrAppend(res, lpFile, -1)) return 0;
                     }
                 }
+                result = 2;
                 break;
+
             /*
-             * IE uses this alot for activating things such as windows media
-             * player. This is not verified to be fully correct but it appears
-             * to work just fine.
-             */
+            * IE uses this alot for activating things such as windows media
+            * player. This is not verified to be fully correct but it appears
+            * to work just fine.
+            */
             case 'L':
-                strcpy(res,lpFile);
-                res += strlen(lpFile);
+                if (!SHELL_heapStrAppend(res, lpFile, -1)) return 0;
+                result = 2;
                 break;
 
-            default: FIXME("Unknown escape sequence %%%c\n", *fmt);
+            default:
+                FIXME("Unknown escape sequence %%%c\n", *fmt);
+                break;
             }
+
             fmt++;
-            done = TRUE;
         }
-        else
-            *res++ = *fmt++;
+        else { // any other character
+            char* ptr = strchr(fmt, '%');
+            if (ptr == NULL) {
+                if (!SHELL_heapStrAppend(res, fmt, -1)) return 0;
+                break;
+            } else {
+                if (!SHELL_heapStrAppend(res, fmt, ptr - fmt)) return 0;
+                fmt += (ptr - fmt);
+            }
+        }
     }
-    *res = '\0';
-    return done;
+
+    return result;
 }
 
 /*************************************************************************
@@ -228,35 +289,45 @@
 static BOOL SHELL_TryAppPath( LPCSTR szName, LPSTR lpResult, void**env)
 {
     HKEY hkApp = 0;
-    char buffer[256];
+    char* regKey = NULL;
+    char value[1024];
     LONG len;
     LONG res;
     BOOL found = FALSE;
 
     if (env) *env = NULL;
-    sprintf(buffer, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s", szName);
-    res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hkApp);
+
+    // open the key
+    if (!SHELL_heapStrAppend(&regKey, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\", -1)) goto end;
+    if (!SHELL_heapStrAppend(&regKey, szName, -1)) goto end;
+    res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, regKey, 0, KEY_READ, &hkApp);
     if (res) goto end;
 
+    // read the default value
     len = MAX_PATH;
     res = RegQueryValueA(hkApp, NULL, lpResult, &len);
     if (res) goto end;
     found = TRUE;
 
+    // build the environment
     if (env)
     {
-        DWORD count = sizeof(buffer);
-        if (!RegQueryValueExA(hkApp, "Path", NULL, NULL, buffer, &count) && buffer[0])
-            *env = build_env( buffer );
+        DWORD count = sizeof(value);
+        if (!RegQueryValueExA(hkApp, "Path", NULL, NULL, value, &count)) {
+            if (value[0]) {
+                *env = build_env( value );
+            }
+        }
     }
 
 end:
+    SHELL_heapStrFree(&regKey);
     if (hkApp) RegCloseKey(hkApp);
     return found;
 }
 
 /*************************************************************************
- *	SHELL_FindExecutable [Internal]
+ * SHELL_FindExecutable [Internal]
  *
  * Utility for code sharing between FindExecutable and ShellExecute
  * in:
@@ -274,14 +345,16 @@
 {
     char *extension = NULL; /* pointer to file extension */
     char tmpext[5];         /* local copy to mung as we please */
-    char filetype[256];     /* registry name for this filetype */
+    char filetype[257];     /* registry name for this filetype */
     LONG filetypelen = 256; /* length of above */
-    char command[256];      /* command from registry */
+    char command[257];      /* command from registry */
     LONG commandlen = 256;  /* This is the most DOS can handle :) */
     char buffer[256];       /* Used to GetProfileString */
     UINT retval = 31;  /* default - 'No association was found' */
     char *tok;              /* token pointer */
     char xlpFile[256] = ""; /* result of SearchPath */
+    char* regKey = NULL;
+    char* tmpResult = NULL;
 
     TRACE("%s\n", (lpFile != NULL) ? lpFile : "-");
 
@@ -315,7 +388,7 @@
                                        /* .\FILE.EXE :( */
     TRACE("xlpFile=%s,extension=%s\n", xlpFile, extension);
 
-    if ((extension == NULL) || (extension == &xlpFile[strlen(xlpFile)]))
+    if ((extension == NULL) || ((extension - xlpFile) == strlen(xlpFile)))
     {
         WARN("Returning 31 - No association\n");
         return 31; /* no association */
@@ -355,10 +428,10 @@
                 TRACE("found %s\n", lpResult);
                 return 33;
 
-		/* Greater than 32 to indicate success FIXME According to the
-		 * docs, I should be returning a handle for the
-		 * executable. Does this mean I'm supposed to open the
-		 * executable file or something? More RTFM, I guess... */
+                /* Greater than 32 to indicate success FIXME According to the
+                * docs, I should be returning a handle for the
+                * executable. Does this mean I'm supposed to open the
+                * executable file or something? More RTFM, I guess... */
             }
             tok = strtok(NULL, " \t");
         }
@@ -368,51 +441,54 @@
     if (RegQueryValueA(HKEY_CLASSES_ROOT, tmpext, filetype,
                        &filetypelen) == ERROR_SUCCESS)
     {
-	filetype[filetypelen] = '\0';
-	TRACE("File type: %s\n", filetype);
+        filetype[filetypelen] = '\0';
+        TRACE("File type: %s\n", filetype);
 
-	/* Looking for ...buffer\shell\lpOperation\command */
-	strcat(filetype, "\\shell\\");
-	strcat(filetype, lpOperation);
-	strcat(filetype, "\\command");
-
-	if (RegQueryValueA(HKEY_CLASSES_ROOT, filetype, command,
-                           &commandlen) == ERROR_SUCCESS)
-	{
-            if (key) strcpy(key, filetype);
+        /* Looking for ...buffer\shell\lpOperation\command */
+        if (!SHELL_heapStrAppend(&regKey, filetype, -1)) goto end;
+        if (!SHELL_heapStrAppend(&regKey, "\\shell\\", -1)) goto end;
+        if (!SHELL_heapStrAppend(&regKey, lpOperation, -1)) goto end;
+        if (!SHELL_heapStrAppend(&regKey, "\\command", -1)) goto end;
+
+        if (RegQueryValueA(HKEY_CLASSES_ROOT, regKey, command,
+                            &commandlen) == ERROR_SUCCESS)
+        {
+            if (key) strcpy(key, regKey);
 #if 0
             LPSTR tmp;
             char param[256];
-	    LONG paramlen = 256;
+            LONG paramlen = 256;
 
             /* FIXME: it seems all Windows version don't behave the same here.
              * the doc states that this ddeexec information can be found after
              * the exec names.
              * on Win98, it doesn't appear, but I think it does on Win2k
              */
-	    /* Get the parameters needed by the application
-	       from the associated ddeexec key */
-	    tmp = strstr(filetype, "command");
-	    tmp[0] = '\0';
-	    strcat(filetype, "ddeexec");
+            /* Get the parameters needed by the application
+            from the associated ddeexec key */
+            tmp = strstr(filetype, "command");
+            tmp[0] = '\0';
+            strcat(filetype, "ddeexec");
 
-	    if (RegQueryValueA(HKEY_CLASSES_ROOT, filetype, param, &paramlen) == ERROR_SUCCESS)
-	    {
+            if (RegQueryValueA(HKEY_CLASSES_ROOT, filetype, param, &paramlen) == ERROR_SUCCESS)
+            {
                 strcat(command, " ");
                 strcat(command, param);
                 commandlen += paramlen;
-	    }
+            }
 #endif
-	    command[commandlen] = '\0';
-            argify(lpResult, sizeof(lpResult), command, xlpFile);
-	    retval = 33; /* FIXME see above */
-	}
+            command[commandlen] = '\0';
+            if (!SHELL_argify(&tmpResult, command, xlpFile)) goto end;
+            strncpy(lpResult, tmpResult, MAX_PATH-1);
+            lpResult[MAX_PATH-1] = 0;
+            retval = 33; /* FIXME see above */
+        }
     }
     else /* Check win.ini */
     {
-	/* Toss the leading dot */
-	extension++;
-	if (GetProfileStringA("extensions", extension, "", command,
+        /* Toss the leading dot */
+        extension++;
+        if (GetProfileStringA("extensions", extension, "", command,
                               sizeof(command)) > 0)
         {
             if (strlen(command) != 0)
@@ -434,6 +510,9 @@
         }
     }
 
+end:
+    SHELL_heapStrFree(&tmpResult);
+    SHELL_heapStrFree(&regKey);
     TRACE("returning %s\n", lpResult);
     return retval;
 }
@@ -463,8 +542,7 @@
                             const char* lpFile, void *env,
                             LPSHELLEXECUTEINFOA sei, SHELL_ExecuteA1632 execfunc)
 {
-    char*       endkey = key + strlen(key);
-    char        app[256], topic[256], ifexec[256], res[256];
+    char        app[256], topic[256], ifexec[256];
     LONG        applen, topiclen, ifexeclen;
     char*       exec;
     DWORD       ddeInst = 0;
@@ -472,25 +550,32 @@
     HSZ         hszApp, hszTopic;
     HCONV       hConv;
     unsigned    ret = 31;
+    char*       regKey = NULL;
+    char*       cmd = NULL;
 
-    strcpy(endkey, "\\application");
+    if (!SHELL_heapStrAppend(&regKey, key, -1)) goto end;
+    if (!SHELL_heapStrAppend(&regKey, "\\application", -1)) goto end;
     applen = sizeof(app);
-    if (RegQueryValueA(HKEY_CLASSES_ROOT, key, app, &applen) != ERROR_SUCCESS)
+    if (RegQueryValueA(HKEY_CLASSES_ROOT, regKey, app, &applen) != ERROR_SUCCESS)
     {
-        FIXME("default app name NIY %s\n", key);
-        return 2;
+        FIXME("default app name NIY %s\n", regKey);
+        ret = 2;
+        goto end;
     }
 
-    strcpy(endkey, "\\topic");
+    SHELL_heapStrFree(&regKey);
+    if (!SHELL_heapStrAppend(&regKey, key, -1)) goto end;
+    if (!SHELL_heapStrAppend(&regKey, "\\topic", -1)) goto end;
     topiclen = sizeof(topic);
-    if (RegQueryValueA(HKEY_CLASSES_ROOT, key, topic, &topiclen) != ERROR_SUCCESS)
+    if (RegQueryValueA(HKEY_CLASSES_ROOT, regKey, topic, &topiclen) != ERROR_SUCCESS)
     {
         strcpy(topic, "System");
     }
 
     if (DdeInitializeA(&ddeInst, dde_cb, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR)
     {
-        return 2;
+        ret = 2;
+        goto end;
     }
 
     hszApp = DdeCreateStringHandleA(ddeInst, app, CP_WINANSI);
@@ -505,30 +590,36 @@
         if (ret < 32)
         {
             TRACE("Couldn't launch\n");
-            goto error;
+            goto end;
         }
         hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
         if (!hConv)
         {
             TRACE("Couldn't connect. ret=%d\n", ret);
             ret = 30; /* whatever */
-            goto error;
+            goto end;
         }
-        strcpy(endkey, "\\ifexec");
+
+        SHELL_heapStrFree(&regKey);
+        SHELL_heapStrAppend(&regKey, key, -1);
+        SHELL_heapStrAppend(&regKey, "\\ifexec", -1);
         ifexeclen = sizeof(ifexec);
-        if (RegQueryValueA(HKEY_CLASSES_ROOT, key, ifexec, &ifexeclen) == ERROR_SUCCESS)
+        if (RegQueryValueA(HKEY_CLASSES_ROOT, regKey, ifexec, &ifexeclen) == ERROR_SUCCESS)
         {
             exec = ifexec;
         }
     }
 
-    argify(res, sizeof(res), exec, lpFile);
-    TRACE("%s %s => %s\n", exec, lpFile, res);
+    if (!SHELL_argify(&cmd, exec, lpFile)) goto end;
+    TRACE("%s %s => %s\n", exec, lpFile, cmd);
 
-    ret = (DdeClientTransaction(res, strlen(res) + 1, hConv, 0L, 0,
+    ret = (DdeClientTransaction(cmd, strlen(cmd) + 1, hConv, 0L, 0,
                                 XTYP_EXECUTE, 10000, &tid) != DMLERR_NO_ERROR) ? 31 : 33;
     DdeDisconnect(hConv);
- error:
+
+end:
+    SHELL_heapStrFree(&cmd);
+    SHELL_heapStrFree(&regKey);
     DdeUninitialize(ddeInst);
     return ret;
 }
@@ -542,6 +633,8 @@
     char cmd[1024] = "";
     LONG cmdlen = sizeof(cmd);
     UINT retval = 31;
+    char* regKey = NULL;
+    char* tmpStr = NULL;
 
     /* Get the application for the registry */
     if (RegQueryValueA(HKEY_CLASSES_ROOT, key, cmd, &cmdlen) == ERROR_SUCCESS)
@@ -552,25 +645,29 @@
 
         /* Get the parameters needed by the application
            from the associated ddeexec key */
-        tmp = strstr(key, "command");
-        assert(tmp);
+        if (!SHELL_heapStrAppend(&regKey, key, -1)) goto end;
+        tmp = strstr(regKey, "command");
+        if (tmp == NULL) goto end;
         strcpy(tmp, "ddeexec");
 
-        if (RegQueryValueA(HKEY_CLASSES_ROOT, key, param, &paramlen) == ERROR_SUCCESS)
+        if (RegQueryValueA(HKEY_CLASSES_ROOT, regKey, param, &paramlen) == ERROR_SUCCESS)
         {
-            TRACE("Got ddeexec %s => %s\n", key, param);
-            retval = dde_connect(key, cmd, param, lpFile, env, sei, execfunc);
+            TRACE("Got ddeexec %s => %s\n", regKey, param);
+            retval = dde_connect(regKey, cmd, param, lpFile, env, sei, execfunc);
         }
         else
         {
             /* Is there a replace() function anywhere? */
             cmd[cmdlen] = '\0';
-            argify(param, sizeof(param), cmd, lpFile);
-            retval = execfunc(param, env, sei, FALSE);
+            if (!SHELL_argify(&tmpStr, cmd, lpFile)) goto end;
+            retval = execfunc(tmpStr, env, sei, FALSE);
         }
     }
-    else TRACE("ooch\n");
+    else TRACE("Failed to find application\n");
 
+end:
+    SHELL_heapStrFree(&regKey);
+    SHELL_heapStrFree(&tmpStr);
     return retval;
 }
 
@@ -591,7 +688,7 @@
     if ((lpFile == NULL) || (lpResult == NULL))
     {
         /* FIXME - should throw a warning, perhaps! */
-	return (HINSTANCE)2; /* File not found. Close enough, I guess. */
+        return (HINSTANCE)2; /* File not found. Close enough, I guess. */
     }
 
     if (lpDirectory)
@@ -622,15 +719,15 @@
  */
 BOOL WINAPI ShellExecuteExA32 (LPSHELLEXECUTEINFOA sei, SHELL_ExecuteA1632 execfunc)
 {
-    CHAR szApplicationName[MAX_PATH],szCommandline[MAX_PATH],szPidl[20],fileName[MAX_PATH];
-    LPSTR pos;
-    void *env;
-    int gap, len;
-    char lpstrProtocol[256];
-    LPCSTR lpFile,lpOperation;
+    LPCSTR lpOperation;
+    void* env = NULL;
+    char* szApplicationName = NULL;
+    char* szCommandLine = NULL;
+    char* szCmd = NULL;
+    CHAR tmpString[MAX_PATH*2];
+    CHAR tmpString2[MAX_PATH*2];
     UINT retval = 31;
-    char cmd[1024];
-    BOOL done;
+    BOOL success = FALSE;
 
     TRACE("mask=0x%08lx hwnd=%p verb=%s file=%s parm=%s dir=%s show=0x%08x class=%s\n",
             sei->fMask, sei->hwnd, debugstr_a(sei->lpVerb),
@@ -639,13 +736,6 @@
             (sei->fMask & SEE_MASK_CLASSNAME) ? debugstr_a(sei->lpClass) : "not used");
 
     sei->hProcess = NULL;
-    ZeroMemory(szApplicationName,MAX_PATH);
-    if (sei->lpFile)
-        strcpy(szApplicationName, sei->lpFile);
-
-    ZeroMemory(szCommandline,MAX_PATH);
-    if (sei->lpParameters)
-        strcpy(szCommandline, sei->lpParameters);
 
     if (sei->fMask & (SEE_MASK_INVOKEIDLIST | SEE_MASK_ICON | SEE_MASK_HOTKEY |
         SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT |
@@ -658,60 +748,100 @@
     /* process the IDList */
     if ( (sei->fMask & SEE_MASK_INVOKEIDLIST) == SEE_MASK_INVOKEIDLIST) /*0x0c*/
     {
-        SHGetPathFromIDListA (sei->lpIDList,szApplicationName);
+        SHGetPathFromIDListA(sei->lpIDList, tmpString);
+        if (!SHELL_heapStrAppend(&szApplicationName, tmpString, -1)) goto end;
+        if (!SHELL_heapStrAppend(&szCommandLine, sei->lpParameters, -1)) goto end;
         TRACE("-- idlist=%p (%s)\n", sei->lpIDList, szApplicationName);
     }
     else
     {
+        if (!SHELL_heapStrAppend(&szApplicationName, sei->lpFile, -1)) goto end;
+
         if (sei->fMask & SEE_MASK_IDLIST )
         {
-            pos = strstr(szCommandline, "%I");
-            if (pos)
-            {
+            char* pos = strstr(sei->lpParameters, "%I");
+            if (pos) {
+                // get the PID
                 LPVOID pv;
                 HGLOBAL hmem = SHAllocShared ( sei->lpIDList, ILGetSize(sei->lpIDList), 0);
                 pv = SHLockShared(hmem,0);
-                sprintf(szPidl,":%p",pv );
+                sprintf(tmpString, ":%p", pv);
                 SHUnlockShared(pv);
 
-                gap = strlen(szPidl);
-                len = strlen(pos)-2;
-                memmove(pos+gap,pos+2,len);
-                memcpy(pos,szPidl,gap);
+                // replace the %I with the PID
+                if (!SHELL_heapStrAppend(&szCommandLine, sei->lpParameters, pos - sei->lpParameters)) goto end;
+                if (!SHELL_heapStrAppend(&szCommandLine, tmpString, -1)) goto end;
+                if (!SHELL_heapStrAppend(&szCommandLine, pos+2, -1)) goto end;
             }
         }
+
+        if (szCommandLine == NULL) {
+            if (!SHELL_heapStrAppend(&szCommandLine, sei->lpParameters, -1)) goto end;
+        }
     }
 
     if (sei->fMask & (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY))
     {
-	/* launch a document by fileclass like 'WordPad.Document.1' */
+        int argFlag;
+
+        /* launch a document by fileclass like 'WordPad.Document.1' */
         /* the Commandline contains 'c:\Path\wordpad.exe "%1"' */
-        /* FIXME: szCommandline should not be of a fixed size. Plus MAX_PATH is way too short! */
         if (sei->fMask & SEE_MASK_CLASSKEY)
             HCR_GetExecuteCommandEx(sei->hkeyClass,
-                                    (sei->fMask & SEE_MASK_CLASSNAME) ? sei->lpClass: NULL,
-                                    (sei->lpVerb) ? sei->lpVerb : "open", szCommandline, sizeof(szCommandline));
+                                    (sei->fMask & SEE_MASK_CLASSNAME) ? sei->lpClass : NULL,
+                                    (sei->lpVerb) ? sei->lpVerb : "open",
+                                    tmpString, sizeof(tmpString));
         else if (sei->fMask & SEE_MASK_CLASSNAME)
-            HCR_GetExecuteCommandA(sei->lpClass, (sei->lpVerb) ? sei->lpVerb :
-                                  "open", szCommandline, sizeof(szCommandline));
+            HCR_GetExecuteCommandA(sei->lpClass,
+                                    (sei->lpVerb) ? sei->lpVerb : "open",
+                                    tmpString, sizeof(tmpString));
 
         /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
-        TRACE("SEE_MASK_CLASSNAME->'%s', doc->'%s'\n", szCommandline, szApplicationName);
+        TRACE("SEE_MASK_CLASSNAME->'%s', doc->'%s'\n", tmpString, szApplicationName);
 
-        cmd[0] = '\0';
-        done = argify(cmd, sizeof(cmd), szCommandline, szApplicationName);
-        if (!done && szApplicationName[0])
-        {
-            strcat(cmd, " ");
-            strcat(cmd, szApplicationName);
+        // try and execute it
+        SHELL_heapStrFree(&szCmd);
+        argFlag = SHELL_argify(&szCmd, tmpString, szApplicationName);
+        if (!argFlag) goto end;
+        if ((argFlag == 1) && szApplicationName[0]) {
+            if (!SHELL_heapStrAppend(&szCmd, " ", -1)) goto end;
+            if (!SHELL_heapStrAppend(&szCmd, szApplicationName, -1)) goto end;
         }
-        retval = execfunc(cmd, NULL, sei, FALSE);
-        if (retval > 32)
-            return TRUE;
-        else
-            return FALSE;
+
+        TRACE("%s\n", szCmd);
+
+        retval = execfunc(szCmd, NULL, sei, FALSE);
+
+        // deal with the results
+            if (retval > 32) {
+            success = TRUE;
+        } else {
+            success = FALSE;
+        }
+        goto end;
     }
 
+
+    /* OK, try just executing it first of all */
+    SHELL_heapStrFree(&szCmd);
+    if (!SHELL_heapStrAppend(&szCmd, "\"", -1)) goto end;
+    if (!SHELL_heapStrAppend(&szCmd, szApplicationName, -1)) goto end;
+    if (!SHELL_heapStrAppend(&szCmd, "\"", -1)) goto end;
+    if (szCommandLine[0]) {
+        if (!SHELL_heapStrAppend(&szCmd, " ", -1)) goto end;
+        if (!SHELL_heapStrAppend(&szCmd, szCommandLine, -1)) goto end;
+    }
+
+
+    TRACE("%s\n", szCmd);
+
+    retval = execfunc(szCmd, NULL, sei, FALSE);
+    if (retval > 32) {
+        success = TRUE;
+        goto end;
+    }
+
+
     /* We set the default to open, and that should generally work.
        But that is not really the way the MS docs say to do it. */
     if (sei->lpVerb == NULL)
@@ -719,85 +849,96 @@
     else
         lpOperation = sei->lpVerb;
 
-    /* Else, try to execute the filename */
-    TRACE("execute:'%s','%s'\n",szApplicationName, szCommandline);
 
-    strcpy(fileName, szApplicationName);
-    lpFile = fileName;
-    if (szCommandline[0]) {
-        strcat(szApplicationName, " ");
-        strcat(szApplicationName, szCommandline);
-    }
+    TRACE("%s/%s/%s\n", sei->lpDirectory, szApplicationName, lpOperation);
 
-    retval = execfunc(szApplicationName, NULL, sei, FALSE);
-    if (retval > 32)
-        return TRUE;
 
     /* Else, try to find the executable */
-    cmd[0] = '\0';
-    retval = SHELL_FindExecutable(sei->lpDirectory, lpFile, lpOperation, cmd, lpstrProtocol, &env);
+    retval = SHELL_FindExecutable(sei->lpDirectory, szApplicationName, lpOperation, tmpString, tmpString2, &env);
     if (retval > 32)  /* Found */
     {
-        CHAR szQuotedCmd[MAX_PATH+2];
-        /* Must quote to handle case where cmd contains spaces, 
-         * else security hole if malicious user creates executable file "C:\\Program"
-         */
-        if (szCommandline[0])
-            sprintf(szQuotedCmd, "\"%s\" %s", cmd, szCommandline);
-        else
-            sprintf(szQuotedCmd, "\"%s\"", cmd);
-        TRACE("%s/%s => %s/%s\n", szApplicationName, lpOperation, szQuotedCmd, lpstrProtocol);
-        if (*lpstrProtocol)
-            retval = execute_from_key(lpstrProtocol, szApplicationName, env, sei, execfunc);
-        else
-            retval = execfunc(szQuotedCmd, env, sei, FALSE);
-        if (env) HeapFree( GetProcessHeap(), 0, env );
+        // execute it
+        if (tmpString2[0]) {
+            TRACE("%s/%s\n", szApplicationName, tmpString2);
+
+            retval = execute_from_key(tmpString2, szApplicationName, env, sei, execfunc);
+        } else {
+            // OK, it has found a path to an executable
+            SHELL_heapStrFree(&szCmd);
+            if (!SHELL_heapStrAppend(&szCmd, "\"", -1)) goto end;
+            if (!SHELL_heapStrAppend(&szCmd, tmpString, -1)) goto end;
+            if (!SHELL_heapStrAppend(&szCmd, "\"", -1)) goto end;
+            if (szCommandLine[0]) {
+                if (!SHELL_heapStrAppend(&szCmd, " ", -1)) goto end;
+                if (!SHELL_heapStrAppend(&szCmd, szCommandLine, -1)) goto end;
+            }
+
+            TRACE("%s\n", szCmd);
+
+            // execute it
+            retval = execfunc(szCmd, env, sei, FALSE);
+        }
     }
-    else if (PathIsURLA((LPSTR)lpFile))    /* File not found, check for URL */
+    else if (PathIsURLA(szApplicationName))    /* File not found, check for URL */
     {
-        LPSTR lpstrRes;
-        INT iSize;
+        int copySize;
+        int offset = 0;
+        char* pos;
 
-        lpstrRes = strchr(lpFile, ':');
-        if (lpstrRes)
-            iSize = lpstrRes - lpFile;
-        else
-            iSize = strlen(lpFile);
+        // get the protocol of the URL
+        pos = strchr(szApplicationName, ':');
+        if (pos) {
+            copySize = pos - szApplicationName;
+        } else {
+            copySize = -1;
+        }
 
-        TRACE("Got URL: %s\n", lpFile);
-        /* Looking for ...protocol\shell\lpOperation\command */
-        strncpy(lpstrProtocol, lpFile, iSize);
-        lpstrProtocol[iSize] = '\0';
-        strcat(lpstrProtocol, "\\shell\\");
-        strcat(lpstrProtocol, lpOperation);
-        strcat(lpstrProtocol, "\\command");
+        /* build up the registry key we need */
+        SHELL_heapStrFree(&szCmd);
+        if (!SHELL_heapStrAppend(&szCmd, szApplicationName, copySize)) goto end;
+        if (!SHELL_heapStrAppend(&szCmd, "\\shell\\", -1)) goto end;
+        if (!SHELL_heapStrAppend(&szCmd, lpOperation, -1)) goto end;
+        if (!SHELL_heapStrAppend(&szCmd, "\\command", -1)) goto end;
 
-        /* Remove File Protocol from lpFile */
+        /* Remove File Protocol from szApplication */
         /* In the case file://path/file     */
-        if (!strncasecmp(lpFile, "file", iSize))
-        {
-            lpFile += iSize;
-            while (*lpFile == ':') lpFile++;
+        if (!strncasecmp(szApplicationName, "file", 4)) {
+            offset = 4;
+            while (szApplicationName[offset] == ':') offset++;
         }
-        retval = execute_from_key(lpstrProtocol, lpFile, NULL, sei, execfunc);
+
+        TRACE("%s/%s\n", szCmd, szApplicationName+offset);
+
+        // execute it
+        retval = execute_from_key(szCmd, szApplicationName + offset, NULL, sei, execfunc);
     }
     /* Check if file specified is in the form www.??????.*** */
-    else if (!strncasecmp(lpFile, "www", 3))
+    else if (!strncasecmp(szApplicationName, "www", 3))
     {
-        /* if so, append lpFile http:// and call ShellExecute */
-        char lpstrTmpFile[256] = "http://"; ;
-        strcat(lpstrTmpFile, lpFile);
-        retval = (UINT)ShellExecuteA(sei->hwnd, lpOperation, lpstrTmpFile, NULL, NULL, 0);
+        SHELL_heapStrFree(&szCmd);
+        if (!SHELL_heapStrAppend(&szCmd, "http://";, -1)) goto end;
+        if (!SHELL_heapStrAppend(&szCmd, szApplicationName, -1)) goto end;
+
+        TRACE("%s/%s\n", szCmd, lpOperation);
+
+        retval = (UINT)ShellExecuteA(sei->hwnd, lpOperation, szCmd, NULL, NULL, 0);
     }
 
-    if (retval <= 32)
-    {
+    /* decide on the result */
+    if (retval <= 32) {
         sei->hInstApp = (HINSTANCE)retval;
-        return FALSE;
+        success = FALSE;
+    } else {
+        sei->hInstApp = (HINSTANCE)33;
+        success = TRUE;
     }
 
-    sei->hInstApp = (HINSTANCE)33;
-    return TRUE;
+end:
+    if (env) HeapFree( GetProcessHeap(), 0, env );
+    SHELL_heapStrFree(&szCmd);
+    SHELL_heapStrFree(&szApplicationName);
+    SHELL_heapStrFree(&szCommandLine);
+    return success;
 }
 
 /*************************************************************************
@@ -835,7 +976,7 @@
 BOOL WINAPI ShellExecuteExAW (LPVOID sei)
 {
     if (SHELL_OsIsUnicode())
-	return ShellExecuteExW (sei);
+        return ShellExecuteExW (sei);
     return ShellExecuteExA32 (sei, SHELL_ExecuteA);
 }
 

[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux