added feature to control uac elevation on desk switch (login screen, lock, etc)

This commit is contained in:
Nick Bolton 2012-07-28 13:34:35 +00:00
parent 268f3a99bb
commit 86bb49aeae
13 changed files with 64 additions and 21 deletions

View File

@ -404,6 +404,14 @@ void MainWindow::startSynergy()
{ {
// tell client/server to talk to daemon through ipc. // tell client/server to talk to daemon through ipc.
args << "--ipc"; args << "--ipc";
#if defined(Q_OS_WIN)
// tell the client/server to shut down when a ms windows desk
// is switched; this is because we may need to elevate or not
// based on which desk the user is in (login always needs
// elevation, where as default desk does not).
args << "--stop-on-desk-switch";
#endif
} }
if ((synergyType() == synergyClient && !clientArgs(args, app)) if ((synergyType() == synergyClient && !clientArgs(args, app))

View File

@ -92,7 +92,7 @@
CMSWindowsDesks::CMSWindowsDesks( CMSWindowsDesks::CMSWindowsDesks(
bool isPrimary, bool noHooks, HINSTANCE hookLibrary, bool isPrimary, bool noHooks, HINSTANCE hookLibrary,
const IScreenSaver* screensaver, IEventQueue& eventQueue, const IScreenSaver* screensaver, IEventQueue& eventQueue,
IJob* updateKeys) : IJob* updateKeys, bool stopOnDeskSwitch) :
m_isPrimary(isPrimary), m_isPrimary(isPrimary),
m_noHooks(noHooks), m_noHooks(noHooks),
m_is95Family(CArchMiscWindows::isWindows95Family()), m_is95Family(CArchMiscWindows::isWindows95Family()),
@ -110,7 +110,8 @@ CMSWindowsDesks::CMSWindowsDesks(
m_mutex(), m_mutex(),
m_deskReady(&m_mutex, false), m_deskReady(&m_mutex, false),
m_updateKeys(updateKeys), m_updateKeys(updateKeys),
m_eventQueue(eventQueue) m_eventQueue(eventQueue),
m_stopOnDeskSwitch(stopOnDeskSwitch)
{ {
if (hookLibrary != NULL) if (hookLibrary != NULL)
queryHookLibrary(hookLibrary); queryHookLibrary(hookLibrary);
@ -906,6 +907,14 @@ CMSWindowsDesks::checkDesk()
desk = index->second; desk = index->second;
} }
// if we are told to shut down on desk switch, and this is not the
// first switch, then shut down.
if (m_stopOnDeskSwitch && m_activeDesk != NULL && name != m_activeDeskName) {
LOG((CLOG_DEBUG "shutting down because of desk switch to \"%s\"", name.c_str()));
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
return;
}
// if active desktop changed then tell the old and new desk threads // if active desktop changed then tell the old and new desk threads
// about the change. don't switch desktops when the screensaver is // about the change. don't switch desktops when the screensaver is
// active becaue we'd most likely switch to the screensaver desktop // active becaue we'd most likely switch to the screensaver desktop

View File

@ -66,7 +66,7 @@ public:
CMSWindowsDesks( CMSWindowsDesks(
bool isPrimary, bool noHooks, HINSTANCE hookLibrary, bool isPrimary, bool noHooks, HINSTANCE hookLibrary,
const IScreenSaver* screensaver, IEventQueue& eventQueue, const IScreenSaver* screensaver, IEventQueue& eventQueue,
IJob* updateKeys); IJob* updateKeys, bool stopOnDeskSwitch);
~CMSWindowsDesks(); ~CMSWindowsDesks();
//! @name manipulators //! @name manipulators
@ -305,6 +305,9 @@ private:
bool m_leaveForegroundOption; bool m_leaveForegroundOption;
IEventQueue& m_eventQueue; IEventQueue& m_eventQueue;
// true if program should stop on desk switch.
bool m_stopOnDeskSwitch;
}; };
#endif #endif

View File

@ -93,7 +93,7 @@ CMSWindowsRelauncher::getSessionId()
} }
BOOL BOOL
CMSWindowsRelauncher::isProcessInSession(const char* name, DWORD sessionId, PHANDLE process) CMSWindowsRelauncher::isProcessInSession(const char* name, DWORD sessionId, PHANDLE process = NULL)
{ {
// first we need to take a snapshot of the running processes // first we need to take a snapshot of the running processes
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
@ -175,14 +175,15 @@ CMSWindowsRelauncher::isProcessInSession(const char* name, DWORD sessionId, PHAN
CloseHandle(snapshot); CloseHandle(snapshot);
if (pid) { if (pid) {
// now get the process so we can get the process, with which if (process != NULL) {
// we'll use to get the process token. // now get the process so we can get the process, with which
LOG((CLOG_DEBUG "found %s in session %i", name, sessionId)); // we'll use to get the process token.
*process = OpenProcess(MAXIMUM_ALLOWED, FALSE, pid); LOG((CLOG_DEBUG "found %s in session %i", name, sessionId));
*process = OpenProcess(MAXIMUM_ALLOWED, FALSE, pid);
}
return true; return true;
} }
else { else {
LOG((CLOG_DEBUG "could not find %s in session %i", name, sessionId));
return false; return false;
} }
} }
@ -219,23 +220,29 @@ CMSWindowsRelauncher::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTE
return newToken; return newToken;
} }
// use either an elevated token (winlogon) or the user's session
// token (non-elevated). processes launched with a non-elevated token
// cannot interact with elevated processes.
HANDLE HANDLE
CMSWindowsRelauncher::getUserToken(DWORD sessionId, LPSECURITY_ATTRIBUTES security) CMSWindowsRelauncher::getUserToken(DWORD sessionId, LPSECURITY_ATTRIBUTES security)
{ {
if (m_elevateProcess) { // always elevate if we are at the vista/7 login screen. we could also
// elevate for the uac dialog (consent.exe) but this would be pointless,
// since synergy would re-launch as non-elevated after the desk switch,
// and so would be unusable with the new elevated process taking focus.
if (m_elevateProcess || isProcessInSession("logonui.exe", sessionId)) {
LOG((CLOG_DEBUG "getting elevated token, %s",
(m_elevateProcess ? "elevation required" : "at login screen")));
HANDLE process; HANDLE process;
if (isProcessInSession("winlogon.exe", sessionId, &process)) { if (isProcessInSession("winlogon.exe", sessionId, &process)) {
return duplicateProcessToken(process, security); return duplicateProcessToken(process, security);
} }
else { else {
LOG((CLOG_ERR "could not find token in session %d", sessionId)); LOG((CLOG_ERR "could not find winlogon in session %i", sessionId));
return NULL; return NULL;
} }
} }
else { else {
LOG((CLOG_DEBUG "getting non-elevated token"));
return getSessionToken(sessionId, security); return getSessionToken(sessionId, security);
} }
} }

View File

@ -80,7 +80,11 @@
HINSTANCE CMSWindowsScreen::s_windowInstance = NULL; HINSTANCE CMSWindowsScreen::s_windowInstance = NULL;
CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL; CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL;
CMSWindowsScreen::CMSWindowsScreen(bool isPrimary, bool noHooks, const CGameDeviceInfo& gameDeviceInfo) : CMSWindowsScreen::CMSWindowsScreen(
bool isPrimary,
bool noHooks,
const CGameDeviceInfo& gameDeviceInfo,
bool stopOnDeskSwitch) :
m_isPrimary(isPrimary), m_isPrimary(isPrimary),
m_noHooks(noHooks), m_noHooks(noHooks),
m_is95Family(CArchMiscWindows::isWindows95Family()), m_is95Family(CArchMiscWindows::isWindows95Family()),
@ -124,7 +128,8 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary, bool noHooks, const CGameDevi
m_hookLibrary, m_screensaver, m_hookLibrary, m_screensaver,
*EVENTQUEUE, *EVENTQUEUE,
new TMethodJob<CMSWindowsScreen>(this, new TMethodJob<CMSWindowsScreen>(this,
&CMSWindowsScreen::updateKeysCB)); &CMSWindowsScreen::updateKeysCB),
stopOnDeskSwitch);
m_keyState = new CMSWindowsKeyState(m_desks, getEventTarget()); m_keyState = new CMSWindowsKeyState(m_desks, getEventTarget());
updateScreenShape(); updateScreenShape();
m_class = createWindowClass(); m_class = createWindowClass();

View File

@ -40,7 +40,11 @@ class CThread;
//! Implementation of IPlatformScreen for Microsoft Windows //! Implementation of IPlatformScreen for Microsoft Windows
class CMSWindowsScreen : public CPlatformScreen { class CMSWindowsScreen : public CPlatformScreen {
public: public:
CMSWindowsScreen(bool isPrimary, bool noHooks, const CGameDeviceInfo &gameDevice); CMSWindowsScreen(
bool isPrimary,
bool noHooks,
const CGameDeviceInfo &gameDevice,
bool stopOnDeskSwitch);
virtual ~CMSWindowsScreen(); virtual ~CMSWindowsScreen();
//! @name manipulators //! @name manipulators

View File

@ -87,6 +87,9 @@ CAppUtilWindows::parseArg(const int& argc, const char* const* argv, int& i)
else if (app().isArg(i, argc, argv, NULL, "--game-poll-freq")) { else if (app().isArg(i, argc, argv, NULL, "--game-poll-freq")) {
app().argsBase().m_gameDevice.m_pollFreq = atoi(argv[++i]); app().argsBase().m_gameDevice.m_pollFreq = atoi(argv[++i]);
} }
else if (app().isArg(i, argc, argv, NULL, "--stop-on-desk-switch")) {
app().argsBase().m_stopOnDeskSwitch = true;
}
else { else {
// option not supported here // option not supported here
return false; return false;

View File

@ -22,6 +22,7 @@ CArgsBase::CArgsBase() :
m_daemon(false), // daemon mode not supported on windows (use --service) m_daemon(false), // daemon mode not supported on windows (use --service)
m_debugServiceWait(false), m_debugServiceWait(false),
m_pauseOnExit(false), m_pauseOnExit(false),
m_stopOnDeskSwitch(false),
#else #else
m_daemon(true), // backward compatibility for unix (daemon by default) m_daemon(true), // backward compatibility for unix (daemon by default)
#endif #endif

View File

@ -40,6 +40,7 @@ public:
bool m_debugServiceWait; bool m_debugServiceWait;
bool m_pauseOnExit; bool m_pauseOnExit;
CGameDeviceInfo m_gameDevice; CGameDeviceInfo m_gameDevice;
bool m_stopOnDeskSwitch;
#endif #endif
#if WINAPI_XWINDOWS #if WINAPI_XWINDOWS
bool m_disableXInitThreads; bool m_disableXInitThreads;

View File

@ -233,7 +233,8 @@ CScreen*
CClientApp::createScreen() CClientApp::createScreen()
{ {
#if WINAPI_MSWINDOWS #if WINAPI_MSWINDOWS
return new CScreen(new CMSWindowsScreen(false, args().m_noHooks, args().m_gameDevice)); return new CScreen(new CMSWindowsScreen(
false, args().m_noHooks, args().m_gameDevice, args().m_stopOnDeskSwitch));
#elif WINAPI_XWINDOWS #elif WINAPI_XWINDOWS
return new CScreen(new CXWindowsScreen( return new CScreen(new CXWindowsScreen(
args().m_display, false, args().m_disableXInitThreads, args().m_display, false, args().m_disableXInitThreads,

View File

@ -221,7 +221,7 @@ CDaemonApp::mainLoop(bool logToFile)
// (such as a stop request from the service controller). // (such as a stop request from the service controller).
CMSWindowsScreen::init(CArchMiscWindows::instanceWin32()); CMSWindowsScreen::init(CArchMiscWindows::instanceWin32());
CGameDeviceInfo gameDevice; CGameDeviceInfo gameDevice;
CScreen dummyScreen(new CMSWindowsScreen(false, true, gameDevice)); CScreen dummyScreen(new CMSWindowsScreen(false, true, gameDevice, false));
CString command = ARCH->setting("Command"); CString command = ARCH->setting("Command");
bool elevate = ARCH->setting("Elevate") == "1"; bool elevate = ARCH->setting("Elevate") == "1";

View File

@ -645,7 +645,8 @@ CScreen*
CServerApp::createScreen() CServerApp::createScreen()
{ {
#if WINAPI_MSWINDOWS #if WINAPI_MSWINDOWS
return new CScreen(new CMSWindowsScreen(true, args().m_noHooks, args().m_gameDevice)); return new CScreen(new CMSWindowsScreen(
true, args().m_noHooks, args().m_gameDevice, args().m_stopOnDeskSwitch));
#elif WINAPI_XWINDOWS #elif WINAPI_XWINDOWS
return new CScreen(new CXWindowsScreen( return new CScreen(new CXWindowsScreen(
args().m_display, true, args().m_disableXInitThreads, 0, *EVENTQUEUE)); args().m_display, true, args().m_disableXInitThreads, 0, *EVENTQUEUE));

View File

@ -55,7 +55,7 @@ protected:
return new CMSWindowsDesks( return new CMSWindowsDesks(
true, false, m_hookLibrary, m_screensaver, eventQueue, true, false, m_hookLibrary, m_screensaver, eventQueue,
new TMethodJob<CMSWindowsKeyStateTests>( new TMethodJob<CMSWindowsKeyStateTests>(
this, &CMSWindowsKeyStateTests::updateKeysCB)); this, &CMSWindowsKeyStateTests::updateKeysCB), false);
} }
void* getEventTarget() const void* getEventTarget() const