chromium/chrome/credential_provider/extension/extension_utils.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/credential_provider/extension/extension_utils.h"

#include "base/strings/string_util.h"
#include "chrome/credential_provider/extension/extension_strings.h"
#include "chrome/credential_provider/extension/os_service_manager.h"
#include "chrome/credential_provider/extension/scoped_handle.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h"

namespace credential_provider {

namespace extension {

DWORD GetGCPWExtensionServiceStatus(SERVICE_STATUS* service_status) {
  DCHECK(service_status);

  credential_provider::extension::OSServiceManager* service_manager =
      credential_provider::extension::OSServiceManager::Get();
  SERVICE_STATUS internal_service_status;
  DWORD error_code =
      service_manager->GetServiceStatus(&internal_service_status);
  if (error_code != ERROR_SUCCESS) {
    LOGFN(ERROR) << "service_manager->GetServiceStatus failed win32="
                 << error_code;
    return error_code;
  }
  *service_status = internal_service_status;
  return ERROR_SUCCESS;
}

bool IsGCPWExtensionRunning() {
  SERVICE_STATUS service_status;
  DWORD error_code = GetGCPWExtensionServiceStatus(&service_status);
  if (error_code == ERROR_SUCCESS) {
    return service_status.dwCurrentState == SERVICE_RUNNING;
  }

  return false;
}

DWORD InstallGCPWExtension(const base::FilePath& extension_exe_path) {
  SERVICE_STATUS service_status;
  DWORD error_code = GetGCPWExtensionServiceStatus(&service_status);
  if (error_code != ERROR && error_code != ERROR_SERVICE_DOES_NOT_EXIST) {
    LOGFN(ERROR)
        << "service_manager->GetGCPWExtensionServiceStatus failed win32="
        << error_code;
    return error_code;
  }

  credential_provider::extension::OSServiceManager* service_manager =
      credential_provider::extension::OSServiceManager::Get();
  if (error_code == ERROR_SUCCESS) {
    if (service_status.dwCurrentState != SERVICE_STOPPED) {
      error_code = service_manager->ControlService(SERVICE_CONTROL_STOP);
      if (error_code != ERROR_SUCCESS) {
        LOGFN(ERROR) << "service_manager->ControlService failed win32="
                     << error_code;
        return error_code;
      }

      error_code = service_manager->WaitForServiceStopped();
      if (error_code != ERROR_SUCCESS) {
        LOGFN(ERROR) << "service_manager->WaitForServiceStopped failed win32="
                     << error_code;
        return error_code;
      }
    }

    error_code = service_manager->DeleteService();
    if (error_code != ERROR_SUCCESS) {
      LOGFN(ERROR) << "service_manager->DeleteService failed win32="
                   << error_code;
      return error_code;
    }
  }

  credential_provider::extension::ScopedScHandle sc_handle;
  error_code = service_manager->InstallService(extension_exe_path, &sc_handle);
  if (error_code != ERROR_SUCCESS) {
    LOGFN(ERROR) << "service_manager->InstallService failed win32="
                 << error_code;
    return error_code;
  }

  return ERROR_SUCCESS;
}

DWORD UninstallGCPWExtension() {
  credential_provider::extension::OSServiceManager* service_manager =
      credential_provider::extension::OSServiceManager::Get();
  SERVICE_STATUS service_status;
  DWORD error_code = service_manager->GetServiceStatus(&service_status);
  if (error_code != ERROR_SUCCESS &&
      error_code != ERROR_SERVICE_DOES_NOT_EXIST) {
    LOGFN(ERROR) << "service_manager->GetServiceStatus failed win32="
                 << error_code;
    return error_code;
  }

  if (error_code == ERROR_SERVICE_DOES_NOT_EXIST) {
    LOGFN(WARNING) << "Service wasn't found when attempting to delete";
    return ERROR_SUCCESS;
  }

  // Update the service start type to manual just in case anything goes wrong,
  // but we don't want service keep running at Windows boot.
  error_code = service_manager->ChangeServiceConfig(
      SERVICE_NO_CHANGE, SERVICE_DEMAND_START, SERVICE_NO_CHANGE);

  if (error_code != ERROR_SUCCESS) {
    LOGFN(ERROR) << "service_manager->ChangeServiceConfig failed win32="
                 << error_code;
    return error_code;
  }

  if (service_status.dwCurrentState != SERVICE_STOPPED) {
    error_code = service_manager->ControlService(SERVICE_CONTROL_STOP);
    if (error_code != ERROR_SUCCESS) {
      LOGFN(ERROR) << "service_manager->ControlService failed win32="
        << error_code;
      return error_code;
    }

    error_code = service_manager->WaitForServiceStopped();
    if (error_code != ERROR_SUCCESS) {
      LOGFN(ERROR) << "service_manager->WaitForServiceStopped failed win32="
        << error_code;
      return error_code;
    }
  }

  error_code = service_manager->DeleteService();
  if (error_code != ERROR_SUCCESS) {
    LOGFN(ERROR) << "service_manager->DeleteService failed win32="
      << error_code;
    return error_code;
  }

  return ERROR_SUCCESS;
}

bool IsGCPWExtensionEnabled() {
  return GetGlobalFlagOrDefault(extension::kEnableGCPWExtension, 1);
}

std::wstring GetLastSyncRegNameForTask(const std::wstring& task_name) {
  return base::ToLowerASCII(task_name) + L"_last_sync_time";
}

}  // namespace extension
}  // namespace credential_provider