diff options
-rw-r--r-- | base/base_paths_win.cc | 6 | ||||
-rw-r--r-- | base/base_paths_win.h | 12 | ||||
-rw-r--r-- | remoting/VERSION | 2 | ||||
-rw-r--r-- | remoting/host/branding.cc | 2 | ||||
-rw-r--r-- | remoting/host/elevated_controller.idl | 13 | ||||
-rw-r--r-- | remoting/host/elevated_controller_win.cc | 155 | ||||
-rw-r--r-- | remoting/host/elevated_controller_win.h | 1 | ||||
-rw-r--r-- | remoting/host/installer/chromoting.wxs | 41 | ||||
-rw-r--r-- | remoting/host/wts_session_process_launcher_win.cc | 24 | ||||
-rw-r--r-- | remoting/remoting.gyp | 8 |
10 files changed, 179 insertions, 85 deletions
diff --git a/base/base_paths_win.cc b/base/base_paths_win.cc index eab412a..0b24833 100644 --- a/base/base_paths_win.cc +++ b/base/base_paths_win.cc @@ -89,6 +89,12 @@ bool PathProviderWin(int key, FilePath* result) { return false; cur = FilePath(system_buffer); break; + case base::DIR_COMMON_APP_DATA: + if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, + SHGFP_TYPE_CURRENT, system_buffer))) + return false; + cur = FilePath(system_buffer); + break; case base::DIR_PROFILE: if (FAILED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, system_buffer))) diff --git a/base/base_paths_win.h b/base/base_paths_win.h index 02b1f49..c005bb2 100644 --- a/base/base_paths_win.h +++ b/base/base_paths_win.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -27,9 +27,13 @@ enum { // Start Menu\Programs" DIR_APP_DATA, // Application Data directory under the user profile. DIR_PROFILE, // Usually "C:\Documents and settings\<user>. - DIR_LOCAL_APP_DATA_LOW, // Local AppData directory for low integrity level. - DIR_LOCAL_APP_DATA, // "Local Settings\Application Data" directory under the - // user profile. + DIR_LOCAL_APP_DATA_LOW, // Local AppData directory for low integrity level. + DIR_LOCAL_APP_DATA, // "Local Settings\Application Data" directory under + // the user profile. + DIR_COMMON_APP_DATA, // W2K, XP, W2K3: "C:\Documents and Settings\ + // All Users\Application Data". + // Vista, W2K8 and above: "C:\ProgramData". + PATH_WIN_END }; diff --git a/remoting/VERSION b/remoting/VERSION index b0ecd30..1807650 100644 --- a/remoting/VERSION +++ b/remoting/VERSION @@ -1,4 +1,4 @@ MAJOR=1 MINOR=4 -BUILD=2 +BUILD=4 PATCH=0 diff --git a/remoting/host/branding.cc b/remoting/host/branding.cc index 2e55190..1316139a 100644 --- a/remoting/host/branding.cc +++ b/remoting/host/branding.cc @@ -42,7 +42,7 @@ FilePath GetConfigDir() { FilePath app_data_dir; #if defined(OS_WIN) - PathService::Get(base::DIR_LOCAL_APP_DATA, &app_data_dir); + PathService::Get(base::DIR_COMMON_APP_DATA, &app_data_dir); #elif defined(OS_MACOSX) PathService::Get(base::DIR_APP_DATA, &app_data_dir); #else diff --git a/remoting/host/elevated_controller.idl b/remoting/host/elevated_controller.idl index 06ba0b5..3d3c82c 100644 --- a/remoting/host/elevated_controller.idl +++ b/remoting/host/elevated_controller.idl @@ -14,10 +14,12 @@ import "ocidl.idl"; pointer_default(unique) ] interface IDaemonControl: IDispatch { - [ id(1), helpstring("Reads the daemon configuration.") ] + [ id(1), helpstring("Returns a filtered copy of the daemon's configuration " + "stripped of all security-sensitive information.") ] HRESULT GetConfig([out, retval] BSTR* config_out); - [ id(2), helpstring("Writes the daemon configuration.") ] + [ id(2), helpstring("Replaces the existing daemon's configuration with " + "the specified settings.") ] HRESULT SetConfig([in] BSTR config); [ id(3), helpstring("Starts the daemon.") ] @@ -25,6 +27,13 @@ interface IDaemonControl: IDispatch { [ id(4), helpstring("Stops the daemon.") ] HRESULT StopDaemon(); + + [ id(5), helpstring("Modifies the existing daemon's configuration by " + "merging it with the specified settings. A subset of " + "items is allowed to be modified using this method. " + "Any read-only settings such as 'host_id' (and some " + "others) are not modified.") ] + HRESULT UpdateConfig([in] BSTR config); }; [ diff --git a/remoting/host/elevated_controller_win.cc b/remoting/host/elevated_controller_win.cc index fbeeea9..f1163e75 100644 --- a/remoting/host/elevated_controller_win.cc +++ b/remoting/host/elevated_controller_win.cc @@ -4,6 +4,8 @@ #include "remoting/host/elevated_controller_win.h" +#include <sddl.h> + #include "base/file_util.h" #include "base/logging.h" #include "base/json/json_reader.h" @@ -20,30 +22,32 @@ namespace { +// The host configuration file name. +const FilePath::CharType kConfigFileName[] = FILE_PATH_LITERAL("host.json"); + +// The extension for the temporary file. +const FilePath::CharType kTempFileExtension[] = FILE_PATH_LITERAL("json~"); + +// The host configuration file security descriptor that enables full access to +// Local System and built-in administrators only. +const char kConfigFileSecurityDescriptor[] = + "O:BA" "G:BA" "D:(A;;GA;;;SY)(A;;GA;;;BA)"; + +// The maximum size of the configuration file. "1MB ought to be enough" for any +// reasonable configuration we will ever need. 1MB is low enough to make +// the probability of out of memory situation fairly low. OOM is still possible +// and we will crash if it occurs. +const size_t kMaxConfigFileSize = 1024 * 1024; + // ReadConfig() filters the configuration file stripping all variables except of // the following two. const char kHostId[] = "host_id"; const char kXmppLogin[] = "xmpp_login"; -// Names of the configuration files. -const FilePath::CharType kAuthConfigFilename[] = FILE_PATH_LITERAL("auth.json"); -const FilePath::CharType kHostConfigFilename[] = FILE_PATH_LITERAL("host.json"); - -// TODO(alexeypa): Remove the hardcoded undocumented paths and store -// the configuration in the registry. -#ifdef OFFICIAL_BUILD -const FilePath::CharType kConfigDir[] = FILE_PATH_LITERAL( - "config\\systemprofile\\AppData\\Local\\Google\\Chrome Remote Desktop"); -#else -const FilePath::CharType kConfigDir[] = - FILE_PATH_LITERAL("config\\systemprofile\\AppData\\Local\\Chromoting"); -#endif - -// Reads and parses a JSON configuration file. +// Reads and parses the configuration file up to |kMaxConfigFileSize| in +// size. HRESULT ReadConfig(const FilePath& filename, scoped_ptr<base::DictionaryValue>* config_out) { - // TODO(alexeypa): Remove 64KB limitation. - const size_t kMaxConfigFileSize = 64 * 1024; // Read raw data from the configuration file. base::win::ScopedHandle file( @@ -58,12 +62,12 @@ HRESULT ReadConfig(const FilePath& filename, if (!file.IsValid()) { DWORD error = GetLastError(); LOG_GETLASTERROR(ERROR) - << "Failed to read '" << filename.value() << "'"; + << "Failed to open '" << filename.value() << "'"; return HRESULT_FROM_WIN32(error); } - std::vector<char> buffer(kMaxConfigFileSize); - DWORD size = static_cast<DWORD>(buffer.size()); + scoped_array<char> buffer(new char[kMaxConfigFileSize]); + DWORD size = kMaxConfigFileSize; if (!::ReadFile(file, &buffer[0], size, &size, NULL)) { DWORD error = GetLastError(); LOG_GETLASTERROR(ERROR) @@ -72,7 +76,7 @@ HRESULT ReadConfig(const FilePath& filename, } // Parse the JSON configuration, expecting it to contain a dictionary. - std::string file_content(&buffer[0], size); + std::string file_content(buffer.get(), size); scoped_ptr<base::Value> value(base::JSONReader::Read(file_content, true)); base::DictionaryValue* dictionary; @@ -86,6 +90,76 @@ HRESULT ReadConfig(const FilePath& filename, return S_OK; } +// Writes the configuration file up to |kMaxConfigFileSize| in size. +HRESULT WriteConfig(const FilePath& filename, + const char* content, + size_t length) { + if (length > kMaxConfigFileSize) { + return E_FAIL; + } + + // Create a security descriptor for the configuration file. + SECURITY_ATTRIBUTES security_attributes; + security_attributes.nLength = sizeof(security_attributes); + security_attributes.bInheritHandle = FALSE; + + ULONG security_descriptor_length = 0; + if (!ConvertStringSecurityDescriptorToSecurityDescriptorA( + kConfigFileSecurityDescriptor, + SDDL_REVISION_1, + reinterpret_cast<PSECURITY_DESCRIPTOR*>( + &security_attributes.lpSecurityDescriptor), + &security_descriptor_length)) { + DWORD error = GetLastError(); + LOG_GETLASTERROR(ERROR) << + "Failed to create a security descriptor for the configuration file"; + return HRESULT_FROM_WIN32(error); + } + + // Create a temporary file and write configuration to it. + FilePath tempname = filename.ReplaceExtension(kTempFileExtension); + { + base::win::ScopedHandle file( + CreateFileW(tempname.value().c_str(), + GENERIC_WRITE, + 0, + &security_attributes, + CREATE_ALWAYS, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL)); + + if (!file.IsValid()) { + DWORD error = GetLastError(); + LOG_GETLASTERROR(ERROR) + << "Failed to create '" << filename.value() << "'"; + return HRESULT_FROM_WIN32(error); + } + + DWORD written; + if (!WriteFile(file, content, static_cast<DWORD>(length), &written, NULL)) { + DWORD error = GetLastError(); + LOG_GETLASTERROR(ERROR) + << "Failed to write to '" << filename.value() << "'"; + return HRESULT_FROM_WIN32(error); + } + } + + // Now that the configuration is stored successfully replace the actual + // configuration file. + if (!MoveFileExW(tempname.value().c_str(), + filename.value().c_str(), + MOVEFILE_REPLACE_EXISTING)) { + DWORD error = GetLastError(); + LOG_GETLASTERROR(ERROR) + << "Failed to rename '" << tempname.value() << "' to '" + << filename.value() << "'"; + return HRESULT_FROM_WIN32(error); + } + + return S_OK; +} + + } // namespace namespace remoting { @@ -101,14 +175,11 @@ void ElevatedControllerWin::FinalRelease() { } STDMETHODIMP ElevatedControllerWin::GetConfig(BSTR* config_out) { - FilePath system_profile; - PathService::Get(base::DIR_SYSTEM, &system_profile); + FilePath config_dir = remoting::GetConfigDir(); // Read the host configuration. scoped_ptr<base::DictionaryValue> config; - HRESULT hr = ReadConfig( - system_profile.Append(kConfigDir).Append(kHostConfigFilename), - &config); + HRESULT hr = ReadConfig(config_dir.Append(kConfigFileName), &config); if (FAILED(hr)) { return hr; } @@ -139,11 +210,7 @@ STDMETHODIMP ElevatedControllerWin::GetConfig(BSTR* config_out) { STDMETHODIMP ElevatedControllerWin::SetConfig(BSTR config) { // Determine the config directory path and create it if necessary. - // N.B. The configuration files are stored in LocalSystems's profile which is - // not readable by non administrators. - FilePath system_profile; - PathService::Get(base::DIR_SYSTEM, &system_profile); - FilePath config_dir = system_profile.Append(kConfigDir); + FilePath config_dir = remoting::GetConfigDir(); if (!file_util::CreateDirectory(config_dir)) { return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); } @@ -151,25 +218,9 @@ STDMETHODIMP ElevatedControllerWin::SetConfig(BSTR config) { std::string file_content = UTF16ToUTF8( string16(static_cast<char16*>(config), ::SysStringLen(config))); - int written = file_util::WriteFile( - config_dir.Append(kAuthConfigFilename), - file_content.c_str(), - file_content.size()); - if (written != static_cast<int>(file_content.size())) { - return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); - } - - // TODO(alexeypa): Store the authentication and host configurations in a - // single file. - written = file_util::WriteFile( - config_dir.Append(kHostConfigFilename), - file_content.c_str(), - file_content.size()); - if (written != static_cast<int>(file_content.size())) { - return E_FAIL; - } - - return S_OK; + return WriteConfig(config_dir.Append(kConfigFileName), + file_content.c_str(), + file_content.size()); } STDMETHODIMP ElevatedControllerWin::StartDaemon() { @@ -212,6 +263,10 @@ STDMETHODIMP ElevatedControllerWin::StopDaemon() { return S_OK; } +STDMETHODIMP ElevatedControllerWin::UpdateConfig(BSTR config) { + return E_NOTIMPL; +} + HRESULT ElevatedControllerWin::OpenService(ScopedScHandle* service_out) { DWORD error; diff --git a/remoting/host/elevated_controller_win.h b/remoting/host/elevated_controller_win.h index 6f73162..af855d4 100644 --- a/remoting/host/elevated_controller_win.h +++ b/remoting/host/elevated_controller_win.h @@ -32,6 +32,7 @@ class ATL_NO_VTABLE ElevatedControllerWin STDMETHOD(SetConfig)(BSTR config); STDMETHOD(StartDaemon)(); STDMETHOD(StopDaemon)(); + STDMETHOD(UpdateConfig)(BSTR config); DECLARE_NO_REGISTRY() diff --git a/remoting/host/installer/chromoting.wxs b/remoting/host/installer/chromoting.wxs index e90fabc..d546a44 100644 --- a/remoting/host/installer/chromoting.wxs +++ b/remoting/host/installer/chromoting.wxs @@ -63,18 +63,27 @@ <Media Id="1" Cabinet="chromoting.cab" EmbedCab="yes"/> <Directory Id="TARGETDIR" Name="SourceDir"> - <Directory Id="ProgramFilesFolder" Name="PFiles"> + <Directory Id="ProgramFilesFolder"> <?ifdef OfficialBuild ?> - <Directory Id="google" Name="Google"> - <Directory Id="chromoting" Name="Chrome Remote Desktop"/> + <Directory Id="program_files_google" Name="Google"> + <Directory Id="binaries" Name="Chrome Remote Desktop"/> </Directory> <?else?> - <Directory Id="chromoting" Name="Chromoting"/> + <Directory Id="binaries" Name="Chromoting"/> + <?endif?> + </Directory> + <Directory Id="CommonAppDataFolder"> + <?ifdef OfficialBuild ?> + <Directory Id="common_app_data_google" Name="Google"> + <Directory Id="config_files" Name="Chrome Remote Desktop"/> + </Directory> + <?else?> + <Directory Id="config_files" Name="Chromoting"/> <?endif?> </Directory> </Directory> - <DirectoryRef Id="chromoting" FileSource="$(var.FileSource)"> + <DirectoryRef Id="binaries" FileSource="$(var.FileSource)"> <Component Id="sas.dll" Guid="3c33dd97-3750-467f-8ec6-730611d346d4"> <File Id="sas.dll" @@ -84,8 +93,8 @@ Vital="yes"/> </Component> - <Component Id="remoting_service.exe" - Guid="23103839-bb02-4007-b149-998ddd8d7cba"> + <Component Id="remoting_host" + Guid="8b5f7392-dfa9-4fa3-83ac-87bd6676da50"> <File Id="remoting_service.exe" DiskId="1" KeyPath="yes" @@ -96,9 +105,9 @@ Type="ownProcess" Vital="yes" Name="$(var.ServiceName)" - DisplayName="@[chromoting]remoting_service.exe,-101" - Description="@[chromoting]remoting_service.exe,-102" - Arguments="--host-binary="[chromoting]remoting_me2me_host.exe"" + DisplayName="@[#remoting_service.exe],-101" + Description="@[#remoting_service.exe],-102" + Arguments="--host-binary="[#remoting_me2me_host.exe]" --auth-config="[config_files]host.json" --host-config="[config_files]host.json"" Start="auto" Account="LocalSystem" ErrorControl="ignore" @@ -109,10 +118,7 @@ Remove="uninstall" Name="$(var.ServiceName)" Wait="yes" /> - </Component> - <Component Id="remoting_me2me_host.exe" - Guid="0e1889af-f3f8-45a2-b2d0-c719d53c4474"> <File Id="remoting_me2me_host.exe" DiskId="1" Name="remoting_me2me_host.exe" @@ -121,8 +127,8 @@ Name="$(var.EventSourceName)" Log="Application" CategoryCount="1" - CategoryMessageFile="[chromoting]remoting_me2me_host.exe" - EventMessageFile="[chromoting]remoting_me2me_host.exe" + CategoryMessageFile="[#remoting_me2me_host.exe]" + EventMessageFile="[#remoting_me2me_host.exe]" SupportsErrors="yes" SupportsInformationals="yes"/> @@ -271,7 +277,7 @@ <RegistryKey Key="HELPDIR" Action="create"> <RegistryValue Type="string" - Value="[chromoting]"/> + Value="[binaries]"/> </RegistryKey> </RegistryKey> </RegistryKey> @@ -285,8 +291,7 @@ <Feature Id="chromoting_host" Level="1" Title="$(var.ChromotingHost)"> <ComponentRef Id="omaha_registration"/> - <ComponentRef Id="remoting_service.exe"/> - <ComponentRef Id="remoting_me2me_host.exe"/> + <ComponentRef Id="remoting_host"/> <ComponentRef Id="sas.dll"/> <ComponentRef Id="service_controller"/> </Feature> diff --git a/remoting/host/wts_session_process_launcher_win.cc b/remoting/host/wts_session_process_launcher_win.cc index 45d81cf..769d9a9 100644 --- a/remoting/host/wts_session_process_launcher_win.cc +++ b/remoting/host/wts_session_process_launcher_win.cc @@ -11,6 +11,7 @@ #include <sddl.h> #include <limits> +#include "base/command_line.h" #include "base/logging.h" #include "base/process_util.h" #include "base/rand_util.h" @@ -43,8 +44,12 @@ const char kDefaultDesktopName[] = "winsta0\\default"; // Match the pipe name prefix used by Chrome IPC channels. const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome."; -// Generates the command line of the host process. -const char kHostProcessCommandLineFormat[] = "\"%ls\" --chromoting-ipc=%ls"; +// The IPC channel name is passed to the host in the command line. +const char kChromotingIpcSwitchName[] = "chromoting-ipc"; + +// The command line parameters that should be copied from the service's command +// line to the host process. +const char* kCopiedSwitchNames[] = { "auth-config", "host-config" }; // The security descriptor of the Chromoting IPC channel. It gives full access // to LocalSystem and denies access by anyone else. @@ -279,15 +284,18 @@ void WtsSessionProcessLauncher::LaunchProcess() { this, io_thread_->message_loop_proxy().get())); - string16 command_line = - base::StringPrintf(ASCIIToUTF16(kHostProcessCommandLineFormat).c_str(), - host_binary_.value().c_str(), - channel_name.c_str()); + // Create the host process command line passing the name of the IPC channel + // to use and copying known switches from the service's command line. + CommandLine command_line(host_binary_); + command_line.AppendSwitchNative(kChromotingIpcSwitchName, channel_name); + command_line.CopySwitchesFrom(*CommandLine::ForCurrentProcess(), + kCopiedSwitchNames, + _countof(kCopiedSwitchNames)); // Try to launch the process and attach an object watcher to the returned // handle so that we get notified when the process terminates. - if (LaunchProcessAsUser(host_binary_, command_line, session_token_, - &process_)) { + if (LaunchProcessAsUser(host_binary_, command_line.GetCommandLineString(), + session_token_, &process_)) { if (process_watcher_.StartWatching(process_.handle(), this)) { state_ = StateAttached; return; diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index da3492b..db396ff 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -412,7 +412,12 @@ { 'rule_name': 'candle', 'extension': 'wxs', - 'inputs': [ ], + 'inputs': [ + '<(PRODUCT_DIR)/remoting_host_controller.exe', + '<(PRODUCT_DIR)/remoting_me2me_host.exe', + '<(PRODUCT_DIR)/remoting_service.exe', + '<(sas_dll_path)' + ], 'outputs': [ '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).wixobj', ], @@ -437,6 +442,7 @@ 'rule_name': 'light', 'extension': 'wixobj', 'inputs': [ + '<(PRODUCT_DIR)/remoting_host_controller.exe', '<(PRODUCT_DIR)/remoting_me2me_host.exe', '<(PRODUCT_DIR)/remoting_service.exe', '<(sas_dll_path)' |