diff options
author | vitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-15 04:25:54 +0000 |
---|---|---|
committer | vitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-15 04:25:54 +0000 |
commit | a8a717ddd32ce52531ae4365632d337b7b7ba1f9 (patch) | |
tree | 205a8c20b62d41c4d8598cc0616b2e33c7b1e290 /cloud_print/service/win | |
parent | b379cc5a3c5f40eb697edc32ea802ba9d1e41e5f (diff) | |
download | chromium_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.cc | 113 | ||||
-rw-r--r-- | cloud_print/service/win/local_security_policy.cc | 119 | ||||
-rw-r--r-- | cloud_print/service/win/local_security_policy.h | 34 |
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_ |