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 token; |
| 145 ATL::CTokenGroups group; |
| 146 group.Add(local_service, 0); |
| 147 |
| 148 const ATL::CTokenGroups empty_group; |
| 149 if (!thread_token.CreateRestrictedToken(&token, empty_group, group)) { |
| 150 LOG(ERROR) << "Failed to create restricted token for " << user << "."; |
| 151 return HResultFromLastError(); |
| 152 } |
| 153 |
| 154 if (!token.Impersonate()) { |
| 155 LOG(ERROR) << "Failed to impersonate " << user << "."; |
| 156 return HResultFromLastError(); |
| 157 } |
| 158 |
| 159 ATL::CAutoRevertImpersonation auto_revert(&token); |
| 160 if (file_util::WriteFile(path, data, size) != size) { |
| 161 LOG(ERROR) << "Failed to write file " << path.value() << "."; |
| 162 return HResultFromLastError(); |
| 163 } |
| 164 return S_OK; |
| 165 } |
| 166 |
127 } // namespace | 167 } // namespace |
128 | 168 |
129 class CloudPrintServiceModule | 169 class CloudPrintServiceModule |
130 : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> { | 170 : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> { |
131 public: | 171 public: |
132 typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule, | 172 typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule, |
133 IDS_SERVICENAME> Base; | 173 IDS_SERVICENAME> Base; |
134 | 174 |
135 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, | 175 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, |
136 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") | 176 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") |
137 | 177 |
138 HRESULT InitializeSecurity() { | 178 HRESULT InitializeSecurity() { |
139 // TODO(gene): Check if we need to call CoInitializeSecurity and provide | 179 // TODO(gene): Check if we need to call CoInitializeSecurity and provide |
140 // the appropriate security settings for service. | 180 // the appropriate security settings for service. |
141 return S_OK; | 181 return S_OK; |
142 } | 182 } |
143 | 183 |
144 HRESULT InstallService(const FilePath& user_data_dir) { | 184 HRESULT InstallService() { |
145 // TODO(vitalybuka): consider "lite" version if we don't want unregister | 185 // TODO(vitalybuka): consider "lite" version if we don't want unregister |
146 // printers here. | 186 // printers here. |
147 HRESULT hr = UninstallService(); | 187 HRESULT hr = UninstallService(); |
148 if (FAILED(hr)) | 188 if (FAILED(hr)) |
149 return hr; | 189 return hr; |
150 | 190 |
151 if (ChromeLauncher::GetChromePath(HKEY_LOCAL_MACHINE).empty()) { | 191 if (ChromeLauncher::GetChromePath(HKEY_LOCAL_MACHINE).empty()) { |
152 LOG(ERROR) << "Found no Chrome installed for all users."; | 192 LOG(ERROR) << "Found no Chrome installed for all users."; |
153 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); | 193 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); |
154 } | 194 } |
155 | 195 |
156 hr = UpdateRegistryAppId(true); | 196 hr = UpdateRegistryAppId(true); |
157 if (FAILED(hr)) | 197 if (FAILED(hr)) |
158 return hr; | 198 return hr; |
159 | 199 |
160 FilePath service_path; | 200 FilePath service_path; |
161 CHECK(PathService::Get(base::FILE_EXE, &service_path)); | 201 CHECK(PathService::Get(base::FILE_EXE, &service_path)); |
162 CommandLine command_line(service_path); | 202 CommandLine command_line(service_path); |
163 command_line.AppendSwitch(kServiceSwitch); | 203 command_line.AppendSwitch(kServiceSwitch); |
164 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir); | 204 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir_); |
165 | 205 |
166 ServiceHandle scm; | 206 ServiceHandle scm; |
167 hr = OpenServiceManager(&scm); | 207 hr = OpenServiceManager(&scm); |
168 if (FAILED(hr)) | 208 if (FAILED(hr)) |
169 return hr; | 209 return hr; |
170 | 210 |
171 ServiceHandle service( | 211 ServiceHandle service( |
172 ::CreateService( | 212 ::CreateService( |
173 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, | 213 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, |
174 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, | 214 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, |
175 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, | 215 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, |
176 L"NT AUTHORITY\\LocalService", NULL)); | 216 kUserToRunService, NULL)); |
177 | 217 |
178 if (!service.IsValid()) | 218 if (!service.IsValid()) |
179 return HResultFromLastError(); | 219 return HResultFromLastError(); |
180 | 220 |
181 return S_OK; | 221 return S_OK; |
182 } | 222 } |
183 | 223 |
184 HRESULT UninstallService() { | 224 HRESULT UninstallService() { |
185 if (!Uninstall()) | 225 if (!Uninstall()) |
186 return E_FAIL; | 226 return E_FAIL; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 | 272 |
233 if (command_line.HasSwitch(kUninstallSwitch)) | 273 if (command_line.HasSwitch(kUninstallSwitch)) |
234 return UninstallService(); | 274 return UninstallService(); |
235 | 275 |
236 if (command_line.HasSwitch(kInstallSwitch)) { | 276 if (command_line.HasSwitch(kInstallSwitch)) { |
237 if (!command_line.HasSwitch(kUserDataDirSwitch)) { | 277 if (!command_line.HasSwitch(kUserDataDirSwitch)) { |
238 InvalidUsage(); | 278 InvalidUsage(); |
239 return S_FALSE; | 279 return S_FALSE; |
240 } | 280 } |
241 | 281 |
242 HRESULT hr = ProcessServiceState(user_data_dir_, | 282 HRESULT hr = ValidateUserDataDir(); |
243 command_line.HasSwitch(kQuietSwitch)); | |
244 if (FAILED(hr)) | 283 if (FAILED(hr)) |
245 return hr; | 284 return hr; |
246 | 285 |
247 hr = InstallService(user_data_dir_); | 286 hr = ProcessServiceState(command_line.HasSwitch(kQuietSwitch)); |
| 287 if (FAILED(hr)) |
| 288 return hr; |
| 289 |
| 290 hr = InstallService(); |
248 if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) | 291 if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) |
249 return StartService(); | 292 return StartService(); |
250 | 293 |
251 return hr; | 294 return hr; |
252 } | 295 } |
253 | 296 |
254 if (command_line.HasSwitch(kStartSwitch)) | 297 if (command_line.HasSwitch(kStartSwitch)) |
255 return StartService(); | 298 return StartService(); |
256 | 299 |
257 if (command_line.HasSwitch(kServiceSwitch)) { | 300 if (command_line.HasSwitch(kServiceSwitch)) { |
258 *is_service = true; | 301 *is_service = true; |
259 return S_OK; | 302 return S_OK; |
260 } | 303 } |
261 | 304 |
262 if (command_line.HasSwitch(kConsoleSwitch)) { | 305 if (command_line.HasSwitch(kConsoleSwitch)) { |
263 ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); | 306 ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); |
264 HRESULT hr = Run(); | 307 HRESULT hr = Run(); |
265 ::SetConsoleCtrlHandler(NULL, FALSE); | 308 ::SetConsoleCtrlHandler(NULL, FALSE); |
266 return hr; | 309 return hr; |
267 } | 310 } |
268 | 311 |
269 InvalidUsage(); | 312 InvalidUsage(); |
270 return S_FALSE; | 313 return S_FALSE; |
271 } | 314 } |
272 | 315 |
273 HRESULT ProcessServiceState(const FilePath& user_data_dir, bool quiet) { | 316 HRESULT ValidateUserDataDir() { |
274 FilePath file = user_data_dir.Append(kServiceStateFileName); | 317 FilePath temp_file; |
| 318 const char some_data[] = "1234"; |
| 319 if (!file_util::CreateTemporaryFileInDir(user_data_dir_, &temp_file)) |
| 320 return E_FAIL; |
| 321 HRESULT hr = WriteFileAsUser(temp_file, kUserToRunService, some_data, |
| 322 sizeof(some_data)); |
| 323 if (FAILED(hr)) { |
| 324 LOG(ERROR) << "Failed to write user data. Make sure that account \'" << |
| 325 kUserToRunService << "\'has full access to \'" << |
| 326 user_data_dir_.value() << "\'."; |
| 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 |