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

Side by Side Diff: cloud_print/service/win/cloud_print_service.cc

Issue 10824294: Changed Windows account to run service. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 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 "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
30 // The traits class for Windows Service. 29 // The traits class for Windows Service.
31 class ServiceHandleTraits { 30 class ServiceHandleTraits {
32 public: 31 public:
33 typedef SC_HANDLE Handle; 32 typedef SC_HANDLE Handle;
34 33
35 // Closes the handle. 34 // Closes the handle.
36 static bool CloseHandle(Handle handle) { 35 static bool CloseHandle(Handle handle) {
37 return ::CloseServiceHandle(handle) != FALSE; 36 return ::CloseServiceHandle(handle) != FALSE;
38 } 37 }
39 38
(...skipping 24 matching lines...) Expand all
64 FilePath service_path; 63 FilePath service_path;
65 CHECK(PathService::Get(base::FILE_EXE, &service_path)); 64 CHECK(PathService::Get(base::FILE_EXE, &service_path));
66 65
67 std::cout << "Usage: "; 66 std::cout << "Usage: ";
68 std::cout << service_path.BaseName().value(); 67 std::cout << service_path.BaseName().value();
69 std::cout << " ["; 68 std::cout << " [";
70 std::cout << "["; 69 std::cout << "[";
71 std::cout << "["; 70 std::cout << "[";
72 std::cout << " -" << kInstallSwitch; 71 std::cout << " -" << kInstallSwitch;
73 std::cout << " -" << kUserDataDirSwitch << "=DIRECTORY"; 72 std::cout << " -" << kUserDataDirSwitch << "=DIRECTORY";
73 std::cout << " -" << kRunAsUser << "=USERNAME";
74 std::cout << " -" << kRunAsPassword << "=PASSWORD";
74 std::cout << " [ -" << kQuietSwitch << " ]"; 75 std::cout << " [ -" << kQuietSwitch << " ]";
75 std::cout << "]"; 76 std::cout << "]";
76 std::cout << "]"; 77 std::cout << "]";
77 std::cout << " | -" << kUninstallSwitch; 78 std::cout << " | -" << kUninstallSwitch;
78 std::cout << " | -" << kStartSwitch; 79 std::cout << " | -" << kStartSwitch;
79 std::cout << " | -" << kStopSwitch; 80 std::cout << " | -" << kStopSwitch;
80 std::cout << " ]\n"; 81 std::cout << " ]\n";
81 std::cout << "Manages cloud print windows service.\n\n"; 82 std::cout << "Manages cloud print windows service.\n\n";
82 83
83 static const struct { 84 static const struct {
84 const char* name; 85 const char* name;
85 const char* description; 86 const char* description;
86 } kSwitchHelp[] = { 87 } kSwitchHelp[] = {
87 { kInstallSwitch, "Installs cloud print as service." }, 88 { kInstallSwitch, "Installs cloud print as service." },
88 { kUserDataDirSwitch, "User data directory with \"Service State\" file." }, 89 { kUserDataDirSwitch, "User data directory with \"Service State\" file." },
89 { kQuietSwitch, "Fails without questions if something wrong." }, 90 { kQuietSwitch, "Fails without questions if something wrong." },
90 { kUninstallSwitch, "Uninstalls service." }, 91 { kUninstallSwitch, "Uninstalls service." },
91 { kStartSwitch, "Starts service. May be combined with installation." }, 92 { kStartSwitch, "Starts service. May be combined with installation." },
92 { kStopSwitch, "Stops service." }, 93 { kStopSwitch, "Stops service." },
94 { kRunAsUser, "Windows user to run the service in form DOMAIN\\USERNAME. "
95 "Make sure user has access to printers." },
96 { kRunAsPassword, "Password for windows user to run the service" },
93 }; 97 };
94 98
95 for (size_t i = 0; i < arraysize(kSwitchHelp); ++i) { 99 for (size_t i = 0; i < arraysize(kSwitchHelp); ++i) {
96 std::cout << std::setiosflags(std::ios::left); 100 std::cout << std::setiosflags(std::ios::left);
97 std::cout << " -" << std::setw(15) << kSwitchHelp[i].name; 101 std::cout << " -" << std::setw(15) << kSwitchHelp[i].name;
98 std::cout << kSwitchHelp[i].description << "\n"; 102 std::cout << kSwitchHelp[i].description << "\n";
99 } 103 }
100 std::cout << "\n"; 104 std::cout << "\n";
101 } 105 }
102 106
(...skipping 18 matching lines...) Expand all
121 ::SetConsoleMode(stdin_handle, saved_mode); 125 ::SetConsoleMode(stdin_handle, saved_mode);
122 std::cout << "\n"; 126 std::cout << "\n";
123 } else { 127 } else {
124 std::getline(std::cin, tmp); 128 std::getline(std::cin, tmp);
125 } 129 }
126 if (tmp.empty()) 130 if (tmp.empty())
127 return default; 131 return default;
128 return tmp; 132 return tmp;
129 } 133 }
130 134
131 HRESULT WriteFileAsUser(const FilePath& path, const wchar_t* user, 135 HRESULT WriteFileAsUser(const FilePath& path, const string16& user,
132 const char* data, int size) { 136 const char* data, int size) {
133 ATL::CAccessToken thread_token; 137 ATL::CAccessToken token;
134 if (!thread_token.OpenThreadToken(TOKEN_DUPLICATE | TOKEN_IMPERSONATE)) { 138 ATL::CAutoRevertImpersonation auto_revert(&token);
135 LOG(ERROR) << "Failed to open thread token."; 139 if (!user.empty()) {
136 return HResultFromLastError(); 140 ATL::CAccessToken thread_token;
141 if (!thread_token.OpenThreadToken(TOKEN_DUPLICATE | TOKEN_IMPERSONATE)) {
142 LOG(ERROR) << "Failed to open thread token.";
143 return HResultFromLastError();
144 }
145
146 ATL::CSid local_service;
147 if (!local_service.LoadAccount(user.c_str())) {
148 LOG(ERROR) << "Failed create SID.";
149 return HResultFromLastError();
150 }
151
152 ATL::CTokenGroups group;
153 group.Add(local_service, 0);
154
155 const ATL::CTokenGroups empty_group;
156 if (!thread_token.CreateRestrictedToken(&token, empty_group, group)) {
157 LOG(ERROR) << "Failed to create restricted token for " << user << ".";
158 return HResultFromLastError();
159 }
160
161 if (!token.Impersonate()) {
162 LOG(ERROR) << "Failed to impersonate " << user << ".";
163 return HResultFromLastError();
164 }
137 } 165 }
138
139 ATL::CSid local_service;
140 if (!local_service.LoadAccount(user)) {
141 LOG(ERROR) << "Failed create SID.";
142 return HResultFromLastError();
143 }
144
145 ATL::CAccessToken token;
146 ATL::CTokenGroups group;
147 group.Add(local_service, 0);
148
149 const ATL::CTokenGroups empty_group;
150 if (!thread_token.CreateRestrictedToken(&token, empty_group, group)) {
151 LOG(ERROR) << "Failed to create restricted token for " << user << ".";
152 return HResultFromLastError();
153 }
154
155 if (!token.Impersonate()) {
156 LOG(ERROR) << "Failed to impersonate " << user << ".";
157 return HResultFromLastError();
158 }
159
160 ATL::CAutoRevertImpersonation auto_revert(&token);
161 if (file_util::WriteFile(path, data, size) != size) { 166 if (file_util::WriteFile(path, data, size) != size) {
162 LOG(ERROR) << "Failed to write file " << path.value() << "."; 167 LOG(ERROR) << "Failed to write file " << path.value() << ".";
163 return HResultFromLastError(); 168 return HResultFromLastError();
164 } 169 }
165 return S_OK; 170 return S_OK;
166 } 171 }
167 172
168 } // namespace 173 } // namespace
169 174
170 class CloudPrintServiceModule 175 class CloudPrintServiceModule
171 : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> { 176 : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> {
172 public: 177 public:
173 typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule, 178 typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule,
174 IDS_SERVICENAME> Base; 179 IDS_SERVICENAME> Base;
175 180
176 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, 181 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE,
177 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") 182 "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}")
178 183
179 HRESULT InitializeSecurity() { 184 HRESULT InitializeSecurity() {
180 // TODO(gene): Check if we need to call CoInitializeSecurity and provide 185 // TODO(gene): Check if we need to call CoInitializeSecurity and provide
181 // the appropriate security settings for service. 186 // the appropriate security settings for service.
182 return S_OK; 187 return S_OK;
183 } 188 }
184 189
185 HRESULT InstallService() { 190 HRESULT InstallService(const string16& user, const string16& password) {
186 using namespace chrome_launcher_support; 191 using namespace chrome_launcher_support;
187 192
188 // TODO(vitalybuka): consider "lite" version if we don't want unregister 193 // TODO(vitalybuka): consider "lite" version if we don't want unregister
189 // printers here. 194 // printers here.
190 HRESULT hr = UninstallService(); 195 HRESULT hr = UninstallService();
191 if (FAILED(hr)) 196 if (FAILED(hr))
192 return hr; 197 return hr;
193 198
194 if (GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION).empty()) { 199 if (GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION).empty()) {
195 LOG(ERROR) << "Found no Chrome installed for all users."; 200 LOG(WARNING) << "Found no Chrome installed for all users.";
196 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
197 } 201 }
198 202
199 hr = UpdateRegistryAppId(true); 203 hr = UpdateRegistryAppId(true);
200 if (FAILED(hr)) 204 if (FAILED(hr))
201 return hr; 205 return hr;
202 206
203 FilePath service_path; 207 FilePath service_path;
204 CHECK(PathService::Get(base::FILE_EXE, &service_path)); 208 CHECK(PathService::Get(base::FILE_EXE, &service_path));
205 CommandLine command_line(service_path); 209 CommandLine command_line(service_path);
206 command_line.AppendSwitch(kServiceSwitch); 210 command_line.AppendSwitch(kServiceSwitch);
207 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir_); 211 command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir_);
208 212
213 LocalSecurityPolicy local_security_policy;
214 if (local_security_policy.Open()) {
215 if (!local_security_policy.IsPrivilegeSet(user, kSeServiceLogonRight)) {
216 LOG(WARNING) << "Setting " << kSeServiceLogonRight << " for " << user;
217 if (!local_security_policy.SetPrivilege(user, kSeServiceLogonRight)) {
218 LOG(ERROR) << "Failed to set" << kSeServiceLogonRight;
219 LOG(ERROR) << "Make sure you can run the service with this user.";
220 }
221 }
222 } else {
223 LOG(ERROR) << "Failed to open security policy.";
224 }
225
209 ServiceHandle scm; 226 ServiceHandle scm;
210 hr = OpenServiceManager(&scm); 227 hr = OpenServiceManager(&scm);
211 if (FAILED(hr)) 228 if (FAILED(hr))
212 return hr; 229 return hr;
213 230
214 ServiceHandle service( 231 ServiceHandle service(
215 ::CreateService( 232 ::CreateService(
216 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, 233 scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS,
217 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, 234 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
218 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, 235 command_line.GetCommandLineString().c_str(), NULL, NULL, NULL,
219 kUserToRunService, NULL)); 236 user.empty() ? NULL : user.c_str(),
237 password.empty() ? NULL : password.c_str()));
220 238
221 if (!service.IsValid()) 239 if (!service.IsValid())
222 return HResultFromLastError(); 240 return HResultFromLastError();
223 241
224 return S_OK; 242 return S_OK;
225 } 243 }
226 244
227 HRESULT UninstallService() { 245 HRESULT UninstallService() {
228 if (!Uninstall()) 246 if (!Uninstall())
229 return E_FAIL; 247 return E_FAIL;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 *is_service = false; 288 *is_service = false;
271 289
272 user_data_dir_ = command_line.GetSwitchValuePath(kUserDataDirSwitch); 290 user_data_dir_ = command_line.GetSwitchValuePath(kUserDataDirSwitch);
273 if (command_line.HasSwitch(kStopSwitch)) 291 if (command_line.HasSwitch(kStopSwitch))
274 return StopService(); 292 return StopService();
275 293
276 if (command_line.HasSwitch(kUninstallSwitch)) 294 if (command_line.HasSwitch(kUninstallSwitch))
277 return UninstallService(); 295 return UninstallService();
278 296
279 if (command_line.HasSwitch(kInstallSwitch)) { 297 if (command_line.HasSwitch(kInstallSwitch)) {
280 if (!command_line.HasSwitch(kUserDataDirSwitch)) { 298 if (!command_line.HasSwitch(kUserDataDirSwitch) ||
299 !command_line.HasSwitch(kRunAsUser) ||
300 !command_line.HasSwitch(kRunAsPassword)) {
281 InvalidUsage(); 301 InvalidUsage();
282 return S_FALSE; 302 return S_FALSE;
283 } 303 }
284 304
285 HRESULT hr = ValidateUserDataDir(); 305 HRESULT hr = ProcessServiceState(command_line.HasSwitch(kQuietSwitch));
286 if (FAILED(hr)) 306 if (FAILED(hr))
287 return hr; 307 return hr;
288 308
289 hr = ProcessServiceState(command_line.HasSwitch(kQuietSwitch)); 309 CommandLine::StringType run_as_user =
290 if (FAILED(hr)) 310 command_line.GetSwitchValueNative(kRunAsUser);
291 return hr; 311 CommandLine::StringType run_as_password =
312 command_line.GetSwitchValueNative(kRunAsPassword);
292 313
293 hr = InstallService(); 314 hr = ValidateUserDataDir(run_as_user.c_str());
315
316 hr = InstallService(run_as_user.c_str(), run_as_password.c_str());
294 if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) 317 if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch))
295 return StartService(); 318 return StartService();
296 319
297 return hr; 320 return hr;
298 } 321 }
299 322
300 if (command_line.HasSwitch(kStartSwitch)) 323 if (command_line.HasSwitch(kStartSwitch))
301 return StartService(); 324 return StartService();
302 325
303 if (command_line.HasSwitch(kServiceSwitch)) { 326 if (command_line.HasSwitch(kServiceSwitch)) {
304 *is_service = true; 327 *is_service = true;
305 return S_OK; 328 return S_OK;
306 } 329 }
307 330
308 if (command_line.HasSwitch(kConsoleSwitch)) { 331 if (command_line.HasSwitch(kConsoleSwitch)) {
309 ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); 332 ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE);
310 HRESULT hr = Run(); 333 HRESULT hr = Run();
311 ::SetConsoleCtrlHandler(NULL, FALSE); 334 ::SetConsoleCtrlHandler(NULL, FALSE);
312 return hr; 335 return hr;
313 } 336 }
314 337
315 InvalidUsage(); 338 InvalidUsage();
316 return S_FALSE; 339 return S_FALSE;
317 } 340 }
318 341
319 HRESULT ValidateUserDataDir() { 342 HRESULT ValidateUserDataDir(const string16& user) {
320 FilePath temp_file; 343 FilePath temp_file;
321 const char some_data[] = "1234"; 344 const char some_data[] = "1234";
322 if (!file_util::CreateTemporaryFileInDir(user_data_dir_, &temp_file)) 345 if (!file_util::CreateTemporaryFileInDir(user_data_dir_, &temp_file))
323 return E_FAIL; 346 return E_FAIL;
324 HRESULT hr = WriteFileAsUser(temp_file, kUserToRunService, some_data, 347 HRESULT hr = WriteFileAsUser(temp_file, user, some_data,
325 sizeof(some_data)); 348 sizeof(some_data));
326 if (FAILED(hr)) { 349 if (FAILED(hr)) {
327 LOG(ERROR) << "Failed to write user data. Make sure that account \'" << 350 LOG(ERROR) << "Failed to write user data. Make sure that account \'" <<
328 kUserToRunService << "\'has full access to \'" << 351 user << "\' has full access to \'" <<
329 user_data_dir_.value() << "\'."; 352 user_data_dir_.value() << "\'.";
330 } 353 }
331 file_util::Delete(temp_file, false); 354 file_util::Delete(temp_file, false);
332 return hr; 355 return hr;
333 } 356 }
334 357
335 HRESULT ProcessServiceState(bool quiet) { 358 HRESULT ProcessServiceState(bool quiet) {
336 FilePath file = user_data_dir_.Append(kServiceStateFileName); 359 FilePath file = user_data_dir_.Append(kServiceStateFileName);
337 360
338 for (;;) { 361 for (;;) {
339 std::string contents; 362 std::string contents;
340 ServiceState service_state; 363 ServiceState service_state;
341 364
342 bool is_valid = file_util::ReadFileToString(file, &contents) && 365 bool is_valid = file_util::ReadFileToString(file, &contents) &&
343 service_state.FromString(contents); 366 service_state.FromString(contents);
344 367
345 if (!quiet) { 368 if (!quiet) {
369 std::cout << "\n";
346 std::cout << file.value() << ":\n"; 370 std::cout << file.value() << ":\n";
347 std::cout << contents << "\n"; 371 std::cout << contents << "\n";
348 } 372 }
349 373
350 if (!is_valid) 374 if (!is_valid)
351 LOG(ERROR) << "Invalid file: " << file.value(); 375 LOG(ERROR) << "Invalid file: " << file.value();
352 376
353 if (quiet) 377 if (quiet)
354 return is_valid ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_INVALID); 378 return is_valid ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_INVALID);
355 379
(...skipping 14 matching lines...) Expand all
370 394
371 while (!is_valid) { 395 while (!is_valid) {
372 std::string email = GetOption("email", service_state.email(), false); 396 std::string email = GetOption("email", service_state.email(), false);
373 std::string password = GetOption("password", "", true); 397 std::string password = GetOption("password", "", true);
374 std::string proxy_id = GetOption("connector_id", 398 std::string proxy_id = GetOption("connector_id",
375 service_state.proxy_id(), false); 399 service_state.proxy_id(), false);
376 is_valid = service_state.Configure(email, password, proxy_id); 400 is_valid = service_state.Configure(email, password, proxy_id);
377 if (is_valid) { 401 if (is_valid) {
378 std::string new_contents = service_state.ToString(); 402 std::string new_contents = service_state.ToString();
379 if (new_contents != contents) { 403 if (new_contents != contents) {
380 HRESULT hr = WriteFileAsUser(file, kUserToRunService, 404 size_t written = file_util::WriteFile(file, new_contents.c_str(),
381 new_contents.c_str(), 405 new_contents.size());
382 new_contents.size()); 406 if (written != new_contents.size()) {
383 if (FAILED(hr)) 407 LOG(ERROR) << "Failed to write file " << file.value() << ".";
384 return hr; 408 return HResultFromLastError();
409 }
385 } 410 }
386 } 411 }
387 } 412 }
388 } 413 }
389 414
390 return S_OK; 415 return S_OK;
391 } 416 }
392 417
393 HRESULT OpenServiceManager(ServiceHandle* service_manager) { 418 HRESULT OpenServiceManager(ServiceHandle* service_manager) {
394 if (!service_manager) 419 if (!service_manager)
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 484
460 BOOL CloudPrintServiceModule::ConsoleCtrlHandler(DWORD type) { 485 BOOL CloudPrintServiceModule::ConsoleCtrlHandler(DWORD type) {
461 PostThreadMessage(_AtlModule.m_dwThreadID, WM_QUIT, 0, 0); 486 PostThreadMessage(_AtlModule.m_dwThreadID, WM_QUIT, 0, 0);
462 return TRUE; 487 return TRUE;
463 } 488 }
464 489
465 int main() { 490 int main() {
466 base::AtExitManager at_exit; 491 base::AtExitManager at_exit;
467 return _AtlModule.WinMain(0); 492 return _AtlModule.WinMain(0);
468 } 493 }
OLDNEW
« no previous file with comments | « cloud_print/service/service_switches.cc ('k') | cloud_print/service/win/local_security_policy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698