#!/bin/bash
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: Copyright 2024 SUSE LLC
# SPDX-FileCopyrightText: Copyright 2024 Richard Brown

set -euo pipefail

# Setup logging
exec 3>&1 4>&2
trap 'exec 2>&4 1>&3' 0 1 2 3
exec 1>>/var/log/yuga-check.log 2>&1

boo1228416() {
    # Problem: boo1228416. TPM2 using pcr hashes not pcrlock
    # Solution: Configure and enrol pcrlock for FDE

    # Determine root device
    rootdev=/dev/$(dmsetup deps -o devname /dev/mapper/yuga_root | cut -d '(' -f2 | cut -d ')' -f1)
    # Check for failure conditions
    tpm2hashpcrs=$(cryptsetup luksDump ${rootdev} | grep 'tpm2-hash-pcrs:' | tr -d ' \t' | cut -d ':' -f2)
    tpm2pcrlock=$(cryptsetup luksDump ${rootdev} | grep 'tpm2-pcrlock:' | tr -d ' \t' | cut -d ':' -f2)
    # For boo1228416 to be an issue hashpcrs must be 7 and pcrlock must be false. Be paranoid, only match on both
    if [ "${tpm2hashpcrs}" == "7" ] && [ "${tpm2pcrlock}" == "false" ]; then
        echo "boo1228416 detected - TPM2 using pcr hashes not pcrlock - correcting"

        # Need a keyfile to avoid requesting the recovery key when re-enrolling
        keyfile=$(mktemp /tmp/yuga-check.XXXXXXXXXX)
        dd bs=512 count=4 if=/dev/urandom of=${keyfile} iflag=fullblock
        chmod 400 ${keyfile}

        # Should be slot 2, but better to check and be sure
        tpm2slot=$(systemd-cryptenroll ${rootdev} | grep tpm2 | xargs | cut -d ' ' -f1)

        # Writing keyfile to slot 31 (end of the LUKS2 space) to avoid clashes with any customisation/extra keys
        cryptsetup luksAddKey --token-only --batch-mode --new-key-slot=31 ${rootdev} ${keyfile}

        # Drop existing enrollment and re enroll
        systemd-cryptenroll --wipe-slot=${tpm2slot} ${rootdev}
        systemd-cryptenroll --unlock-key-file=${keyfile} --tpm2-device=auto ${rootdev}

        # Wipe out keyfile and keyfile keyslot
        systemd-cryptenroll --wipe-slot=31 ${rootdev}
        rm ${keyfile}

        echo "boo1228416 corrected"
    fi
}

boo1234234() {
    # Problem: boo1234234 and related bugs. TPM2 enrolments failing because PCR0 invalidated by firmware updates.
    # Solution: Stop measuring PCR0 and update-predictions with the reduced PCR list

    # Only run if fde-tools is configured
    if test -e /etc/sysconfig/fde-tools ; then
        . /etc/sysconfig/fde-tools

        if [ "${FDE_SEAL_PCR_LIST}" = "0,4,5,7,9" ]; then
            echo "boo1234234 detected - PCR0 measured for TPM FDE sealing - correcting"
            echo "FDE_SEAL_PCR_LIST=4,5,7,9" > /etc/sysconfig/fde-tools
            sdbootutil -v update-predictions
            echo "boo1234234 corrected"
        fi
    fi
}

boo1243182() {
    # Problem: Yuga should be using Zypp's single RPM transaction backend
    # Solution: Add 'techpreview.ZYPP_SINGLE_RPMTRANS=1' to zypp.conf 

    if ! grep -qxF 'techpreview.ZYPP_SINGLE_RPMTRANS=1' /etc/zypp/zypp.conf ; then
         echo 'boo1243182 detected - Not using ZYPP_SINGLE_RPMTRANS - correcting'
         echo 'techpreview.ZYPP_SINGLE_RPMTRANS=1' >> /etc/zypp/zypp.conf
         echo 'boo1243182 corrected'
    fi
}

boo1246605() {
    # Problem: Yuga should have 'ro=vfs' as a mount attribute for / in /etc/fstab
    # Solution: Add 'ro=vfs' as a mount attribute for / in /etc/fstab
    if gawk '$2 == "/" && $4 != "compress=zstd:1,ro=vfs"' /etc/fstab | grep -q / ; then
        echo 'boo1246605 detected - fstab not using ro=vfs for / - correcting'
        gawk -i inplace '$2 == "/" && $4 != "compress=zstd:1,ro=vfs" { $4 = "compress=zstd:1,ro=vfs" } { print $0 }' /etc/fstab
        echo 'boo1246605 corrected'
    fi
}

# Active fixes executed in order of importance
boo1246605
boo1243182
boo1234234

# Deprecated fixes likely to be dropped in future Yuga-check releases
boo1228416
