chromium/chrome/enterprise_companion/installer_mac.mm

// Copyright 2024 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/enterprise_companion/installer.h"

#include <optional>

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/process/launch.h"
#include "base/time/time.h"
#include "chrome/enterprise_companion/enterprise_companion_branding.h"
#include "chrome/enterprise_companion/enterprise_companion_version.h"
#include "chrome/enterprise_companion/installer_paths.h"
#include "chrome/enterprise_companion/installer_posix.h"
#include "third_party/abseil-cpp/absl/cleanup/cleanup.h"

namespace enterprise_companion {

namespace {

constexpr base::TimeDelta kKSAdminTimeout = base::Minutes(5);

// Register the installation with ksadmin.
bool RegisterInstallation(const base::FilePath& install_directory) {
  base::FilePath ksadmin_path = GetKSAdminPath();
  if (!base::PathExists(ksadmin_path)) {
    LOG(ERROR) << "Could not locate ksadmin.";
    return false;
  }

  base::CommandLine command_line(ksadmin_path);
  command_line.AppendArg("-r");
  command_line.AppendArg("-P");
  command_line.AppendArg(ENTERPRISE_COMPANION_APPID);
  command_line.AppendArg("-v");
  command_line.AppendArg(kEnterpriseCompanionVersion);
  command_line.AppendArg("-x");
  command_line.AppendArgPath(install_directory);
  command_line.AppendArg("-S");

  int exit_code = -1;
  base::Process process = base::LaunchProcess(command_line, {});
  if (!process.IsValid()) {
    LOG(ERROR) << "Failed to launch ksadmin";
    return false;
  } else if (!process.WaitForExitWithTimeout(kKSAdminTimeout, &exit_code)) {
    LOG(ERROR) << "Failed to wait for ksadmin to register the installation.";
    return false;
  } else if (exit_code != 0) {
    LOG(ERROR) << "Failed to register the installation with ksadmin. "
               << "Recieved exit code " << exit_code;
    return false;
  }

  return true;
}

}  // namespace

bool Install() {
  std::optional<base::FilePath> install_directory = GetInstallDirectory();
  if (!install_directory) {
    LOG(ERROR) << "Failed to get install directory";
    return false;
  }

  base::FilePath exe_path = install_directory->AppendASCII(kExecutableName);
  base::FilePath backup_exe = exe_path.AddExtensionASCII("old");
  if (base::PathExists(exe_path) && !base::CopyFile(exe_path, backup_exe)) {
    LOG(ERROR) << "Failed to backup existing installation.";
    return false;
  }
  absl::Cleanup delete_backup_exe = [&] { base::DeleteFile(backup_exe); };

  if (!InstallToDir(*install_directory)) {
    return false;
  }

  if (!RegisterInstallation(*install_directory)) {
    if (base::PathExists(backup_exe)) {
      if (!base::Move(backup_exe, exe_path)) {
        LOG(ERROR) << "Failed to restore installation backup.";
      }
    } else {
      if (!base::DeleteFile(exe_path)) {
        LOG(ERROR) << "Failed to clean installation after failure";
      }
    }
    return false;
  }

  return true;
}

}  // namespace enterprise_companion