#!/bin/bash
# barium helper scripts
# author: rosalinux.ru: betcher_

# Не используем root_only и цвета из b-lib/lib,
# а также SYSMNT из /etc/initvars чтобы не сорсить ничего в скрипт

PATH="/bin:/usr/bin:/sbin:/usr/sbin"
unset BOOTPART
unset SET
unset FORCE

red='\033[0;31m'
green='\033[1;32m'
yellow='\033[0;33m'
default='\033[0m'

fprint=/root/.fingerprint

SYSMNT="/.memory"
if [ $(id -un) != "root" ] ; then
    echo -  "${red}You must be root !!!${default}"
    exit 1
fi

HLP () {
    placeholder__="$(basename $0 |sed 's/./ /g')"
    echo "
$(basename $0) - Utility for checking unauthorized system changes

Usage:
    $(basename $0)                     - set fingerprint if file not exists or
    $placeholder__                       check if fingerprint found
    $(basename $0) -f                  - set fingerprint
    $(basename $0) /home/user/.fprint  - set or check fingerprint with own path

Parameters:
    -h | --help            - this help
    -s | --set             - set new fingerprint
    -b | --boot-part       - specify boot partition
    -f | --force           - skip warnings
"
    exit
}

setfingerprint () {
    setbootloader () {
        [ "$BOOTPART" ] || BOOTPART=$(realpath /dev/disk/by-label/BARIUM_EFI)
        if [ $(echo "$BOOTPART" | wc -w) -ne 1 -o "$BOOTPART" == '/dev/disk/by-label/BARIUM_EFI' ] ; then
            echo "Please specify boot partition device name (aka /dev/sda1 )"
            read BOOTPART
        fi
        PARTUUID=$(blkid $BOOTPART -s PARTUUID -o value)
        if [ -z $PARTUUID ] ; then
            echo "Unknown device $PART"
            exit ${LINENO}
        fi
        md5sum=$(md5sum $BOOTPART |cut -f1 -d ' ')
        echo "BOOTPARTUUID=$PARTUUID" >> $fprint
        echo "BOOTPARTMD5=$md5sum" >> $fprint
    }

    setmodules () {
        for module in $(barium ls --hidetop --raw '$dname_source/$bname_source') ; do
            echo "$module processing..."
            echo $SYSMNT/layer-base/0/_REPOLIST |grep $(echo $module |cut -f 5,6 -d '/') || \
            echo "md5sum ${module}#$(md5sum $module |cut -f1 -d ' ')" >> $fprint
        done
    }

    sign () {
        module=$(get_token_lib)
        [ -n "$module" ] && \
        pkcs11-tool --module "$module" --login --sign --input-file "$fprint" --output-file "${fprint}.sign" \
      --mechanism  SHA512-RSA-PKCS --token-label rosa_token
        if [ $? != 0 -o -z "$module" ] ; then
            echo "Error. $fprint not signed."
            echo "Function available with Barium installed on token"
        fi
        }

    cmdline () {
        echo "CMDLINE=$(cat /proc/cmdline)" >> $fprint
    }

    devSN (){
        SN=$(getSN)
        echo "DEVSERIALNUMBER=$SN" >> $fprint
    }

    devSN
    setbootloader
    cmdline
    setmodules
    sign
    # touch заствит overly/aufs создать копию скрипта в changes, находящийся на шифрованном разделе. Подменить сложнее.
    touch $0
}

check () {
    EXITCODE=0

    get_fprint="cat ${fprint}"
    if [ ! -f ${fprint}.sign ] ; then
        if [ ! "$FORCE" ] ; then
            echo -e ${red}"Warning! Fingerprint file not signed!"${default}
            echo "ENTER to continue, ctrl-c to abort"
            read qqq
        fi
    elif ! pkcs11-tool --module librtpkcs11ecp.so --verify --mechanism  SHA512-RSA-PKCS \
  --input-file $fprint --signature-file ${fprint}.sign --token-label rosa_token ; then
        echo -e ${red}"Sign check for $fprint - failed!"${default}
        echo -e ${red}"Fingerprint file may be compromised!"${default}
        echo "ENTER to continue, ctrl-c to abort"
        read qqq
    fi

    BOOTPARTUUID=$($get_fprint 2>/dev/null |grep BOOTPARTUUID |cut -f2 -d '=')
    BOOTPARTMD5=$($get_fprint 2>/dev/null |grep BOOTPARTMD5 |cut -f2 -d '=')
    REALMD5=$(md5sum /dev/disk/by-partuuid/$BOOTPARTUUID |cut -f1 -d ' ')
    if [ $BOOTPARTMD5 != $REALMD5 ] ; then
        echo_exit "Boot partition compromised!"
        EXITCODE=$(( $EXITCODE + 1 ))
    else
        checked "Bootloaders partition"
    fi

    DEVSERIALNUMBER=$($get_fprint 2>/dev/null |grep DEVSERIALNUMBER |cut -f2 -d '=')
    SN=$(getSN)
    if [ "$DEVSERIALNUMBER" != "$SN" ] ; then
        echo_exit "device serial number modified. Wrong device!!!"
        EXITCODE=$(( $EXITCODE + 1 ))
    else
        checked "Serial number checked"
    fi

    CMDLINE=$($get_fprint 2>/dev/null |grep CMDLINE |sed 's/CMDLINE=//')
    REALCMDLINE=$(cat /proc/cmdline)
    if [ "$CMDLINE" != "$REALCMDLINE" ] ; then
        echo_exit "kernel cmdline modified"
        EXITCODE=$(( $EXITCODE + 1 ))
    else
        checked "Kernel cmdline"
    fi
    WARNINGS=$(barium update -cl 2>&1 |grep 'not equal')
    NONTRUSTED=''
    for module in  $(barium ls --hidetop --raw '$dname_source/$bname_source') ; do
        echo $WARNINGS |grep -q $(basename $module) && echo_exit "Check $module" && continue
        grep -qw $(basename $module) ${SYSMNT}/layer-base/0/_REPOLIST && checked "Check $module" && continue
        md5=$($get_fprint 2>/dev/null |grep "md5sum $module" |cut -f2 -d '#')
        if [ -z "$md5" ] ; then
            EXITCODE=$(( $EXITCODE + 1 ))
            echo_exit "Unknown $module"
            NONTRUSTED="$module $NONTRUSTED"
        elif [ "$md5" != $(md5sum $module |cut -f1 -d ' ') ] ; then
            EXITCODE=$(( $EXITCODE + 1 ))
            echo_exit "Check $module"
            NONTRUSTED="$module $NONTRUSTED"
        else
            checked "Check $module"
        fi
    done
    echo -e ${yellow}"\nBarium update -cl warnings:\n============================================================================="${default}
    echo $WARNINGS
    echo -e "\nExecutable files in non trusted layers:"
    echo -e "\n${yellow}Changes:\n============================================================================="${default}
    find $SYSMNT/changes -executable -type f
    for a in $NONTRUSTED ; do
        BUNDLE=$(barium ls --raw '$bundle $dname_source/$bname_source' |grep $a)
        echo -e "\n${yellow}${a}:${default}\n============================================================================="
        find $BUNDLE  -executable -type f | while read a ; do
            REWRITE="\e[25D\e[1A\e[K"
            [ $str_n ] || str_n=1
            if [ $str_n -gt 20 ] ; then
                sleep 0.0001
                echo -e "${REWRITE}And ${red}$str_n${default} other non trusted executable files..."
            else
                echo $a
            fi
        str_n=$(( $str_n + 1 ))
        done
    done
    return $EXITCODE
}

getSN(){
    local SN="unknown"
    PART=$(realpath /dev/disk/by-label/ROSA-SYSTEM)
    [ "$PART" !=  '/dev/disk/by-label/ROSA-SYSTEM' ] && \
    SN=$(udevadm info -a -p  $(udevadm info -q path -n $PART) |grep serial |head -n1 |cut -f3 -d '=')
    echo $SN
}

get_token_lib(){
    ret=$(barium token |cut -f2 -d ' ')
    if [ $(echo $ret |wc -w) == 1 ] ; then
      if echo $ret | grep -qE '.*\.so$' ; then
        echo $ret
        return
      elif echo $ret | grep -qE '.*\.xzm$' ; then
        echo "Token lib not found, you need to inst mod $ret" 1>&2
        return 1
      else
        echo "Token not found? or token unknown" 1>&2
        return 1
      fi
    elif [ $(echo $ret |wc -w) == 0 ] ; then
      echo "Token not found? or token unknown" 1>&2
      return 1
    else
      echo "More then one token plugged" 1>&2
    fi
}

checked () {
    echo -e "$@ -- ${green}OK${default}"
}

echo_exit () {
    echo -e "$1 -- ${red}Warning!${default}"
    [ $2 ] && exit $2
}

while [ -n "$1" ] ; do
    case "${1}" in
    "-h" | "--help")  HLP ;;
    "-s" | "--set" )  SET=yes ;;
    "-b" | "--boot-part" ) shift
                           BOOTPART="$1" ;;
    "-f" | "--force") FORCE=yes ;;
    *) FPRINT="$1";;
    esac
shift
done

if ! df ${SYSMNT}/layer-base/1/ |grep -q '/dev/mapper/' && [ ! "$FORCE" ] ; then
    echo -e ${red}"Warning, partition for ROSA-DATA not encrypted,"${default}
    echo -e ${red}"this use cannot be considered protection."${default}
    echo "ENTER to continue, ctrl-c to abort"
    read qqq
    echo ''
fi

[ "$FPRINT" ] && fprint="$(realpath $FPRINT)"

if [ -f "$fprint" -a ! "$SET" ] ; then
    echo -e "fingerprint: $fprint - found.\n${yellow}Check...${default}"
    check
else
    echo -e "fingerprint: ${fprint}.\n${yellow}Set...${default}"
    rm -f ${fprint}
    setfingerprint
fi
