summaryrefslogtreecommitdiffstats
path: root/cloud_print/service/win
diff options
context:
space:
mode:
authorvitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-15 04:25:54 +0000
committervitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-15 04:25:54 +0000
commita8a717ddd32ce52531ae4365632d337b7b7ba1f9 (patch)
tree205a8c20b62d41c4d8598cc0616b2e33c7b1e290 /cloud_print/service/win
parentb379cc5a3c5f40eb697edc32ea802ba9d1e41e5f (diff)
downloadchromium_src-a8a717ddd32ce52531ae4365632d337b7b7ba1f9.zip
chromium_src-a8a717ddd32ce52531ae4365632d337b7b7ba1f9.tar.gz
chromium_src-a8a717ddd32ce52531ae4365632d337b7b7ba1f9.tar.bz2
Removed default account for service.
Added required options run-as-user and run-as-password. Added code to set security rights required to run service. File access and chrome binary checks changed from fatal error to just error message. BUG=141243 Review URL: https://chromiumcodereview.appspot.com/10824294 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151652 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cloud_print/service/win')
-rw-r--r--cloud_print/service/win/cloud_print_service.cc113
-rw-r--r--cloud_print/service/win/local_security_policy.cc119
-rw-r--r--cloud_print/service/win/local_security_policy.h34
3 files changed, 222 insertions, 44 deletions
diff --git a/cloud_print/service/win/cloud_print_service.cc b/cloud_print/service/win/cloud_print_service.cc
index 7c88591..99030a8 100644
--- a/cloud_print/service/win/cloud_print_service.cc
+++ b/cloud_print/service/win/cloud_print_service.cc
@@ -19,14 +19,13 @@
#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"
namespace {
const wchar_t kServiceStateFileName[] = L"Service State";
-const wchar_t kUserToRunService[] = L"NT AUTHORITY\\LocalService";
-
// The traits class for Windows Service.
class ServiceHandleTraits {
public:
@@ -71,6 +70,8 @@ void InvalidUsage() {
std::cout << "[";
std::cout << " -" << kInstallSwitch;
std::cout << " -" << kUserDataDirSwitch << "=DIRECTORY";
+ std::cout << " -" << kRunAsUser << "=USERNAME";
+ std::cout << " -" << kRunAsPassword << "=PASSWORD";
std::cout << " [ -" << kQuietSwitch << " ]";
std::cout << "]";
std::cout << "]";
@@ -90,6 +91,9 @@ void InvalidUsage() {
{ kUninstallSwitch, "Uninstalls service." },
{ kStartSwitch, "Starts service. May be combined with installation." },
{ kStopSwitch, "Stops service." },
+ { kRunAsUser, "Windows user to run the service in form DOMAIN\\USERNAME. "
+ "Make sure user has access to printers." },
+ { kRunAsPassword, "Password for windows user to run the service" },
};
for (size_t i = 0; i < arraysize(kSwitchHelp); ++i) {
@@ -128,36 +132,37 @@ std::string GetOption(const std::string& name, const std::string& default,
return tmp;
}
-HRESULT WriteFileAsUser(const FilePath& path, const wchar_t* user,
+HRESULT WriteFileAsUser(const FilePath& path, const string16& user,
const char* data, int size) {
- ATL::CAccessToken thread_token;
- if (!thread_token.OpenThreadToken(TOKEN_DUPLICATE | TOKEN_IMPERSONATE)) {
- LOG(ERROR) << "Failed to open thread token.";
- return HResultFromLastError();
- }
+ ATL::CAccessToken token;
+ ATL::CAutoRevertImpersonation auto_revert(&token);
+ if (!user.empty()) {
+ ATL::CAccessToken thread_token;
+ if (!thread_token.OpenThreadToken(TOKEN_DUPLICATE | TOKEN_IMPERSONATE)) {
+ LOG(ERROR) << "Failed to open thread token.";
+ return HResultFromLastError();
+ }
- ATL::CSid local_service;
- if (!local_service.LoadAccount(user)) {
- LOG(ERROR) << "Failed create SID.";
- return HResultFromLastError();
- }
+ ATL::CSid local_service;
+ if (!local_service.LoadAccount(user.c_str())) {
+ LOG(ERROR) << "Failed create SID.";
+ return HResultFromLastError();
+ }
- ATL::CAccessToken token;
- ATL::CTokenGroups group;
- group.Add(local_service, 0);
+ ATL::CTokenGroups group;
+ group.Add(local_service, 0);
- const ATL::CTokenGroups empty_group;
- if (!thread_token.CreateRestrictedToken(&token, empty_group, group)) {
- LOG(ERROR) << "Failed to create restricted token for " << user << ".";
- return HResultFromLastError();
- }
+ const ATL::CTokenGroups empty_group;
+ if (!thread_token.CreateRestrictedToken(&token, empty_group, group)) {
+ LOG(ERROR) << "Failed to create restricted token for " << user << ".";
+ return HResultFromLastError();
+ }
- if (!token.Impersonate()) {
- LOG(ERROR) << "Failed to impersonate " << user << ".";
- return HResultFromLastError();
+ if (!token.Impersonate()) {
+ LOG(ERROR) << "Failed to impersonate " << user << ".";
+ return HResultFromLastError();
+ }
}
-
- ATL::CAutoRevertImpersonation auto_revert(&token);
if (file_util::WriteFile(path, data, size) != size) {
LOG(ERROR) << "Failed to write file " << path.value() << ".";
return HResultFromLastError();
@@ -182,7 +187,7 @@ class CloudPrintServiceModule
return S_OK;
}
- HRESULT InstallService() {
+ HRESULT InstallService(const string16& user, const string16& password) {
using namespace chrome_launcher_support;
// TODO(vitalybuka): consider "lite" version if we don't want unregister
@@ -192,8 +197,7 @@ class CloudPrintServiceModule
return hr;
if (GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION).empty()) {
- LOG(ERROR) << "Found no Chrome installed for all users.";
- return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ LOG(WARNING) << "Found no Chrome installed for all users.";
}
hr = UpdateRegistryAppId(true);
@@ -206,6 +210,19 @@ class CloudPrintServiceModule
command_line.AppendSwitch(kServiceSwitch);
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 with this user.";
+ }
+ }
+ } else {
+ LOG(ERROR) << "Failed to open security policy.";
+ }
+
ServiceHandle scm;
hr = OpenServiceManager(&scm);
if (FAILED(hr))
@@ -216,7 +233,8 @@ class CloudPrintServiceModule
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,
- kUserToRunService, NULL));
+ user.empty() ? NULL : user.c_str(),
+ password.empty() ? NULL : password.c_str()));
if (!service.IsValid())
return HResultFromLastError();
@@ -277,20 +295,25 @@ class CloudPrintServiceModule
return UninstallService();
if (command_line.HasSwitch(kInstallSwitch)) {
- if (!command_line.HasSwitch(kUserDataDirSwitch)) {
+ if (!command_line.HasSwitch(kUserDataDirSwitch) ||
+ !command_line.HasSwitch(kRunAsUser) ||
+ !command_line.HasSwitch(kRunAsPassword)) {
InvalidUsage();
return S_FALSE;
}
- HRESULT hr = ValidateUserDataDir();
+ HRESULT hr = ProcessServiceState(command_line.HasSwitch(kQuietSwitch));
if (FAILED(hr))
return hr;
- hr = ProcessServiceState(command_line.HasSwitch(kQuietSwitch));
- if (FAILED(hr))
- return hr;
+ CommandLine::StringType run_as_user =
+ command_line.GetSwitchValueNative(kRunAsUser);
+ CommandLine::StringType run_as_password =
+ command_line.GetSwitchValueNative(kRunAsPassword);
+
+ hr = ValidateUserDataDir(run_as_user.c_str());
- hr = InstallService();
+ hr = InstallService(run_as_user.c_str(), run_as_password.c_str());
if (SUCCEEDED(hr) && command_line.HasSwitch(kStartSwitch))
return StartService();
@@ -316,16 +339,16 @@ class CloudPrintServiceModule
return S_FALSE;
}
- HRESULT ValidateUserDataDir() {
+ HRESULT ValidateUserDataDir(const string16& user) {
FilePath temp_file;
const char some_data[] = "1234";
if (!file_util::CreateTemporaryFileInDir(user_data_dir_, &temp_file))
return E_FAIL;
- HRESULT hr = WriteFileAsUser(temp_file, kUserToRunService, some_data,
+ HRESULT hr = WriteFileAsUser(temp_file, user, some_data,
sizeof(some_data));
if (FAILED(hr)) {
LOG(ERROR) << "Failed to write user data. Make sure that account \'" <<
- kUserToRunService << "\'has full access to \'" <<
+ user << "\' has full access to \'" <<
user_data_dir_.value() << "\'.";
}
file_util::Delete(temp_file, false);
@@ -343,6 +366,7 @@ class CloudPrintServiceModule
service_state.FromString(contents);
if (!quiet) {
+ std::cout << "\n";
std::cout << file.value() << ":\n";
std::cout << contents << "\n";
}
@@ -377,11 +401,12 @@ class CloudPrintServiceModule
if (is_valid) {
std::string new_contents = service_state.ToString();
if (new_contents != contents) {
- HRESULT hr = WriteFileAsUser(file, kUserToRunService,
- new_contents.c_str(),
- new_contents.size());
- if (FAILED(hr))
- return hr;
+ 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();
+ }
}
}
}
diff --git a/cloud_print/service/win/local_security_policy.cc b/cloud_print/service/win/local_security_policy.cc
new file mode 100644
index 0000000..c1190dd
--- /dev/null
+++ b/cloud_print/service/win/local_security_policy.cc
@@ -0,0 +1,119 @@
+// 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/local_security_policy.h"
+
+#include <atlsecurity.h>
+#include <ntsecapi.h>
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+
+const wchar_t kSeServiceLogonRight[] = L"SeServiceLogonRight";
+
+#ifndef STATUS_SUCCESS
+#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
+#endif
+
+namespace {
+
+template<class T>
+class ScopedLsaMemory {
+ public:
+ ScopedLsaMemory() : lsa_memory_(NULL) {
+ }
+
+ ~ScopedLsaMemory() {
+ Close();
+ }
+
+ void Close() {
+ if (lsa_memory_) {
+ LsaFreeMemory(lsa_memory_);
+ lsa_memory_ = NULL;
+ }
+ }
+
+ T* Get() const {
+ return lsa_memory_;
+ }
+
+ T** Receive() {
+ Close();
+ return &lsa_memory_;
+ }
+
+ private:
+ T* lsa_memory_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedLsaMemory);
+};
+
+} // namespace
+
+LocalSecurityPolicy::LocalSecurityPolicy() : policy_(NULL) {
+}
+
+LocalSecurityPolicy::~LocalSecurityPolicy() {
+ Close();
+}
+
+void LocalSecurityPolicy::Close() {
+ if (policy_) {
+ LsaClose(policy_);
+ policy_ = NULL;
+ }
+}
+
+bool LocalSecurityPolicy::Open() {
+ DCHECK(!policy_);
+ Close();
+ LSA_OBJECT_ATTRIBUTES attributes = {0};
+ return STATUS_SUCCESS ==
+ ::LsaOpenPolicy(NULL, &attributes,
+ POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
+ &policy_);
+}
+
+bool LocalSecurityPolicy::IsPrivilegeSet(const string16& username,
+ const string16& privilage) const {
+ DCHECK(policy_);
+ ATL::CSid user_sid;
+ if (!user_sid.LoadAccount(username.c_str())) {
+ LOG(ERROR) << "Unable to load Sid for" << username;
+ return false;
+ }
+ ScopedLsaMemory<LSA_UNICODE_STRING> rights;
+ ULONG count = 0;
+ NTSTATUS status = ::LsaEnumerateAccountRights(
+ policy_, const_cast<SID*>(user_sid.GetPSID()), rights.Receive(), &count);
+ if (STATUS_SUCCESS != status || !rights.Get())
+ return false;
+ for (size_t i = 0; i < count; ++i) {
+ if (privilage == rights.Get()[i].Buffer)
+ return true;
+ }
+ return false;
+}
+
+bool LocalSecurityPolicy::SetPrivilege(const string16& username,
+ const string16& privilage) {
+ DCHECK(policy_);
+ ATL::CSid user_sid;
+ if (!user_sid.LoadAccount(username.c_str())) {
+ LOG(ERROR) << "Unable to load Sid for" << username;
+ return false;
+ }
+ LSA_UNICODE_STRING privilege_string;
+ string16 privilage_copy(privilage);
+ privilege_string.Buffer = &privilage_copy[0];
+ privilege_string.Length = wcslen(privilege_string.Buffer) *
+ sizeof(privilege_string.Buffer[0]);
+ privilege_string.MaximumLength = privilege_string.Length +
+ sizeof(privilege_string.Buffer[0]);
+ return STATUS_SUCCESS ==
+ ::LsaAddAccountRights(policy_, const_cast<SID*>(user_sid.GetPSID()),
+ &privilege_string, 1);
+}
+
diff --git a/cloud_print/service/win/local_security_policy.h b/cloud_print/service/win/local_security_policy.h
new file mode 100644
index 0000000..712ab19
--- /dev/null
+++ b/cloud_print/service/win/local_security_policy.h
@@ -0,0 +1,34 @@
+// 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_WIN_LOCAL_SECURITY_POLICY_H_
+#define CLOUD_PRINT_SERVICE_WIN_LOCAL_SECURITY_POLICY_H_
+
+#include <wtypes.h> // Has to be before ntsecapi.h
+#include <ntsecapi.h>
+
+#include "base/basictypes.h"
+#include "base/string16.h"
+
+extern const wchar_t kSeServiceLogonRight[];
+
+class LocalSecurityPolicy {
+ public:
+ LocalSecurityPolicy();
+ ~LocalSecurityPolicy();
+
+ bool Open();
+ void Close();
+
+ bool IsPrivilegeSet(const string16& username,
+ const string16& privilage) const;
+ bool SetPrivilege(const string16& username, const string16& privilage);
+
+ private:
+ LSA_HANDLE policy_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocalSecurityPolicy);
+};
+
+#endif // CLOUD_PRINT_SERVICE_WIN_LOCAL_SECURITY_POLICY_H_