#
#   Copyright (C) 2022 SUSE LLC
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#   Written by Olaf Kirch <okir@suse.com>

. /etc/sysconfig/fde-tools
. $SHAREDIR/uefi

##################################################################
# Edit a variable in /etc/default/grub
##################################################################
function grub_set_control {

    sysconfig_set_variable /etc/default/grub "$@"
}

##################################################################
# Obtain the password that the root partition was encrypted with.
##################################################################
function grub_get_fde_password {

    . /etc/default/grub

    if [ -z "$GRUB_CRYPTODISK_PASSWORD" ]; then
	return 1
    fi

    echo "$GRUB_CRYPTODISK_PASSWORD"
}

##################################################################
# Change the cryptomount command in early boot grub.cfg
# This turns something like this:
#	cryptomount -u XX-YY-ZZ -p defpass
# into something like this:
#       tpm2_key_protector_init bla bla bla
#       if ! cryptomount -u XX-YY-ZZ -k tpm2; then
#		cryptomount -u XX-YY-ZZ
#	fi
#	tpm2_key_protector_clear
##################################################################
function grub_frob_cryptomount_command {

    orig_cmd="$*"

    crypto_cmd=""
    orig_protector=""

    while [ $# -gt 0 ]; do
	case $1 in
	-u|--uuid)
		crypto_cmd+=" -u $2"
		shift 2;;
	-p|--password)
		shift 2;;
	-k|--protector)
		orig_protector="$1 $2"
		shift 2;;
	*)	crypto_cmd+=" $1"
		shift;;
	esac
    done

    cat <<-EOF

tpm2_key_protector_init -b $FDE_SEAL_PCR_BANK -p $FDE_SEAL_PCR_LIST -k \$prefix/$sealed_key_file
if ! $crypto_cmd -k tpm2; then
    $crypto_cmd $orig_protector
fi
tpm2_key_protector_clear

EOF
}

##################################################################
# Update the grub.cfg residing on the EFI partition to properly
# unseal the TPM protected LUKS partition
##################################################################
function grub_update_early_config_old {

    grub_dir="$1"
    sealed_key_file="$2"

    grub_cfg_file="${grub_dir}/grub.cfg"

    cat $grub_cfg_file | while read line; do
	case "$line" in
	*cryptomount*)
	    grub_frob_cryptomount_command $line;;
	*)
	    echo "$line";;
	esac
    done >$grub_cfg_file.new

    mv $grub_cfg_file.new $grub_cfg_file
}

function grub_update_early_config {

    sealed_key_file="$1"
    sealed_pcr_bank="$2"
    sealed_pcr_list="$3"

    grub_set_control GRUB_ENABLE_CRYPTODISK "y"
    grub_set_control GRUB_TPM2_SEALED_KEY "$sealed_key_file"
    grub_set_control GRUB_CRYPTODISK_PASSWORD ""
    if [ -n "$sealed_key_file" ]; then
	grub_set_control GRUB_TPM2_PCR_BANK "$sealed_pcr_bank"
	grub_set_control GRUB_TPM2_PCR_LIST "$sealed_pcr_list"
    fi

    extra_opts=
    if [ "$(ls /boot/efi/EFI)" = "BOOT" ]; then
	extra_opts="--removable"
    fi

    shim-install --no-grub-install $extra_opts
}

function grub_enable_fde_with_tpm {

    luks_keyfile="$1"

    grub_efi_dir=$(uefi_get_current_efidir)
    if [ -z "$grub_efi_dir" ]; then
	return 1
    fi

    # First update grub.cfg...
    grub_update_early_config sealed.key "$FDE_SEAL_PCR_BANK" "$FDE_SEAL_PCR_LIST"

    # ... then seal the key against a PCR9 value that covers grub.cfg
    tpm_seal_secret "${luks_keyfile}" "${grub_efi_dir}" "$grub_efi_dir/sealed.key"
}

function grub_enable_fde_without_tpm {

    grub_efi_dir=$(uefi_get_current_efidir)
    if [ -z "$grub_efi_dir" ]; then
	return 1
    fi

    # Update grub.cfg inside the EFI partition without enabling the TPM
    # key protector.
    grub_update_early_config
}
