diff options
Diffstat (limited to 'OSpiceX.cpp')
-rw-r--r-- | OSpiceX.cpp | 1485 |
1 files changed, 1485 insertions, 0 deletions
diff --git a/OSpiceX.cpp b/OSpiceX.cpp new file mode 100644 index 0000000..869ef3b --- /dev/null +++ b/OSpiceX.cpp @@ -0,0 +1,1485 @@ +/* + * Copyright 2013 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the GNU General Public License, version 2 or any + * later version. See the file COPYING in the top-level directory of + * this distribution or http://www.gnu.org/licenses/gpl-2.0.txt. + */ +// OSpiceX.cpp : Implementation of COSpiceX
+#include "stdafx.h"
+
+#pragma warning(disable: 4995) // 'gets' (and more): name was marked as #pragma deprecated
+#include <sstream>
+
+#include "OSpiceX.h"
+#include <spice/controller_prot.h>
+#include <spice/error_codes.h>
+#include <security.h>
+
+// MSDN: The maximum length of this string is 32K characters.
+// ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.WIN32COM.v10.en/dllproc/base/createprocess.htm
+#define CMDLINE_LENGTH 32768
+
+#define SPICE_X_DLL _T("SpiceX.DLL")
+
+// COSpiceX
+
+DWORD WINAPI COSpiceX::event_thread(PVOID pv)
+{
+ COSpiceX* spicex = (COSpiceX*)pv;
+ HANDLE events[2] = {spicex->m_OverlappedRead.hEvent, spicex->m_OverlappedWrite.hEvent};
+ bool running = true;
+ ControllerValue msg;
+ DWORD error_code;
+ DWORD exit_code;
+ DWORD wait_res;
+
+ //Handles only ControllerValue msgs
+ ReadFile(spicex->m_hClientPipe, &msg, sizeof(msg), NULL, &spicex->m_OverlappedRead);
+ while (running) {
+ wait_res = WaitForMultipleObjects(2, events, FALSE, INFINITE);
+ switch (wait_res) {
+ case WAIT_OBJECT_0:
+ running = spicex->handle_in_msg(msg);
+ break;
+ case WAIT_OBJECT_0 + 1:
+ running = spicex->handle_out_msg();
+ break;
+ case WAIT_FAILED:
+ LOG_INFO("WaitForMultipleObjects failed, err=%lu", GetLastError()); + running = false;
+ break;
+ }
+ }
+
+ //Wait for proccess to terminate
+ wait_res = WaitForSingleObject(spicex->m_hClientProcess, 3000);
+
+ //Handle errors
+ if (wait_res != WAIT_OBJECT_0 || !GetExitCodeProcess(spicex->m_hClientProcess, &exit_code) ||
+ exit_code == STILL_ACTIVE) {
+ TerminateProcess(spicex->m_hClientProcess, 0);
+ CloseHandle(spicex->m_hClientProcess);
+ spicex->m_hClientProcess = NULL;
+ exit_code = SPICEC_ERROR_CODE_ERROR;
+ }
+
+ switch (exit_code) {
+ case SPICEC_ERROR_CODE_SUCCESS:
+ error_code = RDP_ERROR_CODE_LOCAL_DISCONNECTION;
+ break;
+ case SPICEC_ERROR_CODE_GETHOSTBYNAME_FAILED:
+ error_code = RDP_ERROR_CODE_HOST_NOT_FOUND;
+ break;
+ case SPICEC_ERROR_CODE_CONNECT_FAILED:
+ error_code = RDP_ERROR_CODE_WINSOCK_CONNECT_FAILED;
+ break;
+ case SPICEC_ERROR_CODE_ERROR:
+ case SPICEC_ERROR_CODE_SOCKET_FAILED:
+ error_code = RDP_ERROR_CODE_INTERNAL_ERROR;
+ break;
+ case SPICEC_ERROR_CODE_RECV_FAILED:
+ error_code = RDP_ERROR_RECV_WINSOCK_FAILED;
+ break;
+ case SPICEC_ERROR_CODE_SEND_FAILED:
+ error_code = RDP_ERROR_SEND_WINSOCK_FAILED;
+ break;
+ case SPICEC_ERROR_CODE_NOT_ENOUGH_MEMORY:
+ error_code = RDP_ERROR_CODE_OUT_OF_MEMORY;
+ break;
+ case SPICEC_ERROR_CODE_AGENT_TIMEOUT:
+ error_code = RDP_ERROR_CODE_TIMEOUT;
+ break;
+ case SPICEC_ERROR_CODE_AGENT_ERROR:
+ default:
+ error_code = exit_code + SPICE_ERROR_BASE;
+ }
+
+ LOG_INFO("exit_code=%lu error_code=%lu", exit_code, error_code); + spicex->PostMessage(SPICEX_ON_DISCONNECTED_MSG, error_code, 0);
+ spicex->cleanup();
+ return 0;
+}
+
+bool COSpiceX::handle_in_msg(ControllerValue& msg)
+{
+ DWORD bytes_read;
+ bool res;
+
+ if (!GetOverlappedResult(m_hClientPipe, &m_OverlappedRead, &bytes_read, FALSE) ||
+ bytes_read != sizeof(msg) || msg.base.size != sizeof(msg)) {
+ return false;
+ }
+ switch(msg.base.id) {
+ case CONTROLLER_MENU_ITEM_CLICK:
+ DBG(3, "menu-item-click: value=%u", msg.value); + ((COSpiceX*)this)->PostMessage(SPICEX_ON_MENU_ITEM_SELECTED_MSG, msg.value, 0);
+ break;
+ default:
+ LOG_INFO("unknown message: %u", msg.base.id); + return false;
+ }
+ res = ReadFile(m_hClientPipe, &msg, sizeof(msg), NULL, &m_OverlappedRead) ||
+ GetLastError() == ERROR_IO_PENDING;
+ return res;
+}
+
+bool COSpiceX::handle_out_msg()
+{
+ bool res = true;
+ DWORD written;
+ size_t size;
+
+ EnterCriticalSection(&m_WriteLock);
+ if (!GetOverlappedResult(m_hClientPipe, &m_OverlappedWrite, &written, FALSE)) {
+ LeaveCriticalSection(&m_WriteLock);
+ return false;
+ }
+
+ m_WritePending = false;
+ m_WriteStart = m_WriteBuffer + (m_WriteStart - m_WriteBuffer + written) % PIPE_BUF_SIZE;
+ if (m_WriteStart <= m_WriteEnd) {
+ size = m_WriteEnd - m_WriteStart;
+ } else {
+ size = m_WriteBuffer + PIPE_BUF_SIZE - m_WriteStart;
+ }
+ if (size) {
+ if (WriteFile(m_hClientPipe, m_WriteStart, (DWORD)size, NULL, &m_OverlappedWrite) ||
+ GetLastError() == ERROR_IO_PENDING) {
+ m_WritePending = true;
+ } else {
+ res = false;
+ }
+ }
+ LeaveCriticalSection(&m_WriteLock);
+ return res;
+}
+
+DWORD WINAPI COSpiceX::UsbCtrlWatchDog(PVOID pv)
+{
+ COSpiceX *pThis = reinterpret_cast<COSpiceX*>(pv);
+
+ if (pThis != NULL)
+ {
+ if (::WaitForSingleObject(pThis->m_hUsbCtrlProcess, INFINITE) == WAIT_OBJECT_0)
+ {
+ DWORD dwExitCode;
+
+ ::CloseHandle(pThis->m_hUsbCtrlLog);
+ pThis->m_hUsbCtrlLog = INVALID_HANDLE_VALUE;
+
+ if (::GetExitCodeProcess(pThis->m_hUsbCtrlProcess, &dwExitCode) == TRUE)
+ {
+ pThis->m_hUsbCtrlProcess = NULL;
+
+ if (dwExitCode != 0)
+ {
+ LOG_INFO("Restarting USB controller"); + // The USB controller was terminated, re-run it again.
+ pThis->ExecuteUsbCtrl();
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+ +STDMETHODIMP COSpiceX::Connect(void)
+{
+ wchar_t lpCommandLine[CMDLINE_LENGTH] = {0}; + LPTSTR lpProcName;
+ DWORD dwRetVal;
+ HMODULE hModule;
+ STARTUPINFO si;
+ HKEY hkey; + LONG lret; + +
+ if (m_hClientProcess != NULL) {
+ return SPICEX_ERROR_CLIENT_PROCESS_ALREADY_CONNECTED;
+ }
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ ZeroMemory(&m_pi, sizeof(m_pi));
+
+ // FIXME: do we need the GetModuleXXX calls?
+ // we assume the Spice client binary is located in the same dir as the ActiveX dll
+ if (hModule = GetModuleHandle(SPICE_X_DLL)) {
+ if (dwRetVal = GetModuleFileName(hModule, lpCommandLine, MAX_PATH)) { + // locate the 1st char of the ActiveX name (past the last '\')
+ lpProcName = (wcsrchr(lpCommandLine, L'\\') + 1); + // zero it so we can append the red client name
+ if (lpProcName) {
+ lpProcName[0] = 0;
+ }
+ }
+ }
+ + lret = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\spice-space.org\\spicex", 0, KEY_READ, &hkey); + if (lret == ERROR_SUCCESS) { + DWORD dwType = REG_SZ; + DWORD dwSize = sizeof(lpCommandLine); + lret = RegQueryValueEx(hkey, L"client", NULL, &dwType, (LPBYTE)lpCommandLine, &dwSize); + RegCloseKey(hkey); + } + + if (lret != ERROR_SUCCESS) { + lret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\spice-space.org\\spicex", 0, KEY_READ, &hkey); + if (lret == ERROR_SUCCESS) { + DWORD dwType = REG_SZ; + DWORD dwSize = sizeof(lpCommandLine); + lret = RegQueryValueEx(hkey, L"client", NULL, &dwType, (LPBYTE)lpCommandLine, &dwSize); + RegCloseKey(hkey); + } + } + + if (lret != ERROR_SUCCESS) { + StringCchPrintf(lpCommandLine, CMDLINE_LENGTH, L"%s%s --controller", + lpCommandLine, RED_CLIENT_FILE_NAME); + } + + DBG(0, "Running spicec (%S)", lpCommandLine); + + if (!CreateProcess(NULL, lpCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &m_pi)) { + DWORD err = GetLastError(); + LOG_ERROR("Failed to run spicec (%S) -- %lu", lpCommandLine, err); + return MAKE_HRESULT(1, FACILITY_CREATE_RED_PROCESS, err); + }
+ LOG_INFO("spicec pid %lu", ::GetProcessId(m_pi.hProcess)); + m_hClientProcess = m_pi.hProcess;
+ + if (WaitForInputIdle(m_hClientProcess, 5000) != 0) + LOG_WARN("Waiting for client idle failed, trying to connnect"); +
+ DBG(0, "connecting to spice client's pipe"); + wchar_t lpszClientPipeName[RED_CLIENT_PIPE_NAME_MAX_LEN];
+ StringCchPrintf(lpszClientPipeName, RED_CLIENT_PIPE_NAME_MAX_LEN, RED_CLIENT_PIPE_NAME, + m_pi.dwProcessId); + for (int retry = 0; retry < 5; retry++) {
+ m_hClientPipe = CreateFile(lpszClientPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS |
+ FILE_FLAG_OVERLAPPED, NULL);
+ if (m_hClientPipe != INVALID_HANDLE_VALUE) {
+ break;
+ }
+ Sleep(1000);
+ }
+ + // Verify the named-pipe-server owner is the current user. + // Do it here so upon failure use next condition cleanup code. + if (m_hClientPipe != INVALID_HANDLE_VALUE) { + if (!is_same_user(m_hClientPipe)) { + LOG_ERROR("Closing pipe to spicec -- it is not safe"); + CloseHandle(m_hClientPipe); + m_hClientPipe = INVALID_HANDLE_VALUE; + } + } +
+ if (m_hClientPipe == INVALID_HANDLE_VALUE) {
+ LOG_ERROR("failed to connect to spice client pipe"); + TerminateProcess(m_hClientProcess, 0);
+ CloseHandle(m_hClientProcess);
+ m_hClientProcess = NULL;
+ return MAKE_HRESULT(1, FACILITY_CREATE_RED_PIPE, GetLastError());
+ }
+
+ m_hEventThread = CreateThread(NULL, 0, event_thread, this, 0, NULL);
+ if (m_hEventThread == NULL) {
+ LOG_ERROR("failed to create event thread"); + cleanup();
+ return MAKE_HRESULT(1, FACILITY_CREATE_RED_PIPE, GetLastError());
+ }
+
+ + send_init();
+ send_wstr(CONTROLLER_HOST, m_HostIP, true); + send_value(CONTROLLER_PORT, m_Port); + send_value(CONTROLLER_SPORT, m_SecurePort); + send_wstr(CONTROLLER_PASSWORD, m_szPassword, true); + send_wstr(CONTROLLER_SET_TITLE, m_Title, true); + send_value(CONTROLLER_FULL_SCREEN, (m_FullScreen ? CONTROLLER_SET_FULL_SCREEN : 0) | + (m_AdminConsole ? 0 : CONTROLLER_AUTO_DISPLAY_RES)); + send_wstr(CONTROLLER_HOTKEYS, m_HotKey.c_str(), true);
+ send_wstr(CONTROLLER_CREATE_MENU, m_strMenuResource, true);
+ send_wstr(CONTROLLER_SECURE_CHANNELS, m_szSSLChannels, true); + send_wstr(CONTROLLER_TLS_CIPHERS, m_szCipherSuite, true); + send_wstr(CONTROLLER_HOST_SUBJECT, m_HostSubject.c_str(), true); + send_wstr(CONTROLLER_PROXY, m_Proxy.c_str(), true); + if (!m_TrustStore.empty()) { + WCHAR szCAFileName[MAX_PATH]; + if (SUCCEEDED(CreateCAFile(szCAFileName, sizeof(szCAFileName)))) { + send_wstr(CONTROLLER_CA_FILE, szCAFileName, true); + } + } + if (m_ColorDepth) {
+ send_value(CONTROLLER_COLOR_DEPTH, m_ColorDepth);
+ }
+ if (!m_DisableEffects.empty()) {
+ send_wstr(CONTROLLER_DISABLE_EFFECTS, m_DisableEffects.c_str(), true);
+ }
+ send_bool(CONTROLLER_ENABLE_SMARTCARD, !!m_SmartCard);
+ send_bool(CONTROLLER_SEND_CAD, !!m_SendCtrlAltDelete);
+ send_msg(CONTROLLER_CONNECT);
+ send_msg(CONTROLLER_SHOW);
+
+ if (m_UsbListenPort != 0) {
+ /* old USB, disable new USB solution */
+ send_value(CONTROLLER_ENABLE_USB, FALSE);
+ ExecuteUsbCtrl();
+ } else {
+ send_value(CONTROLLER_ENABLE_USB, TRUE);
+ send_bool(CONTROLLER_ENABLE_USB_AUTOSHARE, !!m_UsbAutoShare); + send_wstr(CONTROLLER_USB_FILTER, m_UsbFilter.c_str());
+ }
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::Disconnect(void)
+{
+ if (m_hClientProcess == NULL) {
+ return SPICEX_ERROR_CLIENT_PROCESS_NOT_CONNECTED;
+ }
+ cleanup();
+ return S_OK;
+}
+
+void COSpiceX::cleanup()
+{
+ if (m_hClientProcess) {
+ TerminateProcess(m_hClientProcess, 0);
+ CloseHandle(m_hClientProcess);
+ m_hClientProcess = NULL;
+ }
+ if (m_hClientPipe) {
+ CloseHandle(m_hClientPipe);
+ m_hClientPipe = NULL;
+ }
+ if (m_hEventThread) {
+ CloseHandle(m_hEventThread);
+ m_hEventThread = NULL;
+ }
+}
+
+STDMETHODIMP COSpiceX::SendCAD(void)
+{
+ // TODO: Add your implementation code here
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::Show(void)
+{
+ return send_msg(CONTROLLER_SHOW);
+}
+
+STDMETHODIMP COSpiceX::Hide(void)
+{
+ return send_msg(CONTROLLER_HIDE);
+}
+
+STDMETHODIMP COSpiceX::SetSecondaryAddress(void)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::Load(IPropertyBag *pPropBag, IErrorLog* pErrorLog)
+{
+ CComVariant pVar;
+ HRESULT hRes;
+
+ pVar.vt = VT_UI2;
+ hRes = pPropBag->Read(L"Port", &pVar, pErrorLog);
+ if (hRes == S_OK)
+ {
+ m_Port = pVar.uiVal;
+ }
+
+ pVar.vt = VT_UI2;
+ hRes = pPropBag->Read(L"SecurePort", &pVar, pErrorLog);
+ if (hRes == S_OK)
+ {
+ m_SecurePort = pVar.uiVal;
+ }
+
+ pVar.vt = VT_BSTR;
+ hRes = pPropBag->Read(L"HostIP", &pVar, pErrorLog);
+ if (hRes == S_OK)
+ {
+ StringCchCopyN(m_HostIP, MAX_PATH, pVar.bstrVal, MAX_PATH);
+ }
+
+ pVar.vt = VT_BSTR;
+ hRes = pPropBag->Read(L"Title", &pVar, pErrorLog);
+ if (hRes == S_OK)
+ {
+ StringCchCopyN(m_Title, RED_CLIENT_MAX_TITLE_SIZE, pVar.bstrVal, RED_CLIENT_MAX_TITLE_SIZE);
+ }
+
+ pVar.vt = VT_BSTR;
+ hRes = pPropBag->Read(L"CipherSuite", &pVar, pErrorLog);
+ if (hRes == S_OK && lstrlen(V_BSTR(&pVar)) > 0)
+ {
+ m_bIsSSL = true;
+ StringCchCopyN(m_szCipherSuite, MAX_PATH, V_BSTR(&pVar), MAX_PATH);
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_CipherSuite(BSTR* pVal)
+{
+ *pVal=::SysAllocString(m_szCipherSuite);
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_CipherSuite(BSTR newVal)
+{
+ if (newVal) {
+ wcscpy_s(m_szCipherSuite, MAX_PATH, newVal);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_SSLChannels(BSTR* pVal)
+{
+ *pVal=::SysAllocString(m_szSSLChannels);
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_SSLChannels(BSTR newVal)
+{
+ ZeroMemory(m_szSSLChannels, sizeof(m_szSSLChannels));
+
+ // validate input arg
+ if (newVal != NULL && lstrlen(newVal) > 0)
+ {
+ m_bIsSSL = true;
+ StringCchCopyN(m_szSSLChannels, MAX_PATH, newVal, MAX_PATH);
+
+ /*
+ * Backward Compatibility:
+ * Remove leading 's' from m_ssl_channels, e.g. "main" not "smain"
+ * RHEL5 uses 'smain' and 'sinpusts
+ * RHEL6 uses 'main' and 'inputs'
+ */
+ const wchar_t* chan_names[] = {
+ L"smain", L"sdisplay", L"sinputs",
+ L"scursor", L"splayback", L"srecord",
+ L"susbredir", L"ssmartcard", L"stunnel"
+ };
+ const int nnames = sizeof(chan_names) / sizeof(chan_names[0]);
+ wchar_t *p;
+ const wchar_t *cn;
+ size_t len, n, i, j;
+
+ n = wcslen(m_szSSLChannels);
+ for (i=0 ; i<n ; i++) {
+ p = &m_szSSLChannels[i];
+ for (j = 0; j < nnames; j++) {
+ cn = chan_names[j];
+ len = wcslen(cn);
+ if (wcsncmp(cn, p, len) == 0) {
+ while ((*p) = *(p+1)) { /* copy is done in condition */
+ p++;
+ }
+ i+=len-1; /* no need to check copied name */
+ break; /* out of inner loop */ + }
+ }
+ }
+ DBG(3, "New SSL Channels %S", m_szSSLChannels);
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_HostIP(BSTR* pVal)
+{
+ *pVal=::SysAllocString(m_HostIP);
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_HostIP(BSTR newVal)
+{
+ ZeroMemory(m_HostIP, sizeof(m_HostIP));
+
+ // validate input arg
+ if (newVal != NULL)
+ {
+ StringCchCopyN(m_HostIP, MAX_PATH, newVal, MAX_PATH);
+ DBG(3, "New HostIP %S", m_HostIP); + }
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_GuestHostName(BSTR* pVal)
+{
+ *pVal = ::SysAllocString(m_GuestHostName);
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_GuestHostName(BSTR newVal)
+{
+ if (newVal == NULL) {
+ return E_INVALIDARG;
+ }
+
+ ZeroMemory(m_GuestHostName, sizeof(m_GuestHostName));
+ StringCchCopyN(m_GuestHostName, MAX_PATH, newVal, MAX_PATH);
+ DBG(3, "New GuestHostName %S", m_GuestHostName); +
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_HotKey(BSTR* pVal)
+{
+ *pVal = ::SysAllocString(m_HotKey.c_str());
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_HotKey(BSTR newVal)
+{
+ if (newVal == NULL) {
+ return E_INVALIDARG;
+ }
+
+ m_HotKey = newVal;
+ DBG(3, "New HotKey %S", m_HotKey.c_str()); +
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_Port(USHORT* pVal)
+{
+ *pVal= m_Port;
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_SecurePort(USHORT newVal)
+{
+ m_SecurePort = newVal;
+ DBG(3, "New Secure Port %u", m_SecurePort); +
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_SecurePort(USHORT* pVal)
+{
+ *pVal= m_SecurePort;
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_Port(USHORT newVal)
+{
+ m_Port = newVal;
+ DBG(3, "New Port %u", m_Port); +
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_Password(BSTR* pVal)
+{
+ *pVal=::SysAllocString(m_szPassword);
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_Password(BSTR newVal)
+{
+ if (newVal) {
+ wcscpy_s(m_szPassword, RED_MAX_PASSWORD_LENGTH, newVal);
+ DBG(3, "New Password"); + }
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_ScaleEnable(ULONG* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_ScaleEnable(ULONG newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_ScaleNum(ULONG* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_ScaleNum(ULONG newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_ScaleDen(ULONG* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_ScaleDen(ULONG newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_FullScreen(ULONG* pVal)
+{
+ // TODO: Add your implementation code here
+
+ *pVal = m_FullScreen;
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_FullScreen(ULONG newVal)
+{
+ // TODO: Add your implementation code here
+
+ m_FullScreen = newVal;
+ LOG_INFO("New FullScreen request newVal=0x%lx", newVal); + return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_MsUser(BSTR* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_MsUser(BSTR newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_MSDomain(BSTR* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_MSDomain(BSTR newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_MSPassword(BSTR* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_MSPassword(BSTR newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_StretchMode(ULONG* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_StretchMode(ULONG newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_ScreenHeight(ULONG* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_ScreenHeight(ULONG newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_ConnectingText(BSTR* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_ConnectingText(BSTR newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_DisconnectingText(BSTR* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_DisconnectingText(BSTR newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_SwapMouseButtons(ULONG* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_SwapMouseButtons(ULONG newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_AudioRedirection(ULONG* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_AudioRedirection(ULONG newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_SecondaryHostIP(BSTR* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_SecondaryHostIP(BSTR newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_SecondaryPort(USHORT* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_SecondaryPort(USHORT newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_PollingInterval(ULONG* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_PollingInterval(ULONG newVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_Title(BSTR* pVal)
+{
+ *pVal=::SysAllocString(m_Title);
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_Title(BSTR newVal)
+{
+ if (!newVal || newVal[0] == '\0') {
+ return S_OK;
+ }
+ wcscpy_s(m_Title, RED_CLIENT_MAX_TITLE_SIZE, newVal);
+ DBG(3, "New Title %S", m_Title); + if (m_hClientPipe) {
+ return send_wstr(CONTROLLER_SET_TITLE, m_Title);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::ConnectAudio(void)
+{
+ // Still here to prevent web interface errors
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::DisconnectAudio(void)
+{
+ // Still here to prevent web interface errors
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_AudioGuestIP(BSTR* pVal)
+{
+ *pVal=::SysAllocString(m_AudioGuestIP);
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_AudioGuestIP(BSTR newVal)
+{
+ ZeroMemory(m_AudioGuestIP, sizeof(m_AudioGuestIP));
+
+ // validate input arg
+ if (newVal != NULL)
+ {
+ StringCchCopyN(m_AudioGuestIP, MAX_PATH, newVal, MAX_PATH);
+ LOG_INFO("New AudioGuestIP %S", m_AudioGuestIP); + }
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_AudioGuestPort(SHORT* pVal)
+{
+ *pVal= m_AudioPort;
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_AudioGuestPort(SHORT newVal)
+{
+ m_AudioPort = newVal;
+ DBG(3, "New AudioGuestPort %u", m_AudioPort); +
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::CreateMenu(BSTR MenuResourceString)
+{
+ if (!MenuResourceString || MenuResourceString[0] == '\0') {
+ return S_OK;
+ }
+ wcscpy_s(m_strMenuResource, RED_CLIENT_MAX_MENU_SIZE, MenuResourceString);
+ DBG(3, "New Menu '%S'", m_strMenuResource); + if (m_hClientPipe) {
+ return send_wstr(CONTROLLER_CREATE_MENU, m_strMenuResource);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::DeleteMenu(void)
+{
+ m_strMenuResource[0] = '\0';
+ return send_msg(CONTROLLER_DELETE_MENU);
+ DBG(3, "Menu Deleted"); +}
+
+#define MIN(a, b) ((a) > (b) ? (b) : (a)) +
+HRESULT COSpiceX::write_to_pipe(const void* data, uint32_t size) +{ + bool res = true;
+
+ EnterCriticalSection(&m_WriteLock);
+ size_t free_size = (PIPE_BUF_SIZE + m_WriteStart - m_WriteEnd - 1) % PIPE_BUF_SIZE; + if (size > free_size) { + res = false; + } else if (m_WriteEnd < m_WriteStart) { + memcpy(m_WriteEnd, data, size); + m_WriteEnd += size; + } else { + size_t n = MIN(size, (size_t)(m_WriteBuffer + PIPE_BUF_SIZE - m_WriteEnd)); + memcpy(m_WriteEnd, data, n); + if (size > n) { + memcpy(m_WriteBuffer, (uint8_t*)data + n, size - n); + } + m_WriteEnd = m_WriteBuffer + (m_WriteEnd - m_WriteBuffer + size) % PIPE_BUF_SIZE; + } +
+ if (res && !m_WritePending) {
+ if (WriteFile(m_hClientPipe, data, size, NULL, &m_OverlappedWrite) ||
+ GetLastError() == ERROR_IO_PENDING) {
+ res = m_WritePending = true;
+ }
+ } + LeaveCriticalSection(&m_WriteLock);
+
+ return (res ? S_OK : MAKE_HRESULT(SEVERITY_ERROR, FACILITY_PIPE_OPERATION, GetLastError()));
+} + +HRESULT COSpiceX::send_init() +{ + DBG(0, "sending init"); + ControllerInit msg = {{CONTROLLER_MAGIC, CONTROLLER_VERSION, sizeof(msg)}, 0, + CONTROLLER_FLAG_EXCLUSIVE}; + return write_to_pipe(&msg, sizeof(msg)); +} + +HRESULT COSpiceX::send_msg(uint32_t id) +{ + ControllerMsg msg = {id, sizeof(msg)}; + DBG(0, "sending msg id %u", id); + return write_to_pipe(&msg, sizeof(msg)); +} + +HRESULT COSpiceX::send_value(uint32_t id, uint32_t value) +{ + if (!value) { + return S_OK; + } + DBG(0, "sending msg id %u value %u", id, value); + ControllerValue msg = {{id, sizeof(msg)}, value}; + return write_to_pipe(&msg, sizeof(msg)); +} + +HRESULT COSpiceX::send_bool(uint32_t id, uint32_t value) +{ + DBG(0, "sending msg id %u bool %u", id, !!value); + ControllerValue msg = {{id, sizeof(msg)}, !!value}; + return write_to_pipe(&msg, sizeof(msg)); +} + +HRESULT COSpiceX::send_wstr(uint32_t id, const wchar_t* str, bool use_mb_str) +{ + HRESULT res; + + if (!str || !wcslen(str)) { + return S_OK; + } + if (id == CONTROLLER_PASSWORD) { + DBG(0, "sending password"); + } else { + DBG(0, "sending msg id %u : str %S (%d)", id, str, (int)use_mb_str); + } + size_t size = sizeof(ControllerData) + (wcslen(str) + 1) * (use_mb_str ? 1 : sizeof(wchar_t)); + ControllerData* msg = (ControllerData*)malloc(size); + msg->base.id = id; + msg->base.size = (uint32_t)size; + if (use_mb_str) { + sprintf_s((char*)msg->data, wcslen(str) + 1, "%S", str); + } else { + wcscpy_s((wchar_t*)msg->data, wcslen(str) + 1, str); + } + res = write_to_pipe(msg, (uint32_t)size); + free(msg); + return res; +} + +STDMETHODIMP COSpiceX::get_multimediaPorts(BSTR* pVal)
+{
+ *pVal=::SysAllocString(m_AudioGuestPorts);
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_multimediaPorts(BSTR newVal)
+{
+ ZeroMemory(m_AudioGuestPorts, sizeof(m_AudioGuestPorts));
+
+ // validate input arg
+ if (newVal != NULL)
+ {
+ StringCchCopyN(m_AudioGuestPorts, MAX_PATH, newVal, MAX_PATH);
+ DBG(3, "multi-media ports %S", m_AudioGuestPorts); + }
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_DynamicMenu(BSTR* pVal)
+{
+ // TODO: Add your implementation code here
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_DynamicMenu(BSTR newVal)
+{
+ // TODO: Add your implementation code here
+ DBG(0, "DynamicMenu %S", newVal); + return CreateMenu(newVal);
+}
+
+STDMETHODIMP COSpiceX::get_NumberOfMonitors(ULONG* pVal)
+{
+ // TODO: Add your implementation code here
+ *pVal = m_ulNumberOfMonitors;
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_NumberOfMonitors(ULONG newVal)
+{
+ // TODO: Add your implementation code here
+ if(newVal)
+ m_ulNumberOfMonitors = newVal;
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_UsbListenPort(USHORT* pVal)
+{
+ if (pVal == NULL) {
+ return E_INVALIDARG;
+ }
+ *pVal = m_UsbListenPort;
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_UsbListenPort(USHORT newVal)
+{
+ m_UsbListenPort = newVal;
+ DBG(3, "New USB listen port %u", m_UsbListenPort); + return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_AdminConsole(BOOL* pVal)
+{
+ if (pVal == NULL) {
+ return E_INVALIDARG;
+ }
+ *pVal = m_AdminConsole;
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_AdminConsole(BOOL newVal)
+{
+ m_AdminConsole = newVal;
+ DBG(3, "New AdminConsole %u", (int)(!!m_AdminConsole)); + return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_SendCtrlAltDelete(BOOL* pVal)
+{
+ if (pVal == NULL) {
+ return E_INVALIDARG;
+ }
+ *pVal = m_SendCtrlAltDelete;
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_SendCtrlAltDelete(BOOL newVal)
+{
+ m_SendCtrlAltDelete = newVal;
+ DBG(3, "New SendCtrlAltDelete %u", (int)(!!m_SendCtrlAltDelete)); + return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_NoTaskMgrExecution(BOOL* pVal)
+{
+ if (pVal == NULL) {
+ return E_INVALIDARG;
+ }
+ *pVal = m_NoTaskMgrExecution;
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_NoTaskMgrExecution(BOOL newVal)
+{
+ m_NoTaskMgrExecution = newVal;
+ DBG(3, "New NoTaskMgr %u", (int)(!!m_NoTaskMgrExecution)); + return S_OK;
+}
+
+STDMETHODIMP COSpiceX::SetUsbFilter(BSTR newVal)
+{
+ if (newVal == NULL) {
+ return E_INVALIDARG;
+ }
+
+ m_UsbFilter = newVal;
+ DBG(3, "New UsbFilter %S", m_UsbFilter.c_str()); +
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_Version(BSTR* pVal)
+{
+ DWORD dwDummy;
+ UINT nSize;
+
+ nSize = ::GetFileVersionInfoSize(SPICE_X_DLL, &dwDummy);
+ if (nSize == 0) {
+ // No version information available.
+ return HRESULT_FROM_WIN32(::GetLastError());
+ }
+
+ LPBYTE pVersionInfo = reinterpret_cast<LPBYTE>(_alloca(nSize));
+
+ if (!::GetFileVersionInfo(SPICE_X_DLL, 0L, nSize, pVersionInfo))
+ {
+ return HRESULT_FROM_WIN32(::GetLastError());
+ }
+
+ LPVOID pData;
+
+ if (!::VerQueryValue(pVersionInfo, _T("\\"), &pData, &nSize))
+ {
+ return HRESULT_FROM_WIN32(::GetLastError());
+ }
+
+ VS_FIXEDFILEINFO ffi;
+ ::CopyMemory(&ffi, pData, nSize);
+
+ WCHAR szVersion[16];
+ StringCchPrintf(szVersion, sizeof(szVersion), _T("%d.%d.%d.%d"),
+ HIWORD(ffi.dwFileVersionMS), LOWORD(ffi.dwFileVersionMS),
+ HIWORD(ffi.dwFileVersionLS), LOWORD(ffi.dwFileVersionLS));
+
+ *pVal = ::SysAllocString(szVersion);
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_UsbAutoShare(BOOL* pVal)
+{
+ if (pVal == NULL) {
+ return E_INVALIDARG;
+ }
+ *pVal = m_UsbAutoShare;
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_UsbAutoShare(BOOL newVal)
+{
+ m_UsbAutoShare = newVal;
+ DBG(3, "New UsbAutoShare %u", (int)(!!m_UsbAutoShare)); + return S_OK;
+}
+
+STDMETHODIMP COSpiceX::SetLanguageStrings(BSTR bzSection, BSTR bzLangStr)
+{
+ if ((bzSection == NULL) || (bzLangStr == NULL)) {
+ return E_POINTER;
+ }
+
+ if ((lstrlen(bzSection) == 0) || (lstrlen(bzLangStr) == 0)) {
+ return E_INVALIDARG;
+ }
+
+ m_Language[bzSection] = bzLangStr;
+
+ return S_OK; +} + +STDMETHODIMP COSpiceX::get_TrustStore(BSTR* pVal) +{ + *pVal = ::SysAllocString(m_TrustStore.c_str()); + + return S_OK; +} + +STDMETHODIMP COSpiceX::put_TrustStore(BSTR newVal) +{ + if (newVal == NULL) { + return E_INVALIDARG; + }
+
+ m_TrustStore = newVal; + DBG(3, "New TrustStore"); + + return S_OK; +} + +STDMETHODIMP COSpiceX::get_HostSubject(BSTR* pVal) +{ + *pVal = ::SysAllocString(m_HostSubject.c_str()); + + return S_OK; +} + +STDMETHODIMP COSpiceX::put_HostSubject(BSTR newVal) +{ + if (newVal == NULL) { + return E_INVALIDARG; + } + + m_HostSubject = newVal; + DBG(3, "New HostSubject %S", m_HostSubject.c_str()); + + return S_OK; +}
+
+STDMETHODIMP COSpiceX::get_ColorDepth(USHORT* pVal)
+{
+ if (pVal == NULL) {
+ return E_INVALIDARG;
+ }
+ *pVal = m_ColorDepth;
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_ColorDepth(USHORT newVal)
+{
+ m_ColorDepth = newVal;
+ DBG(3, "New ColorDepth %u", m_ColorDepth);
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_DisableEffects(BSTR* pVal)
+{
+ *pVal = ::SysAllocString(m_DisableEffects.c_str());
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_DisableEffects(BSTR newVal)
+{
+ if (newVal == NULL) {
+ return E_INVALIDARG;
+ }
+
+ m_DisableEffects= newVal;
+ DBG(3, "New DisableEffects %S", m_DisableEffects.c_str());
+
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::get_SmartCard(BOOL* pVal)
+{
+ if (pVal == NULL) {
+ return E_INVALIDARG;
+ }
+ *pVal = m_SmartCard;
+ return S_OK;
+}
+
+STDMETHODIMP COSpiceX::put_SmartCard(BOOL newVal)
+{
+ m_SmartCard = newVal;
+ DBG(3, "New SmartCard %u", !!m_SmartCard); + return S_OK;
+}
+ +STDMETHODIMP COSpiceX::get_Proxy(BSTR* pVal) +{ + *pVal = ::SysAllocString(m_Proxy.c_str()); + + return S_OK; +} + +STDMETHODIMP COSpiceX::put_Proxy(BSTR newVal) +{ + if (newVal == NULL) { + return E_INVALIDARG; + } + + m_Proxy = newVal; + DBG(3, "New Proxy %S", m_Proxy.c_str()); + + return S_OK; +}
+ +HRESULT COSpiceX::ExecuteUsbCtrl()
+{
+ if ((m_hClientProcess == NULL) || (m_UsbListenPort == 0)) {
+ LOG_INFO("USB sharing is not requested"); + return S_OK;
+ }
+
+ // Find executable path.
+
+ CRegKey reg;
+ LONG result;
+ const wchar_t* const reg_key = \
+ L"SOFTWARE\\RedHat\\Red Hat Enterprise Virtualization Tools\\USB Controller";
+
+ /* first try the default registry */
+ result = reg.Open(HKEY_LOCAL_MACHINE, reg_key, KEY_READ);
+ +#ifdef _WIN64
+ if (result != ERROR_SUCCESS) {
+ /* For 64 bit machines, 64 bit SpiceX, look at 32 bit registry too */
+ LOG_INFO("Looking for USB path in 32 bit registry");
+ result = reg.Open(HKEY_LOCAL_MACHINE, reg_key, KEY_READ | KEY_WOW64_32KEY);
+ }
+#else
+ if (result != ERROR_SUCCESS) {
+ /* For 64 bit machines, 32 bit SpiceX, look at 64 bit registry too */
+ LOG_INFO("Looking for USB path in 64 bit registry");
+ result = reg.Open(HKEY_LOCAL_MACHINE, reg_key, KEY_READ | KEY_WOW64_64KEY);
+ }
+#endif
+
+ if (result != ERROR_SUCCESS) {
+ LOG_INFO("Could not find registry entry for USB Controller"); + return HRESULT_FROM_WIN32(result);
+ }
+
+ WCHAR szCmdLine[MAX_PATH];
+ ULONG ulCmdLineLen = sizeof(szCmdLine) / sizeof(WCHAR);
+
+ result = reg.QueryStringValue(L"InstallDir", szCmdLine, &ulCmdLineLen);
+
+ if (result != ERROR_SUCCESS)
+ {
+ return HRESULT_FROM_WIN32(result);
+ }
+
+ reg.Close();
+
+ // Build command line.
+
+ std::wostringstream cmdline;
+
+ cmdline << szCmdLine << " "
+ << m_GuestHostName << L" " << m_UsbListenPort
+ << " -c \\\\.\\pipe\\SpiceForeignMenu-" << ::GetProcessId(m_hClientProcess);
+
+ if (!m_Language[L"USB"].empty()) {
+ cmdline << " -l \"" << m_Language[L"USB"].c_str() << "\"";
+ }
+
+ if (!m_UsbFilter.empty()) {
+ cmdline << " -f " << m_UsbFilter.c_str();
+ }
+
+ if (m_UsbAutoShare) {
+ cmdline << " -a";
+ }
+
+ // Prepare a log file.
+
+ WCHAR szLogFile[MAX_PATH]; + + if (::ExpandEnvironmentStrings(L"%TEMP%", szLogFile, sizeof(szLogFile))) + { + SECURITY_ATTRIBUTES sa; + + sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL; + + // GetCurrentProcessId() return the IE process id and the usbrdrctrl + // is not executed. So we use the spice client process id. + StringCchPrintf((STRSAFE_LPWSTR)szLogFile, sizeof(szLogFile), + L"%s\\usbrdrctrl-%d.log", szLogFile, ::GetProcessId(m_hClientProcess)); + + m_hUsbCtrlLog = ::CreateFile(szLogFile, GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ, &sa, CREATE_ALWAYS, 0, NULL); + } + + // Execute application.
+
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+
+ ZeroMemory(&pi, sizeof(pi));
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ if (m_hUsbCtrlLog != INVALID_HANDLE_VALUE)
+ {
+ DBG(0, "redirecting usb out/err to logfile '%S'", szLogFile); + si.dwFlags |= STARTF_USESTDHANDLES;
+ si.hStdError = m_hUsbCtrlLog;
+ si.hStdOutput = m_hUsbCtrlLog;
+ } else { + LOG_INFO("Failed to open log file (%S) -- %lu", + szLogFile, ::GetLastError()); + } +
+ DBG(0, "Running usbrdr (%S)", cmdline.str().c_str()); + + ::CreateProcess(NULL, const_cast<LPWSTR>(cmdline.str().c_str()),
+ NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
+
+ m_hUsbCtrlProcess = pi.hProcess;
+
+ if (m_hUsbCtrlProcess != NULL)
+ {
+ LOG_INFO("usbrdr pid %lu", ::GetProcessId(m_hUsbCtrlProcess)); + ::CreateThread(NULL, 0, UsbCtrlWatchDog, this, 0, NULL);
+ }
+ else
+ {
+ LOG_ERROR("Failed to run usbrdr (%S) -- %lu", + cmdline.str().c_str(), ::GetLastError()); + ::CloseHandle(m_hUsbCtrlLog);
+ m_hUsbCtrlLog = INVALID_HANDLE_VALUE;
+ }
+
+ return S_OK;
+}
+ +HRESULT COSpiceX::CreateCAFile(OUT LPWSTR szCAFileName, DWORD nSize) +{ + USES_CONVERSION; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; + PACL dacl = NULL; + + // Allow access only to current user + if (DWORD err = get_security_attributes(&sa, &sd, &dacl)) + { + return HRESULT_FROM_WIN32(err); + } + + if (::ExpandEnvironmentStrings(L"%TEMP%\\truststore.pem", + szCAFileName, nSize) == 0) + { + LocalFree(dacl); + return HRESULT_FROM_WIN32(::GetLastError()); + } + + HANDLE hTrustStore = ::CreateFile(szCAFileName, GENERIC_WRITE, + 0, NULL, CREATE_ALWAYS, 0, &sa); + LocalFree(dacl); + if (hTrustStore == INVALID_HANDLE_VALUE) + { + return HRESULT_FROM_WIN32(::GetLastError()); + } + + std::string truststore = W2A(m_TrustStore.c_str()); + DWORD dwBytesWritten; + + if ((::WriteFile(hTrustStore, truststore.c_str(), + DWORD(truststore.length() + 1), &dwBytesWritten, NULL) == FALSE) || + (dwBytesWritten != (truststore.length() + 1))) + { + ::CloseHandle(hTrustStore); + return HRESULT_FROM_WIN32(::GetLastError()); + } + + ::CloseHandle(hTrustStore); + + return S_OK; +} |