summaryrefslogtreecommitdiffstats
path: root/cloud_print/service/win/service_controller.cc
diff options
context:
space:
mode:
authorvitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-12 04:20:38 +0000
committervitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-12 04:20:38 +0000
commita9734a2c32754e3f00a0ab9e1e8511288d74f717 (patch)
treeddc8c79cfc944ac20e1ca9bb5493265e2b4c2c4f /cloud_print/service/win/service_controller.cc
parentee479cdca22f7c0166ce371af4e432cd21293e90 (diff)
downloadchromium_src-a9734a2c32754e3f00a0ab9e1e8511288d74f717.zip
chromium_src-a9734a2c32754e3f00a0ab9e1e8511288d74f717.tar.gz
chromium_src-a9734a2c32754e3f00a0ab9e1e8511288d74f717.tar.bz2
Exctracted ServiceController.
BUG=0 Review URL: https://chromiumcodereview.appspot.com/12729003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187489 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cloud_print/service/win/service_controller.cc')
-rw-r--r--cloud_print/service/win/service_controller.cc182
1 files changed, 182 insertions, 0 deletions
diff --git a/cloud_print/service/win/service_controller.cc b/cloud_print/service/win/service_controller.cc
new file mode 100644
index 0000000..b9a749d
--- /dev/null
+++ b/cloud_print/service/win/service_controller.cc
@@ -0,0 +1,182 @@
+// 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() {
+ return GetLastError() ? HRESULT_FROM_WIN32(GetLastError()) : E_FAIL;
+}
+
+// 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;
+}
+