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 "cloud_print/service/win/cloud_print_service.h" | 5 #include "cloud_print/service/win/cloud_print_service.h" |
6 | 6 |
7 #include <atlsecurity.h> | |
7 #include <iomanip> | 8 #include <iomanip> |
8 #include <iostream> | 9 #include <iostream> |
9 | 10 |
10 #include "base/at_exit.h" | 11 #include "base/at_exit.h" |
11 #include "base/command_line.h" | 12 #include "base/command_line.h" |
12 #include "base/file_path.h" | 13 #include "base/file_path.h" |
13 #include "base/file_util.h" | 14 #include "base/file_util.h" |
14 #include "base/path_service.h" | 15 #include "base/path_service.h" |
15 #include "base/string_util.h" | 16 #include "base/string_util.h" |
16 #include "base/win/scoped_handle.h" | 17 #include "base/win/scoped_handle.h" |
17 #include "cloud_print/service/win/chrome_launcher.h" | 18 #include "cloud_print/service/win/chrome_launcher.h" |
18 #include "cloud_print/service/win/resource.h" | 19 #include "cloud_print/service/win/resource.h" |
19 #include "cloud_print/service/win/service_state.h" | 20 #include "cloud_print/service/win/service_state.h" |
20 #include "cloud_print/service/win/service_switches.h" | 21 #include "cloud_print/service/win/service_switches.h" |
21 | 22 |
22 namespace { | 23 namespace { |
23 | 24 |
24 const wchar_t kServiceStateFileName[] = L"Service State"; | 25 const wchar_t kServiceStateFileName[] = L"Service State"; |
25 | 26 |
27 const wchar_t kUserToRunService[] = L"NT AUTHORITY\\LocalService"; | |
28 | |
26 // The traits class for Windows Service. | 29 // The traits class for Windows Service. |
27 class ServiceHandleTraits { | 30 class ServiceHandleTraits { |
28 public: | 31 public: |
29 typedef SC_HANDLE Handle; | 32 typedef SC_HANDLE Handle; |
30 | 33 |
31 // Closes the handle. | 34 // Closes the handle. |
32 static bool CloseHandle(Handle handle) { | 35 static bool CloseHandle(Handle handle) { |
33 return ::CloseServiceHandle(handle) != FALSE; | 36 return ::CloseServiceHandle(handle) != FALSE; |
34 } | 37 } |
35 | 38 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
117 ::SetConsoleMode(stdin_handle, saved_mode); | 120 ::SetConsoleMode(stdin_handle, saved_mode); |
118 std::cout << "\n"; | 121 std::cout << "\n"; |
119 } else { | 122 } else { |
120 std::getline(std::cin, tmp); | 123 std::getline(std::cin, tmp); |
121 } | 124 } |
122 if (tmp.empty()) | 125 if (tmp.empty()) |
123 return default; | 126 return default; |
124 return tmp; | 127 return tmp; |
125 } | 128 } |
126 | 129 |
130 HRESULT WriteFileAsUser(const FilePath& path, const wchar_t* user, | |
131 const char* data, int size) { | |
132 ATL::CAccessToken thread_token; | |
133 if (!thread_token.OpenThreadToken(TOKEN_DUPLICATE | TOKEN_IMPERSONATE)) { | |
134 LOG(ERROR) << "Failed to open thread token."; | |
135 return HResultFromLastError(); | |
136 } | |
137 | |
138 ATL::CSid local_service; | |
139 if (!local_service.LoadAccount(user)) { | |
140 LOG(ERROR) << "Failed create SID."; | |
141 return HResultFromLastError(); | |
142 } | |
143 | |
144 ATL::CAccessToken restricted_token; | |
145 ATL::CTokenGroups restrict_group; | |
146 restrict_group.Add(local_service, 0); | |
147 | |
148 if (!thread_token.CreateRestrictedToken(&restricted_token, | |
149 ATL::CTokenGroups(), | |
gene
2012/06/01 17:39:33
put 2 past params to the same line, check alignmen
Vitaly Buka (NO REVIEWS)
2012/06/01 18:02:55
Done.
| |
150 restrict_group)) { | |
151 LOG(ERROR) << "Failed to create restricted token for " << user << "."; | |
152 return HResultFromLastError(); | |
153 } | |
154 | |
155 if (!restricted_token.Impersonate()) { | |
156 LOG(ERROR) << "Failed to impersonate " << user << "."; | |
157 return HResultFromLastError(); | |
158 } | |
159 | |
160 ATL::CAutoRevertImpersonation auto_revert(&restricted_token); | |
161 if (file_util::WriteFile(path, data, size) != size) { | |
162 LOG(ERROR) << "Failed to write file " << path.value() << "."; | |
163 return HResultFromLastError(); | |
164 } | |
165 return S_OK; | |
166 } | |
167 | |
127 } // namespace | 168 } // namespace |
128 | 169 |
129 class CloudPrintServiceModule | 170 class CloudPrintServiceModule |
130 : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> { | 171 : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> { |
131 public: | 172 public: |
132 typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule, | 173 typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule, |
133 IDS_SERVICENAME> Base; | 174 IDS_SERVICENAME> Base; |
134 | 175 |
135 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, | 176 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, |
136 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") | 177 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") |
137 | 178 |
138 HRESULT InitializeSecurity() { | 179 HRESULT InitializeSecurity() { |
139 // TODO(gene): Check if we need to call CoInitializeSecurity and provide | 180 // TODO(gene): Check if we need to call CoInitializeSecurity and provide |
140 // the appropriate security settings for service. | 181 // the appropriate security settings for service. |
141 return S_OK; | 182 return S_OK; |
142 } | 183 } |
143 | 184 |
144 HRESULT InstallService(const FilePath& user_data_dir) { | 185 HRESULT InstallService() { |
145 // TODO(vitalybuka): consider "lite" version if we don't want unregister | 186 // TODO(vitalybuka): consider "lite" version if we don't want unregister |
146 // printers here. | 187 // printers here. |
147 HRESULT hr = UninstallService(); | 188 HRESULT hr = UninstallService(); |
148 if (FAILED(hr)) | 189 if (FAILED(hr)) |
149 return hr; | 190 return hr; |
150 | 191 |
151 if (ChromeLauncher::GetChromePath(HKEY_LOCAL_MACHINE).empty()) { | 192 if (ChromeLauncher::GetChromePath(HKEY_LOCAL_MACHINE).empty()) { |
152 LOG(ERROR) << "Found no Chrome installed for all users."; | 193 LOG(ERROR) << "Found no Chrome installed for all users."; |
153 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | 194 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); |
154 } | 195 } |
155 | 196 |
156 hr = UpdateRegistryAppId(true); | 197 hr = UpdateRegistryAppId(true); |
157 if (FAILED(hr)) | 198 if (FAILED(hr)) |
158 return hr; | 199 return hr; |
159 | 200 |
160 FilePath service_path; | 201 FilePath service_path; |
161 CHECK(PathService::Get(base::FILE_EXE, &service_path)); | 202 CHECK(PathService::Get(base::FILE_EXE, &service_path)); |
162 CommandLine command_line(service_path); | 203 CommandLine command_line(service_path); |
163 command_line.AppendSwitch(kServiceSwitch); | 204 command_line.AppendSwitch(kServiceSwitch); |
164 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir); | 205 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir_); |
165 | 206 |
166 ServiceHandle scm; | 207 ServiceHandle scm; |
167 hr = OpenServiceManager(&scm); | 208 hr = OpenServiceManager(&scm); |
168 if (FAILED(hr)) | 209 if (FAILED(hr)) |
169 return hr; | 210 return hr; |
170 | 211 |
171 ServiceHandle service( | 212 ServiceHandle service( |
172 ::CreateService( | 213 ::CreateService( |
173 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, | 214 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, |
174 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, | 215 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, |
175 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, | 216 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, |
176 L"NT AUTHORITY\\LocalService", NULL)); | 217 kUserToRunService, NULL)); |
177 | 218 |
178 if (!service.IsValid()) | 219 if (!service.IsValid()) |
179 return HResultFromLastError(); | 220 return HResultFromLastError(); |
180 | 221 |
181 return S_OK; | 222 return S_OK; |
182 } | 223 } |
183 | 224 |
184 HRESULT UninstallService() { | 225 HRESULT UninstallService() { |
185 if (!Uninstall()) | 226 if (!Uninstall()) |
186 return E_FAIL; | 227 return E_FAIL; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
232 | 273 |
233 if (command_line.HasSwitch(kUninstallSwitch)) | 274 if (command_line.HasSwitch(kUninstallSwitch)) |
234 return UninstallService(); | 275 return UninstallService(); |
235 | 276 |
236 if (command_line.HasSwitch(kInstallSwitch)) { | 277 if (command_line.HasSwitch(kInstallSwitch)) { |
237 if (!command_line.HasSwitch(kUserDataDirSwitch)) { | 278 if (!command_line.HasSwitch(kUserDataDirSwitch)) { |
238 InvalidUsage(); | 279 InvalidUsage(); |
239 return S_FALSE; | 280 return S_FALSE; |
240 } | 281 } |
241 | 282 |
242 HRESULT hr = ProcessServiceState(user_data_dir_, | 283 HRESULT hr = ValidateUserDataDir(); |
243 command_line.HasSwitch(kQuietSwitch)); | |
244 if (FAILED(hr)) | 284 if (FAILED(hr)) |
245 return hr; | 285 return hr; |
246 | 286 |
247 hr = InstallService(user_data_dir_); | 287 hr = ProcessServiceState(command_line.HasSwitch(kQuietSwitch)); |
288 if (FAILED(hr)) | |
289 return hr; | |
290 | |
291 hr = InstallService(); | |
248 if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) | 292 if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) |
249 return StartService(); | 293 return StartService(); |
250 | 294 |
251 return hr; | 295 return hr; |
252 } | 296 } |
253 | 297 |
254 if (command_line.HasSwitch(kStartSwitch)) | 298 if (command_line.HasSwitch(kStartSwitch)) |
255 return StartService(); | 299 return StartService(); |
256 | 300 |
257 if (command_line.HasSwitch(kServiceSwitch)) { | 301 if (command_line.HasSwitch(kServiceSwitch)) { |
258 *is_service = true; | 302 *is_service = true; |
259 return S_OK; | 303 return S_OK; |
260 } | 304 } |
261 | 305 |
262 if (command_line.HasSwitch(kConsoleSwitch)) { | 306 if (command_line.HasSwitch(kConsoleSwitch)) { |
263 ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); | 307 ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); |
264 HRESULT hr = Run(); | 308 HRESULT hr = Run(); |
265 ::SetConsoleCtrlHandler(NULL, FALSE); | 309 ::SetConsoleCtrlHandler(NULL, FALSE); |
266 return hr; | 310 return hr; |
267 } | 311 } |
268 | 312 |
269 InvalidUsage(); | 313 InvalidUsage(); |
270 return S_FALSE; | 314 return S_FALSE; |
271 } | 315 } |
272 | 316 |
273 HRESULT ProcessServiceState(const FilePath& user_data_dir, bool quiet) { | 317 HRESULT ValidateUserDataDir() { |
274 FilePath file = user_data_dir.Append(kServiceStateFileName); | 318 FilePath temp_file; |
319 const char some_data[] = "1234"; | |
320 if (!file_util::CreateTemporaryFileInDir(user_data_dir_, &temp_file)) | |
321 return E_FAIL; | |
322 HRESULT hr = WriteFileAsUser(temp_file, kUserToRunService, some_data, | |
323 sizeof(some_data)); | |
324 if (FAILED(hr)) { | |
325 std::cout << "Check if user " << kUserToRunService; | |
326 std::cout << " has write access to " << user_data_dir_.value() << ".\n"; | |
gene
2012/06/01 17:39:33
".\n" -> " has failed.\n"
Vitaly Buka (NO REVIEWS)
2012/06/01 18:02:55
Done.
| |
327 } | |
328 file_util::Delete(temp_file, false); | |
329 return hr; | |
330 } | |
331 | |
332 HRESULT ProcessServiceState(bool quiet) { | |
333 FilePath file = user_data_dir_.Append(kServiceStateFileName); | |
275 | 334 |
276 for (;;) { | 335 for (;;) { |
277 std::string contents; | 336 std::string contents; |
278 ServiceState service_state; | 337 ServiceState service_state; |
279 | 338 |
280 bool is_valid = file_util::ReadFileToString(file, &contents) && | 339 bool is_valid = file_util::ReadFileToString(file, &contents) && |
281 service_state.FromString(contents); | 340 service_state.FromString(contents); |
282 | 341 |
283 if (!quiet) { | 342 if (!quiet) { |
284 std::cout << file.value() << ":\n"; | 343 std::cout << file.value() << ":\n"; |
(...skipping 23 matching lines...) Expand all Loading... | |
308 | 367 |
309 while (!is_valid) { | 368 while (!is_valid) { |
310 std::string email = GetOption("email", service_state.email(), false); | 369 std::string email = GetOption("email", service_state.email(), false); |
311 std::string password = GetOption("password", "", true); | 370 std::string password = GetOption("password", "", true); |
312 std::string proxy_id = GetOption("connector_id", | 371 std::string proxy_id = GetOption("connector_id", |
313 service_state.proxy_id(), false); | 372 service_state.proxy_id(), false); |
314 is_valid = service_state.Configure(email, password, proxy_id); | 373 is_valid = service_state.Configure(email, password, proxy_id); |
315 if (is_valid) { | 374 if (is_valid) { |
316 std::string new_contents = service_state.ToString(); | 375 std::string new_contents = service_state.ToString(); |
317 if (new_contents != contents) { | 376 if (new_contents != contents) { |
318 if (file_util::WriteFile(file, new_contents.c_str(), | 377 HRESULT hr = WriteFileAsUser(file, kUserToRunService, |
319 new_contents.size()) <= 0) { | 378 new_contents.c_str(), |
320 return HResultFromLastError(); | 379 new_contents.size()); |
321 } | 380 if (FAILED(hr)) |
381 return hr; | |
322 } | 382 } |
323 } | 383 } |
324 } | 384 } |
325 } | 385 } |
326 | 386 |
327 return S_OK; | 387 return S_OK; |
328 } | 388 } |
329 | 389 |
330 HRESULT OpenServiceManager(ServiceHandle* service_manager) { | 390 HRESULT OpenServiceManager(ServiceHandle* service_manager) { |
331 if (!service_manager) | 391 if (!service_manager) |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
396 | 456 |
397 BOOL CloudPrintServiceModule::ConsoleCtrlHandler(DWORD type) { | 457 BOOL CloudPrintServiceModule::ConsoleCtrlHandler(DWORD type) { |
398 PostThreadMessage(_AtlModule.m_dwThreadID, WM_QUIT, 0, 0); | 458 PostThreadMessage(_AtlModule.m_dwThreadID, WM_QUIT, 0, 0); |
399 return TRUE; | 459 return TRUE; |
400 } | 460 } |
401 | 461 |
402 int main() { | 462 int main() { |
403 base::AtExitManager at_exit; | 463 base::AtExitManager at_exit; |
404 return _AtlModule.WinMain(0); | 464 return _AtlModule.WinMain(0); |
405 } | 465 } |
OLD | NEW |