#!/bin/sh
#
# $Id$
#
# Copyright 2019-2020, Juniper Networks, Inc
# All Rights Reserved
#

VERIEXEC=/sbin/veriexec

if ! type is_verified > /dev/null 2>&1; then
    # we'll override this below if appropriate
    is_verified() { return 0; }

    if test -s $VERIEXEC; then
        if $VERIEXEC -i active > /dev/null 2>&1; then
            is_verified() { $VERIEXEC -x $1; }
        fi
    fi
fi

# avoid multiple inclusion and duplicate effort
_VDOT_SH=:

# current state of O_VERIFY
o_verify() {
    set -o | sed -n '/^verify/s,.*[[:space:]],,p'
}

# check if set -o verify is supported
case `o_verify` in
"") skip_o_verify=: ;;
*) skip_o_verify= ;;
esac

##
# o_verify_set want [save]
#
# record current state of verify in $save
# and set it to $want if different
#
o_verify_set() {
    local x=`$skip_o_verify o_verify`

    test -z "$x" && return 0
    test -z "$2" || eval $2=$x
    test "$x" = "$1" && return 0
    case "$1" in
    on) set -o verify;;
    off) set +o verify;;
    esac
}

# in case we want to avoid repeats
dotted=
# try not to include things we cannot verify
vdot() {
    local f rc=0 verify

    o_verify_set on verify
    for f in "$@"
    do
        test -f $f -a -s $f || continue
        if is_verified $f 2> /dev/null; then
            dotted="$dotted $f"
	    . $f
        else
            rc=80               # EAUTH
        fi
    done
    o_verify_set $verify
    return $rc
}

vdot_once() {
    local f rc=0

    for f in "$@"
    do
        case " $dotted " in
        *" $f "*) continue;;
        esac
        vdot $f || rc=$?
    done
    return $rc
}

# for unverified things
dot() {
    local f verify

    o_verify_set off verify
    for f in "$@"
    do
        if test -f $f -a -s $f; then
            dotted="$dotted $f"
            . $f
        fi
    done
    o_verify_set $verify
}

dot_once() {
    local f

    for f in "$@"
    do
        case " $dotted " in
        *" $f "*) continue;;
        esac
        dot $f
    done
}

# unit test
case "/$0" in
*/vdot*) vdot "$@";;
esac
#!/bin/sh

CHECK_EFI_HASH=cb382c2ff5749f93fb33d4dcec7d5d753a5fa3277a08a4bc282223a769f9bfd3

#!/bin/sh

# Copyright (c) 2020, Juniper Networks, Inc.
# All rights reserved.

Exists() {
    case "$1" in
    -?) _t=$1; shift;;
    *) _t=-s;;
    esac
    for x in "$@"
    do
        test $_t $x || continue
        echo $x
        break
    done
}

ECHO=echo

# provide a list of devs with type efi
efi_devs() {
    media list |
        sed -n '/type=efi/s,.*: \([^[:space:]]*\) label.*,\1,p'
}

vdot /usr/libexec/hooks.sh

all_efi_devs() {
    EFI_DEVS=${EFI_DEVS:-$ALL_EFI_DEVS}
}

# the device we booted from
active_efi_dev() {
    if [ -z "$ACTIVE_EFI_DEV" ]; then
        ALL_EFI_DEVS=${ALL_EFI_DEVS:-`efi_devs`}
        if test -c /dev/oamctl; then
            efi_filter=`oamctl get-last-boot-device 2> /dev/null |
            sed 's,HD.*\([0-9]\)\.\([0-9]\),\1p\2,'`
        fi
        efi_filter=${efi_filter:-`efivar -Nn 8be4df61-93ca-11d2-aa0d-00e098032b8c-BootCurrent 2> /dev/null |
        sed 's,^0*\(.\): 0\([0-9]\).*,\1p\2,'`}
        efi_filter=${efi_filter:-`kenv loaddev | sed 's,disk,,;s,[0-9]:,,'`}
        for d in $ALL_EFI_DEVS
        do
            case "$efi_filter" in
            *p0) # not valid - assume 1st dev is it
                ACTIVE_EFI_DEV=$d; break;;
            esac
            case "$d" in
            *$efi_filter*) ACTIVE_EFI_DEV=$d; break;;
            esac
        done
    fi
}

# the device we didn't boot from
inactive_efi_dev() {
    if [ -z "$INACTIVE_EFI_DEV" ]; then
        active_efi_dev
        for d in $ALL_EFI_DEVS
        do
            case "$d" in
            $ACTIVE_EFI_DEV) continue;;
            esac
            INACTIVE_EFI_DEV="$INACTIVE_EFI_DEV $d"
        done
    fi
}

# can override the above or just add hooks
vdot /usr/libexec/update-efi.d/*.sh

# defaults we run after any platform specific hooks
add_hooks update_efi_devs_hooks all_efi_devs
add_hooks active_efi_dev_hooks active_efi_dev

# assumes called from update_efi
_update_esp() {
    for d in "$@"
    do
        dev=/dev/${d#/dev/}
        if [ -c $dev ]; then
            mkdir -p $efimnt
            mount -t msdosfs $dev $efimnt || continue
            bootefi=$efimnt/efi/boot/bootaa64.efi
            utc=`test -s $bootefi && what $bootefi | sed -n '/UTC=/s,.*=,,p'`
            if [ ${utc:-0} -gt 1751354881 ]; then
                $ECHO Skipping EFI on $d: newer
                umount $efimnt
                return
            fi
            case "$EFI_TAR" in
            */os-boot-efi[/-]*)
                if [ -s $bootefi.esig ]; then
                    have_hash=`sha256 < $bootefi.esig`
                else
                    have_hash=
                fi
                if [ x$have_hash != x$CHECK_EFI_HASH ]; then
                    $ECHO Updating EFI on $d ...
                    tar xf $EFI_TAR -C $efimnt
                fi
                ;;
            *)  # hope you know what you are doing!
                tar xf $EFI_TAR -C $efimnt
                ;;
            esac
            umount $efimnt
        fi
    done
}

##
# update efi on specified (or all type efi) devices
update_efi() {
    while :
    do
        case "$1" in
        *=*) eval "$1"; shift;;
        -q) ECHO=:; shift;;
        -t) EFI_TAR=$2; shift 2;;
        -v) ECHO=echo; shift;;
	-x) shift; set -x;;
        *) break;;
        esac
    done

    EFI_TAR=${EFI_TAR:-`Exists -s /packages/sets/active/os-boot-efi/contents/efi.tar /usr/mdec/efi.tar`}

    [ -n "$EFI_TAR" ] || return 1
    # make sure it is verified
    if [ -x /sbin/veriexec ]; then
	veriexec -x $EFI_TAR || return 1
    fi
    if [ -d /efi ]; then
        efimnt=/efi
    else
        efimnt=/tmp/efi$$
    fi
    ALL_EFI_DEVS=${ALL_EFI_DEVS:-`efi_devs`}
    run_hooks update_efi_devs_hooks
    for d in "${@:-$EFI_DEVS}"
    do
        case "$d" in
        active) active_efi_dev; d=$ACTIVE_EFI_DEV;;
        inactive) inactive_efi_dev; d="$INACTIVE_EFI_DEV";;
        esac
        _update_esp $d
    done
    case "$efimnt" in
    /tmp/*) rmdir $efimnt > /dev/null 2>&1 || true;;
    esac
}

case "/$0" in
*/update-efi*)
    case ",$DEBUG_SH," in
    *,update-efi,*) set -x;;
    esac
    update_efi "$@"
    ;;
esac

efi_version=`kenv -q efi-version`
case "$efi_version" in
[1-9]*) ;;			# ok
*) exit 0;;			# we should not be here
esac

case "$1" in
activate)
    case "$PKG_COMMAND" in
    add|setop) # only update on pkg add or activate of pending set
        run_hooks active_efi_dev_hooks
        EFI_TAR=${PKGDIR}/contents/efi.tar
        update_efi -v active
        ;;
    esac
    ;;
esac
