// 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