summaryrefslogtreecommitdiff
path: root/SpiceXPI/src/plugin/controller-win.cpp
diff options
context:
space:
mode:
authorChristophe Fergeau <cfergeau@redhat.com>2013-03-01 17:55:59 +0100
committerChristophe Fergeau <cfergeau@redhat.com>2013-03-14 11:10:09 +0100
commitdf2cbfac026d39552959f1421f4a1ecc9a4ebf91 (patch)
tree34c74f427ad9ca5302168ba793e2dd77e0d69e6b /SpiceXPI/src/plugin/controller-win.cpp
parent4ecc97f7f0b90e49e6672a3cb2b937d5d6f9c708 (diff)
Win support
Diffstat (limited to 'SpiceXPI/src/plugin/controller-win.cpp')
-rw-r--r--SpiceXPI/src/plugin/controller-win.cpp281
1 files changed, 281 insertions, 0 deletions
diff --git a/SpiceXPI/src/plugin/controller-win.cpp b/SpiceXPI/src/plugin/controller-win.cpp
new file mode 100644
index 0000000..036082e
--- /dev/null
+++ b/SpiceXPI/src/plugin/controller-win.cpp
@@ -0,0 +1,281 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Copyright 2009-2011, Red Hat Inc.
+ * Copyright 2013, Red Hat Inc.
+ * Based on mozilla.org's scriptable plugin example
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Uri Lublin
+ * Martin Stransky
+ * Peter Hatina
+ * Christophe Fergeau
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "config.h"
+
+#include <aclapi.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <glib.h>
+#include <gio/gwin32outputstream.h>
+
+#include "rederrorcodes.h"
+#include "controller-win.h"
+#include "plugin.h"
+
+SpiceControllerWin::SpiceControllerWin(nsPluginInstance *aPlugin):
+ SpiceController(aPlugin)
+{
+}
+
+SpiceControllerWin::~SpiceControllerWin()
+{
+}
+
+int SpiceControllerWin::Connect()
+{
+ HANDLE hClientPipe;
+
+ hClientPipe = CreateFile(m_name.c_str(),
+ GENERIC_READ | GENERIC_WRITE,
+ 0, NULL,
+ OPEN_EXISTING,
+ SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
+ NULL);
+ if (hClientPipe != INVALID_HANDLE_VALUE) {
+ g_warning("Connection OK");
+ m_pipe = g_win32_output_stream_new(hClientPipe, TRUE);
+ return 0;
+ } else {
+ g_warning("Connection failed");
+ return -1;
+ }
+ g_return_val_if_reached(-1);
+}
+
+static int get_sid(HANDLE handle, PSID* ppsid, PSECURITY_DESCRIPTOR* ppsec_desc)
+{
+ DWORD ret = GetSecurityInfo(handle, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION,
+ ppsid, NULL, NULL, NULL, ppsec_desc);
+ if (ret != ERROR_SUCCESS) {
+ return ret;
+ }
+ if (!IsValidSid(*ppsid)) {
+ return -1;
+ }
+ return 0;
+}
+
+//checks whether the handle owner is the current user.
+static bool is_same_user(HANDLE handle)
+{
+ PSECURITY_DESCRIPTOR psec_desc_handle = NULL;
+ PSECURITY_DESCRIPTOR psec_desc_user = NULL;
+ PSID psid_handle;
+ PSID psid_user;
+ bool ret;
+
+ ret = !get_sid(handle, &psid_handle, &psec_desc_handle) &&
+ !get_sid(GetCurrentProcess(), &psid_user, &psec_desc_user) &&
+ EqualSid(psid_handle, psid_user);
+ LocalFree(psec_desc_handle);
+ LocalFree(psec_desc_user);
+ return ret;
+}
+
+bool SpiceControllerWin::CheckPipe()
+{
+ void *hClientPipe;
+
+ if (!G_IS_WIN32_OUTPUT_STREAM(m_pipe))
+ return false;
+
+ hClientPipe = g_win32_output_stream_get_handle(G_WIN32_OUTPUT_STREAM(m_pipe));
+ // Verify the named-pipe-server owner is the current user.
+ // Do it here so upon failure use next condition cleanup code.
+ if (hClientPipe != INVALID_HANDLE_VALUE) {
+ if (!is_same_user(hClientPipe)) {
+ g_critical("Closing pipe to spicec -- it is not safe");
+ g_object_unref(G_OBJECT(m_pipe));
+ m_pipe = NULL;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#ifdef _UNICODE
+#define _T L
+#else
+#define _T
+#endif
+
+#define SPICE_CLIENT_REGISTRY_KEY _T("Software\\spice-space.org\\spicex")
+#define SPICE_XPI_DLL _T("npSpiceConsole.dll")
+#define RED_CLIENT_FILE_NAME _T("spicec.exe")
+#define CMDLINE_LENGTH 32768
+
+GStrv SpiceControllerWin::GetClientPath()
+{
+ LONG lret;
+ HKEY hkey;
+
+ lret = RegOpenKeyEx(HKEY_CURRENT_USER, SPICE_CLIENT_REGISTRY_KEY,
+ 0, KEY_READ, &hkey);
+ if (lret == ERROR_SUCCESS) {
+ DWORD dwType = REG_SZ;
+ TCHAR lpCommandLine[CMDLINE_LENGTH] = {0};
+ DWORD dwSize = sizeof(lpCommandLine);
+ GArray *argv_garray;
+ char *it;
+
+ lret = RegQueryValueEx(hkey, "client", NULL, &dwType,
+ (LPBYTE)lpCommandLine, &dwSize);
+ RegCloseKey(hkey);
+
+ /* Some convoluted code here, the registry key contains the
+ * command to run as a string, the GSpawn API expects an array
+ * of strings. The awkward part is that the GSpawn API will
+ * then rebuild a commandline string from this array :-/ */
+ argv_garray = g_array_new(TRUE, FALSE, sizeof(char *));
+ /* Look for .exe from the end as the path in which the SPICE
+ * client is installed may contain '.exe' */
+ it = g_strrstr_len(lpCommandLine, dwSize, ".exe ");
+ if (it != NULL) {
+ gchar **args;
+ gchar *val;
+ it += strlen(".exe");
+ *it = '\0';
+ it++;
+ val = g_strdup(lpCommandLine);
+ g_array_prepend_val(argv_garray, val);
+ args = g_strsplit(it, " ", -1);
+ g_array_append_vals(argv_garray, args, g_strv_length(args));
+ /* We don't want to free the strings stored in args, just
+ * the container */
+ g_free(args);
+ return (GStrv)g_array_free(argv_garray, FALSE);
+ }
+ }
+
+ g_warn_if_reached();
+
+ return NULL;
+}
+
+GStrv SpiceControllerWin::GetFallbackClientPath()
+{
+ HMODULE hModule;
+ // we assume the Spice client binary is located in the same dir as the
+ // Firefox plugin
+ if ((hModule = GetModuleHandle(SPICE_XPI_DLL))) {
+ gchar *module_path;
+ GStrv fallback_argv;
+
+ module_path = g_win32_get_package_installation_directory_of_module(hModule);
+ if (module_path != NULL) {
+ fallback_argv = g_new0(char *, 3);
+ fallback_argv[0] = g_build_filename(module_path, RED_CLIENT_FILE_NAME, NULL);
+ fallback_argv[1] = g_strdup("--controller");
+ g_free(module_path);
+ return fallback_argv;
+ }
+ }
+
+ g_warn_if_reached();
+
+ return NULL;
+}
+
+#if 0
+static void GetClientPaths(GStrv *client_argv, GStrv *fallback_argv)
+{
+ if (client_argv != NULL) {
+ *client_argv = g_new0(char *, 2);
+ (*client_argv)[0] = g_strdup("/usr/libexec/spice-xpi-client");
+ }
+
+ if (fallback_argv != NULL) {
+ *client_argv = g_new0(char *, 3);
+ (*client_argv)[0] = g_strdup("/usr/bin/spicec");
+ (*client_argv)[0] = g_strdup("--controller");
+ }
+}
+#endif
+
+#define RED_CLIENT_PIPE_NAME TEXT("\\\\.\\pipe\\SpiceController-%lu")
+void SpiceControllerWin::SetupControllerPipe(GStrv &env)
+{
+ char *pipe_name;
+ pipe_name = g_strdup_printf(RED_CLIENT_PIPE_NAME, (unsigned long)g_random_int());
+ this->SetFilename(pipe_name);
+ /* FIXME set SPICE_XPI_NAMEDPIPE */
+ env = g_environ_setenv(env, "SPICE_XPI_NAMEDPIPE", pipe_name, TRUE);
+ g_free(pipe_name);
+}
+
+void SpiceControllerWin::StopClient()
+{
+ if (m_pid_controller != NULL) {
+ //WaitForPid will take care of closing the handle
+ TerminateProcess(m_pid_controller, 0);
+ m_pid_controller = NULL;
+ }
+}
+
+
+uint32_t SpiceControllerWin::Write(const void *lpBuffer, uint32_t nBytesToWrite)
+{
+ GError *error = NULL;
+ gsize bytes_written;
+
+ g_return_val_if_fail(G_IS_OUTPUT_STREAM(m_pipe), 0);
+
+ g_output_stream_write_all(m_pipe, lpBuffer, nBytesToWrite,
+ &bytes_written, NULL, &error);
+ if (error != NULL) {
+ g_warning("Error writing to controller pipe: %s", error->message);
+ g_clear_error(&error);
+ return -1;
+ }
+ if (bytes_written != nBytesToWrite) {
+ g_warning("Partial write (%"G_GSIZE_MODIFIER"u instead of %u",
+ bytes_written, (unsigned int)nBytesToWrite);
+ }
+
+ return bytes_written;
+}