+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "d3dservice.h"
-
-#include <QtCore/QFile>
-
-#include <wincred.h>
-#include <ntsecapi.h>
-#define SECURITY_WIN32
-#include <security.h>
-
-// Utility methods for getting user credentials and elevating the process
-bool D3DService::getCredentials(LPWSTR username, DWORD *usernameSize,
- LPWSTR password, DWORD *passwordSize)
-{
- WCHAR user[MAX_PATH];
- ULONG userSize = MAX_PATH;
- GetUserNameEx(NameSamCompatible, user, &userSize);
-
- // Get LSA handle and package ID
- HANDLE lsaHandle;
- DWORD result = LsaConnectUntrusted(&lsaHandle);
- if (result != ERROR_SUCCESS) {
- qCWarning(lcD3DService) << "Unable to get LSA handle:"
- << qt_error_string(LsaNtStatusToWinError(result));
- return false;
- }
- LSA_STRING packageName = { sizeof(NEGOSSP_NAME_A) - 1, sizeof(NEGOSSP_NAME_A), NEGOSSP_NAME_A };
- ULONG packageId;
- result = LsaLookupAuthenticationPackage(lsaHandle, &packageName, &packageId);
- if (result != ERROR_SUCCESS) {
- qCWarning(lcD3DService) << "Unable to get authentication package:"
- << qt_error_string(LsaNtStatusToWinError(result));
- LsaClose(lsaHandle);
- return false;
- }
- LsaClose(lsaHandle);
-
- CREDUI_INFO uiInfo = { sizeof(CREDUI_INFO), GetForegroundWindow(),
- L"Enter the credentials for your local user. Or, simply click OK "
- L"and update the credentials later in the Services console.",
- L"Qt D3D Compilation Service", NULL };
- QByteArray credentialsStorage(256, Qt::Uninitialized);
- BLOB credentials = { credentialsStorage.size(), (BYTE *)credentialsStorage.data() };
- if (!CredPackAuthenticationBuffer(CRED_PACK_GENERIC_CREDENTIALS, user, L"",
- credentials.pBlobData, &credentials.cbSize)) {
- qCWarning(lcD3DService) << "Unable to pack authentication buffer:"
- << qt_error_string(GetLastError());
- return false;
- }
-
- BLOB authBuffer;
- result = CredUIPromptForWindowsCredentials(&uiInfo, 0, &packageId,
- credentials.pBlobData, credentials.cbSize,
- (LPVOID *)&authBuffer.pBlobData, &authBuffer.cbSize,
- NULL, CREDUIWIN_GENERIC);
- if (result == ERROR_SUCCESS) {
- WCHAR domain[MAX_PATH] = { 0 };
- DWORD domainSize = MAX_PATH;
- const BOOL unpackOk = CredUnPackAuthenticationBuffer(
- 0, authBuffer.pBlobData, authBuffer.cbSize,
- username, usernameSize, domain, &domainSize,
- password, passwordSize);
- if (unpackOk) {
- return true;
- } else {
- qCWarning(lcD3DService) << "Unable to unpack credentials:"
- << qt_error_string(GetLastError());
- }
- }
-
- qCWarning(lcD3DService) << qt_error_string(result);
- SecureZeroMemory(password, *passwordSize);
- SecureZeroMemory(username, *usernameSize);
- *usernameSize = *passwordSize = 0;
- return false;
-}
-
-bool D3DService::executeElevated(LPCWSTR exe, LPCWSTR param, DWORD *exitCode)
-{
- // Create a temporary file for redirected output
- wchar_t tempPath[MAX_PATH];
- if (!GetTempPath(MAX_PATH, tempPath)) {
- qCWarning(lcD3DService) << "Unable to get the temporary file path for redirected output:"
- << qt_error_string(GetLastError());
- return false;
- }
- wchar_t tempFileName[MAX_PATH];
- if (!GetTempFileName(tempPath, L"temp", 0, tempFileName)) {
- qCWarning(lcD3DService) << "Unable to get a temporary file name for redirected output:"
- << qt_error_string(GetLastError());
- return false;
- }
-
- qCWarning(lcD3DService) << "Requesting administrative permissions...";
- const QString args = QString::fromWCharArray(param) + QStringLiteral(" -output \"")
- + QString::fromWCharArray(tempFileName) + QLatin1Char('"');
- SHELLEXECUTEINFO executeInfo = {
- sizeof(SHELLEXECUTEINFO), SEE_MASK_NOCLOSEPROCESS, GetConsoleWindow(),
- L"runas", exe, reinterpret_cast<LPCWSTR>(args.utf16()), 0, SW_HIDE
- };
- if (!ShellExecuteEx(&executeInfo)) {
- qCWarning(lcD3DService) << "Unable to elevate the process:"
- << qt_error_string(GetLastError());
- return false;
- }
-
- qCWarning(lcD3DService) << "Elevation successful.";
-
- WaitForSingleObject(executeInfo.hProcess, INFINITE);
-
- // Fetch program output
- QFile output(QString::fromWCharArray(tempFileName));
- if (output.open(QFile::ReadOnly)) {
- while (!output.atEnd())
- qCWarning(lcD3DService) << output.readLine().trimmed().constData();
- } else {
- qCWarning(lcD3DService) << "Unable to open output file:"
- << output.errorString();
- }
- if (!output.remove()) {
- qCWarning(lcD3DService) << "Unable to remove the output file:"
- << output.errorString();
- }
-
- if (!GetExitCodeProcess(executeInfo.hProcess, exitCode)) {
- qCWarning(lcD3DService) << "Exit status unknown:"
- << qt_error_string(GetLastError());
- CloseHandle(executeInfo.hProcess);
- return false;
- }
- CloseHandle(executeInfo.hProcess);
-
- return true;
-}
-
-bool D3DService::addLogonRight(LPCWSTR username)
-{
- HANDLE lsaHandle;
- LSA_OBJECT_ATTRIBUTES attributes = { 0 };
- DWORD result = LsaOpenPolicy(NULL, &attributes, POLICY_LOOKUP_NAMES, &lsaHandle);
- if (result != ERROR_SUCCESS) {
- qCWarning(lcD3DService) << "Unable to get LSA handle:"
- << qt_error_string(LsaNtStatusToWinError(result));
- return false;
- }
-
- char sid[96]; // Maximum binary size of SID should be 68; use 96 to be safe
- DWORD sidSize = sizeof(sid);
- SID_NAME_USE use;
- wchar_t domain[MAX_PATH];
- DWORD domainSize = MAX_PATH;
- if (!LookupAccountName(NULL, username, sid, &sidSize, domain, &domainSize, &use)) {
- qCWarning(lcD3DService) << "Unable to lookup account SID:"
- << qt_error_string(GetLastError());
- LsaClose(lsaHandle);
- return false;
- }
-
- ushort len = wcslen(SE_SERVICE_LOGON_NAME) * sizeof(WCHAR);
- LSA_UNICODE_STRING rights = { len, len + sizeof(WCHAR), SE_SERVICE_LOGON_NAME };
- result = LsaAddAccountRights(lsaHandle, sid, &rights, 1);
- if (result != ERROR_SUCCESS) {
- qCWarning(lcD3DService) << "Unable to grant the user service logon rights:"
- << qt_error_string(LsaNtStatusToWinError(result));
- LsaClose(lsaHandle);
- return false;
- }
-
- LsaClose(lsaHandle);
- return true;
-}
extern QStringList xapDeviceNames();
// Callbacks
-static void __stdcall run(DWORD argc, LPWSTR argv[]);
-static DWORD __stdcall control(DWORD control, DWORD eventType, void *eventData, void *context);
static BOOL __stdcall control(DWORD type);
static LRESULT __stdcall control(HWND window, UINT msg, WPARAM wParam, LPARAM lParam);
static DWORD __stdcall deviceWorker(LPVOID param);
struct D3DServicePrivate
{
D3DServicePrivate()
- : name(L"qtd3dservice")
- , checkPoint(1)
- , isService(false)
- , controlEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
+ : controlEvent(CreateEvent(NULL, FALSE, FALSE, NULL))
, controlWindow(0)
, deviceHandle(0)
{
- GetModuleFileName(NULL, path, MAX_PATH);
- status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- status.dwServiceSpecificExitCode = 0;
}
~D3DServicePrivate()
{
CloseHandle(controlEvent);
}
- // Service use
- const wchar_t *name;
- wchar_t path[MAX_PATH];
- SERVICE_STATUS status;
- SERVICE_STATUS_HANDLE statusHandle;
- DWORD checkPoint;
-
- // Internal use
- bool isService;
HANDLE controlEvent;
HWND controlWindow;
HDEVNOTIFY deviceHandle;
HANDLE m_thread;
};
-void d3dserviceMessageHandler(QtMsgType type, const QMessageLogContext &, const QString &text)
-{
- LPCWSTR strings[2] = { d->name, reinterpret_cast<const wchar_t *>(text.utf16()) };
- HANDLE eventSource = RegisterEventSource(NULL, d->name);
- if (eventSource) {
- if (type > QtDebugMsg) {
- ErrorId id = { ushort(FACILITY_NULL | ErrorId::Customer), type };
- WORD eventType;
- switch (type) {
- default:
- case 1:
- id.facility |= ErrorId::Informational;
- eventType = EVENTLOG_SUCCESS;
- break;
- case 2:
- id.facility |= ErrorId::Warning;
- eventType = EVENTLOG_WARNING_TYPE;
- break;
- case 3:
- id.facility |= ErrorId::Error;
- eventType = EVENTLOG_ERROR_TYPE;
- break;
- }
- ReportEvent(eventSource, eventType, 0, id.val, NULL, 2, 0, strings, NULL);
- DeregisterEventSource(eventSource);
- }
- }
-}
-
static QString prepareCache(const QString &device, const QString &app)
{
// Make sure we have a writable cache
return QDir::toNativeSeparators(baseDir.absolutePath());
}
-bool D3DService::install()
-{
- SC_HANDLE manager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE);
- if (!manager) {
- // Try to self-elevate if access is denied
- DWORD error = GetLastError();
- if (error == ERROR_ACCESS_DENIED) {
- DWORD exitCode;
- if (!D3DService::executeElevated(d->path, L"-install", &exitCode))
- return false;
-
- return exitCode == 0;
- }
-
- qCWarning(lcD3DService) << qt_error_string(GetLastError());
- qCWarning(lcD3DService) << "When installing, run this program as an administrator.";
- return false;
- }
-
- WCHAR username[MAX_PATH] = { 0 };
- DWORD usernameSize = MAX_PATH;
- WCHAR password[MAX_PATH] = { 0 };
- DWORD passwordSize = MAX_PATH;
- if (!D3DService::getCredentials(username, &usernameSize, password, &passwordSize)) {
- qCWarning(lcD3DService) << "Failed to install the service.";
- return false;
- }
-
- // Ensure the user has the "Log on as a service" right
- if (!D3DService::addLogonRight(username)) {
- qCWarning(lcD3DService) << "Failed to install the service.";
- return false;
- }
-
- SC_HANDLE service = CreateService(manager, d->name, L"Qt D3D Compiler Service " LQT_VERSION_STR,
- SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
- SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
- d->path, NULL, NULL, NULL, NULL, NULL);
- if (!service) {
- qCWarning(lcD3DService) << qt_error_string(GetLastError());
- switch (GetLastError()) {
- case ERROR_SERVICE_EXISTS:
- qCWarning(lcD3DService) << "Please remove the service before reinstalling.";
- break;
- default:
- qCWarning(lcD3DService) << "Failed to install the service.";
- break;
- }
- CloseServiceHandle(manager);
- return false;
- }
-
- qCWarning(lcD3DService) << "Service installation successful.";
-
- // Do some more stuff
-
- CloseServiceHandle(service);
- CloseServiceHandle(manager);
- return true;
-}
-
-bool D3DService::remove()
+bool D3DService::start()
{
- SC_HANDLE manager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, DELETE);
- if (!manager) {
- // Try to self-elevate if access is denied
- DWORD error = GetLastError();
- if (error == ERROR_ACCESS_DENIED) {
- DWORD exitCode;
- if (!executeElevated(d->path, L"-remove", &exitCode))
- return false;
-
- return exitCode == 0;
- }
- qCWarning(lcD3DService) << qt_error_string(GetLastError());
- qCWarning(lcD3DService) << "When removing, run this program as an administrator.";
- return false;
- }
-
- // Get a handle to the SCM database.
- SC_HANDLE service = OpenService(manager, d->name, DELETE);
- if (!service) {
- // System message
- qCWarning(lcD3DService) << qt_error_string(GetLastError());
- // Friendly message
- switch (GetLastError()) {
- case ERROR_ACCESS_DENIED:
- qCWarning(lcD3DService) << "When removing, run this program as an administrator.";
- break;
- default:
- qCWarning(lcD3DService) << "Failed to remove the service.";
- break;
- }
- CloseServiceHandle(manager);
- return false;
- }
-
- if (!DeleteService(service)) {
- qCWarning(lcD3DService) << qt_error_string(GetLastError());
- qCWarning(lcD3DService) << "Unable to remove the service.";
- CloseServiceHandle(service);
- CloseServiceHandle(manager);
+ SetConsoleCtrlHandler(&control, TRUE);
+
+ // Create an invisible window for getting broadcast events
+ WNDCLASS controlWindowClass = { 0, &control, 0, 0, NULL, NULL,
+ NULL, NULL, NULL, L"controlWindow" };
+ if (!RegisterClass(&controlWindowClass)) {
+ qCCritical(lcD3DService) << "Unable to register control window class:"
+ << qt_error_string(GetLastError());
return false;
}
-
- qCWarning(lcD3DService) << "Service removal successful.";
- CloseServiceHandle(service);
- CloseServiceHandle(manager);
- return true;
-}
-
-bool D3DService::startService(bool replaceMessageHandler)
-{
- d->isService = true;
- if (replaceMessageHandler)
- qInstallMessageHandler(&d3dserviceMessageHandler);
- SERVICE_TABLE_ENTRY dispatchTable[] = {
- { const_cast<wchar_t *>(d->name), &run },
- { NULL, NULL }
- };
- return StartServiceCtrlDispatcher(dispatchTable);
-}
-
-bool D3DService::startDirectly()
-{
- run(0, 0);
- return true;
-}
-
-void D3DService::reportStatus(DWORD state, DWORD exitCode, DWORD waitHint)
-{
- if (!d->isService)
- return;
-
- d->status.dwCurrentState = state;
- d->status.dwWin32ExitCode = exitCode;
- d->status.dwWaitHint = waitHint;
- d->status.dwControlsAccepted = state == SERVICE_START_PENDING ? 0 : SERVICE_ACCEPT_STOP;
- d->status.dwCheckPoint = (state == SERVICE_RUNNING || state == SERVICE_STOPPED) ? 0 : d->checkPoint++;
- SetServiceStatus(d->statusHandle, &d->status);
-}
-
-void __stdcall run(DWORD argc, LPWSTR argv[])
-{
- Q_UNUSED(argc);
- Q_UNUSED(argv);
- if (d->isService) {
-#if defined(_DEBUG)
- // Debugging aid. Gives 15 seconds after startup to attach a debuggger.
- // The SCM will give the service 30 seconds to start.
- int count = 0;
- while (!IsDebuggerPresent() && count++ < 15)
- Sleep(1000);
-#endif
- d->statusHandle = RegisterServiceCtrlHandlerEx(d->name, &control, NULL);
- D3DService::reportStatus(SERVICE_START_PENDING, NO_ERROR, 0);
- D3DService::reportStatus(SERVICE_RUNNING, NO_ERROR, 0);
- } else {
- SetConsoleCtrlHandler(&control, TRUE);
-
- // Create an invisible window for getting broadcast events
- WNDCLASS controlWindowClass = { 0, &control, 0, 0, NULL, NULL,
- NULL, NULL, NULL, L"controlWindow" };
- if (!RegisterClass(&controlWindowClass)) {
- qCCritical(lcD3DService) << "Unable to register control window class:"
- << qt_error_string(GetLastError());
- return;
- }
- d->controlWindow = CreateWindowEx(0, L"controlWindow", NULL, 0, 0, 0, 0, 0,
- NULL, NULL, NULL, NULL);
- }
+ d->controlWindow = CreateWindowEx(0, L"controlWindow", NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
// Register for USB notifications
DEV_BROADCAST_DEVICEINTERFACE filter = {
sizeof(DEV_BROADCAST_DEVICEINTERFACE), DBT_DEVTYP_DEVICEINTERFACE,
0, GUID_DEVICE_WINPHONE8_USB, 0
};
- d->deviceHandle = RegisterDeviceNotification(
- d->isService ? d->statusHandle : static_cast<HANDLE>(d->controlWindow), &filter,
- d->isService ? DEVICE_NOTIFY_SERVICE_HANDLE : DEVICE_NOTIFY_WINDOW_HANDLE);
+ d->deviceHandle = RegisterDeviceNotification(d->controlWindow, &filter, DEVICE_NOTIFY_WINDOW_HANDLE);
QVector<HANDLE> waitHandles;
waitHandles.append(d->controlEvent);
}
// TODO: check return val for this
- if (!d->isService) {
- MSG msg;
- if (PeekMessage(&msg, d->controlWindow, 0, 0, PM_REMOVE))
- DispatchMessage(&msg);
- }
+ MSG msg;
+ if (PeekMessage(&msg, d->controlWindow, 0, 0, PM_REMOVE))
+ DispatchMessage(&msg);
}
qDeleteAll(workers);
CloseHandle(handle);
}
- D3DService::reportStatus(SERVICE_STOPPED, NO_ERROR, 0);
+ return true;
}
DWORD __stdcall deviceWorker(LPVOID param)
return handleDevice(deviceIndex, args->app, cachePath, args->runLock);
}
-// Service controller
-DWORD __stdcall control(DWORD code, DWORD eventType, void *eventData, void *context)
-{
- Q_UNUSED(context);
-
- switch (code) {
- case SERVICE_CONTROL_INTERROGATE:
- D3DService::reportStatus(0, NO_ERROR, 0);
- return NO_ERROR;
- case SERVICE_CONTROL_STOP: {
- d->eventQueue.append(Stop);
- SetEvent(d->controlEvent);
- return NO_ERROR;
- }
- case SERVICE_CONTROL_DEVICEEVENT: {
- if (eventType == DBT_DEVICEARRIVAL) {
- DEV_BROADCAST_DEVICEINTERFACE *header =
- reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE *>(eventData);
- if (header->dbcc_classguid != GUID_DEVICE_WINPHONE8_USB)
- break;
- d->eventQueue.append(PhoneConnected);
- SetEvent(d->controlEvent);
- return NO_ERROR;
- }
- break;
- }
- default:
- break;
- }
- return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
// Console message controller
LRESULT __stdcall control(HWND window, UINT msg, WPARAM wParam, LPARAM lParam)
{