When re-launching the application after an update is installed, do it from a non-elevated process.

Previously the application was restarted from the main install process, which may have
  been elevated.  The main application must be started from a non-elevated updater/updater.exe
  process otherwise the main app will inherit the elevated status from its parent.

  * Modify ProcessUtils::runElevated() to return the status code of the process
  * Change UpdateInstaller to run the main installation synchronously from the initial
    updater process in the case where elevation is not required.
  * Remove calls in main.cpp to relaunch the main application after the UI is closed.
This commit is contained in:
Robert Knight 2011-08-26 11:17:09 +01:00
parent d705095fe9
commit 098c9cb194
4 changed files with 63 additions and 30 deletions

View file

@ -71,15 +71,15 @@ void ProcessUtils::runAsync(const std::string& executable,
#endif
}
void ProcessUtils::runElevated(const std::string& executable,
int ProcessUtils::runElevated(const std::string& executable,
const std::list<std::string>& args)
{
#ifdef PLATFORM_WINDOWS
runElevatedWindows(executable,args);
return runElevatedWindows(executable,args);
#elif defined(PLATFORM_MAC)
runElevatedMac(executable,args);
return runElevatedMac(executable,args);
#elif defined(PLATFORM_LINUX)
runElevatedLinux(executable,args);
return runElevatedLinux(executable,args);
#endif
}
@ -114,7 +114,7 @@ bool ProcessUtils::waitForProcess(PLATFORM_PID pid)
}
#ifdef PLATFORM_LINUX
void ProcessUtils::runElevatedLinux(const std::string& executable,
int ProcessUtils::runElevatedLinux(const std::string& executable,
const std::list<std::string>& args)
{
std::string sudoMessage = FileOps::fileName(executable.c_str()) + " needs administrative privileges. Please enter your password.";
@ -152,9 +152,11 @@ void ProcessUtils::runElevatedLinux(const std::string& executable,
int result = ProcessUtils::runSync(sudoBinary,sudoArgs);
if (result != 255)
{
return result;
break;
}
}
return RUN_ELEVATED_FAILED;
}
#endif
@ -245,10 +247,13 @@ void ProcessUtils::runElevatedMac(const std::string& executable,
{
LOG(Info,"elevated process succeded with pid " + intToStr(childPid));
}
return childStatus;
}
else
{
LOG(Error,"failed to launch elevated process " + intToStr(status));
return RUN_ELEVATED_FAILED;
}
// If we want to know more information about what has happened:
@ -262,13 +267,18 @@ void ProcessUtils::runElevatedMac(const std::string& executable,
else
{
LOG(Error,"failed to get rights to launch elevated process. status: " + intToStr(status));
return RUN_ELEVATED_FAILED;
}
}
else
{
return RUN_ELEVATED_FAILED;
}
}
#endif
#ifdef PLATFORM_WINDOWS
void ProcessUtils::runElevatedWindows(const std::string& executable,
int ProcessUtils::runElevatedWindows(const std::string& executable,
const std::list<std::string>& arguments)
{
std::string args;
@ -304,10 +314,14 @@ void ProcessUtils::runElevatedWindows(const std::string& executable,
if (!ShellExecuteEx(&executeInfo))
{
LOG(Error,"Failed to start with admin priviledges using ShellExecuteEx()");
return;
return RUN_ELEVATED_FAILED;
}
WaitForSingleObject(executeInfo.hProcess, INFINITE);
// this assumes the process succeeded - we need to check whether
// this is actually the case.
return 0;
}
#endif

View file

@ -8,6 +8,14 @@
class ProcessUtils
{
public:
enum Errors
{
/** Status code returned by runElevated() if launching
* the elevated process fails.
*/
RUN_ELEVATED_FAILED = 255
};
static PLATFORM_PID currentProcessId();
static std::string currentProcessPath();
@ -18,7 +26,13 @@ class ProcessUtils
static void runAsync(const std::string& executable,
const std::list<std::string>& args);
static void runElevated(const std::string& executable,
/** Run a process with administrative privileges and return the
* status code of the process, or 0 on Windows.
*
* Returns RUN_ELEVATED_FAILED if the elevated process could
* not be started.
*/
static int runElevated(const std::string& executable,
const std::list<std::string>& args);
static bool waitForProcess(PLATFORM_PID pid);
@ -32,11 +46,11 @@ class ProcessUtils
#endif
private:
static void runElevatedLinux(const std::string& executable,
static int runElevatedLinux(const std::string& executable,
const std::list<std::string>& args);
static void runElevatedMac(const std::string& executable,
static int runElevatedMac(const std::string& executable,
const std::list<std::string>& args);
static void runElevatedWindows(const std::string& executable,
static int runElevatedWindows(const std::string& executable,
const std::list<std::string>& args);
static PLATFORM_PID runAsyncUnix(const std::string& executable,

View file

@ -98,20 +98,40 @@ void UpdateInstaller::run() throw ()
args.push_back("--wait");
args.push_back(intToStr(ProcessUtils::currentProcessId()));
int installStatus = 0;
if (!checkAccess())
{
LOG(Info,"Insufficient rights to install app to " + m_installDir + " requesting elevation");
// start a copy of the updater with admin rights
ProcessUtils::runElevated(updaterPath,args);
installStatus = ProcessUtils::runElevated(updaterPath,args);
}
else
{
LOG(Info,"Sufficient rights to install app - restarting with same permissions");
// TODO - Change this to run synchronously
ProcessUtils::runAsync(updaterPath,args);
installStatus = ProcessUtils::runSync(updaterPath,args);
}
if (installStatus == 0)
{
LOG(Info,"Update install completed");
}
else
{
LOG(Error,"Update install failed with status " + intToStr(installStatus));
}
// restart the main application - this is currently done
// regardless of whether the installation succeeds or not
restartMainApp();
// clean up files created by the updater
std::list<std::string> cleanupArgs = updaterArgs();
cleanupArgs.push_back("--mode");
cleanupArgs.push_back("cleanup");
cleanupArgs.push_back("--wait");
cleanupArgs.push_back(intToStr(ProcessUtils::currentProcessId()));
ProcessUtils::runAsync(updaterPath,cleanupArgs);
}
else if (m_mode == Main)
{
@ -152,13 +172,6 @@ void UpdateInstaller::run() throw ()
{
m_observer->updateFinished();
}
std::list<std::string> args = updaterArgs();
args.push_back("--mode");
args.push_back("cleanup");
args.push_back("--wait");
args.push_back(intToStr(ProcessUtils::currentProcessId()));
ProcessUtils::runAsync(updaterPath,args);
}
else if (m_mode == Cleanup)
{

View file

@ -94,15 +94,9 @@ void runWithUi(int argc, char** argv, UpdateInstaller* installer)
tthread::thread updaterThread(runUpdaterThread,installer);
dialog.exec();
updaterThread.join();
if (dialog.restartApp())
{
installer->restartMainApp();
}
#else
// no UI available - do a silent install
installer->run();
installer->restartMainApp();
#endif
}
#endif
@ -116,7 +110,6 @@ void runWithUi(int argc, char** argv, UpdateInstaller* installer)
tthread::thread updaterThread(runUpdaterThread,installer);
dialog.exec();
updaterThread.join();
installer->restartMainApp();
}
#endif
@ -141,6 +134,5 @@ void runWithUi(int argc, char** argv, UpdateInstaller* installer)
tthread::thread updaterThread(runUpdaterThread,installer);
dialog.exec();
updaterThread.join();
installer->restartMainApp();
}
#endif