// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifdef OS_WIN

#include "server/cache_service_manager.h"

#include <windows.h>
#include <shlwapi.h>  // for SHLoadIndirectString
#include <strsafe.h>
#include <wincrypt.h>

#include <memory>
#include <string>

#include "base/const.h"
#include "base/file_util.h"
#include "base/scoped_handle.h"
#include "base/system_util.h"
#include "base/util.h"
#include "server/mozc_cache_service_resource.h"
#include "server/win32_service_state.pb.h"

using std::unique_ptr;

namespace mozc {
namespace {

const uint64 kMinimumRequiredMemorySizeForInstall = 384 * 1024 * 1024;

class ScopedSCHandle {
 public:
  ScopedSCHandle()
      : handle_(NULL) {}
  explicit ScopedSCHandle(SC_HANDLE handle)
      : handle_(handle) {}

  ~ScopedSCHandle() {
    if (NULL != handle_) {
      ::CloseServiceHandle(handle_);
    }
  }

  SC_HANDLE get() const { return handle_; }

  void swap(ScopedSCHandle & other) {
    SC_HANDLE tmp = handle_;
    handle_ = other.handle_;
    other.handle_ = tmp;
  }

 private:
  SC_HANDLE handle_;
};

// Returns a redirector for the specified string resource for Vista or later.
// Returns an empty string if any error occurs.
// See http://msdn.microsoft.com/en-us/library/dd374120.aspx for details.
wstring GetRegistryStringRedirector(int resource_id) {
  const wchar_t kRegistryStringRedirectionPattern[] = L"@%s,-%d";
  const wstring &service_path = CacheServiceManager::GetUnquotedServicePath();
  wchar_t buffer[MAX_PATH] = { L'\0' };

  HRESULT hr = ::StringCchPrintf(
      buffer, arraysize(buffer), kRegistryStringRedirectionPattern,
      CacheServiceManager::GetUnquotedServicePath().c_str(), resource_id);
  if (hr != S_OK) {
    return L"";
  }
  const wstring redirector(buffer);
  // If this program is running on Windows Vista or later,
  // just returns the redirector.
  return redirector;
}

wstring GetDisplayName() {
  return GetRegistryStringRedirector(IDS_DISPLAYNAME);
}

wstring GetDescription() {
  return GetRegistryStringRedirector(IDS_DESCRIPTION);
}

// This function serializes a given message (any type of protobuf message)
// as a wstring encoded by base64.
// Returns true if succeeds.
bool SerializeToBase64WString(const ::google::protobuf::Message &message,
                              wstring *dest) {
  if (dest == NULL) {
    return false;
  }

  const int serialized_len = message.ByteSize();
  unique_ptr<BYTE[]> serialized(new BYTE[serialized_len]);
  if (!message.SerializeToArray(serialized.get(), serialized_len)) {
    LOG(ERROR) << "SerializeAsArray failed";
    return false;
  }

  DWORD base64_string_len = 0;
  BOOL result = ::CryptBinaryToString(serialized.get(), serialized_len,
                                      CRYPT_STRING_BASE64, NULL,
                                      &base64_string_len);
  if (result == FALSE) {
    return false;
  }
  unique_ptr<wchar_t[]> base64_string(new wchar_t[base64_string_len]);
  result = ::CryptBinaryToString(serialized.get(), serialized_len,
                                 CRYPT_STRING_BASE64, base64_string.get(),
                                 &base64_string_len);
  if (result == FALSE) {
    return false;
  }
  dest->assign(base64_string.get(), base64_string_len);
  return true;
}

// This function deserializes a message (any type of protobuf message)
// from the given wstring.  This wstring should be generated by
// SerializeToBase64WString.
// Returns true if succeeds
bool DeserializeFromBase64WString(const wstring &src,
                                  ::google::protobuf::Message *message) {
  if (message == NULL) {
    return false;
  }

  DWORD buffer_len = 0;
  BOOL result = ::CryptStringToBinary(src.c_str(),
                                      src.size(),
                                      CRYPT_STRING_BASE64,
                                      NULL,
                                      &buffer_len,
                                      NULL,
                                      NULL);
  if (result == FALSE) {
    return false;
  }
  unique_ptr<BYTE[]> buffer(new BYTE[buffer_len]);
  result = ::CryptStringToBinary(src.c_str(),
                                 src.size(),
                                 CRYPT_STRING_BASE64,
                                 buffer.get(),
                                 &buffer_len,
                                 NULL,
                                 NULL);
  if (result == FALSE) {
    return false;
  }
  if (!message->ParseFromArray(buffer.get(), buffer_len)) {
    LOG(ERROR) << "ParseFromArray failed";
    return false;
  }
  return true;
}

// A helper function to retrieve a service handle of the cache service
// with specified access rights.
// Returns true if one of the following conditions is satisfied.
//  - A valid service handle is retrieved.  In this case, |handle| owns the
//    retrieved handle.
//  - It turns out w/o any error that the cache service is not installed.
//    In this case, |handle| owns a NULL handle.
// Otherwise, returns false.
bool GetCacheService(DWORD service_controler_rights, DWORD service_rights,
                     ScopedSCHandle *handle) {
  if (NULL == handle) {
    return false;
  }

  ScopedSCHandle sc_handle(::OpenSCManager(NULL, NULL,
                                           service_controler_rights));
  if (NULL == sc_handle.get()) {
    LOG(ERROR) << "OpenSCManager failed: " << ::GetLastError();
    return false;
  }

  ScopedSCHandle service_handle(::OpenService(
      sc_handle.get(), CacheServiceManager::GetServiceName(), service_rights));
  const int error = ::GetLastError();

  if (NULL == service_handle.get() && ERROR_SERVICE_DOES_NOT_EXIST != error) {
    LOG(ERROR) << "OpenService failed: " << error;
    return false;
  }

  // |service_handle| is null if and only if the cache service is not
  // installed.
  service_handle.swap(*handle);
  return true;
}

bool IsServiceRunning(const ScopedSCHandle &service_handle) {
  if (NULL == service_handle.get()) {
    return false;
  }

  SERVICE_STATUS service_status = {};
  if (!::QueryServiceStatus(service_handle.get(), &service_status)) {
    LOG(ERROR) << "QueryServiceStatus failed: " << ::GetLastError();
    return false;
  }

  return service_status.dwCurrentState == SERVICE_RUNNING;
}

bool StartServiceInternal(const ScopedSCHandle &service_handle,
                          const vector<wstring> &arguments) {
  if (arguments.size() <= 0) {
    if (!::StartService(service_handle.get(), 0, NULL)) {
      LOG(ERROR) << "StartService failed: " << ::GetLastError();
      return false;
    }
    return true;
  }

  unique_ptr<const wchar_t*[]> args(new const wchar_t*[arguments.size()]);
  for (size_t i = 0; i < arguments.size(); ++i) {
    args[i] = arguments[i].c_str();
  }
  if (!::StartService(service_handle.get(), arguments.size(), args.get())) {
    LOG(ERROR) << "StartService failed: " << ::GetLastError();
    return false;
  }

  return true;
}

bool StopService(const ScopedSCHandle &service_handle) {
  SERVICE_STATUS status;
  if (!::ControlService(service_handle.get(), SERVICE_CONTROL_STOP, &status)) {
    LOG(ERROR) << "ControlService failed: " << ::GetLastError();
    return false;
  }
  return true;
}

bool SetServiceDescription(const ScopedSCHandle &service_handle,
                           const wstring &description) {
  // +1 for '\0'
  const size_t buffer_length = description.size() + 1;
  unique_ptr<wchar_t[]> buffer(new wchar_t[buffer_length]);
  description._Copy_s(buffer.get(), buffer_length, description.size());
  buffer[buffer_length - 1] = L'\0';

  SERVICE_DESCRIPTION desc = {};
  desc.lpDescription = buffer.get();
  if (!::ChangeServiceConfig2(service_handle.get(),
                              SERVICE_CONFIG_DESCRIPTION, &desc)) {
    LOG(ERROR) << "ChangeServiceConfig2 failed: " << ::GetLastError();
    return false;
  }

  return true;
}

// Set *nice-to-have* features for the cache service.
// We do not care about any failure because it is not critical for the
// functionality of the cache service itself.
void SetAdvancedConfig(const ScopedSCHandle &service_handle) {
  // Windows Vista or later has some nice features as described in the
  // following documents.
  // http://msdn.microsoft.com/en-us/magazine/cc164252.aspx

  // Enable "Delayed Auto-start".
  {
    SERVICE_DELAYED_AUTO_START_INFO info = {};
    info.fDelayedAutostart = TRUE;

    if (!::ChangeServiceConfig2(service_handle.get(),
                                SERVICE_CONFIG_DELAYED_AUTO_START_INFO,
                                &info)) {
      LOG(ERROR) << "ChangeServiceConfig2 failed: " << ::GetLastError();
    }
  }

  // http://blogs.technet.com/richard_macdonald/archive/2007/06/27/1375523.aspx
  // See also http://b/2470180

  // Only SE_INC_BASE_PRIORITY_NAME and SE_CHANGE_NOTIFY are needed.
  // According to MSDN Library, we need not explicitly specify the later.
  // See http://msdn.microsoft.com/en-us/library/ms685976.aspx for details.
  {
    SERVICE_REQUIRED_PRIVILEGES_INFO privileges_info = {};
    privileges_info.pmszRequiredPrivileges = SE_INC_BASE_PRIORITY_NAME
                                             TEXT("\0");
    if (!::ChangeServiceConfig2(service_handle.get(),
                                SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO,
                                &privileges_info)) {
      LOG(ERROR) << "ChangeServiceConfig2 failed: " << ::GetLastError();
    }
  }

  // Remove write privileges from the cache service.
  // See http://msdn.microsoft.com/en-us/library/ms685987.aspx for details.
  // This may restrict glog functions such as LOG(ERROR).
  // TODO(yukawa): Output logging messages as debug strings, or output them
  // to the Win32 event log.
  {
    SERVICE_SID_INFO sid_info = {};
    sid_info.dwServiceSidType = SERVICE_SID_TYPE_RESTRICTED;
    if (!::ChangeServiceConfig2(service_handle.get(),
                                SERVICE_CONFIG_SERVICE_SID_INFO,
                                &sid_info)) {
      LOG(ERROR) << "ChangeServiceConfig2 failed: " << ::GetLastError();
    }
  }
}

// This function updates the following settings of the cache service as
// specified.
//  - Display name
//  - Desctiption
//  - Load type (regardless of the amount of the system memory)
// This function also starts or stops the cache service.
// Win32ServiceState::IsInstalled() will be ignored.  You cannot use this
// function to install nor uninstall the cache service.
bool RestoreStateInternal(const cache_service::Win32ServiceState &state) {
  ScopedSCHandle service_handle;
  const DWORD kSCRights = SC_MANAGER_CONNECT;
  const DWORD kServiceRights =
      GENERIC_READ | GENERIC_WRITE | SERVICE_START | SERVICE_STOP;
  if (!GetCacheService(kSCRights, kServiceRights, &service_handle)
      || (NULL == service_handle.get())) {
    return false;
  }

  if (!::ChangeServiceConfig(service_handle.get(), SERVICE_NO_CHANGE,
                             static_cast<DWORD>(state.load_type()),
                             SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL,
                             NULL, GetDisplayName().c_str())) {
    LOG(ERROR) << "ChangeServiceConfig failed: " << ::GetLastError();
    return false;
  }

  if (!SetServiceDescription(service_handle, GetDescription())) {
    return false;
  }

  // We ignore any failure of advanced configurations because they are
  // *nice-to-have* features.
  SetAdvancedConfig(service_handle);

  const bool now_running = IsServiceRunning(service_handle);

  // If the service was runnning and is not running now, start it unless the
  // load type is not DISABLED.
  if (state.running() && !now_running &&
      (state.load_type() != cache_service::Win32ServiceState::DISABLED)) {
    vector<wstring> arguments(state.arguments_size());
    arguments.resize(state.arguments_size());
    for (size_t i = 0; i < state.arguments_size(); ++i) {
      if (Util::UTF8ToWide(state.arguments(i).c_str(), &arguments[i]) <= 0) {
        return false;
      }
    }
    return StartServiceInternal(service_handle, arguments);
  // If the service is now runnning and was not running, stop it.
  } else if (!state.running() && now_running) {
    return StopService(service_handle);
  // Nothing to do.
  } else {
    return true;
  }

  assert(0);
  return false;
}

// Returns true if a byte array which contains valid QUERY_SERVICE_CONFIG
// is successfully retrieved.  Some members of QUERY_SERVICE_CONFIG points
// memory addresses inside the retrieved byte array.
bool GetServiceConfig(const ScopedSCHandle &service_handle,
                      unique_ptr<char[]> *result) {
  if (NULL == result) {
    return false;
  }

  if (NULL == service_handle.get()) {
    return false;
  }

  DWORD size = 0;
  if (!::QueryServiceConfig(service_handle.get(), NULL, 0, &size) &&
      ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
    LOG(ERROR) << "QueryServiceConfig failed: " << ::GetLastError();
    return false;
  }

  if (size == 0) {
    LOG(ERROR) << "buffer size is 0";
    return false;
  }

  unique_ptr<char[]> buf(new char[size]);
  LPQUERY_SERVICE_CONFIG service_config =
      reinterpret_cast<LPQUERY_SERVICE_CONFIG>(buf.get());

  if (!::QueryServiceConfig(service_handle.get(),
                            service_config, size, &size)) {
    LOG(ERROR) << "QueryServiceConfig failed: " << ::GetLastError();
    return false;
  }

  buf.swap(*result);
  return true;
}
}  // anonymous namespace

bool CacheServiceManager::IsInstalled() {
  ScopedSCHandle service_handle;
  if (!GetCacheService(SC_MANAGER_CONNECT | GENERIC_READ, SERVICE_QUERY_STATUS,
                       &service_handle)
      || (NULL == service_handle.get())) {
    return false;
  }
  return true;
}

bool CacheServiceManager::IsRunning() {
  ScopedSCHandle service_handle;
  if (!GetCacheService(SC_MANAGER_CONNECT | GENERIC_READ, SERVICE_QUERY_STATUS,
                       &service_handle)
      || (NULL == service_handle.get())) {
    return false;
  }
  return IsServiceRunning(service_handle);
}

bool CacheServiceManager::IsEnabled() {
  ScopedSCHandle service_handle;
  if (!GetCacheService(SC_MANAGER_CONNECT | GENERIC_READ, SERVICE_QUERY_CONFIG,
                       &service_handle)
      || (NULL == service_handle.get())) {
    return false;
  }

  // This byte array will contain both QUERY_SERVICE_CONFIG and some
  // string buffers which are reffered by corresponding members of
  // QUERY_SERVICE_CONFIG.  We have to keep the array until we complete
  // all tasks which use the contents of QUERY_SERVICE_CONFIG.
  unique_ptr<char[]> buffer;
  if (!GetServiceConfig(service_handle, &buffer)) {
    return false;
  }
  const LPQUERY_SERVICE_CONFIG service_config =
      reinterpret_cast<const LPQUERY_SERVICE_CONFIG>(buffer.get());
  return service_config->dwStartType == SERVICE_AUTO_START;
}

const wchar_t *CacheServiceManager::GetServiceName() {
  return kMozcCacheServiceName;
}

wstring CacheServiceManager::GetUnquotedServicePath() {
  const string lock_service_path =
      FileUtil::JoinPath(SystemUtil::GetServerDirectory(),
                         kMozcCacheServiceExeName);
  wstring wlock_service_path;
  if (Util::UTF8ToWide(lock_service_path.c_str(), &wlock_service_path) <= 0) {
    return L"";
  }
  return wlock_service_path;
}

wstring CacheServiceManager::GetQuotedServicePath() {
  return L"\"" + GetUnquotedServicePath() + L"\"";
}

bool CacheServiceManager::EnableAutostart() {
  if (!IsInstalled()) {
    return false;
  }

  const bool enough = CacheServiceManager::HasEnoughMemory();

  // Fortunately, the expected service settings can be descried by
  // Win32ServiceState so we can use RestoreStateInternal to change the
  // settings and start the service (if needed).
  // If the system does not have enough memory, disable the service
  // to reduce the performance impact on the boot-time.
  cache_service::Win32ServiceState state;
  state.set_version(1);
  state.set_installed(true);
  state.set_load_type(enough ? cache_service::Win32ServiceState::AUTO_START
                             : cache_service::Win32ServiceState::DISABLED);
  state.set_running(enough);
  const bool result = RestoreStateInternal(state);
  return enough ? result : false;
}

bool CacheServiceManager::DisableService() {
  if (!IsInstalled()) {
    return false;
  }

  // Fortunately, the expected service settings can be descried by
  // Win32ServiceState so we can use RestoreStateInternal to change the
  // settings and stop the service (if needed).
  cache_service::Win32ServiceState state;
  state.set_version(1);
  state.set_installed(true);
  state.set_load_type(cache_service::Win32ServiceState::DISABLED);
  state.set_running(false);
  return RestoreStateInternal(state);
}

bool CacheServiceManager::RestartService() {
  ScopedSCHandle service_handle;
  if (!GetCacheService(SC_MANAGER_CONNECT,
                       SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS,
                       &service_handle)
      || (NULL == service_handle.get())) {
    return false;
  }

  SERVICE_STATUS status;
  if (!::ControlService(service_handle.get(), SERVICE_CONTROL_STOP, &status)) {
    LOG(ERROR) << "ControlService failed: " << ::GetLastError();
  }

  const int kNumTrial = 10;
  for (int i = 0; i < kNumTrial; ++i) {
    SERVICE_STATUS service_status = {};
    if (!::QueryServiceStatus(service_handle.get(), &service_status)) {
      LOG(ERROR) << "QueryServiceStatus failed: " << ::GetLastError();
      return false;
    }
    if (service_status.dwCurrentState != SERVICE_RUNNING) {
      break;
    }
    ::Sleep(200);  // wait for 0.2sec
  }

  return StartServiceInternal(service_handle, vector<wstring>());
}

bool CacheServiceManager::HasEnoughMemory() {
  return SystemUtil::GetTotalPhysicalMemory() >=
      kMinimumRequiredMemorySizeForInstall;
}

bool CacheServiceManager::BackupStateAsString(wstring *result) {
  if (result == NULL) {
    return false;
  }
  result->clear();

  cache_service::Win32ServiceState state;
  state.set_version(1);

  ScopedSCHandle service_handle;
  if (!GetCacheService(SC_MANAGER_CONNECT | GENERIC_READ,
                       SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG,
                       &service_handle)) {
    // If it turns out w/o any error that the cache service is not installed,
    // |GetCacheService| returns true.  We can conclude any other error
    // occurred.
    return false;
  }

  // If the cachse service is actually installed, |service_handle| should have
  // non-null value.
  state.set_installed(NULL != service_handle.get());
  if (!state.installed()) {
    // The cache service is not installed.
    // Use default settings with setting |installed| flag to false.
    state.set_load_type(cache_service::Win32ServiceState::AUTO_START);
    state.set_running(true);
  } else {
    // This byte array will contain both QUERY_SERVICE_CONFIG and some
    // string buffers which are reffered by corresponding members of
    // QUERY_SERVICE_CONFIG.  We have to keep the array until we complete
    // all tasks which use the contents of QUERY_SERVICE_CONFIG.
    unique_ptr<char[]> buffer;
    if (!GetServiceConfig(service_handle, &buffer)) {
      return false;
    }
    const LPQUERY_SERVICE_CONFIG service_config =
        reinterpret_cast<const LPQUERY_SERVICE_CONFIG>(buffer.get());
    // retrieves the server load type.
    state.set_load_type(
        static_cast<cache_service::Win32ServiceState::LoadType>(
            service_config->dwStartType));
    // retrieves the server running status.
    state.set_running(IsServiceRunning(service_handle));
  }

  if (!SerializeToBase64WString(state, result)) {
    return false;
  }

  return true;
}

bool CacheServiceManager::RestoreStateFromString(const wstring &serialized) {
  cache_service::Win32ServiceState state;
  if (!DeserializeFromBase64WString(serialized, &state)) {
    return false;
  }

  return RestoreStateInternal(state);
}

bool CacheServiceManager::EnsureServiceStopped() {
  ScopedSCHandle service_handle;
  const DWORD kSCRights = SC_MANAGER_CONNECT;
  const DWORD kServiceRights = GENERIC_READ | SERVICE_STOP;
  if (!GetCacheService(kSCRights, kServiceRights, &service_handle)) {
    return false;
  }

  if (NULL == service_handle.get()) {
    return true;
  }

  if (!IsServiceRunning(service_handle)) {
    return true;
  }

  if (!StopService(service_handle)) {
    return false;
  }

  return IsServiceRunning(service_handle);
}

}  // namespace mozc
#endif  // OS_WIN
