| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/win/elevated_controller.h" | 5 #include "remoting/host/win/elevated_controller.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/file_version_info.h" | 8 #include "base/file_version_info.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 | 25 |
| 26 namespace { | 26 namespace { |
| 27 | 27 |
| 28 // The maximum size of the configuration file. "1MB ought to be enough" for any | 28 // The maximum size of the configuration file. "1MB ought to be enough" for any |
| 29 // reasonable configuration we will ever need. 1MB is low enough to make | 29 // reasonable configuration we will ever need. 1MB is low enough to make |
| 30 // the probability of out of memory situation fairly low. OOM is still possible | 30 // the probability of out of memory situation fairly low. OOM is still possible |
| 31 // and we will crash if it occurs. | 31 // and we will crash if it occurs. |
| 32 const size_t kMaxConfigFileSize = 1024 * 1024; | 32 const size_t kMaxConfigFileSize = 1024 * 1024; |
| 33 | 33 |
| 34 // The host configuration file name. | 34 // The host configuration file name. |
| 35 const FilePath::CharType kConfigFileName[] = FILE_PATH_LITERAL("host.json"); | 35 const base::FilePath::CharType kConfigFileName[] = FILE_PATH_LITERAL("host.json"
); |
| 36 | 36 |
| 37 // The unprivileged configuration file name. | 37 // The unprivileged configuration file name. |
| 38 const FilePath::CharType kUnprivilegedConfigFileName[] = | 38 const base::FilePath::CharType kUnprivilegedConfigFileName[] = |
| 39 FILE_PATH_LITERAL("host_unprivileged.json"); | 39 FILE_PATH_LITERAL("host_unprivileged.json"); |
| 40 | 40 |
| 41 // The extension for the temporary file. | 41 // The extension for the temporary file. |
| 42 const FilePath::CharType kTempFileExtension[] = FILE_PATH_LITERAL("json~"); | 42 const base::FilePath::CharType kTempFileExtension[] = FILE_PATH_LITERAL("json~")
; |
| 43 | 43 |
| 44 // The host configuration file security descriptor that enables full access to | 44 // The host configuration file security descriptor that enables full access to |
| 45 // Local System and built-in administrators only. | 45 // Local System and built-in administrators only. |
| 46 const char kConfigFileSecurityDescriptor[] = | 46 const char kConfigFileSecurityDescriptor[] = |
| 47 "O:BAG:BAD:(A;;GA;;;SY)(A;;GA;;;BA)"; | 47 "O:BAG:BAD:(A;;GA;;;SY)(A;;GA;;;BA)"; |
| 48 | 48 |
| 49 const char kUnprivilegedConfigFileSecurityDescriptor[] = | 49 const char kUnprivilegedConfigFileSecurityDescriptor[] = |
| 50 "O:BAG:BAD:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;AU)"; | 50 "O:BAG:BAD:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;AU)"; |
| 51 | 51 |
| 52 // Configuration keys. | 52 // Configuration keys. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 } | 85 } |
| 86 | 86 |
| 87 hr = CoRevertToSelf(); | 87 hr = CoRevertToSelf(); |
| 88 CHECK(SUCCEEDED(hr)); | 88 CHECK(SUCCEEDED(hr)); |
| 89 | 89 |
| 90 return !!result; | 90 return !!result; |
| 91 } | 91 } |
| 92 | 92 |
| 93 // Reads and parses the configuration file up to |kMaxConfigFileSize| in | 93 // Reads and parses the configuration file up to |kMaxConfigFileSize| in |
| 94 // size. | 94 // size. |
| 95 HRESULT ReadConfig(const FilePath& filename, | 95 HRESULT ReadConfig(const base::FilePath& filename, |
| 96 scoped_ptr<base::DictionaryValue>* config_out) { | 96 scoped_ptr<base::DictionaryValue>* config_out) { |
| 97 | 97 |
| 98 // Read raw data from the configuration file. | 98 // Read raw data from the configuration file. |
| 99 base::win::ScopedHandle file( | 99 base::win::ScopedHandle file( |
| 100 CreateFileW(filename.value().c_str(), | 100 CreateFileW(filename.value().c_str(), |
| 101 GENERIC_READ, | 101 GENERIC_READ, |
| 102 FILE_SHARE_READ | FILE_SHARE_WRITE, | 102 FILE_SHARE_READ | FILE_SHARE_WRITE, |
| 103 NULL, | 103 NULL, |
| 104 OPEN_EXISTING, | 104 OPEN_EXISTING, |
| 105 FILE_FLAG_SEQUENTIAL_SCAN, | 105 FILE_FLAG_SEQUENTIAL_SCAN, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 130 if (value.get() == NULL || !value->GetAsDictionary(&dictionary)) { | 130 if (value.get() == NULL || !value->GetAsDictionary(&dictionary)) { |
| 131 LOG(ERROR) << "Failed to read '" << filename.value() << "'."; | 131 LOG(ERROR) << "Failed to read '" << filename.value() << "'."; |
| 132 return E_FAIL; | 132 return E_FAIL; |
| 133 } | 133 } |
| 134 | 134 |
| 135 value.release(); | 135 value.release(); |
| 136 config_out->reset(dictionary); | 136 config_out->reset(dictionary); |
| 137 return S_OK; | 137 return S_OK; |
| 138 } | 138 } |
| 139 | 139 |
| 140 FilePath GetTempLocationFor(const FilePath& filename) { | 140 base::FilePath GetTempLocationFor(const base::FilePath& filename) { |
| 141 return filename.ReplaceExtension(kTempFileExtension); | 141 return filename.ReplaceExtension(kTempFileExtension); |
| 142 } | 142 } |
| 143 | 143 |
| 144 // Writes a config file to a temporary location. | 144 // Writes a config file to a temporary location. |
| 145 HRESULT WriteConfigFileToTemp(const FilePath& filename, | 145 HRESULT WriteConfigFileToTemp(const base::FilePath& filename, |
| 146 const char* security_descriptor, | 146 const char* security_descriptor, |
| 147 const char* content, | 147 const char* content, |
| 148 size_t length) { | 148 size_t length) { |
| 149 // Create the security descriptor for the configuration file. | 149 // Create the security descriptor for the configuration file. |
| 150 ScopedSd sd = ConvertSddlToSd(security_descriptor); | 150 ScopedSd sd = ConvertSddlToSd(security_descriptor); |
| 151 if (!sd) { | 151 if (!sd) { |
| 152 DWORD error = GetLastError(); | 152 DWORD error = GetLastError(); |
| 153 LOG_GETLASTERROR(ERROR) << | 153 LOG_GETLASTERROR(ERROR) << |
| 154 "Failed to create a security descriptor for the configuration file"; | 154 "Failed to create a security descriptor for the configuration file"; |
| 155 return HRESULT_FROM_WIN32(error); | 155 return HRESULT_FROM_WIN32(error); |
| 156 } | 156 } |
| 157 | 157 |
| 158 SECURITY_ATTRIBUTES security_attributes = {0}; | 158 SECURITY_ATTRIBUTES security_attributes = {0}; |
| 159 security_attributes.nLength = sizeof(security_attributes); | 159 security_attributes.nLength = sizeof(security_attributes); |
| 160 security_attributes.lpSecurityDescriptor = sd.get(); | 160 security_attributes.lpSecurityDescriptor = sd.get(); |
| 161 security_attributes.bInheritHandle = FALSE; | 161 security_attributes.bInheritHandle = FALSE; |
| 162 | 162 |
| 163 // Create a temporary file and write configuration to it. | 163 // Create a temporary file and write configuration to it. |
| 164 FilePath tempname = GetTempLocationFor(filename); | 164 base::FilePath tempname = GetTempLocationFor(filename); |
| 165 base::win::ScopedHandle file( | 165 base::win::ScopedHandle file( |
| 166 CreateFileW(tempname.value().c_str(), | 166 CreateFileW(tempname.value().c_str(), |
| 167 GENERIC_WRITE, | 167 GENERIC_WRITE, |
| 168 0, | 168 0, |
| 169 &security_attributes, | 169 &security_attributes, |
| 170 CREATE_ALWAYS, | 170 CREATE_ALWAYS, |
| 171 FILE_FLAG_SEQUENTIAL_SCAN, | 171 FILE_FLAG_SEQUENTIAL_SCAN, |
| 172 NULL)); | 172 NULL)); |
| 173 | 173 |
| 174 if (!file.IsValid()) { | 174 if (!file.IsValid()) { |
| 175 DWORD error = GetLastError(); | 175 DWORD error = GetLastError(); |
| 176 LOG_GETLASTERROR(ERROR) | 176 LOG_GETLASTERROR(ERROR) |
| 177 << "Failed to create '" << filename.value() << "'"; | 177 << "Failed to create '" << filename.value() << "'"; |
| 178 return HRESULT_FROM_WIN32(error); | 178 return HRESULT_FROM_WIN32(error); |
| 179 } | 179 } |
| 180 | 180 |
| 181 DWORD written; | 181 DWORD written; |
| 182 if (!WriteFile(file, content, static_cast<DWORD>(length), &written, NULL)) { | 182 if (!WriteFile(file, content, static_cast<DWORD>(length), &written, NULL)) { |
| 183 DWORD error = GetLastError(); | 183 DWORD error = GetLastError(); |
| 184 LOG_GETLASTERROR(ERROR) | 184 LOG_GETLASTERROR(ERROR) |
| 185 << "Failed to write to '" << filename.value() << "'"; | 185 << "Failed to write to '" << filename.value() << "'"; |
| 186 return HRESULT_FROM_WIN32(error); | 186 return HRESULT_FROM_WIN32(error); |
| 187 } | 187 } |
| 188 | 188 |
| 189 return S_OK; | 189 return S_OK; |
| 190 } | 190 } |
| 191 | 191 |
| 192 // Moves a config file from its temporary location to its permanent location. | 192 // Moves a config file from its temporary location to its permanent location. |
| 193 HRESULT MoveConfigFileFromTemp(const FilePath& filename) { | 193 HRESULT MoveConfigFileFromTemp(const base::FilePath& filename) { |
| 194 // Now that the configuration is stored successfully replace the actual | 194 // Now that the configuration is stored successfully replace the actual |
| 195 // configuration file. | 195 // configuration file. |
| 196 FilePath tempname = GetTempLocationFor(filename); | 196 base::FilePath tempname = GetTempLocationFor(filename); |
| 197 if (!MoveFileExW(tempname.value().c_str(), | 197 if (!MoveFileExW(tempname.value().c_str(), |
| 198 filename.value().c_str(), | 198 filename.value().c_str(), |
| 199 MOVEFILE_REPLACE_EXISTING)) { | 199 MOVEFILE_REPLACE_EXISTING)) { |
| 200 DWORD error = GetLastError(); | 200 DWORD error = GetLastError(); |
| 201 LOG_GETLASTERROR(ERROR) | 201 LOG_GETLASTERROR(ERROR) |
| 202 << "Failed to rename '" << tempname.value() << "' to '" | 202 << "Failed to rename '" << tempname.value() << "' to '" |
| 203 << filename.value() << "'"; | 203 << filename.value() << "'"; |
| 204 return HRESULT_FROM_WIN32(error); | 204 return HRESULT_FROM_WIN32(error); |
| 205 } | 205 } |
| 206 | 206 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 const char* key = kUnprivilegedConfigKeys[i]; | 246 const char* key = kUnprivilegedConfigKeys[i]; |
| 247 string16 value; | 247 string16 value; |
| 248 if (config_dict->GetString(key, &value)) { | 248 if (config_dict->GetString(key, &value)) { |
| 249 unprivileged_config_dict.SetString(key, value); | 249 unprivileged_config_dict.SetString(key, value); |
| 250 } | 250 } |
| 251 } | 251 } |
| 252 std::string unprivileged_config_str; | 252 std::string unprivileged_config_str; |
| 253 base::JSONWriter::Write(&unprivileged_config_dict, &unprivileged_config_str); | 253 base::JSONWriter::Write(&unprivileged_config_dict, &unprivileged_config_str); |
| 254 | 254 |
| 255 // Write the full configuration file to a temporary location. | 255 // Write the full configuration file to a temporary location. |
| 256 FilePath full_config_file_path = | 256 base::FilePath full_config_file_path = |
| 257 remoting::GetConfigDir().Append(kConfigFileName); | 257 remoting::GetConfigDir().Append(kConfigFileName); |
| 258 HRESULT hr = WriteConfigFileToTemp(full_config_file_path, | 258 HRESULT hr = WriteConfigFileToTemp(full_config_file_path, |
| 259 kConfigFileSecurityDescriptor, | 259 kConfigFileSecurityDescriptor, |
| 260 content, | 260 content, |
| 261 length); | 261 length); |
| 262 if (FAILED(hr)) { | 262 if (FAILED(hr)) { |
| 263 return hr; | 263 return hr; |
| 264 } | 264 } |
| 265 | 265 |
| 266 // Write the unprivileged configuration file to a temporary location. | 266 // Write the unprivileged configuration file to a temporary location. |
| 267 FilePath unprivileged_config_file_path = | 267 base::FilePath unprivileged_config_file_path = |
| 268 remoting::GetConfigDir().Append(kUnprivilegedConfigFileName); | 268 remoting::GetConfigDir().Append(kUnprivilegedConfigFileName); |
| 269 hr = WriteConfigFileToTemp(unprivileged_config_file_path, | 269 hr = WriteConfigFileToTemp(unprivileged_config_file_path, |
| 270 kUnprivilegedConfigFileSecurityDescriptor, | 270 kUnprivilegedConfigFileSecurityDescriptor, |
| 271 unprivileged_config_str.data(), | 271 unprivileged_config_str.data(), |
| 272 unprivileged_config_str.size()); | 272 unprivileged_config_str.size()); |
| 273 if (FAILED(hr)) { | 273 if (FAILED(hr)) { |
| 274 return hr; | 274 return hr; |
| 275 } | 275 } |
| 276 | 276 |
| 277 // Move the full configuration file to its permanent location. | 277 // Move the full configuration file to its permanent location. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 295 } | 295 } |
| 296 | 296 |
| 297 HRESULT ElevatedController::FinalConstruct() { | 297 HRESULT ElevatedController::FinalConstruct() { |
| 298 return S_OK; | 298 return S_OK; |
| 299 } | 299 } |
| 300 | 300 |
| 301 void ElevatedController::FinalRelease() { | 301 void ElevatedController::FinalRelease() { |
| 302 } | 302 } |
| 303 | 303 |
| 304 STDMETHODIMP ElevatedController::GetConfig(BSTR* config_out) { | 304 STDMETHODIMP ElevatedController::GetConfig(BSTR* config_out) { |
| 305 FilePath config_dir = remoting::GetConfigDir(); | 305 base::FilePath config_dir = remoting::GetConfigDir(); |
| 306 | 306 |
| 307 // Read the unprivileged part of host configuration. | 307 // Read the unprivileged part of host configuration. |
| 308 scoped_ptr<base::DictionaryValue> config; | 308 scoped_ptr<base::DictionaryValue> config; |
| 309 HRESULT hr = ReadConfig(config_dir.Append(kUnprivilegedConfigFileName), | 309 HRESULT hr = ReadConfig(config_dir.Append(kUnprivilegedConfigFileName), |
| 310 &config); | 310 &config); |
| 311 if (FAILED(hr)) { | 311 if (FAILED(hr)) { |
| 312 return hr; | 312 return hr; |
| 313 } | 313 } |
| 314 | 314 |
| 315 // Convert the config back to a string and return it to the caller. | 315 // Convert the config back to a string and return it to the caller. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 340 *version_out = ::SysAllocString(version.c_str()); | 340 *version_out = ::SysAllocString(version.c_str()); |
| 341 if (version_out == NULL) { | 341 if (version_out == NULL) { |
| 342 return E_OUTOFMEMORY; | 342 return E_OUTOFMEMORY; |
| 343 } | 343 } |
| 344 | 344 |
| 345 return S_OK; | 345 return S_OK; |
| 346 } | 346 } |
| 347 | 347 |
| 348 STDMETHODIMP ElevatedController::SetConfig(BSTR config) { | 348 STDMETHODIMP ElevatedController::SetConfig(BSTR config) { |
| 349 // Determine the config directory path and create it if necessary. | 349 // Determine the config directory path and create it if necessary. |
| 350 FilePath config_dir = remoting::GetConfigDir(); | 350 base::FilePath config_dir = remoting::GetConfigDir(); |
| 351 if (!file_util::CreateDirectory(config_dir)) { | 351 if (!file_util::CreateDirectory(config_dir)) { |
| 352 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); | 352 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); |
| 353 } | 353 } |
| 354 | 354 |
| 355 std::string file_content = UTF16ToUTF8( | 355 std::string file_content = UTF16ToUTF8( |
| 356 string16(static_cast<char16*>(config), ::SysStringLen(config))); | 356 string16(static_cast<char16*>(config), ::SysStringLen(config))); |
| 357 | 357 |
| 358 return WriteConfig(file_content.c_str(), file_content.size(), owner_window_); | 358 return WriteConfig(file_content.c_str(), file_content.size(), owner_window_); |
| 359 } | 359 } |
| 360 | 360 |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 if (!config_value->GetAsDictionary(&config_dict)) { | 455 if (!config_value->GetAsDictionary(&config_dict)) { |
| 456 return E_FAIL; | 456 return E_FAIL; |
| 457 } | 457 } |
| 458 // Check for bad keys. | 458 // Check for bad keys. |
| 459 for (int i = 0; i < arraysize(kReadonlyKeys); ++i) { | 459 for (int i = 0; i < arraysize(kReadonlyKeys); ++i) { |
| 460 if (config_dict->HasKey(kReadonlyKeys[i])) { | 460 if (config_dict->HasKey(kReadonlyKeys[i])) { |
| 461 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); | 461 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); |
| 462 } | 462 } |
| 463 } | 463 } |
| 464 // Get the old config. | 464 // Get the old config. |
| 465 FilePath config_dir = remoting::GetConfigDir(); | 465 base::FilePath config_dir = remoting::GetConfigDir(); |
| 466 scoped_ptr<base::DictionaryValue> config_old; | 466 scoped_ptr<base::DictionaryValue> config_old; |
| 467 HRESULT hr = ReadConfig(config_dir.Append(kConfigFileName), &config_old); | 467 HRESULT hr = ReadConfig(config_dir.Append(kConfigFileName), &config_old); |
| 468 if (FAILED(hr)) { | 468 if (FAILED(hr)) { |
| 469 return hr; | 469 return hr; |
| 470 } | 470 } |
| 471 // Merge items from the given config into the old config. | 471 // Merge items from the given config into the old config. |
| 472 config_old->MergeDictionary(config_dict); | 472 config_old->MergeDictionary(config_dict); |
| 473 // Write the updated config. | 473 // Write the updated config. |
| 474 std::string config_updated_str; | 474 std::string config_updated_str; |
| 475 base::JSONWriter::Write(config_old.get(), &config_updated_str); | 475 base::JSONWriter::Write(config_old.get(), &config_updated_str); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 << "Failed to open to the '" << kWindowsServiceName << "' service"; | 522 << "Failed to open to the '" << kWindowsServiceName << "' service"; |
| 523 | 523 |
| 524 return HRESULT_FROM_WIN32(error); | 524 return HRESULT_FROM_WIN32(error); |
| 525 } | 525 } |
| 526 | 526 |
| 527 service_out->Set(service.Take()); | 527 service_out->Set(service.Take()); |
| 528 return S_OK; | 528 return S_OK; |
| 529 } | 529 } |
| 530 | 530 |
| 531 } // namespace remoting | 531 } // namespace remoting |
| OLD | NEW |