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

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

Issue 9953002: The me2me host is now configurable from the web UI on Windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: CR feedback 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 "base/file_util.h"
8 #include "base/logging.h"
9 #include "base/json/json_reader.h"
10 #include "base/json/json_writer.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/path_service.h"
13 #include "base/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "base/win/scoped_handle.h"
16 #include "remoting/host/branding.h"
17
7 // MIDL-generated definitions. 18 // MIDL-generated definitions.
8 #include <elevated_controller_i.c> 19 #include "elevated_controller_i.c"
9 20
10 using ATL::CComQIPtr; 21 namespace {
11 using ATL::CComPtr; 22
23 // TODO(alexeypa): remove this limitation.
24 const size_t kMaxConfigFileSize = 0x10000;
Wez 2012/03/30 22:11:01 nit: Specifying the max file size in hex makes it
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
25
26 const char kHostId[] = "host_id";
27 const char kXmppLogin[] = "xmpp_login";
Wez 2012/03/30 22:11:01 nit: Add a comment to explain what these constants
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
28
29 // Names of the configuration files.
30 const FilePath::CharType kAuthConfig[] = FILE_PATH_LITERAL("auth.json");
Wez 2012/03/30 22:11:01 nit: These should really be kAuthConfig -> kAuthCo
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
31 const FilePath::CharType kHostConfig[] = FILE_PATH_LITERAL("host.json");
32
33 // TODO(alexeypa): remove the hardcoded undocimented paths and store
Wez 2012/03/30 22:11:01 typos: remove -> Remove, undocimented.
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
34 // the configuration in the registry.
35 #ifdef OFFICIAL_BUILD
36 const FilePath::CharType kConfigDir[] = FILE_PATH_LITERAL(
37 "config\\systemprofile\\AppData\\Local\\Google\\Chrome Remote Desktop");
38 #else
39 const FilePath::CharType kConfigDir[] =
40 FILE_PATH_LITERAL("config\\systemprofile\\AppData\\Local\\Chromoting");
41 #endif
42
43 // Reads and parses a JSON configuration file (up to 64KB in size).
Wez 2012/03/30 22:11:01 nit: The "up to 64KB in size" comment goes with th
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
44 HRESULT ReadConfig(const FilePath& filename,
45 scoped_ptr<base::DictionaryValue>* config_out) {
46 // Read raw data from the configuration file.
47 base::win::ScopedHandle file(
48 CreateFileW(filename.value().c_str(),
49 GENERIC_READ,
50 FILE_SHARE_READ | FILE_SHARE_WRITE,
51 NULL,
52 OPEN_EXISTING,
53 FILE_FLAG_SEQUENTIAL_SCAN,
54 NULL));
55
56 if (!file.IsValid()) {
57 DWORD error = GetLastError();
58 LOG_GETLASTERROR(ERROR)
59 << "Failed to read '" << filename.value() << "'";
60 return HRESULT_FROM_WIN32(error);
61 }
62
63 std::vector<char> buffer(kMaxConfigFileSize);
64 DWORD size = static_cast<DWORD>(buffer.size());
65 if (!::ReadFile(file, &buffer[0], size, &size, NULL)) {
66 DWORD error = GetLastError();
67 LOG_GETLASTERROR(ERROR)
68 << "Failed to read '" << filename.value() << "'";
69 return HRESULT_FROM_WIN32(error);
70 }
71
72 // Parse JSON data.
Wez 2012/03/30 22:11:01 nit: "Parse the JSON configuration, expecting it t
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
73 std::string file_content(&buffer[0], size);
74 scoped_ptr<base::Value> value(base::JSONReader::Read(file_content, true));
75
76 base::DictionaryValue* dictionary;
77 if (value.get() == NULL || !value->GetAsDictionary(&dictionary)) {
78 LOG(ERROR) << "Failed to read '" << filename.value() << "'.";
79 return E_FAIL;
80 }
81
82 value.release();
83 config_out->reset(dictionary);
Wez 2012/03/30 22:11:01 Gah. Gross. Can't see a better way to do it, off
84 return S_OK;
85 }
86
87 } // namespace
12 88
13 namespace remoting { 89 namespace remoting {
14 90
15 ElevatedControllerWin::ElevatedControllerWin() { 91 ElevatedControllerWin::ElevatedControllerWin() {
16 } 92 }
17 93
18 HRESULT ElevatedControllerWin::FinalConstruct() { 94 HRESULT ElevatedControllerWin::FinalConstruct() {
19 return S_OK; 95 return S_OK;
20 } 96 }
21 97
22 void ElevatedControllerWin::FinalRelease() { 98 void ElevatedControllerWin::FinalRelease() {
23 } 99 }
24 100
25 STDMETHODIMP ElevatedControllerWin::get_State(DaemonState* state_out) { 101 STDMETHODIMP ElevatedControllerWin::GetConfig(BSTR* config_out) {
26 return E_NOTIMPL; 102 FilePath system_profile;
103 PathService::Get(base::DIR_SYSTEM, &system_profile);
104
105 // Build the host configuration.
Wez 2012/03/30 22:11:01 nit: Isn't this reading it, rather than "building"
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
106 scoped_ptr<base::DictionaryValue> config;
107 HRESULT hr = ReadConfig(system_profile.Append(kConfigDir).Append(kHostConfig),
108 &config);
109 if (FAILED(hr)) {
110 return hr;
111 }
112
113 // Build the filtered config.
Wez 2012/03/30 22:11:01 Why? What is the purpose of the filtering?
alexeypa (please no reviews) 2012/03/30 23:47:09 This matched Mac implementation.
Lambros 2012/03/31 00:48:34 GetConfig() is documented to return only certain k
Wez 2012/04/01 01:25:27 Right; my point is that the comment should clarify
alexeypa (please no reviews) 2012/04/02 16:26:39 Oh, well. I'll try to address this in one of the f
114 scoped_ptr<base::DictionaryValue> filtered_config(
115 new base::DictionaryValue());
116
117 std::string value;
118 if (config->GetString(kHostId, &value)) {
119 filtered_config->SetString(kHostId, value);
120 }
121
Wez 2012/03/30 22:11:01 nit: No need for this blank line.
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
122 if (config->GetString(kXmppLogin, &value)) {
123 filtered_config->SetString(kXmppLogin, value);
124 }
125
126 // Convert the filtered config back to string and return it to the caller.
Wez 2012/03/30 22:11:01 typo: ... back to a string ...
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
127 std::string file_content;
128 base::JSONWriter::Write(filtered_config.get(), &file_content);
129
130 *config_out = ::SysAllocString(UTF8ToUTF16(file_content).c_str());
131 if (config_out == NULL) {
132 return E_OUTOFMEMORY;
133 }
134
135 return S_OK;
27 } 136 }
28 137
29 STDMETHODIMP ElevatedControllerWin::ReadConfig(BSTR* config_out) { 138 STDMETHODIMP ElevatedControllerWin::SetConfig(BSTR config) {
30 return E_NOTIMPL; 139 FilePath system_profile;
Wez 2012/03/30 22:11:01 nit: Comment before these lines e.g. "Determine th
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
31 } 140 PathService::Get(base::DIR_SYSTEM, &system_profile);
32 141
Wez 2012/03/30 22:11:01 nit: No need for this blank line?
alexeypa (please no reviews) 2012/03/30 23:47:09 Removed. My eyes hurt now! :-)
33 STDMETHODIMP ElevatedControllerWin::WriteConfig(BSTR config) { 142 FilePath config_dir = system_profile.Append(kConfigDir);
34 return E_NOTIMPL; 143 if (!file_util::CreateDirectory(config_dir)) {
144 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
145 }
146
147 std::string file_content = UTF16ToUTF8(
148 string16(static_cast<char16*>(config), ::SysStringLen(config)));
149
150 int written = file_util::WriteFile(
Wez 2012/03/30 22:11:01 Should we be doing the write-temp-file-then-delete
alexeypa (please no reviews) 2012/03/30 23:47:09 We could. However the whole configuration flow is
151 config_dir.Append(kAuthConfig),
152 file_content.c_str(),
153 file_content.size());
154
155 if (written != static_cast<int>(file_content.size())) {
156 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
157 }
158
159 // TODO(alexeypa): make it a single file.
Wez 2012/03/30 22:11:01 nit: I think you mean "Store the authentication an
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
160 written = file_util::WriteFile(
161 config_dir.Append(kHostConfig),
162 file_content.c_str(),
163 file_content.size());
164
165 if (written != static_cast<int>(file_content.size())) {
166 return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
Wez 2012/03/30 22:11:01 nit: That's not strictly the right error, and in f
alexeypa (please no reviews) 2012/03/30 23:47:09 Nope. I bet something else bad happened. I replace
167 }
168
169 return S_OK;
35 } 170 }
36 171
37 STDMETHODIMP ElevatedControllerWin::StartDaemon() { 172 STDMETHODIMP ElevatedControllerWin::StartDaemon() {
38 return E_NOTIMPL; 173 ScopedScHandle service;
39 } 174 HRESULT hr = OpenService(&service);
40 175 if (FAILED(hr)) {
41 STDMETHODIMP ElevatedControllerWin::StopDaemon() { 176 return hr;
42 return E_NOTIMPL;
43 }
44
45 HRESULT ElevatedControllerWin::FireOnStateChange(DaemonState state) {
46 CComPtr<IConnectionPoint> connection_point;
47 FindConnectionPoint(__uuidof(IDaemonEvents), &connection_point);
48 if (!connection_point) {
49 return S_OK;
50 } 177 }
51 178
52 CComPtr<IEnumConnections> connections; 179 if (!StartService(service, 0, NULL)) {
53 if (FAILED(connection_point->EnumConnections(&connections))) { 180 DWORD error = GetLastError();
54 return S_OK; 181 if (error != ERROR_SERVICE_ALREADY_RUNNING) {
55 } 182 LOG_GETLASTERROR(ERROR)
183 << "Failed to start the '" << kWindowsServiceName << "'service";
56 184
57 CONNECTDATA connect_data; 185 return HRESULT_FROM_WIN32(error);
58 while (connections->Next(1, &connect_data, NULL) == S_OK) {
59 if (connect_data.pUnk != NULL) {
60 CComQIPtr<IDaemonEvents, &__uuidof(IDaemonEvents)> sink(
61 connect_data.pUnk);
62
63 if (sink != NULL) {
64 sink->OnStateChange(state);
65 }
66
67 connect_data.pUnk->Release();
68 } 186 }
69 } 187 }
70 188
71 return S_OK; 189 return S_OK;
72 } 190 }
73 191
192 STDMETHODIMP ElevatedControllerWin::StopDaemon() {
193 ScopedScHandle service;
194 HRESULT hr = OpenService(&service);
195 if (FAILED(hr)) {
196 return hr;
Wez 2012/03/30 22:11:01 Do you actually want to return potentially arbitra
alexeypa (please no reviews) 2012/03/30 23:47:09 I don't think so. Something better defined is "ope
Wez 2012/04/01 01:25:27 The word "here" was missing from my sentence; I th
alexeypa (please no reviews) 2012/04/02 16:26:39 That is not the only reason. I don't think that us
197 }
198
199 SERVICE_STATUS status;
200 if (!ControlService(service, SERVICE_CONTROL_STOP, &status)) {
201 DWORD error = GetLastError();
202 if (error != ERROR_SERVICE_NOT_ACTIVE) {
203 LOG_GETLASTERROR(ERROR)
204 << "Failed to stop the '" << kWindowsServiceName << "'service";
205 return HRESULT_FROM_WIN32(error);
206 }
207 }
208
209 return S_OK;
210 }
211
212 HRESULT ElevatedControllerWin::OpenService(ScopedScHandle* service_out) {
213 DWORD error;
214
215 ScopedScHandle scmanager(
216 ::OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE,
217 SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE));
218 if (!scmanager.IsValid()) {
219 error = GetLastError();
220 LOG_GETLASTERROR(ERROR)
221 << "Failed to connect to the service control manager";
222
223 return HRESULT_FROM_WIN32(error);
224 }
225
226 ScopedScHandle service(
227 ::OpenServiceA(scmanager, kWindowsServiceName,
Wez 2012/03/30 22:11:01 nit: Why are we using OpenServiceA but OpenSCManag
alexeypa (please no reviews) 2012/03/30 23:47:09 Done.
228 SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP));
229 if (!service.IsValid()) {
230 error = GetLastError();
231 LOG_GETLASTERROR(ERROR)
232 << "Failed to open to the '" << kWindowsServiceName << "' service";
233
234 return HRESULT_FROM_WIN32(error);
235 }
236
237 service_out->Set(service.Take());
238 return S_OK;
239 }
240
74 } // namespace remoting 241 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698