#!/bin/bash
#
# Copyright (c) 2017 Shawn Rose
# Author: Shawn Rose <shawnandrewrose@gmail.com>
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
#


PREREQ="cryptroot"
prereqs()
{
     echo "$PREREQ"
}

case $1 in
prereqs)
     prereqs
     exit 0
     ;;
esac

. /usr/share/initramfs-tools/hook-functions

die() {
    code="$1"
    msg="$2"
    echo "    (ERROR): $msg" >&2
    exit $1
}

find_binary() {
    bin_name="$1"
    resolved=$(command -v ${bin_name})
    [ -z "$resolved" ] && die 1 "Unable to find ${bin_name}"
    echo "$resolved"
}

find_library() {
    lib_name="$1"
    for lib_path in \
        {/usr,}/libexec/${lib_name} \
        {/usr,}/lib64/${lib_name} \
        {/usr,}/lib/${lib_name} \
        /usr/lib/`uname -m`-linux-gnu*/${lib_name} \
    ; do
        if [ -e "$lib_path" ]; then
            echo "$lib_path"
            return
        fi
    done
    die 1 "Unable to find library ${lib_name}"
}

if [ -n "${FORCE_CLEVIS}" ] && [ "${FORCE_CLEVIS}" != "n" ]; then
    for f in /sbin/cryptsetup /sbin/dmsetup /lib/cryptsetup/askpass; do
        if [ ! -e "${DESTDIR}${f}" ]; then
            die 2 "cryptsetup utility '$f' wasn't found in the generated ramdisk image. "
        fi
    done
fi


copy_exec /usr/bin/clevis-decrypt-tang || die 1 "/usr/bin/clevis-decrypt-tang not found"
copy_exec /usr/bin/clevis-decrypt-sss || die 1 "/usr/bin/clevis-decrypt-sss not found"
copy_exec /usr/bin/clevis-decrypt-null || die 1 "/usr/bin/clevis-decrypt-null not found"
copy_exec /usr/bin/clevis-decrypt || die 1 "/usr/bin/clevis-decrypt not found"
copy_exec /usr/bin/clevis-luks-common-functions || die 1 "/usr/bin/clevis-luks-common-functions not found"
copy_exec /usr/bin/clevis-luks-list || die 1 "/usr/bin/clevis-luks-list not found"
copy_exec /usr/bin/clevis-luks-unlock || die 1 "/usr/bin/clevis-luks-unlock not found"
if [ -x /usr/bin/clevis-decrypt-tpm2 ]; then
    copy_exec /usr/bin/clevis-decrypt-tpm2 || die 1 "/usr/bin/clevis-decrypt-tpm2 not found"
    tpm2_creatprimary_bin=$(find_binary "tpm2_createprimary")
    tpm2_unseal_bin=$(find_binary "tpm2_unseal")
    tpm2_load_bin=$(find_binary "tpm2_load")
    tpm2_flushcontext=$(find_binary "tpm2_flushcontext")
    copy_exec "${tpm2_creatprimary_bin}" || die 1 "Unable to copy ${tpm2_creatprimary_bin}" 
    copy_exec "${tpm2_unseal_bin}" || die 1 "Unable to copy ${tpm2_unseal_bin}"
    copy_exec "${tpm2_load_bin}" || die 1 "Unable to copy ${tpm2_load_bin}"
    copy_exec "${tpm2_flushcontext}" || die 1 "Unable to copy ${tpm2_flushcontext}"
    for _LIBRARY in /usr/lib/loongarch64-linux-gnu/libtss2-tcti-device.so*; do
        if [ -e "${_LIBRARY}" ]; then
            copy_exec "${_LIBRARY}" || die 2 "Unable to copy ${_LIBRARY}"
        fi
    done
    manual_add_modules tpm_crb
    manual_add_modules tpm_tis
fi
if [ -x /usr/bin/clevis-decrypt-tpm1 ]; then
    copy_exec /usr/bin/clevis-decrypt-tpm1 || die 1 "/usr/bin/clevis-decrypt-tpm1 not found"
    copy_exec /usr/libexec/clevis-luks-tpm1-functions || die 1 "/usr/libexec/clevis-luks-tpm1-functions not found"
    copy_exec /usr/lib/loongarch64-linux-gnu/libclevis-tpm1-tcsd-preload.so || die 1 "/usr/lib/loongarch64-linux-gnu/libclevis-tpm1-tcsd-preload.so not found"

    tcsd_bin=$(find_binary "tcsd")
    # libgcc_s.so.* is no longer installed for gcc 2.34+ (no link to libpthread)
    libgcc_s=$(find_library "libgcc_s.so.[1-9]")
    tpm_version_bin=$(find_binary "tpm_version")
    tpm_unsealdata_bin=$(find_binary "tpm_unsealdata")

    copy_exec "${tpm_version_bin}" || die 1 "Unable to copy ${tpm_version_bin}"
    copy_exec "${tpm_unsealdata_bin}" || die 1 "Unable to copy ${tpm_unsealdata_bin}"

    copy_exec "${tcsd_bin}" || die 1 "Unable to copy ${tcsd_bin}"
    copy_exec "${libgcc_s}" || die 1 "Unable to copy ${libgcc_s}"
    copy_file config /etc/tcsd.conf || die 2 "Unable to copy /etc/tcsd.conf"

    mkdir -p "${DESTDIR}/var/lib/tpm" || die 2 "Unable to create /var/lib/tpm"
    cp /var/lib/tpm/* "${DESTDIR}/var/lib/tpm/" || die 2 "Unable to copy /var/lib/tpm"
    chown -R tss:tss "${DESTDIR}/var/lib/tpm" || die 2 "Unable to change owner of /var/lib/tpm"
    chmod -R u=rwX,go= "${DESTDIR}/var/lib/tpm" || die 2 "Unable to change permissions of /var/lib/tpm"

    if (( $(umask) & 0004 )); then
        # Root-only readable initrd filesystem, we need to run as root
        # shellcheck disable=SC2154 # $verbose is a dracut variable
        [ "${verbose}" = "y" ] && echo "Forcing tcsd to run as root"
        sed -i 's/^\([ ]*remote_ops\)/#\1/' "${DESTDIR}/etc/tcsd.conf"
        echo "TCSD_NO_PRIVILEGE_DROP=1" >> "${DESTDIR}/conf/conf.d/clevis"
    fi

    mkdir -p "${DESTDIR}/lib/udev/rules.d" || die 2 "Unable to create /lib/udev/rules.d"
    # shellcheck disable=SC2043
    for rule in 60-tpm-udev.rules; do
      if   [ -e /etc/udev/rules.d/$rule ]; then
        copy_file udev_rule /etc/udev/rules.d/$rule "/lib/udev/rules.d" || die 2 "Unable to copy $rule"
      elif [ -e /lib/udev/rules.d/$rule ]; then
        copy_file udev_rule /lib/udev/rules.d/$rule "/lib/udev/rules.d" || die 2 "Unable to copy $rule"
      fi
    done

    echo "root:x:0:0:root:/root:/bin/bash" >> "${DESTDIR}/etc/passwd"
    echo "root:x:0:" >> "${DESTDIR}/etc/group"

    group_id=`id -g tss` || die 2 "Unable to get tss group ID"
    user_id=`id -u tss` || die 2 "Unable to get tss user ID"
    echo "tss:x:$user_id:$group_id::/var/lib/tpm:/bin/false" >> "${DESTDIR}/etc/passwd"
    echo "tss:x:$group_id:" >>  "${DESTDIR}/etc/group"

    echo "127.0.0.1 localhost" >> "${DESTDIR}/etc/hosts"
    echo "::1 localhost ip6-localhost ip6-loopback" >> "${DESTDIR}/etc/hosts"
    echo "ff02::1 ip6-allnodes" >> "${DESTDIR}/etc/hosts"
    echo "ff02::2 ip6-allrouters" >> "${DESTDIR}/etc/hosts"

    manual_add_modules tpm_tis
fi


luksmeta_bin=$(find_binary "luksmeta")
jose_bin=$(find_binary "jose")
copy_exec "${luksmeta_bin}" || die 2 "Unable to copy ${luksmeta_bin}"
copy_exec "${jose_bin}" || die 2 "Unable to copy ${jose_bin}"


copy_exec /usr/bin/clevis || die 1 "/usr/bin/clevis not found"
curl_bin=$(find_binary "curl")
awk_bin=$(find_binary "awk")
bash_bin=$(find_binary "bash")
copy_exec "${curl_bin}" || die 2 "Unable to copy ${curl_bin} to initrd image"
copy_exec "${awk_bin}" || die 2 "Unable to copy ${awk_bin} to initrd image"
copy_exec "${bash_bin}" || die 2 "Unable to copy ${bash_bin} to initrd image"

# Copy latest versions of shared objects needed for DNS resolution
for so in $(ldconfig -p | sed -nr 's/^\s*libnss_files\.so\.[0-9]+\s.*=>\s*//p'); do
  copy_exec "${so}"
done
for so in $(ldconfig -p | sed -nr 's/^\s*libnss_dns\.so\.[0-9]+\s.*=>\s*//p'); do
  copy_exec "${so}"
done

copy_file data /etc/ssl/certs/ca-certificates.crt || die 2 "Unable to copy certificate bundle to initrd image"
