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 <atlsecurity.h> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <iostream> | 9 #include <iostream> |
10 | 10 |
11 #include "base/at_exit.h" | 11 #include "base/at_exit.h" |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/file_path.h" | 13 #include "base/file_path.h" |
14 #include "base/file_util.h" | 14 #include "base/file_util.h" |
15 #include "base/path_service.h" | 15 #include "base/path_service.h" |
16 #include "base/string_util.h" | 16 #include "base/string_util.h" |
17 #include "base/win/scoped_handle.h" | 17 #include "base/win/scoped_handle.h" |
18 #include "chrome/installer/launcher_support/chrome_launcher_support.h" | 18 #include "chrome/installer/launcher_support/chrome_launcher_support.h" |
19 #include "cloud_print/service/service_state.h" | 19 #include "cloud_print/service/service_state.h" |
20 #include "cloud_print/service/service_switches.h" | 20 #include "cloud_print/service/service_switches.h" |
21 #include "cloud_print/service/win/chrome_launcher.h" | 21 #include "cloud_print/service/win/chrome_launcher.h" |
22 #include "cloud_print/service/win/local_security_policy.h" | |
22 #include "cloud_print/service/win/resource.h" | 23 #include "cloud_print/service/win/resource.h" |
23 | 24 |
24 namespace { | 25 namespace { |
25 | 26 |
26 const wchar_t kServiceStateFileName[] = L"Service State"; | 27 const wchar_t kServiceStateFileName[] = L"Service State"; |
27 | 28 |
28 const wchar_t kUserToRunService[] = L"NT AUTHORITY\\LocalService"; | 29 const wchar_t kUserToRunService[] = L"NT AUTHORITY\\SYSTEM"; |
Albert Bodenhamer
2012/08/14 20:38:18
I'm a bit nervous running as SYSTEM by default. A
Vitaly Buka (NO REVIEWS)
2012/08/14 20:58:51
For current user we need to ask password.
Probably
Vitaly Buka (NO REVIEWS)
2012/08/14 21:51:00
Removed default user.
On 2012/08/14 20:58:51, Vit
| |
29 | 30 |
30 // The traits class for Windows Service. | 31 // The traits class for Windows Service. |
31 class ServiceHandleTraits { | 32 class ServiceHandleTraits { |
32 public: | 33 public: |
33 typedef SC_HANDLE Handle; | 34 typedef SC_HANDLE Handle; |
34 | 35 |
35 // Closes the handle. | 36 // Closes the handle. |
36 static bool CloseHandle(Handle handle) { | 37 static bool CloseHandle(Handle handle) { |
37 return ::CloseServiceHandle(handle) != FALSE; | 38 return ::CloseServiceHandle(handle) != FALSE; |
38 } | 39 } |
(...skipping 25 matching lines...) Expand all Loading... | |
64 FilePath service_path; | 65 FilePath service_path; |
65 CHECK(PathService::Get(base::FILE_EXE, &service_path)); | 66 CHECK(PathService::Get(base::FILE_EXE, &service_path)); |
66 | 67 |
67 std::cout << "Usage: "; | 68 std::cout << "Usage: "; |
68 std::cout << service_path.BaseName().value(); | 69 std::cout << service_path.BaseName().value(); |
69 std::cout << " ["; | 70 std::cout << " ["; |
70 std::cout << "["; | 71 std::cout << "["; |
71 std::cout << "["; | 72 std::cout << "["; |
72 std::cout << " -" << kInstallSwitch; | 73 std::cout << " -" << kInstallSwitch; |
73 std::cout << " -" << kUserDataDirSwitch << "=DIRECTORY"; | 74 std::cout << " -" << kUserDataDirSwitch << "=DIRECTORY"; |
75 std::cout << "["; | |
76 std::cout << " -" << kRunAsUser << "=USERNAME"; | |
77 std::cout << " -" << kRunAsPassword << "=PASSWORD"; | |
78 std::cout << "]"; | |
74 std::cout << " [ -" << kQuietSwitch << " ]"; | 79 std::cout << " [ -" << kQuietSwitch << " ]"; |
75 std::cout << "]"; | 80 std::cout << "]"; |
76 std::cout << "]"; | 81 std::cout << "]"; |
77 std::cout << " | -" << kUninstallSwitch; | 82 std::cout << " | -" << kUninstallSwitch; |
78 std::cout << " | -" << kStartSwitch; | 83 std::cout << " | -" << kStartSwitch; |
79 std::cout << " | -" << kStopSwitch; | 84 std::cout << " | -" << kStopSwitch; |
80 std::cout << " ]\n"; | 85 std::cout << " ]\n"; |
81 std::cout << "Manages cloud print windows service.\n\n"; | 86 std::cout << "Manages cloud print windows service.\n\n"; |
82 | 87 |
83 static const struct { | 88 static const struct { |
84 const char* name; | 89 const char* name; |
85 const char* description; | 90 const char* description; |
86 } kSwitchHelp[] = { | 91 } kSwitchHelp[] = { |
87 { kInstallSwitch, "Installs cloud print as service." }, | 92 { kInstallSwitch, "Installs cloud print as service." }, |
88 { kUserDataDirSwitch, "User data directory with \"Service State\" file." }, | 93 { kUserDataDirSwitch, "User data directory with \"Service State\" file." }, |
89 { kQuietSwitch, "Fails without questions if something wrong." }, | 94 { kQuietSwitch, "Fails without questions if something wrong." }, |
90 { kUninstallSwitch, "Uninstalls service." }, | 95 { kUninstallSwitch, "Uninstalls service." }, |
91 { kStartSwitch, "Starts service. May be combined with installation." }, | 96 { kStartSwitch, "Starts service. May be combined with installation." }, |
92 { kStopSwitch, "Stops service." }, | 97 { kStopSwitch, "Stops service." }, |
98 { kRunAsUser, "Windows user to run the service in form DOMAIN\USERNAME. " | |
99 "Default is LocalSystem. Current User is recommended." }, | |
100 { kRunAsPassword, "Password for windows user to run the service" }, | |
93 }; | 101 }; |
94 | 102 |
95 for (size_t i = 0; i < arraysize(kSwitchHelp); ++i) { | 103 for (size_t i = 0; i < arraysize(kSwitchHelp); ++i) { |
96 std::cout << std::setiosflags(std::ios::left); | 104 std::cout << std::setiosflags(std::ios::left); |
97 std::cout << " -" << std::setw(15) << kSwitchHelp[i].name; | 105 std::cout << " -" << std::setw(15) << kSwitchHelp[i].name; |
98 std::cout << kSwitchHelp[i].description << "\n"; | 106 std::cout << kSwitchHelp[i].description << "\n"; |
99 } | 107 } |
100 std::cout << "\n"; | 108 std::cout << "\n"; |
101 } | 109 } |
102 | 110 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
175 | 183 |
176 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, | 184 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, |
177 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") | 185 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") |
178 | 186 |
179 HRESULT InitializeSecurity() { | 187 HRESULT InitializeSecurity() { |
180 // TODO(gene): Check if we need to call CoInitializeSecurity and provide | 188 // TODO(gene): Check if we need to call CoInitializeSecurity and provide |
181 // the appropriate security settings for service. | 189 // the appropriate security settings for service. |
182 return S_OK; | 190 return S_OK; |
183 } | 191 } |
184 | 192 |
185 HRESULT InstallService() { | 193 HRESULT InstallService(const wchar_t* user, const wchar_t* password) { |
186 using namespace chrome_launcher_support; | 194 using namespace chrome_launcher_support; |
187 | 195 |
188 // TODO(vitalybuka): consider "lite" version if we don't want unregister | 196 // TODO(vitalybuka): consider "lite" version if we don't want unregister |
189 // printers here. | 197 // printers here. |
190 HRESULT hr = UninstallService(); | 198 HRESULT hr = UninstallService(); |
191 if (FAILED(hr)) | 199 if (FAILED(hr)) |
192 return hr; | 200 return hr; |
193 | 201 |
194 if (GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION).empty()) { | 202 if (GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION).empty()) { |
195 LOG(ERROR) << "Found no Chrome installed for all users."; | 203 LOG(WARNING) << "Found no Chrome installed for all users."; |
196 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | |
197 } | 204 } |
198 | 205 |
199 hr = UpdateRegistryAppId(true); | 206 hr = UpdateRegistryAppId(true); |
200 if (FAILED(hr)) | 207 if (FAILED(hr)) |
201 return hr; | 208 return hr; |
202 | 209 |
203 FilePath service_path; | 210 FilePath service_path; |
204 CHECK(PathService::Get(base::FILE_EXE, &service_path)); | 211 CHECK(PathService::Get(base::FILE_EXE, &service_path)); |
205 CommandLine command_line(service_path); | 212 CommandLine command_line(service_path); |
206 command_line.AppendSwitch(kServiceSwitch); | 213 command_line.AppendSwitch(kServiceSwitch); |
207 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir_); | 214 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir_); |
208 | 215 |
216 LocalSecurityPolicy local_security_policy; | |
217 if (local_security_policy.Open()) { | |
218 if (!local_security_policy.IsPrivilegeSet(user, kSeServiceLogonRight)) { | |
219 LOG(WARNING) << "Setting " << kSeServiceLogonRight << " for " << user; | |
220 if (!local_security_policy.SetPrivilege(user, kSeServiceLogonRight)) { | |
221 LOG(ERROR) << "Failed to set" << kSeServiceLogonRight; | |
222 LOG(ERROR) << "Make sure you can run the service with this user."; | |
223 } | |
224 } | |
225 } else { | |
226 LOG(ERROR) << "Failed to open security policy."; | |
227 } | |
228 | |
209 ServiceHandle scm; | 229 ServiceHandle scm; |
210 hr = OpenServiceManager(&scm); | 230 hr = OpenServiceManager(&scm); |
211 if (FAILED(hr)) | 231 if (FAILED(hr)) |
212 return hr; | 232 return hr; |
213 | 233 |
214 ServiceHandle service( | 234 ServiceHandle service( |
215 ::CreateService( | 235 ::CreateService( |
216 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, | 236 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, |
217 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, | 237 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, |
218 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, | 238 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, |
219 kUserToRunService, NULL)); | 239 user, password)); |
220 | 240 |
221 if (!service.IsValid()) | 241 if (!service.IsValid()) |
222 return HResultFromLastError(); | 242 return HResultFromLastError(); |
223 | 243 |
224 return S_OK; | 244 return S_OK; |
225 } | 245 } |
226 | 246 |
227 HRESULT UninstallService() { | 247 HRESULT UninstallService() { |
228 if (!Uninstall()) | 248 if (!Uninstall()) |
229 return E_FAIL; | 249 return E_FAIL; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
275 | 295 |
276 if (command_line.HasSwitch(kUninstallSwitch)) | 296 if (command_line.HasSwitch(kUninstallSwitch)) |
277 return UninstallService(); | 297 return UninstallService(); |
278 | 298 |
279 if (command_line.HasSwitch(kInstallSwitch)) { | 299 if (command_line.HasSwitch(kInstallSwitch)) { |
280 if (!command_line.HasSwitch(kUserDataDirSwitch)) { | 300 if (!command_line.HasSwitch(kUserDataDirSwitch)) { |
281 InvalidUsage(); | 301 InvalidUsage(); |
282 return S_FALSE; | 302 return S_FALSE; |
283 } | 303 } |
284 | 304 |
285 HRESULT hr = ValidateUserDataDir(); | 305 CommandLine::StringType run_as_user = |
286 if (FAILED(hr)) | 306 command_line.GetSwitchValueNative(kRunAsUser); |
287 return hr; | 307 CommandLine::StringType run_as_password = |
308 command_line.GetSwitchValueNative(kRunAsPassword); | |
309 if (run_as_user.empty()) | |
310 run_as_user = kUserToRunService; | |
311 | |
312 HRESULT hr = ValidateUserDataDir(run_as_user.c_str()); | |
288 | 313 |
289 hr = ProcessServiceState(command_line.HasSwitch(kQuietSwitch)); | 314 hr = ProcessServiceState(command_line.HasSwitch(kQuietSwitch)); |
290 if (FAILED(hr)) | 315 if (FAILED(hr)) |
291 return hr; | 316 return hr; |
292 | 317 |
293 hr = InstallService(); | 318 hr = InstallService(run_as_user.c_str(), run_as_password.c_str()); |
294 if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) | 319 if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) |
295 return StartService(); | 320 return StartService(); |
296 | 321 |
297 return hr; | 322 return hr; |
298 } | 323 } |
299 | 324 |
300 if (command_line.HasSwitch(kStartSwitch)) | 325 if (command_line.HasSwitch(kStartSwitch)) |
301 return StartService(); | 326 return StartService(); |
302 | 327 |
303 if (command_line.HasSwitch(kServiceSwitch)) { | 328 if (command_line.HasSwitch(kServiceSwitch)) { |
304 *is_service = true; | 329 *is_service = true; |
305 return S_OK; | 330 return S_OK; |
306 } | 331 } |
307 | 332 |
308 if (command_line.HasSwitch(kConsoleSwitch)) { | 333 if (command_line.HasSwitch(kConsoleSwitch)) { |
309 ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); | 334 ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); |
310 HRESULT hr = Run(); | 335 HRESULT hr = Run(); |
311 ::SetConsoleCtrlHandler(NULL, FALSE); | 336 ::SetConsoleCtrlHandler(NULL, FALSE); |
312 return hr; | 337 return hr; |
313 } | 338 } |
314 | 339 |
315 InvalidUsage(); | 340 InvalidUsage(); |
316 return S_FALSE; | 341 return S_FALSE; |
317 } | 342 } |
318 | 343 |
319 HRESULT ValidateUserDataDir() { | 344 HRESULT ValidateUserDataDir(const wchar_t* user) { |
320 FilePath temp_file; | 345 FilePath temp_file; |
321 const char some_data[] = "1234"; | 346 const char some_data[] = "1234"; |
322 if (!file_util::CreateTemporaryFileInDir(user_data_dir_, &temp_file)) | 347 if (!file_util::CreateTemporaryFileInDir(user_data_dir_, &temp_file)) |
323 return E_FAIL; | 348 return E_FAIL; |
324 HRESULT hr = WriteFileAsUser(temp_file, kUserToRunService, some_data, | 349 HRESULT hr = WriteFileAsUser(temp_file, user, some_data, |
325 sizeof(some_data)); | 350 sizeof(some_data)); |
326 if (FAILED(hr)) { | 351 if (FAILED(hr)) { |
327 LOG(ERROR) << "Failed to write user data. Make sure that account \'" << | 352 LOG(ERROR) << "Failed to write user data. Make sure that account \'" << |
328 kUserToRunService << "\'has full access to \'" << | 353 user << "\' has full access to \'" << |
329 user_data_dir_.value() << "\'."; | 354 user_data_dir_.value() << "\'."; |
330 } | 355 } |
331 file_util::Delete(temp_file, false); | 356 file_util::Delete(temp_file, false); |
332 return hr; | 357 return hr; |
333 } | 358 } |
334 | 359 |
335 HRESULT ProcessServiceState(bool quiet) { | 360 HRESULT ProcessServiceState(bool quiet) { |
336 FilePath file = user_data_dir_.Append(kServiceStateFileName); | 361 FilePath file = user_data_dir_.Append(kServiceStateFileName); |
337 | 362 |
338 for (;;) { | 363 for (;;) { |
339 std::string contents; | 364 std::string contents; |
340 ServiceState service_state; | 365 ServiceState service_state; |
341 | 366 |
342 bool is_valid = file_util::ReadFileToString(file, &contents) && | 367 bool is_valid = file_util::ReadFileToString(file, &contents) && |
343 service_state.FromString(contents); | 368 service_state.FromString(contents); |
344 | 369 |
345 if (!quiet) { | 370 if (!quiet) { |
371 std::cout << "\n"; | |
346 std::cout << file.value() << ":\n"; | 372 std::cout << file.value() << ":\n"; |
347 std::cout << contents << "\n"; | 373 std::cout << contents << "\n"; |
348 } | 374 } |
349 | 375 |
350 if (!is_valid) | 376 if (!is_valid) |
351 LOG(ERROR) << "Invalid file: " << file.value(); | 377 LOG(ERROR) << "Invalid file: " << file.value(); |
352 | 378 |
353 if (quiet) | 379 if (quiet) |
354 return is_valid ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_INVALID); | 380 return is_valid ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_INVALID); |
355 | 381 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
459 | 485 |
460 BOOL CloudPrintServiceModule::ConsoleCtrlHandler(DWORD type) { | 486 BOOL CloudPrintServiceModule::ConsoleCtrlHandler(DWORD type) { |
461 PostThreadMessage(_AtlModule.m_dwThreadID, WM_QUIT, 0, 0); | 487 PostThreadMessage(_AtlModule.m_dwThreadID, WM_QUIT, 0, 0); |
462 return TRUE; | 488 return TRUE; |
463 } | 489 } |
464 | 490 |
465 int main() { | 491 int main() { |
466 base::AtExitManager at_exit; | 492 base::AtExitManager at_exit; |
467 return _AtlModule.WinMain(0); | 493 return _AtlModule.WinMain(0); |
468 } | 494 } |
OLD | NEW |