diff options
author | vitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-10 14:52:49 +0000 |
---|---|---|
committer | vitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-10 14:52:49 +0000 |
commit | 0d78a46aa89b4f613be0fff330ed7420b691d4ea (patch) | |
tree | 0bf6b3d74460b2cbbc22dbc01ee0bd89f178a751 /cloud_print | |
parent | dd358e59b1e1f4654fafe90ba36a6004bf67bddf (diff) | |
download | chromium_src-0d78a46aa89b4f613be0fff330ed7420b691d4ea.zip chromium_src-0d78a46aa89b4f613be0fff330ed7420b691d4ea.tar.gz chromium_src-0d78a46aa89b4f613be0fff330ed7420b691d4ea.tar.bz2 |
Exctracted ServiceController.
BUG=0
TBR=gene
Review URL: https://chromiumcodereview.appspot.com/12412017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187205 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cloud_print')
-rw-r--r-- | cloud_print/service/service.gyp | 19 | ||||
-rw-r--r-- | cloud_print/service/win/cloud_print_service.cc | 559 | ||||
-rw-r--r-- | cloud_print/service/win/cloud_print_service.h | 59 | ||||
-rw-r--r-- | cloud_print/service/win/cloud_print_service_main.cc | 14 | ||||
-rw-r--r-- | cloud_print/service/win/service_controller.cc | 186 | ||||
-rw-r--r-- | cloud_print/service/win/service_controller.h | 41 |
6 files changed, 498 insertions, 380 deletions
diff --git a/cloud_print/service/service.gyp b/cloud_print/service/service.gyp index 73dfcc1..bbefb74 100644 --- a/cloud_print/service/service.gyp +++ b/cloud_print/service/service.gyp @@ -14,6 +14,15 @@ { 'target_name': 'cloud_print_service_lib', 'type': 'static_library', + 'variables': { 'enable_wexit_time_destructors': 1, }, + 'defines' : [ + '_ATL_APARTMENT_THREADED', + '_ATL_CSTRING_EXPLICIT_CONSTRUCTORS', + '_ATL_NO_AUTOMATIC_NAMESPACE', + '_ATL_NO_EXCEPTIONS', + 'SECURITY_WIN32', + 'STRICT', + ], 'dependencies': [ '<(DEPTH)/base/base.gyp:base', '<(DEPTH)/build/temp_gyp/googleurl.gyp:googleurl', @@ -25,10 +34,16 @@ 'service_state.h', 'service_switches.cc', 'service_switches.h', + 'win/cloud_print_service.cc', + 'win/cloud_print_service.h', + 'win/cloud_print_service.rc', 'win/chrome_launcher.cc', 'win/chrome_launcher.h', 'win/local_security_policy.cc', 'win/local_security_policy.h', + 'win/resource.h', + 'win/service_controller.cc', + 'win/service_controller.h', ], 'conditions': [ ['OS=="win"', { @@ -48,10 +63,8 @@ '<(SHARED_INTERMEDIATE_DIR)', ], 'sources': [ - 'win/cloud_print_service.cc', - 'win/cloud_print_service.h', + 'win/cloud_print_service_main.cc', 'win/cloud_print_service.rc', - 'win/resource.h', ], 'dependencies': [ 'cloud_print_service_lib', diff --git a/cloud_print/service/win/cloud_print_service.cc b/cloud_print/service/win/cloud_print_service.cc index b22c603..32f7c91 100644 --- a/cloud_print/service/win/cloud_print_service.cc +++ b/cloud_print/service/win/cloud_print_service.cc @@ -4,27 +4,23 @@ #include "cloud_print/service/win/cloud_print_service.h" -#define SECURITY_WIN32 #include <security.h> #include <iomanip> #include <iostream> -#include "base/at_exit.h" #include "base/command_line.h" #include "base/file_util.h" -#include "base/files/file_path.h" #include "base/guid.h" +#include "base/logging.h" #include "base/path_service.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" -#include "base/win/scoped_handle.h" #include "chrome/installer/launcher_support/chrome_launcher_support.h" #include "cloud_print/service/service_state.h" #include "cloud_print/service/service_switches.h" #include "cloud_print/service/win/chrome_launcher.h" -#include "cloud_print/service/win/local_security_policy.h" -#include "cloud_print/service/win/resource.h" +#include "cloud_print/service/win/service_controller.h" #include "printing/backend/print_backend.h" namespace { @@ -34,39 +30,6 @@ const char kChromeIsAvalible[] = "\nChrome is available\n"; const wchar_t kRequirementsFileName[] = L"cloud_print_service_requirements.txt"; const wchar_t kServiceStateFileName[] = L"Service State"; -// The traits class for Windows Service. -class ServiceHandleTraits { - public: - typedef SC_HANDLE Handle; - - // Closes the handle. - static bool CloseHandle(Handle handle) { - return ::CloseServiceHandle(handle) != FALSE; - } - - static bool IsHandleValid(Handle handle) { - return handle != NULL; - } - - static Handle NullHandle() { - return NULL; - } - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceHandleTraits); -}; - -typedef base::win::GenericScopedHandle< - ServiceHandleTraits, base::win::DummyVerifierTraits> ServiceHandle; - -HRESULT HResultFromLastError() { - HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); - // Something already failed if function called. - if (SUCCEEDED(hr)) - hr = E_FAIL; - return hr; -} - void InvalidUsage() { base::FilePath service_path; CHECK(PathService::Get(base::FILE_EXE, &service_path)); @@ -162,383 +125,261 @@ string16 GetCurrentUserName() { } // namespace -class CloudPrintServiceModule - : public ATL::CAtlServiceModuleT<CloudPrintServiceModule, IDS_SERVICENAME> { - public: - typedef ATL::CAtlServiceModuleT<CloudPrintServiceModule, - IDS_SERVICENAME> Base; +CloudPrintService::CloudPrintService() + : check_requirements_(false), + controller_(new ServiceController(m_szServiceName)) { +} + +CloudPrintService::~CloudPrintService() { +} - DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, - "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") +wchar_t* CloudPrintService::GetAppIdT() { + return ServiceController::GetAppIdT(); +}; - CloudPrintServiceModule() : check_requirements_(false) { - } +HRESULT CloudPrintService::InitializeSecurity() { + // TODO(gene): Check if we need to call CoInitializeSecurity and provide + // the appropriate security settings for service. + return S_OK; +} - HRESULT InitializeSecurity() { - // TODO(gene): Check if we need to call CoInitializeSecurity and provide - // the appropriate security settings for service. - return S_OK; +bool CloudPrintService::ParseCommandLine(LPCTSTR lpCmdLine, + HRESULT* pnRetCode) { + CHECK(pnRetCode); + CommandLine command_line(CommandLine::NO_PROGRAM); + command_line.ParseFromString(lpCmdLine); + bool is_service = false; + *pnRetCode = ParseCommandLine(command_line, &is_service); + if (FAILED(*pnRetCode)) { + LOG(ERROR) << "Operation failed. 0x" << std::setw(8) << + std::setbase(16) << *pnRetCode; } + return is_service; +} + +HRESULT CloudPrintService::PreMessageLoop(int nShowCmd) { + HRESULT hr = Base::PreMessageLoop(nShowCmd); + if (FAILED(hr)) + return hr; - HRESULT InstallService(const string16& user, - const string16& password, - const char* run_switch) { - // TODO(vitalybuka): consider "lite" version if we don't want unregister - // printers here. - HRESULT hr = UninstallService(); + if (check_requirements_) { + hr = CheckRequirements(); if (FAILED(hr)) return hr; - - hr = UpdateRegistryAppId(true); + // Don't run message loop and stop service. + return S_FALSE; + } else { + hr = StartConnector(); if (FAILED(hr)) return hr; + } - base::FilePath service_path; - CHECK(PathService::Get(base::FILE_EXE, &service_path)); - CommandLine command_line(service_path); - command_line.AppendSwitch(run_switch); - command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir_); - - LocalSecurityPolicy local_security_policy; - if (local_security_policy.Open()) { - if (!local_security_policy.IsPrivilegeSet(user, kSeServiceLogonRight)) { - LOG(WARNING) << "Setting " << kSeServiceLogonRight << " for " << user; - if (!local_security_policy.SetPrivilege(user, kSeServiceLogonRight)) { - LOG(ERROR) << "Failed to set" << kSeServiceLogonRight; - LOG(ERROR) << "Make sure you can run the service as " << user << "."; - } - } - } else { - LOG(ERROR) << "Failed to open security policy."; - } + LogEvent(_T("Service started/resumed")); + SetServiceStatus(SERVICE_RUNNING); - ServiceHandle scm; - hr = OpenServiceManager(&scm); - if (FAILED(hr)) - return hr; + return hr; +} - ServiceHandle service( - ::CreateService( - scm, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, - SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, - user.empty() ? NULL : user.c_str(), - password.empty() ? NULL : password.c_str())); - - if (!service.IsValid()) { - LOG(ERROR) << "Failed to install service as " << user << "."; - return HResultFromLastError(); - } +HRESULT CloudPrintService::PostMessageLoop() { + StopConnector(); + return Base::PostMessageLoop(); +} - return S_OK; - } +HRESULT CloudPrintService::ParseCommandLine(const CommandLine& command_line, + bool* is_service) { + if (!is_service) + return E_INVALIDARG; + *is_service = false; - HRESULT UninstallService() { - StopService(); - if (!Uninstall()) - return E_FAIL; - return UpdateRegistryAppId(false); - } + user_data_dir_ = command_line.GetSwitchValuePath(kUserDataDirSwitch); + if (command_line.HasSwitch(kStopSwitch)) + return controller_->StopService(); + + if (command_line.HasSwitch(kUninstallSwitch)) + return controller_->UninstallService(); - bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) { - CHECK(pnRetCode); - CommandLine command_line(CommandLine::NO_PROGRAM); - command_line.ParseFromString(lpCmdLine); - bool is_service = false; - *pnRetCode = ParseCommandLine(command_line, &is_service); - if (FAILED(*pnRetCode)) { - LOG(ERROR) << "Operation failed. 0x" << std::setw(8) << - std::setbase(16) << *pnRetCode; + if (command_line.HasSwitch(kInstallSwitch)) { + if (!command_line.HasSwitch(kUserDataDirSwitch)) { + InvalidUsage(); + return S_FALSE; } - return is_service; - } - HRESULT PreMessageLoop(int nShowCmd) { - HRESULT hr = Base::PreMessageLoop(nShowCmd); + string16 run_as_user; + string16 run_as_password; + SelectWindowsAccount(&run_as_user, &run_as_password); + + HRESULT hr = SetupServiceState(); if (FAILED(hr)) return hr; - if (check_requirements_) { - hr = CheckRequirements(); - if (FAILED(hr)) - return hr; - // Don't run message loop and stop service. - return S_FALSE; - } else { - hr = StartConnector(); - if (FAILED(hr)) - return hr; - } - - LogEvent(_T("Service started/resumed")); - SetServiceStatus(SERVICE_RUNNING); + hr = controller_->InstallService(run_as_user, run_as_password, + kServiceSwitch, user_data_dir_); + if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) + return controller_->StartService(); return hr; } - HRESULT PostMessageLoop() { - StopConnector(); - return Base::PostMessageLoop(); - } - - private: - HRESULT ParseCommandLine(const CommandLine& command_line, bool* is_service) { - if (!is_service) - return E_INVALIDARG; - *is_service = false; - - user_data_dir_ = command_line.GetSwitchValuePath(kUserDataDirSwitch); - if (command_line.HasSwitch(kStopSwitch)) - return StopService(); + if (command_line.HasSwitch(kStartSwitch)) + return controller_->StartService(); - if (command_line.HasSwitch(kUninstallSwitch)) - return UninstallService(); - - if (command_line.HasSwitch(kInstallSwitch)) { - if (!command_line.HasSwitch(kUserDataDirSwitch)) { - InvalidUsage(); - return S_FALSE; - } + if (command_line.HasSwitch(kServiceSwitch) || + command_line.HasSwitch(kRequirementsSwitch)) { + *is_service = true; + check_requirements_ = command_line.HasSwitch(kRequirementsSwitch); + return S_OK; + } - string16 run_as_user; - string16 run_as_password; - SelectWindowsAccount(&run_as_user, &run_as_password); + if (command_line.HasSwitch(kConsoleSwitch)) { + ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); + HRESULT hr = Run(); + ::SetConsoleCtrlHandler(NULL, FALSE); + return hr; + } - HRESULT hr = SetupServiceState(); - if (FAILED(hr)) - return hr; + InvalidUsage(); + return S_FALSE; +} - hr = InstallService(run_as_user.c_str(), run_as_password.c_str(), - kServiceSwitch); - if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch)) - return StartService(); +void CloudPrintService::SelectWindowsAccount(string16* run_as_user, + string16* run_as_password) { + *run_as_user = GetCurrentUserName(); + for (;;) { + std::cout << "\nPlease provide Windows account to run service.\n"; + *run_as_user = ASCIIToWide(GetOption("Account as DOMAIN\\USERNAME", + WideToASCII(*run_as_user), false)); + *run_as_password = ASCIIToWide(GetOption("Password", "", true)); - return hr; + base::FilePath requirements_filename(user_data_dir_); + requirements_filename = + requirements_filename.Append(kRequirementsFileName); + + file_util::Delete(requirements_filename, false); + if (file_util::PathExists(requirements_filename)) { + LOG(ERROR) << "Unable to delete " << + requirements_filename.value() << "."; + continue; } - - if (command_line.HasSwitch(kStartSwitch)) - return StartService(); - - if (command_line.HasSwitch(kServiceSwitch) || - command_line.HasSwitch(kRequirementsSwitch)) { - *is_service = true; - check_requirements_ = command_line.HasSwitch(kRequirementsSwitch); - return S_OK; + if (FAILED(controller_->InstallService(*run_as_user, *run_as_password, + kRequirementsSwitch, + user_data_dir_))) { + continue; } - - if (command_line.HasSwitch(kConsoleSwitch)) { - ::SetConsoleCtrlHandler(&ConsoleCtrlHandler, TRUE); - HRESULT hr = Run(); - ::SetConsoleCtrlHandler(NULL, FALSE); - return hr; + bool service_started = SUCCEEDED(controller_->StartService()); + controller_->UninstallService(); + if (!service_started) { + LOG(ERROR) << "Failed to start service as " << *run_as_user << "."; + continue; + } + std::string printers; + if (!file_util::PathExists(requirements_filename) || + !file_util::ReadFileToString(requirements_filename, &printers)) { + LOG(ERROR) << "Service can't create " << requirements_filename.value(); + continue; } - InvalidUsage(); - return S_FALSE; - } - - void SelectWindowsAccount(string16* run_as_user, - string16* run_as_password) { - *run_as_user = GetCurrentUserName(); - for (;;) { - std::cout << "\nPlease provide Windows account to run service.\n"; - *run_as_user = ASCIIToWide(GetOption("Account as DOMAIN\\USERNAME", - WideToASCII(*run_as_user), false)); - *run_as_password = ASCIIToWide(GetOption("Password", "", true)); - - base::FilePath requirements_filename(user_data_dir_); - requirements_filename = - requirements_filename.Append(kRequirementsFileName); - - file_util::Delete(requirements_filename, false); - if (file_util::PathExists(requirements_filename)) { - LOG(ERROR) << "Unable to delete " << - requirements_filename.value() << "."; - continue; - } - if (FAILED(InstallService(run_as_user->c_str(), - run_as_password->c_str(), - kRequirementsSwitch))) { - continue; - } - bool service_started = SUCCEEDED(StartService()); - UninstallService(); - if (!service_started) { - LOG(ERROR) << "Failed to start service as " << *run_as_user << "."; - continue; - } - std::string printers; - if (!file_util::PathExists(requirements_filename) || - !file_util::ReadFileToString(requirements_filename, &printers)) { - LOG(ERROR) << "Service can't create " << requirements_filename.value(); - continue; - } - - if (EndsWith(printers, kChromeIsNotAvalible, true)) { - LOG(ERROR) << kChromeIsNotAvalible << " for " << *run_as_user << "."; - continue; - } + if (EndsWith(printers, kChromeIsNotAvalible, true)) { + LOG(ERROR) << kChromeIsNotAvalible << " for " << *run_as_user << "."; + continue; + } - std::cout << "\nService requirements check result: \n"; - std::cout << printers << "\n"; - file_util::Delete(requirements_filename, false); + std::cout << "\nService requirements check result: \n"; + std::cout << printers << "\n"; + file_util::Delete(requirements_filename, false); - if (AskUser("Do you want to use " + WideToASCII(*run_as_user) + "?")) - return; - } + if (AskUser("Do you want to use " + WideToASCII(*run_as_user) + "?")) + return; } +} - HRESULT SetupServiceState() { - base::FilePath file = user_data_dir_.Append(kServiceStateFileName); +HRESULT CloudPrintService::SetupServiceState() { + base::FilePath file = user_data_dir_.Append(kServiceStateFileName); - for (;;) { - std::string contents; - ServiceState service_state; + for (;;) { + std::string contents; + ServiceState service_state; - bool is_valid = file_util::ReadFileToString(file, &contents) && - service_state.FromString(contents); + bool is_valid = file_util::ReadFileToString(file, &contents) && + service_state.FromString(contents); - std::cout << "\nFile '" << file.value() << "' content:\n"; - std::cout << contents << "\n"; + std::cout << "\nFile '" << file.value() << "' content:\n"; + std::cout << contents << "\n"; - if (!is_valid) - LOG(ERROR) << "Invalid file: " << file.value(); + if (!is_valid) + LOG(ERROR) << "Invalid file: " << file.value(); - if (!contents.empty()) { - if (AskUser("Do you want to use '" + WideToASCII(file.value()) + "'")) { - return S_OK; - } else { - is_valid = false; - } + if (!contents.empty()) { + if (AskUser("Do you want to use '" + WideToASCII(file.value()) + "'")) { + return S_OK; + } else { + is_valid = false; } + } - while (!is_valid) { - std::cout << "\nPlease provide Cloud Print Settings.\n"; - std::string email = GetOption("email", service_state.email(), false); - std::string password = GetOption("password", "", true); - std::string proxy_id = service_state.proxy_id(); - if (proxy_id.empty()) - proxy_id = base::GenerateGUID(); - proxy_id = GetOption("connector_id", proxy_id, false); - is_valid = service_state.Configure(email, password, proxy_id); - if (is_valid) { - std::string new_contents = service_state.ToString(); - if (new_contents != contents) { - size_t written = file_util::WriteFile(file, new_contents.c_str(), - new_contents.size()); - if (written != new_contents.size()) { - LOG(ERROR) << "Failed to write file " << file.value() << "."; - return HResultFromLastError(); - } + while (!is_valid) { + std::cout << "\nPlease provide Cloud Print Settings.\n"; + std::string email = GetOption("email", service_state.email(), false); + std::string password = GetOption("password", "", true); + std::string proxy_id = service_state.proxy_id(); + if (proxy_id.empty()) + proxy_id = base::GenerateGUID(); + proxy_id = GetOption("connector_id", proxy_id, false); + is_valid = service_state.Configure(email, password, proxy_id); + if (is_valid) { + std::string new_contents = service_state.ToString(); + if (new_contents != contents) { + size_t written = file_util::WriteFile(file, new_contents.c_str(), + new_contents.size()); + if (written != new_contents.size()) { + LOG(ERROR) << "Failed to write file " << file.value() << "."; + HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + if (SUCCEEDED(hr)) + return E_FAIL; + return hr; } } } } - - return S_OK; } - HRESULT OpenServiceManager(ServiceHandle* service_manager) { - if (!service_manager) - return E_POINTER; - - service_manager->Set(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); - if (!service_manager->IsValid()) - return HResultFromLastError(); - - return S_OK; - } - - HRESULT OpenService(DWORD access, ServiceHandle* service) { - if (!service) - return E_POINTER; - - ServiceHandle scm; - HRESULT hr = OpenServiceManager(&scm); - if (FAILED(hr)) - return hr; - - service->Set(::OpenService(scm, m_szServiceName, access)); - - if (!service->IsValid()) - return HResultFromLastError(); - - return S_OK; - } - - HRESULT StartService() { - ServiceHandle service; - HRESULT hr = OpenService(SERVICE_START, &service); - if (FAILED(hr)) - return hr; - if (!::StartService(service, 0, NULL)) - return HResultFromLastError(); - return S_OK; - } - - HRESULT StopService() { - ServiceHandle service; - HRESULT hr = OpenService(SERVICE_STOP | SERVICE_QUERY_STATUS, &service); - if (FAILED(hr)) - return hr; - SERVICE_STATUS status = {0}; - if (!::ControlService(service, SERVICE_CONTROL_STOP, &status)) - return HResultFromLastError(); - while (::QueryServiceStatus(service, &status) && - status.dwCurrentState > SERVICE_STOPPED) { - Sleep(500); - } - return S_OK; - } - - HRESULT CheckRequirements() { - base::FilePath requirements_filename(user_data_dir_); - requirements_filename = requirements_filename.Append(kRequirementsFileName); - std::string output; - output.append("Printers available for " + - WideToASCII(GetCurrentUserName()) + ":\n"); - scoped_refptr<printing::PrintBackend> backend( - printing::PrintBackend::CreateInstance(NULL)); - printing::PrinterList printer_list; - backend->EnumeratePrinters(&printer_list); - for (size_t i = 0; i < printer_list.size(); ++i) { - output += " "; - output += printer_list[i].printer_name; - output += "\n"; - } - base::FilePath chrome = chrome_launcher_support::GetAnyChromePath(); - output.append(chrome.empty() ? kChromeIsNotAvalible : kChromeIsAvalible); - file_util::WriteFile(requirements_filename, output.c_str(), output.size()); - return S_OK; - } + return S_OK; +} - HRESULT StartConnector() { - chrome_.reset(new ChromeLauncher(user_data_dir_)); - return chrome_->Start() ? S_OK : E_FAIL; +void CloudPrintService::StopConnector() { + if (chrome_.get()) { + chrome_->Stop(); + chrome_.reset(); } +} - void StopConnector() { - if (chrome_.get()) { - chrome_->Stop(); - chrome_.reset(); - } +HRESULT CloudPrintService::CheckRequirements() { + base::FilePath requirements_filename(user_data_dir_); + requirements_filename = requirements_filename.Append(kRequirementsFileName); + std::string output; + output.append("Printers available for " + + WideToASCII(GetCurrentUserName()) + ":\n"); + scoped_refptr<printing::PrintBackend> backend( + printing::PrintBackend::CreateInstance(NULL)); + printing::PrinterList printer_list; + backend->EnumeratePrinters(&printer_list); + for (size_t i = 0; i < printer_list.size(); ++i) { + output += " "; + output += printer_list[i].printer_name; + output += "\n"; } + base::FilePath chrome = chrome_launcher_support::GetAnyChromePath(); + output.append(chrome.empty() ? kChromeIsNotAvalible : kChromeIsAvalible); + file_util::WriteFile(requirements_filename, output.c_str(), output.size()); + return S_OK; +} - static BOOL WINAPI ConsoleCtrlHandler(DWORD type); - - bool check_requirements_; - base::FilePath user_data_dir_; - scoped_ptr<ChromeLauncher> chrome_; -}; - -CloudPrintServiceModule _AtlModule; +HRESULT CloudPrintService::StartConnector() { + chrome_.reset(new ChromeLauncher(user_data_dir_)); + return chrome_->Start() ? S_OK : E_FAIL; +} -BOOL CloudPrintServiceModule::ConsoleCtrlHandler(DWORD type) { +BOOL CloudPrintService::ConsoleCtrlHandler(DWORD type) { PostThreadMessage(_AtlModule.m_dwThreadID, WM_QUIT, 0, 0); return TRUE; } -int main() { - base::AtExitManager at_exit; - return _AtlModule.WinMain(0); -} diff --git a/cloud_print/service/win/cloud_print_service.h b/cloud_print/service/win/cloud_print_service.h index a07189c..4976f52 100644 --- a/cloud_print/service/win/cloud_print_service.h +++ b/cloud_print/service/win/cloud_print_service.h @@ -5,25 +5,48 @@ #ifndef CLOUD_PRINT_SERVICE_CLOUD_PRINT_SERVICE_H_ #define CLOUD_PRINT_SERVICE_CLOUD_PRINT_SERVICE_H_ -#ifndef STRICT -#define STRICT -#endif - -#define _ATL_FREE_THREADED - -#define _ATL_NO_AUTOMATIC_NAMESPACE - -// Service has no COM objects. http://support.microsoft.com/kb/2480736 -#define _ATL_NO_COM_SUPPORT - -// some CString constructors will be explicit -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS - -#define ATL_NO_ASSERT_ON_DESTROY_NONEXISTENT_WINDOW - #include <atlbase.h> -#include <atlcom.h> -#include <atlctl.h> + +#include "base/files/file_path.h" +#include "base/memory/scoped_ptr.h" +#include "base/string16.h" +#include "cloud_print/service/win/resource.h" + +class ChromeLauncher; +class CommandLine; +class ServiceController; + +class CloudPrintService + : public ATL::CAtlServiceModuleT<CloudPrintService, IDS_SERVICENAME> { + public: + typedef ATL::CAtlServiceModuleT<CloudPrintService, IDS_SERVICENAME> Base; + + CloudPrintService(); + ~CloudPrintService(); + + // CAtlServiceModuleT ovverides. + static wchar_t* GetAppIdT(); + HRESULT InitializeSecurity(); + bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode); + HRESULT PreMessageLoop(int nShowCmd); + HRESULT PostMessageLoop(); + + private: + HRESULT ParseCommandLine(const CommandLine& command_line, bool* is_service); + void SelectWindowsAccount(string16* run_as_user, string16* run_as_password); + HRESULT SetupServiceState(); + HRESULT CheckRequirements(); + HRESULT StartConnector(); + void StopConnector(); + static BOOL WINAPI ConsoleCtrlHandler(DWORD type); + + bool check_requirements_; + base::FilePath user_data_dir_; + scoped_ptr<ChromeLauncher> chrome_; + scoped_ptr<ServiceController> controller_; +}; + +extern CloudPrintService _AtlModule; #endif // CLOUD_PRINT_SERVICE_CLOUD_PRINT_SERVICE_H_ diff --git a/cloud_print/service/win/cloud_print_service_main.cc b/cloud_print/service/win/cloud_print_service_main.cc new file mode 100644 index 0000000..606ddea --- /dev/null +++ b/cloud_print/service/win/cloud_print_service_main.cc @@ -0,0 +1,14 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cloud_print/service/win/cloud_print_service.h" + +#include "base/at_exit.h" + +CloudPrintService _AtlModule; + +int main() { + base::AtExitManager at_exit; + return _AtlModule.WinMain(0); +} diff --git a/cloud_print/service/win/service_controller.cc b/cloud_print/service/win/service_controller.cc new file mode 100644 index 0000000..e4e5217 --- /dev/null +++ b/cloud_print/service/win/service_controller.cc @@ -0,0 +1,186 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cloud_print/service/win/service_controller.h" + +#include <atlbase.h> +#include <atlcom.h> +#include <atlctl.h> + +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/path_service.h" +#include "base/win/scoped_handle.h" +#include "cloud_print/service/service_switches.h" +#include "cloud_print/service/win/local_security_policy.h" + +namespace { + +HRESULT HResultFromLastError() { + HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + // Something already failed if function called. + if (SUCCEEDED(hr)) + hr = E_FAIL; + return hr; +} + +// The traits class for Windows Service. +class ServiceHandleTraits { + public: + typedef SC_HANDLE Handle; + + // Closes the handle. + static bool CloseHandle(Handle handle) { + return ::CloseServiceHandle(handle) != FALSE; + } + + static bool IsHandleValid(Handle handle) { + return handle != NULL; + } + + static Handle NullHandle() { + return NULL; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceHandleTraits); +}; + +typedef base::win::GenericScopedHandle< + ServiceHandleTraits, base::win::DummyVerifierTraits> ServiceHandle; + +HRESULT OpenServiceManager(ServiceHandle* service_manager) { + if (!service_manager) + return E_POINTER; + + service_manager->Set(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); + if (!service_manager->IsValid()) + return HResultFromLastError(); + + return S_OK; +} + +HRESULT OpenService(const string16& name, DWORD access, + ServiceHandle* service) { + if (!service) + return E_POINTER; + + ServiceHandle scm; + HRESULT hr = OpenServiceManager(&scm); + if (FAILED(hr)) + return hr; + + service->Set(::OpenService(scm, name.c_str(), access)); + + if (!service->IsValid()) + return HResultFromLastError(); + + return S_OK; +} + +} // namespace + +ServiceController::ServiceController(const string16& name) + : name_(name) { +} + +ServiceController::~ServiceController() { +} + +HRESULT ServiceController::StartService() { + ServiceHandle service; + HRESULT hr = OpenService(name_, SERVICE_START, &service); + if (FAILED(hr)) + return hr; + if (!::StartService(service, 0, NULL)) + return HResultFromLastError(); + return S_OK; +} + +HRESULT ServiceController::StopService() { + ServiceHandle service; + HRESULT hr = OpenService(name_, SERVICE_STOP | SERVICE_QUERY_STATUS, + &service); + if (FAILED(hr)) + return hr; + SERVICE_STATUS status = {0}; + if (!::ControlService(service, SERVICE_CONTROL_STOP, &status)) + return HResultFromLastError(); + while (::QueryServiceStatus(service, &status) && + status.dwCurrentState > SERVICE_STOPPED) { + Sleep(500); + } + return S_OK; +} + +HRESULT ServiceController::InstallService(const string16& user, + const string16& password, + const std::string& run_switch, + const base::FilePath& user_data_dir) { + // TODO(vitalybuka): consider "lite" version if we don't want unregister + // printers here. + HRESULT hr = UninstallService(); + if (FAILED(hr)) + return hr; + + hr = UpdateRegistryAppId(true); + if (FAILED(hr)) + return hr; + + base::FilePath service_path; + CHECK(PathService::Get(base::FILE_EXE, &service_path)); + CommandLine command_line(service_path); + command_line.AppendSwitch(run_switch); + command_line.AppendSwitchPath(kUserDataDirSwitch, user_data_dir); + + LocalSecurityPolicy local_security_policy; + if (local_security_policy.Open()) { + if (!local_security_policy.IsPrivilegeSet(user, kSeServiceLogonRight)) { + LOG(WARNING) << "Setting " << kSeServiceLogonRight << " for " << user; + if (!local_security_policy.SetPrivilege(user, kSeServiceLogonRight)) { + LOG(ERROR) << "Failed to set" << kSeServiceLogonRight; + LOG(ERROR) << "Make sure you can run the service as " << user << "."; + } + } + } else { + LOG(ERROR) << "Failed to open security policy."; + } + + ServiceHandle scm; + hr = OpenServiceManager(&scm); + if (FAILED(hr)) + return hr; + + ServiceHandle service( + ::CreateService( + scm, name_.c_str(), name_.c_str(), SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, + command_line.GetCommandLineString().c_str(), NULL, NULL, NULL, + user.empty() ? NULL : user.c_str(), + password.empty() ? NULL : password.c_str())); + + if (!service.IsValid()) { + LOG(ERROR) << "Failed to install service as " << user << "."; + return HResultFromLastError(); + } + + return S_OK; +} + +HRESULT ServiceController::UninstallService() { + StopService(); + + ServiceHandle service; + OpenService(name_, SERVICE_STOP | DELETE, &service); + HRESULT hr = S_FALSE; + if (service) { + if (!::DeleteService(service)) { + LOG(ERROR) << "Failed to uninstall service"; + hr = HResultFromLastError(); + } + } + UpdateRegistryAppId(false); + return hr; +} + diff --git a/cloud_print/service/win/service_controller.h b/cloud_print/service/win/service_controller.h new file mode 100644 index 0000000..4e06059 --- /dev/null +++ b/cloud_print/service/win/service_controller.h @@ -0,0 +1,41 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CLOUD_PRINT_SERVICE_SERVICE_CONTROLLER_H_ +#define CLOUD_PRINT_SERVICE_SERVICE_CONTROLLER_H_ + +#include <atlbase.h> +#include <string> + +#include "base/string16.h" +#include "cloud_print/service/win/resource.h" + +namespace base { +class FilePath; +} // base + +class ServiceController { + public: + DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CLOUDPRINTSERVICE, + "{8013FB7C-2E3E-4992-B8BD-05C0C4AB0627}") + + explicit ServiceController(const string16& name); + ~ServiceController(); + + HRESULT InstallService(const string16& user, + const string16& password, + const std::string& run_switch, + const base::FilePath& user_data_dir); + + HRESULT UninstallService(); + + HRESULT StartService(); + HRESULT StopService(); + + private: + const string16 name_; +}; + +#endif // CLOUD_PRINT_SERVICE_SERVICE_CONTROLLER_H_ + |