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

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: Review. Created 8 years, 8 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 {
alexeypa (please no reviews) 2012/04/25 16:36:56 nit: This scope is not needed any more. It was nee
simonmorris 2012/04/25 17:08:44 Done.
148 base::win::ScopedHandle file( 130 base::win::ScopedHandle file(
149 CreateFileW(tempname.value().c_str(), 131 CreateFileW(tempname.value().c_str(),
150 GENERIC_WRITE, 132 GENERIC_WRITE,
151 0, 133 0,
152 &security_attributes, 134 &security_attributes,
153 CREATE_ALWAYS, 135 CREATE_ALWAYS,
154 FILE_FLAG_SEQUENTIAL_SCAN, 136 FILE_FLAG_SEQUENTIAL_SCAN,
155 NULL)); 137 NULL));
156 138
157 if (!file.IsValid()) { 139 if (!file.IsValid()) {
158 DWORD error = GetLastError(); 140 DWORD error = GetLastError();
159 LOG_GETLASTERROR(ERROR) 141 LOG_GETLASTERROR(ERROR)
160 << "Failed to create '" << filename.value() << "'"; 142 << "Failed to create '" << filename.value() << "'";
161 return HRESULT_FROM_WIN32(error); 143 return HRESULT_FROM_WIN32(error);
162 } 144 }
163 145
164 DWORD written; 146 DWORD written;
165 if (!WriteFile(file, content, static_cast<DWORD>(length), &written, NULL)) { 147 if (!WriteFile(file, content, static_cast<DWORD>(length), &written, NULL)) {
166 DWORD error = GetLastError(); 148 DWORD error = GetLastError();
167 LOG_GETLASTERROR(ERROR) 149 LOG_GETLASTERROR(ERROR)
168 << "Failed to write to '" << filename.value() << "'"; 150 << "Failed to write to '" << filename.value() << "'";
169 return HRESULT_FROM_WIN32(error); 151 return HRESULT_FROM_WIN32(error);
170 } 152 }
171 } 153 }
172 154
155 return S_OK;
156 }
157
158 // Moves a config file from its temporary location to its permanent location.
159 HRESULT MoveConfigFileFromTemp(const FilePath& filename) {
173 // Now that the configuration is stored successfully replace the actual 160 // Now that the configuration is stored successfully replace the actual
174 // configuration file. 161 // configuration file.
162 FilePath tempname = GetTempLocationFor(filename);
175 if (!MoveFileExW(tempname.value().c_str(), 163 if (!MoveFileExW(tempname.value().c_str(),
176 filename.value().c_str(), 164 filename.value().c_str(),
177 MOVEFILE_REPLACE_EXISTING)) { 165 MOVEFILE_REPLACE_EXISTING)) {
178 DWORD error = GetLastError(); 166 DWORD error = GetLastError();
179 LOG_GETLASTERROR(ERROR) 167 LOG_GETLASTERROR(ERROR)
180 << "Failed to rename '" << tempname.value() << "' to '" 168 << "Failed to rename '" << tempname.value() << "' to '"
181 << filename.value() << "'"; 169 << filename.value() << "'";
182 return HRESULT_FROM_WIN32(error); 170 return HRESULT_FROM_WIN32(error);
183 } 171 }
184 172
185 return S_OK; 173 return S_OK;
186 } 174 }
187 175
176 // Writes the configuration file up to |kMaxConfigFileSize| in size.
177 HRESULT WriteConfig(const char* content, size_t length) {
178 if (length > remoting::kMaxConfigFileSize) {
179 return E_FAIL;
180 }
181
182 // Extract the configuration data that the user will verify.
183 scoped_ptr<base::Value> config_value(base::JSONReader::Read(content));
184 if (!config_value.get()) {
185 return E_FAIL;
186 }
187 base::DictionaryValue* config_dict = NULL;
188 if (!config_value->GetAsDictionary(&config_dict)) {
189 return E_FAIL;
190 }
191 std::string email, host_id, host_secret_hash;
192 if (!config_dict->GetString(kXmppLogin, &email) ||
193 !config_dict->GetString(kHostId, &host_id) ||
194 !config_dict->GetString(kHostSecretHash, &host_secret_hash)) {
195 return E_FAIL;
196 }
197
198 // Ask the user to verify the configuration.
199 remoting::VerifyConfigWindowWin verify_win(email, host_id, host_secret_hash);
200 if (!verify_win.Run()) {
201 return E_FAIL;
202 }
203
204 // Extract the unprivileged fields from the configuration.
205 base::DictionaryValue unprivileged_config_dict;
206 for (int i = 0; i < arraysize(kUnprivilegedConfigKeys); ++i) {
207 const char* key = kUnprivilegedConfigKeys[i];
208 string16 value;
209 if (config_dict->GetString(key, &value)) {
210 unprivileged_config_dict.SetString(key, value);
211 }
212 }
213 std::string unprivileged_config_str;
214 base::JSONWriter::Write(&unprivileged_config_dict, &unprivileged_config_str);
215
216 // Write the full configuration file to a temporary location.
217 FilePath full_config_file_path =
218 remoting::GetConfigDir().Append(kConfigFileName);
219 HRESULT hr = WriteConfigFileToTemp(full_config_file_path,
220 kConfigFileSecurityDescriptor,
221 content,
222 length);
223 if (FAILED(hr)) {
224 return hr;
225 }
226
227 // Write the unprivileged configuration file to a temporary location.
228 FilePath unprivileged_config_file_path =
229 remoting::GetConfigDir().Append(remoting::kUnprivilegedConfigFileName);
230 hr = WriteConfigFileToTemp(unprivileged_config_file_path,
231 kUnprivilegedConfigFileSecurityDescriptor,
232 unprivileged_config_str.data(),
233 unprivileged_config_str.size());
234 if (FAILED(hr)) {
235 return hr;
236 }
237
238 // Move the full configuration file to its permanent location.
239 hr = MoveConfigFileFromTemp(full_config_file_path);
240 if (FAILED(hr)) {
241 return hr;
242 }
243
244 // Move the unprivileged configuration file to its permanent location.
245 hr = MoveConfigFileFromTemp(unprivileged_config_file_path);
246 if (FAILED(hr)) {
247 return hr;
248 }
249
250 return S_OK;
251 }
188 252
189 } // namespace 253 } // namespace
190 254
191 namespace remoting { 255 namespace remoting {
192 256
193 ElevatedControllerWin::ElevatedControllerWin() { 257 ElevatedControllerWin::ElevatedControllerWin() {
194 } 258 }
195 259
196 HRESULT ElevatedControllerWin::FinalConstruct() { 260 HRESULT ElevatedControllerWin::FinalConstruct() {
197 return S_OK; 261 return S_OK;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 STDMETHODIMP ElevatedControllerWin::SetConfig(BSTR config) { 301 STDMETHODIMP ElevatedControllerWin::SetConfig(BSTR config) {
238 // Determine the config directory path and create it if necessary. 302 // Determine the config directory path and create it if necessary.
239 FilePath config_dir = remoting::GetConfigDir(); 303 FilePath config_dir = remoting::GetConfigDir();
240 if (!file_util::CreateDirectory(config_dir)) { 304 if (!file_util::CreateDirectory(config_dir)) {
241 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); 305 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
242 } 306 }
243 307
244 std::string file_content = UTF16ToUTF8( 308 std::string file_content = UTF16ToUTF8(
245 string16(static_cast<char16*>(config), ::SysStringLen(config))); 309 string16(static_cast<char16*>(config), ::SysStringLen(config)));
246 310
247 return WriteConfig(config_dir.Append(kConfigFileName), 311 return WriteConfig(file_content.c_str(), file_content.size());
248 file_content.c_str(),
249 file_content.size());
250 } 312 }
251 313
252 STDMETHODIMP ElevatedControllerWin::StartDaemon() { 314 STDMETHODIMP ElevatedControllerWin::StartDaemon() {
253 ScopedScHandle service; 315 ScopedScHandle service;
254 HRESULT hr = OpenService(&service); 316 HRESULT hr = OpenService(&service);
255 if (FAILED(hr)) { 317 if (FAILED(hr)) {
256 return hr; 318 return hr;
257 } 319 }
258 320
259 // Change the service start type to 'auto'. 321 // 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; 414 scoped_ptr<base::DictionaryValue> config_old;
353 HRESULT hr = ReadConfig(config_dir.Append(kConfigFileName), &config_old); 415 HRESULT hr = ReadConfig(config_dir.Append(kConfigFileName), &config_old);
354 if (FAILED(hr)) { 416 if (FAILED(hr)) {
355 return hr; 417 return hr;
356 } 418 }
357 // Merge items from the given config into the old config. 419 // Merge items from the given config into the old config.
358 config_old->MergeDictionary(config_dict); 420 config_old->MergeDictionary(config_dict);
359 // Write the updated config. 421 // Write the updated config.
360 std::string config_updated_str; 422 std::string config_updated_str;
361 base::JSONWriter::Write(config_old.get(), &config_updated_str); 423 base::JSONWriter::Write(config_old.get(), &config_updated_str);
362 return WriteConfig(config_dir.Append(kConfigFileName), 424 return WriteConfig(config_updated_str.c_str(), config_updated_str.size());
363 config_updated_str.c_str(),
364 config_updated_str.size());
365 } 425 }
366 426
367 HRESULT ElevatedControllerWin::OpenService(ScopedScHandle* service_out) { 427 HRESULT ElevatedControllerWin::OpenService(ScopedScHandle* service_out) {
368 DWORD error; 428 DWORD error;
369 429
370 ScopedScHandle scmanager( 430 ScopedScHandle scmanager(
371 ::OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, 431 ::OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE,
372 SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE)); 432 SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE));
373 if (!scmanager.IsValid()) { 433 if (!scmanager.IsValid()) {
374 error = GetLastError(); 434 error = GetLastError();
(...skipping 13 matching lines...) Expand all
388 << "Failed to open to the '" << kWindowsServiceName << "' service"; 448 << "Failed to open to the '" << kWindowsServiceName << "' service";
389 449
390 return HRESULT_FROM_WIN32(error); 450 return HRESULT_FROM_WIN32(error);
391 } 451 }
392 452
393 service_out->Set(service.Take()); 453 service_out->Set(service.Take());
394 return S_OK; 454 return S_OK;
395 } 455 }
396 456
397 } // namespace remoting 457 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698