Bug 437349 - updater.exe lacks elevation manifest and fails to start when installer detection is disabled r=jmathies r=ted.mielczarek
--- a/toolkit/mozapps/update/src/updater/updater.cpp
+++ b/toolkit/mozapps/update/src/updater/updater.cpp
@@ -16,16 +16,17 @@
* The Initial Developer of the Original Code is
* Benjamin Smedberg <benjamin@smedbergs.us>
*
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@meer.net>
+ * Robert Strong <robert.bugzilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -1096,17 +1097,17 @@ LaunchWinPostProcess(const WCHAR *appExe
static int argc = 2;
static WCHAR* argv[3] = {
L"argv0ignoredbywinlaunchchild",
exearg,
L"\0"
};
- WinLaunchChild(exefullpath, argc, argv, 1);
+ WinLaunchChild(exefullpath, argc, argv, 0);
free(argv);
}
#endif
static void
LaunchCallbackApp(const NS_tchar *workingDir, int argc, NS_tchar **argv)
{
putenv("NO_EM_RESTART=");
@@ -1115,17 +1116,17 @@ LaunchCallbackApp(const NS_tchar *workin
// Run from the specified working directory (see bug 312360).
NS_tchdir(workingDir);
#if defined(USE_EXECV)
execv(argv[0], argv);
#elif defined(XP_MACOSX)
LaunchChild(argc, argv);
#elif defined(XP_WIN)
- WinLaunchChild(argv[0], argc, argv, -1);
+ WinLaunchChild(argv[0], argc, argv, 0);
#else
# warning "Need implementaton of LaunchCallbackApp"
#endif
}
static void
WriteStatusFile(int status)
{
@@ -1207,16 +1208,101 @@ int NS_main(int argc, NS_tchar **argv)
Sleep(50);
}
#else
int status;
waitpid(pid, &status, 0);
#endif
}
+#ifdef XP_WIN
+ // Launch a second instance of the updater with the runas verb on Windows
+ // when write access is denied to the installation directory.
+
+ NS_tchar updateLockFilePath[MAXPATHLEN];
+ NS_tsnprintf(updateLockFilePath, MAXPATHLEN,
+ NS_T("%s/update_in_progress.lock"), argv[3]);
+
+ // The update_in_progress.lock file should only exist during an update. In
+ // case it exists attempt to remove it and exit if that fails to prevent
+ // simultaneous updates occurring.
+ if (!_waccess(updateLockFilePath, F_OK) &&
+ NS_tremove(updateLockFilePath) != 0) {
+ fprintf(stderr, "Update already in progress! Exiting\n");
+ return 1;
+ }
+
+ HANDLE updateLockFileHandle;
+ updateLockFileHandle = CreateFileW(updateLockFilePath,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_FLAG_DELETE_ON_CLOSE,
+ NULL);
+
+ NS_tchar elevatedLockFilePath[MAXPATHLEN];
+ NS_tsnprintf(elevatedLockFilePath, MAXPATHLEN,
+ NS_T("%s/update_elevated.lock"), argv[1]);
+
+ if (updateLockFileHandle == INVALID_HANDLE_VALUE) {
+ if (!_waccess(elevatedLockFilePath, F_OK) &&
+ NS_tremove(elevatedLockFilePath) != 0) {
+ fprintf(stderr, "Update already elevated! Exiting\n");
+ return 1;
+ }
+
+ HANDLE elevatedFileHandle;
+ elevatedFileHandle = CreateFileW(elevatedLockFilePath,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_FLAG_DELETE_ON_CLOSE,
+ NULL);
+
+ if (elevatedFileHandle == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "Unable to create elevated lock file! Exiting\n");
+ return 1;
+ }
+
+ PRUnichar *cmdLine = MakeCommandLine(argc - 1, argv + 1);
+ if (!cmdLine) {
+ CloseHandle(elevatedFileHandle);
+ return 1;
+ }
+
+ SHELLEXECUTEINFO sinfo;
+ memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO));
+ sinfo.cbSize = sizeof(SHELLEXECUTEINFO);
+ sinfo.fMask = SEE_MASK_NOASYNC |
+ SEE_MASK_FLAG_NO_UI |
+ SEE_MASK_NOCLOSEPROCESS;
+ sinfo.hwnd = NULL;
+ sinfo.lpFile = argv[0];
+ sinfo.lpParameters = cmdLine;
+ sinfo.lpVerb = L"runas";
+ sinfo.nShow = SW_SHOWNORMAL;
+
+ BOOL result = ShellExecuteEx(&sinfo);
+ free(cmdLine);
+
+ if (result) {
+ WaitForSingleObject(sinfo.hProcess, INFINITE);
+ CloseHandle(sinfo.hProcess);
+ }
+
+ if (argc > 4)
+ LaunchCallbackApp(argv[3], argc - 4, argv + 4);
+
+ CloseHandle(elevatedFileHandle);
+ return 0;
+ }
+#endif
+
gSourcePath = argv[1];
LogInit();
// Run update process on a background thread. ShowProgressUI may return
// before QuitProgressUI has been called, so wait for UpdateThreadFunc to
// terminate.
Thread t;
@@ -1224,16 +1310,22 @@ int NS_main(int argc, NS_tchar **argv)
ShowProgressUI();
t.Join();
LogFinish();
#ifdef XP_WIN
if (gSucceeded && argc > 4)
LaunchWinPostProcess(argv[4]);
+ CloseHandle(updateLockFileHandle);
+ // If elevated return early and let the process that launched this process
+ // launch the callback application.
+ if (!_waccess(elevatedLockFilePath, F_OK) &&
+ NS_tremove(elevatedLockFilePath) != 0)
+ return 0;
#endif
// The callback to execute is given as the last N arguments of our command
// line. The first of those arguments specifies the working directory for
// the callback.
if (argc > 4)
LaunchCallbackApp(argv[3], argc - 4, argv + 4);
--- a/toolkit/mozapps/update/src/updater/updater.exe.manifest
+++ b/toolkit/mozapps/update/src/updater/updater.exe.manifest
@@ -14,9 +14,17 @@
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
+<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
+ <ms_asmv3:security>
+ <ms_asmv3:requestedPrivileges>
+ <ms_asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false">
+ </ms_asmv3:requestedExecutionLevel>
+ </ms_asmv3:requestedPrivileges>
+ </ms_asmv3:security>
+</ms_asmv3:trustInfo>
</assembly>
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1539,18 +1539,17 @@ int OS2LaunchChild(const char *aExePath,
return 0;
}
#endif
// If aBlankCommandLine is true, then the application will be launched with a
// blank command line instead of being launched with the same command line that
// it was initially started with.
static nsresult LaunchChild(nsINativeAppSupport* aNative,
- PRBool aBlankCommandLine = PR_FALSE,
- int needElevation = 0)
+ PRBool aBlankCommandLine = PR_FALSE)
{
aNative->Quit(); // release DDE mutex, if we're holding it
// Restart this process by exec'ing it into the current process
// if supported by the platform. Otherwise, use NSPR.
if (aBlankCommandLine) {
gRestartArgc = 1;
@@ -1568,17 +1567,17 @@ static nsresult LaunchChild(nsINativeApp
return rv;
#if defined(XP_WIN)
nsAutoString exePath;
rv = lf->GetPath(exePath);
if (NS_FAILED(rv))
return rv;
- if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, needElevation))
+ if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, 0))
return NS_ERROR_FAILURE;
#else
nsCAutoString exePath;
rv = lf->GetNativePath(exePath);
if (NS_FAILED(rv))
return rv;
@@ -3270,17 +3269,17 @@ XRE_main(int argc, char* argv[], const n
}
}
#endif
#ifdef MOZ_WIDGET_GTK2
MOZ_gdk_display_close(display);
#endif
- rv = LaunchChild(nativeApp, appInitiatedRestart, upgraded ? -1 : 0);
+ rv = LaunchChild(nativeApp, appInitiatedRestart);
#ifdef MOZ_CRASHREPORTER
if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
CrashReporter::UnsetExceptionHandler();
#endif
return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
}
--- a/toolkit/xre/nsUpdateDriver.cpp
+++ b/toolkit/xre/nsUpdateDriver.cpp
@@ -469,17 +469,17 @@ ApplyUpdate(nsIFile *greDir, nsIFile *up
LOG(("spawning updater process [%s]\n", updaterPath.get()));
#if defined(USE_EXECV)
chdir(applyToDir.get());
execv(updaterPath.get(), argv);
#elif defined(XP_WIN)
_wchdir(applyToDir.get());
- if (!WinLaunchChild(updaterPathW.get(), appArgc + 4, argv, 1))
+ if (!WinLaunchChild(updaterPathW.get(), appArgc + 4, argv, 0))
return;
_exit(0);
#else
PRStatus status;
PRProcessAttr *attr;
attr = PR_NewProcessAttr();
if (!attr)