Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(319)

Side by Side Diff: remoting/host/elevated_controller_win.cc

Issue 10191007: [Chromoting] Let the Windows daemon controller read the unprivileged part of the config without ele… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sync. Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/elevated_controller_win.h" 5 #include "remoting/host/elevated_controller_win.h"
6 6
7 #include <sddl.h> 7 #include <sddl.h>
8 8
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/json/json_reader.h" 11 #include "base/json/json_reader.h"
12 #include "base/json/json_writer.h" 12 #include "base/json/json_writer.h"
13 #include "base/memory/scoped_ptr.h" 13 #include "base/memory/scoped_ptr.h"
14 #include "base/path_service.h" 14 #include "base/path_service.h"
15 #include "base/stringize_macros.h" 15 #include "base/stringize_macros.h"
16 #include "base/utf_string_conversions.h" 16 #include "base/utf_string_conversions.h"
17 #include "base/values.h" 17 #include "base/values.h"
18 #include "base/win/scoped_handle.h" 18 #include "base/win/scoped_handle.h"
19 #include "remoting/host/branding.h" 19 #include "remoting/host/branding.h"
20 #include "remoting/host/daemon_controller_common_win.h"
20 #include "remoting/host/elevated_controller_resource.h" 21 #include "remoting/host/elevated_controller_resource.h"
21 #include "remoting/host/verify_config_window_win.h" 22 #include "remoting/host/verify_config_window_win.h"
22 23
23 namespace { 24 namespace {
24 25
25 // The host configuration file name. 26 // The host configuration file name.
26 const FilePath::CharType kConfigFileName[] = FILE_PATH_LITERAL("host.json"); 27 const FilePath::CharType kConfigFileName[] = FILE_PATH_LITERAL("host.json");
27 28
28 // The extension for the temporary file. 29 // The extension for the temporary file.
29 const FilePath::CharType kTempFileExtension[] = FILE_PATH_LITERAL("json~"); 30 const FilePath::CharType kTempFileExtension[] = FILE_PATH_LITERAL("json~");
30 31
31 // The host configuration file security descriptor that enables full access to 32 // The host configuration file security descriptor that enables full access to
32 // Local System and built-in administrators only. 33 // Local System and built-in administrators only.
33 const char16 kConfigFileSecurityDescriptor[] = 34 const char16 kConfigFileSecurityDescriptor[] =
34 TO_L_STRING("O:BAG:BAD:(A;;GA;;;SY)(A;;GA;;;BA)"); 35 TO_L_STRING("O:BAG:BAD:(A;;GA;;;SY)(A;;GA;;;BA)");
35 36
36 // The maximum size of the configuration file. "1MB ought to be enough" for any 37 const char16 kUnprivilegedConfigFileSecurityDescriptor[] =
37 // reasonable configuration we will ever need. 1MB is low enough to make 38 TO_L_STRING("O:BAG:BAD:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;AU)");
38 // the probability of out of memory situation fairly low. OOM is still possible
39 // and we will crash if it occurs.
40 const size_t kMaxConfigFileSize = 1024 * 1024;
41 39
42 // ReadConfig() filters the configuration file stripping all variables except of 40 // Configuration keys.
43 // the following two.
44 const char kHostId[] = "host_id"; 41 const char kHostId[] = "host_id";
45 const char kXmppLogin[] = "xmpp_login"; 42 const char kXmppLogin[] = "xmpp_login";
43 const char kHostSecretHash[] = "host_secret_hash";
46 44
47 // The configuration keys that cannot be specified in UpdateConfig(). 45 // The configuration keys that cannot be specified in UpdateConfig().
48 const char* const kReadonlyKeys[] = { kHostId, kXmppLogin }; 46 const char* const kReadonlyKeys[] = { kHostId, kXmppLogin };
49 47
48 // The configuration keys whose values may be read by GetConfig().
49 const char* const kUnprivilegedConfigKeys[] = { kHostId, kXmppLogin };
50
51 // TODO(simonmorris): Remove this routine: the plugin implements GetConfig(),
52 // so it's no longer used.
50 // Reads and parses the configuration file up to |kMaxConfigFileSize| in 53 // Reads and parses the configuration file up to |kMaxConfigFileSize| in
51 // size. 54 // size.
52 HRESULT ReadConfig(const FilePath& filename, 55 HRESULT ReadConfig(const FilePath& filename,
53 scoped_ptr<base::DictionaryValue>* config_out) { 56 scoped_ptr<base::DictionaryValue>* config_out) {
54 57
55 // Read raw data from the configuration file. 58 // Read raw data from the configuration file.
56 base::win::ScopedHandle file( 59 base::win::ScopedHandle file(
57 CreateFileW(filename.value().c_str(), 60 CreateFileW(filename.value().c_str(),
58 GENERIC_READ, 61 GENERIC_READ,
59 FILE_SHARE_READ | FILE_SHARE_WRITE, 62 FILE_SHARE_READ | FILE_SHARE_WRITE,
60 NULL, 63 NULL,
61 OPEN_EXISTING, 64 OPEN_EXISTING,
62 FILE_FLAG_SEQUENTIAL_SCAN, 65 FILE_FLAG_SEQUENTIAL_SCAN,
63 NULL)); 66 NULL));
64 67
65 if (!file.IsValid()) { 68 if (!file.IsValid()) {
66 DWORD error = GetLastError(); 69 DWORD error = GetLastError();
67 LOG_GETLASTERROR(ERROR) 70 LOG_GETLASTERROR(ERROR)
68 << "Failed to open '" << filename.value() << "'"; 71 << "Failed to open '" << filename.value() << "'";
69 return HRESULT_FROM_WIN32(error); 72 return HRESULT_FROM_WIN32(error);
70 } 73 }
71 74
72 scoped_array<char> buffer(new char[kMaxConfigFileSize]); 75 scoped_array<char> buffer(new char[remoting::kMaxConfigFileSize]);
73 DWORD size = kMaxConfigFileSize; 76 DWORD size = remoting::kMaxConfigFileSize;
74 if (!::ReadFile(file, &buffer[0], size, &size, NULL)) { 77 if (!::ReadFile(file, &buffer[0], size, &size, NULL)) {
75 DWORD error = GetLastError(); 78 DWORD error = GetLastError();
76 LOG_GETLASTERROR(ERROR) 79 LOG_GETLASTERROR(ERROR)
77 << "Failed to read '" << filename.value() << "'"; 80 << "Failed to read '" << filename.value() << "'";
78 return HRESULT_FROM_WIN32(error); 81 return HRESULT_FROM_WIN32(error);
79 } 82 }
80 83
81 // Parse the JSON configuration, expecting it to contain a dictionary. 84 // Parse the JSON configuration, expecting it to contain a dictionary.
82 std::string file_content(buffer.get(), size); 85 std::string file_content(buffer.get(), size);
83 scoped_ptr<base::Value> value( 86 scoped_ptr<base::Value> value(
84 base::JSONReader::Read(file_content, base::JSON_ALLOW_TRAILING_COMMAS)); 87 base::JSONReader::Read(file_content, base::JSON_ALLOW_TRAILING_COMMAS));
85 88
86 base::DictionaryValue* dictionary; 89 base::DictionaryValue* dictionary;
87 if (value.get() == NULL || !value->GetAsDictionary(&dictionary)) { 90 if (value.get() == NULL || !value->GetAsDictionary(&dictionary)) {
88 LOG(ERROR) << "Failed to read '" << filename.value() << "'."; 91 LOG(ERROR) << "Failed to read '" << filename.value() << "'.";
89 return E_FAIL; 92 return E_FAIL;
90 } 93 }
91 94
92 value.release(); 95 value.release();
93 config_out->reset(dictionary); 96 config_out->reset(dictionary);
94 return S_OK; 97 return S_OK;
95 } 98 }
96 99
97 // Writes the configuration file up to |kMaxConfigFileSize| in size. 100 FilePath GetTempLocationFor(const FilePath& filename) {
98 HRESULT WriteConfig(const FilePath& filename, 101 return filename.ReplaceExtension(kTempFileExtension);
99 const char* content, 102 }
100 size_t length) {
101 if (length > kMaxConfigFileSize) {
102 return E_FAIL;
103 }
104 103
105 // Extract the configuration data that the user will verify. 104 // Writes a config file to a temporary location.
106 scoped_ptr<base::Value> config_value(base::JSONReader::Read(content)); 105 HRESULT WriteConfigFileToTemp(const FilePath& filename,
107 if (!config_value.get()) { 106 const char16* security_descriptor,
108 return E_FAIL; 107 const char* content,
109 } 108 size_t length) {
110 base::DictionaryValue* config_dict = NULL;
111 if (!config_value->GetAsDictionary(&config_dict)) {
112 return E_FAIL;
113 }
114 std::string email, host_id, host_secret_hash;
115 if (!config_dict->GetString("xmpp_login", &email) ||
116 !config_dict->GetString("host_id", &host_id) ||
117 !config_dict->GetString("host_secret_hash", &host_secret_hash)) {
118 return E_FAIL;
119 }
120
121 // Ask the user to verify the configuration.
122 remoting::VerifyConfigWindowWin verify_win(email, host_id, host_secret_hash);
123 if (!verify_win.Run()) {
124 return E_FAIL;
125 }
126
127 // Create a security descriptor for the configuration file. 109 // Create a security descriptor for the configuration file.
128 SECURITY_ATTRIBUTES security_attributes; 110 SECURITY_ATTRIBUTES security_attributes;
129 security_attributes.nLength = sizeof(security_attributes); 111 security_attributes.nLength = sizeof(security_attributes);
130 security_attributes.bInheritHandle = FALSE; 112 security_attributes.bInheritHandle = FALSE;
131 113
132 ULONG security_descriptor_length = 0; 114 ULONG security_descriptor_length = 0;
133 if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( 115 if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
134 kConfigFileSecurityDescriptor, 116 security_descriptor,
135 SDDL_REVISION_1, 117 SDDL_REVISION_1,
136 reinterpret_cast<PSECURITY_DESCRIPTOR*>( 118 reinterpret_cast<PSECURITY_DESCRIPTOR*>(
137 &security_attributes.lpSecurityDescriptor), 119 &security_attributes.lpSecurityDescriptor),
138 &security_descriptor_length)) { 120 &security_descriptor_length)) {
139 DWORD error = GetLastError(); 121 DWORD error = GetLastError();
140 LOG_GETLASTERROR(ERROR) << 122 LOG_GETLASTERROR(ERROR) <<
141 "Failed to create a security descriptor for the configuration file"; 123 "Failed to create a security descriptor for the configuration file";
142 return HRESULT_FROM_WIN32(error); 124 return HRESULT_FROM_WIN32(error);
143 } 125 }
144 126
145 // Create a temporary file and write configuration to it. 127 // Create a temporary file and write configuration to it.
146 FilePath tempname = filename.ReplaceExtension(kTempFileExtension); 128 FilePath tempname = GetTempLocationFor(filename);
147 { 129 base::win::ScopedHandle file(
148 base::win::ScopedHandle file( 130 CreateFileW(tempname.value().c_str(),
149 CreateFileW(tempname.value().c_str(), 131 GENERIC_WRITE,
150 GENERIC_WRITE, 132 0,
151 0, 133 &security_attributes,
152 &security_attributes, 134 CREATE_ALWAYS,
153 CREATE_ALWAYS, 135 FILE_FLAG_SEQUENTIAL_SCAN,
154 FILE_FLAG_SEQUENTIAL_SCAN, 136 NULL));
155 NULL));
156 137
157 if (!file.IsValid()) { 138 if (!file.IsValid()) {
158 DWORD error = GetLastError(); 139 DWORD error = GetLastError();
159 LOG_GETLASTERROR(ERROR) 140 LOG_GETLASTERROR(ERROR)
160 << "Failed to create '" << filename.value() << "'"; 141 << "Failed to create '" << filename.value() << "'";
161 return HRESULT_FROM_WIN32(error); 142 return HRESULT_FROM_WIN32(error);
162 }
163
164 DWORD written;
165 if (!WriteFile(file, content, static_cast<DWORD>(length), &written, NULL)) {
166 DWORD error = GetLastError();
167 LOG_GETLASTERROR(ERROR)
168 << "Failed to write to '" << filename.value() << "'";
169 return HRESULT_FROM_WIN32(error);
170 }
171 } 143 }
172 144
145 DWORD written;
146 if (!WriteFile(file, content, static_cast<DWORD>(length), &written, NULL)) {
147 DWORD error = GetLastError();
148 LOG_GETLASTERROR(ERROR)
149 << "Failed to write to '" << filename.value() << "'";
150 return HRESULT_FROM_WIN32(error);
151 }
152
153 return S_OK;
154 }
155
156 // Moves a config file from its temporary location to its permanent location.
157 HRESULT MoveConfigFileFromTemp(const FilePath& filename) {
173 // Now that the configuration is stored successfully replace the actual 158 // Now that the configuration is stored successfully replace the actual
174 // configuration file. 159 // configuration file.
160 FilePath tempname = GetTempLocationFor(filename);
175 if (!MoveFileExW(tempname.value().c_str(), 161 if (!MoveFileExW(tempname.value().c_str(),
176 filename.value().c_str(), 162 filename.value().c_str(),
177 MOVEFILE_REPLACE_EXISTING)) { 163 MOVEFILE_REPLACE_EXISTING)) {
178 DWORD error = GetLastError(); 164 DWORD error = GetLastError();
179 LOG_GETLASTERROR(ERROR) 165 LOG_GETLASTERROR(ERROR)
180 << "Failed to rename '" << tempname.value() << "' to '" 166 << "Failed to rename '" << tempname.value() << "' to '"
181 << filename.value() << "'"; 167 << filename.value() << "'";
182 return HRESULT_FROM_WIN32(error); 168 return HRESULT_FROM_WIN32(error);
183 } 169 }
184 170
185 return S_OK; 171 return S_OK;
186 } 172 }
187 173
174 // Writes the configuration file up to |kMaxConfigFileSize| in size.
175 HRESULT WriteConfig(const char* content, size_t length) {
176 if (length > remoting::kMaxConfigFileSize) {
177 return E_FAIL;
178 }
179
180 // Extract the configuration data that the user will verify.
181 scoped_ptr<base::Value> config_value(base::JSONReader::Read(content));
182 if (!config_value.get()) {
183 return E_FAIL;
184 }
185 base::DictionaryValue* config_dict = NULL;
186 if (!config_value->GetAsDictionary(&config_dict)) {
187 return E_FAIL;
188 }
189 std::string email, host_id, host_secret_hash;
190 if (!config_dict->GetString(kXmppLogin, &email) ||
191 !config_dict->GetString(kHostId, &host_id) ||
192 !config_dict->GetString(kHostSecretHash, &host_secret_hash)) {
193 return E_FAIL;
194 }
195
196 // Ask the user to verify the configuration.
197 remoting::VerifyConfigWindowWin verify_win(email, host_id, host_secret_hash);
198 if (!verify_win.Run()) {
199 return E_FAIL;
200 }
201
202 // Extract the unprivileged fields from the configuration.
203 base::DictionaryValue unprivileged_config_dict;
204 for (int i = 0; i < arraysize(kUnprivilegedConfigKeys); ++i) {
205 const char* key = kUnprivilegedConfigKeys[i];
206 string16 value;
207 if (config_dict->GetString(key, &value)) {
208 unprivileged_config_dict.SetString(key, value);
209 }
210 }
211 std::string unprivileged_config_str;
212 base::JSONWriter::Write(&unprivileged_config_dict, &unprivileged_config_str);
213
214 // Write the full configuration file to a temporary location.
215 FilePath full_config_file_path =
216 remoting::GetConfigDir().Append(kConfigFileName);
217 HRESULT hr = WriteConfigFileToTemp(full_config_file_path,
218 kConfigFileSecurityDescriptor,
219 content,
220 length);
221 if (FAILED(hr)) {
222 return hr;
223 }
224
225 // Write the unprivileged configuration file to a temporary location.
226 FilePath unprivileged_config_file_path =
227 remoting::GetConfigDir().Append(remoting::kUnprivilegedConfigFileName);
228 hr = WriteConfigFileToTemp(unprivileged_config_file_path,
229 kUnprivilegedConfigFileSecurityDescriptor,
230 unprivileged_config_str.data(),
231 unprivileged_config_str.size());
232 if (FAILED(hr)) {
233 return hr;
234 }
235
236 // Move the full configuration file to its permanent location.
237 hr = MoveConfigFileFromTemp(full_config_file_path);
238 if (FAILED(hr)) {
239 return hr;
240 }
241
242 // Move the unprivileged configuration file to its permanent location.
243 hr = MoveConfigFileFromTemp(unprivileged_config_file_path);
244 if (FAILED(hr)) {
245 return hr;
246 }
247
248 return S_OK;
249 }
188 250
189 } // namespace 251 } // namespace
190 252
191 namespace remoting { 253 namespace remoting {
192 254
193 ElevatedControllerWin::ElevatedControllerWin() { 255 ElevatedControllerWin::ElevatedControllerWin() {
194 } 256 }
195 257
196 HRESULT ElevatedControllerWin::FinalConstruct() { 258 HRESULT ElevatedControllerWin::FinalConstruct() {
197 return S_OK; 259 return S_OK;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 STDMETHODIMP ElevatedControllerWin::SetConfig(BSTR config) { 299 STDMETHODIMP ElevatedControllerWin::SetConfig(BSTR config) {
238 // Determine the config directory path and create it if necessary. 300 // Determine the config directory path and create it if necessary.
239 FilePath config_dir = remoting::GetConfigDir(); 301 FilePath config_dir = remoting::GetConfigDir();
240 if (!file_util::CreateDirectory(config_dir)) { 302 if (!file_util::CreateDirectory(config_dir)) {
241 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); 303 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
242 } 304 }
243 305
244 std::string file_content = UTF16ToUTF8( 306 std::string file_content = UTF16ToUTF8(
245 string16(static_cast<char16*>(config), ::SysStringLen(config))); 307 string16(static_cast<char16*>(config), ::SysStringLen(config)));
246 308
247 return WriteConfig(config_dir.Append(kConfigFileName), 309 return WriteConfig(file_content.c_str(), file_content.size());
248 file_content.c_str(),
249 file_content.size());
250 } 310 }
251 311
252 STDMETHODIMP ElevatedControllerWin::StartDaemon() { 312 STDMETHODIMP ElevatedControllerWin::StartDaemon() {
253 ScopedScHandle service; 313 ScopedScHandle service;
254 HRESULT hr = OpenService(&service); 314 HRESULT hr = OpenService(&service);
255 if (FAILED(hr)) { 315 if (FAILED(hr)) {
256 return hr; 316 return hr;
257 } 317 }
258 318
259 // Change the service start type to 'auto'. 319 // Change the service start type to 'auto'.
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 scoped_ptr<base::DictionaryValue> config_old; 412 scoped_ptr<base::DictionaryValue> config_old;
353 HRESULT hr = ReadConfig(config_dir.Append(kConfigFileName), &config_old); 413 HRESULT hr = ReadConfig(config_dir.Append(kConfigFileName), &config_old);
354 if (FAILED(hr)) { 414 if (FAILED(hr)) {
355 return hr; 415 return hr;
356 } 416 }
357 // Merge items from the given config into the old config. 417 // Merge items from the given config into the old config.
358 config_old->MergeDictionary(config_dict); 418 config_old->MergeDictionary(config_dict);
359 // Write the updated config. 419 // Write the updated config.
360 std::string config_updated_str; 420 std::string config_updated_str;
361 base::JSONWriter::Write(config_old.get(), &config_updated_str); 421 base::JSONWriter::Write(config_old.get(), &config_updated_str);
362 return WriteConfig(config_dir.Append(kConfigFileName), 422 return WriteConfig(config_updated_str.c_str(), config_updated_str.size());
363 config_updated_str.c_str(),
364 config_updated_str.size());
365 } 423 }
366 424
367 HRESULT ElevatedControllerWin::OpenService(ScopedScHandle* service_out) { 425 HRESULT ElevatedControllerWin::OpenService(ScopedScHandle* service_out) {
368 DWORD error; 426 DWORD error;
369 427
370 ScopedScHandle scmanager( 428 ScopedScHandle scmanager(
371 ::OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, 429 ::OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE,
372 SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE)); 430 SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE));
373 if (!scmanager.IsValid()) { 431 if (!scmanager.IsValid()) {
374 error = GetLastError(); 432 error = GetLastError();
(...skipping 13 matching lines...) Expand all
388 << "Failed to open to the '" << kWindowsServiceName << "' service"; 446 << "Failed to open to the '" << kWindowsServiceName << "' service";
389 447
390 return HRESULT_FROM_WIN32(error); 448 return HRESULT_FROM_WIN32(error);
391 } 449 }
392 450
393 service_out->Set(service.Take()); 451 service_out->Set(service.Take());
394 return S_OK; 452 return S_OK;
395 } 453 }
396 454
397 } // namespace remoting 455 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/daemon_controller_common_win.cc ('k') | remoting/host/plugin/daemon_controller_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698