Skip to content
This repository has been archived by the owner on May 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #501 from cboulay/noadmin
Browse files Browse the repository at this point in the history
Adding a non-admin version of psms for windows builds
  • Loading branch information
HipsterSloth authored Jan 1, 2018
2 parents 04429c9 + c66e588 commit d8c16b8
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
# Build directories
build*
bin*
dist*

# Auto-downloaded Dependencies
deps
Expand Down
169 changes: 161 additions & 8 deletions src/psmoveconfigtool/AppStage_ControllerSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,146 @@
#include <imgui.h>
#include <sstream>

#ifdef _WIN32
#include <windows.h> // Required for data types
#include <winuser.h>
#include <bthsdpdef.h>
#include <bluetoothapis.h>
#include <Dbt.h>
#include <guiddef.h>
#include <setupapi.h> // Device setup APIs
#include <assert.h>
#include <strsafe.h>
#include <winreg.h>
#include <Shellapi.h>
#include <TlHelp32.h>
#include <Psapi.h>
#endif // _WIN32

#ifdef _MSC_VER
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': snprintf
#define snprintf _snprintf
#endif

#ifdef _WIN32
class Win32AdminCheck {

public:
BOOL psMoveServiceFound = FALSE;
BOOL psMoveServiceAdminFound = FALSE;
BOOL psMoveServiceElevated = FALSE;
BOOL psMoveServiceAdminElevated = FALSE;
DWORD psMoveServiceId = 0;
DWORD psMoveServiceAdminEId = 0;

BOOL IsElevated(HANDLE hProcess) {
BOOL fRet = FALSE;
HANDLE hToken = NULL;
if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
TOKEN_ELEVATION Elevation;
DWORD cbSize = sizeof(TOKEN_ELEVATION);
if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize)) {
fRet = Elevation.TokenIsElevated;
}
}
if (hToken) {
CloseHandle(hToken);
}
return fRet;
}

void CheckProcesses() {

psMoveServiceFound = FALSE;
psMoveServiceAdminFound = FALSE;
psMoveServiceElevated = FALSE;
psMoveServiceAdminElevated = FALSE;
psMoveServiceId = 0;
psMoveServiceAdminEId = 0;


PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);

HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
if (stricmp(entry.szExeFile, "PSMoveService.exe") == 0)
{
psMoveServiceId = entry.th32ProcessID;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.th32ProcessID);

psMoveServiceFound = TRUE;
psMoveServiceElevated = IsElevated(hProcess);

CloseHandle(hProcess);
}

if (stricmp(entry.szExeFile, "PSMoveServiceAdmin.exe") == 0)
{
psMoveServiceAdminEId = entry.th32ProcessID;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.th32ProcessID);

psMoveServiceAdminFound = TRUE;
psMoveServiceAdminElevated = IsElevated(hProcess);

CloseHandle(hProcess);
}

}
}

CloseHandle(snapshot);
}

void RestartAdminMode() {
if (psMoveServiceId != 0 && !psMoveServiceElevated)
{
char moduleFileName[MAXCHAR];
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, psMoveServiceId);
if (hProcess != NULL) {

GetModuleFileNameEx(hProcess, NULL, moduleFileName, MAXCHAR);

TerminateProcess(hProcess, 0);
CloseHandle(hProcess);

char drive[5];
char dir[MAXCHAR];
_splitpath_s(moduleFileName, drive, sizeof(drive), dir, sizeof(dir), NULL, 0, NULL, 0);

std::string adminDir = drive;
adminDir = adminDir + dir;
std::string adminPath = adminDir + "PSMoveServiceAdmin.exe";

SHELLEXECUTEINFO ShExecInfo;
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = NULL;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpFile = adminPath.c_str();
ShExecInfo.lpParameters = NULL;
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_NORMAL;
ShExecInfo.hInstApp = NULL;

BOOL create = ShellExecuteEx(&ShExecInfo);
}
}
}

BOOL IsAnyElevated() {
return psMoveServiceElevated || psMoveServiceAdminElevated;
}

};

Win32AdminCheck adminCheck;
#endif

//-- statics ----
const char *AppStage_ControllerSettings::APP_STAGE_NAME= "ControllerSettings";
const char *AppStage_ControllerSettings::GAMEPAD_COMBO_LABELS[MAX_GAMEPAD_LABELS] = {
Expand Down Expand Up @@ -88,6 +223,10 @@ AppStage_ControllerSettings::AppStage_ControllerSettings(App *app)

void AppStage_ControllerSettings::enter()
{
#ifdef _WIN32
adminCheck.CheckProcesses();
#endif

m_app->setCameraType(_cameraFixed);

request_controller_list();
Expand Down Expand Up @@ -324,22 +463,36 @@ void AppStage_ControllerSettings::renderUI()

if (controllerInfo.ControllerType == PSMController_Move)
{
if (controllerInfo.IsBluetooth)
#ifdef _WIN32
if (adminCheck.IsAnyElevated())
{
if (ImGui::Button("Unpair Controller"))
#endif
if (controllerInfo.IsBluetooth)
{
m_app->getAppStage<AppStage_PairController>()->request_controller_unpair(controllerInfo.ControllerID, controllerInfo.ControllerType);
m_app->setAppStage(AppStage_PairController::APP_STAGE_NAME);
if (ImGui::Button("Unpair Controller"))
{
m_app->getAppStage<AppStage_PairController>()->request_controller_unpair(controllerInfo.ControllerID, controllerInfo.ControllerType);
m_app->setAppStage(AppStage_PairController::APP_STAGE_NAME);
}
}
else
{
if (ImGui::Button("Pair Controller"))
{
m_app->getAppStage<AppStage_PairController>()->request_controller_pair(controllerInfo.ControllerID, controllerInfo.ControllerType);
m_app->setAppStage(AppStage_PairController::APP_STAGE_NAME);
}
}
#ifdef _WIN32
}
else
else
{
if (ImGui::Button("Pair Controller"))
if (ImGui::Button("Restart Service in Admin mode\nto Pair or Unpair Controller"))
{
m_app->getAppStage<AppStage_PairController>()->request_controller_pair(controllerInfo.ControllerID, controllerInfo.ControllerType);
m_app->setAppStage(AppStage_PairController::APP_STAGE_NAME);
adminCheck.RestartAdminMode();
}
}
#endif
}

if (!m_app->excludePositionSettings &&
Expand Down
2 changes: 1 addition & 1 deletion src/psmoveconfigtool/AppStage_MainMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ bool AppStage_MainMenu::onClientAPIEvent(
case PSMEventMessage::PSMEvent_disconnectedFromService:
{
// Tell the user that we failed to connect
m_menuState= AppStage_MainMenu::failedConnectionToService;
m_menuState= AppStage_MainMenu::disconnectedFromService;

// If we weren't running this stage, make sure we are now
if (m_app->getCurrentAppStage() != this)
Expand Down
2 changes: 1 addition & 1 deletion src/psmoveprotocol/ProtocolVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#define PSM_RELEASE_VERSION_MAJOR 9
#define PSM_RELEASE_VERSION_PHASE alpha
#define PSM_RELEASE_VERSION_MINOR 8
#define PSM_RELEASE_VERSION_RELEASE 9
#define PSM_RELEASE_VERSION_RELEASE 10
#define PSM_RELEASE_VERSION_HOTFIX 0

/// "Product.Major-Phase Minor.Release.Hotfix"
Expand Down
38 changes: 33 additions & 5 deletions src/psmoveservice/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,6 @@ add_executable(PSMoveService ${PSMOVESERVICE_SRC})
target_include_directories(PSMoveService PUBLIC ${PSMOVE_SERVICE_INCL_DIRS})
target_link_libraries(PSMoveService ${PSMOVE_SERVICE_REQ_LIBS})

IF(MSVC)
# set the UAC level in the property sheet
set_target_properties(PSMoveService PROPERTIES LINK_FLAGS "/level='requireAdministrator' /uiAccess='false'")
ENDIF()

IF(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
add_dependencies(PSMoveService opencv)
ENDIF()
Expand Down Expand Up @@ -241,6 +236,39 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
ELSE() #Linux/Darwin
ENDIF()

# On Windows builds we want to create an additional admin version of PSMS.
# This is used for when we want to pair new controllers.
# Part of the pairing process in Windows requires manually poking entries in the
# "SYSTEM\CurrentControlSet\Services\HidBth\Parameters\Devices" registry key folder,
# which only an admin account can do.
# Since you can't change the permissions of an exe after it's started
# and since relaunching a process as admin is un-reliable, having a second
# admin version of the PSMS exe is the simplest option
# https://stackoverflow.com/questions/19617955/c-run-program-as-administrator
# https://blogs.msdn.microsoft.com/winsdk/2013/03/22/how-to-launch-a-process-as-a-full-administrator-when-uac-is-enabled/
IF(MSVC)
# Create the new PSMS admin exe (same code as PSMS)
add_executable(PSMoveServiceAdmin ${PSMOVESERVICE_SRC})
target_include_directories(PSMoveServiceAdmin PUBLIC ${PSMOVE_SERVICE_INCL_DIRS})
target_link_libraries(PSMoveServiceAdmin ${PSMOVE_SERVICE_REQ_LIBS})

add_dependencies(PSMoveServiceAdmin opencv)

# set the UAC level in the property sheet
set_target_properties(PSMoveServiceAdmin PROPERTIES LINK_FLAGS "/level='requireAdministrator' /uiAccess='false'")

install(TARGETS PSMoveServiceAdmin
CONFIGURATIONS Debug
RUNTIME DESTINATION ${PSM_DEBUG_INSTALL_PATH}/bin
LIBRARY DESTINATION ${PSM_DEBUG_INSTALL_PATH}/lib
ARCHIVE DESTINATION ${PSM_DEBUG_INSTALL_PATH}/lib)
install(TARGETS PSMoveServiceAdmin
CONFIGURATIONS Release
RUNTIME DESTINATION ${PSM_RELEASE_INSTALL_PATH}/bin
LIBRARY DESTINATION ${PSM_RELEASE_INSTALL_PATH}/lib
ARCHIVE DESTINATION ${PSM_RELEASE_INSTALL_PATH}/lib)
ENDIF()

IF(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
IF(NOT(${CMAKE_C_SIZEOF_DATA_PTR} EQUAL 8))
IF(${CL_EYE_SDK_PATH} STREQUAL "CL_EYE_SDK_PATH-NOTFOUND")
Expand Down

0 comments on commit d8c16b8

Please sign in to comment.