#!/bin/sh -efu
#
# Configures the system bootloader to load the kernel in
# IMA fix mode and reboots the system. It then is used to
# run the signing process and to configure the system bootloader
# to load the kernel in IMA enforce mode and to reboot the system.
#
# Copyright (C) 2026  Paul Wolneykien.
#
# 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

PROG="${0##*/}"
VERSION='0.1.0'

if [ -e /etc/chpkgcon.conf ]; then
    # shellcheck disable=SC1091
    . /etc/chpkgcon.conf
fi

SYSCONFDIR="${SYSCONFDIR:-/etc}"
LOCALSTATEDIR="${LOCALSTATEDIR:-/var}"
RUNSTATEDIR="${RUNSTATEDIR:-/run}"
UNITDIR="${UNITDIR:-/usr/lib/systemd/system}"
USERCTX="${USERCTX:-generic_u:generic_r:generic_t}"
OBJCTX="${OBJCTX:-generic_u:object_r:def_t}"

usage()
{
    [ "$1" = 0 ] || exec >&2
    cat <<EOF
Usage: $PROG [ options ] RPMNAME LEVEL[:CAT]

Options:

  -u USERCTX, --userctx=USERCTX    set user context to USERCTX;

  -o OBJCTX, --objctx=OBJCTX       set object context to OBJCTX;

  -n, --dry-run           print operations but don't execute them;

  -v, --verbose           be verbose;

  -V, --version           print program version and exit;

  -h, --help              show this text and exit.

Report bugs to https://bugzilla.altlinux.org/.
EOF
    exit "${1:-0}"
}

TEMP="$(getopt -n "$PROG" -o u:o:nvVh -l userctx:,objctx:,dry-run,verbose,version,help -- "$@")" || usage 1
eval set -- "$TEMP"

dry_run=
verbose=
while :; do
    case "$1" in
	-u|--userctx)
	    shift; USERCTX="$1"
	    ;;
	-o|--objctx)
	    shift; OBJCTX="$1"
	    ;;
	-n|--dry-run)
	    dry_run=1
	    ;;
	-v|--verbose)
	    verbose=1
	    ;;
        -h|--help)
	    usage 0
            ;;
	-V|--version)
	    cat <<EOF
$VERSION 2026
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.
EOF
	    exit 0
	    ;;
        --)
	    shift
	    break
            ;;
        *)
	    message "$PROG: unrecognized option: $1" >&2
	    usage 1
            ;;
    esac
    shift
done

[ $# -eq 2 ] || usage 1

RPMNAME="$1"
CTX="$2"

cleanup()
{
    if [ -n "${workdir:-}" ]; then
	rm -rf "$workdir"
    fi
}
trap 'cleanup' EXIT
workdir="$(mktemp -d --tmpdir "$PROG.XXXX")"

q() {
    echo "$1" | sed -e "/[][()~\$;#*\"\!?&@^[:space:]]/ { s/'/'\\''/g; s/^.*\$/'&'/ }"
}

rpm -ql "$RPMNAME" | (
    while read -r path; do
	if [ ! -e "$path" ]; then
	    if [ -n "$verbose" ]; then
		printf 'Skip non-existent path: %s\n' "$(q "$path")" >&2
	    fi
	    continue
	fi
	case "$path" in
	    "$SYSCONFDIR"/*|"$LOCALSTATEDIR"/*|"$RUNSTATEDIR"/*)
		if [ -d "$path" ]; then
		    printf "chcon${verbose:+ -v} -R %s %s\\n" \
			   "$(q "$OBJCTX:$CTX")" "$(q "$path")"
		elif [ -f "$path" ]; then
		    printf "chcon${verbose:+ -v} %s %s\\n" \
			   "$(q "$OBJCTX:$CTX")" "$(q "$path")"
		fi
		;;
	    "$UNITDIR"/*.service)
		opath="$SYSCONFDIR/systemd/system/${path##*/}.d/$PROG.conf"
		printf "mkdir${verbose:+ --verbose} -p %s\\n" \
		       "$(q "${opath%/*}")"
		printf "echo '[Service]' >%s\\n" "$(q "$opath")"
		printf "echo 'SELinuxContext=%s' >>%s\\n" \
		       "$USERCTX:$CTX" "$(q "$opath")"
		printf 'systemctl daemon-reload\n'
		;;
	esac
    done >"$workdir"/script.sh
)

if [ -n "$dry_run" ]; then
    cat "$workdir"/script.sh
else
    sh -e "$workdir"/script.sh
fi
