#!/bin/sh

# Linux Vulnerability Mitigation
# Copyright (C) 2026 Daniel Baumann <daniel@debian.org>
#
# SPDX-License-Identifier: PD
#
# This program is free software: you have unlimited permission
# to copy, distribute and modify it.
#
# 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.

set -e

PROGRAM="linux-vulnerability-mitigation"
COMMAND="$(basename "${0}")"

SHARE="/usr/share/${PROGRAM}"

if [ -t 1 ] && [ -t 2 ]
then
	RED="\033[1;33;31m"
	GREEN="\033[1;33;32m"
	YELLOW="\033[1;33;33m"
	NORMAL="\033[0m"
fi

Parameters ()
{
	GETOPT_LONGOPTIONS="install,remove,force,help,"
	GETOPT_OPTIONS="i,r,f,h,"

	PARAMETERS="$(getopt --longoptions ${GETOPT_LONGOPTIONS} --name="${COMMAND}" --options ${GETOPT_OPTIONS} --shell sh -- "${@}")"

	# shellcheck disable=SC2181
	if [ "${?}" != "0" ]
	then
		echo "'${COMMAND}': getopt exit" >&2
		exit 1
	fi

	eval set -- "${PARAMETERS}"

	while true
	do
		case "${1}" in
			-i|--install)
				RUNS="${RUNS} install"
				shift 1
				;;

			-r|--remove)
				RUNS="${RUNS} remove"
				shift 1
				;;

			-f|--force)
				FORCE="true"
				shift 1
				;;

			-h|--help)
				Usage
				;;

			--)
				shift 1
				break
				;;

			*)
				echo "'${COMMAND}': getopt error" >&2
				exit 1
				;;
		esac
	done
}

Usage ()
{
	echo "Usage: ${PROGRAM} ${COMMAND} [{-i, --install|-r, --remove}] [-f, --force} " >&2
	echo
	echo "See ${PROGRAM}-${COMMAND}(1), ${PROGRAM}(1) and ${PROGRAM}(7) for more information."

	exit 1
}

RUNS=""

Parameters "${@}"

if [ -z "${RUNS}" ]
then
	RUNS="remove install"
fi

# Run
case "$(id -u)" in
	0)
		;;

	*)
		echo "${RED}error:${NORMAL} '${COMMAND}' operation requires superuser privilege" >&2
		exit 1
		;;
esac

MITIGATIONS="$(find "${SHARE}/mitigations" -mindepth 1 -printf '%f\n' | sort -V)"

for RUN in ${RUNS}
do
	case "${RUN}" in
		install)
			for MITIGATION in ${MITIGATIONS}
			do
				case "${FORCE}" in
					true)
						# run mitigation even if run before
						;;

					*)
						set +e
						"${SHARE}/mitigations/${MITIGATION}" check > /dev/null 2>&1
						RETURN="${?}"
						set -e

						case "${RETURN}" in
							0)
								echo "  ${YELLOW}already installed${NORMAL}  $(basename "${MITIGATION}")  $(awk -F= '/^DATE=/ { print $2 }' "${SHARE}/mitigations/${MITIGATION}")  $(awk -F= '/^NAME=/ { print $2 }' "${SHARE}/mitigations/${MITIGATION}")"
								continue
								;;
						esac
						;;
				esac

				set +e
				"${SHARE}/mitigations/${MITIGATION}" status
				RETURN="${?}"
				set -e

				case "${RETURN}" in
					0)
						# fixed
						;;

					*)
						# mitigated or vulnerable
						"${SHARE}/mitigations/${MITIGATION}" install
						echo "  ${GREEN}installing       ${NORMAL}  $(basename "${MITIGATION}")  $(awk -F= '/^DATE=/ { print $2 }' "${SHARE}/mitigations/${MITIGATION}")  $(awk -F= '/^NAME=/ { print $2 }' "${SHARE}/mitigations/${MITIGATION}")"
						;;
				esac
			done
			;;

		remove)
			for MITIGATION in ${MITIGATIONS}
			do
				case "${FORCE}" in
					true)
						# run mitigation even if run before
						;;

					*)
						set +e
						"${SHARE}/mitigations/${MITIGATION}" check > /dev/null 2>&1
						RETURN="${?}"
						set -e

						case "${RETURN}" in
							0)
								# removing
								;;

							*)
								echo "  ${YELLOW}already removed  ${NORMAL}  $(basename "${MITIGATION}")  $(awk -F= '/^DATE=/ { print $2 }' "${SHARE}/mitigations/${MITIGATION}")  $(awk -F= '/^NAME=/ { print $2 }' "${SHARE}/mitigations/${MITIGATION}")"
								continue
								;;
						esac
						;;
				esac

				set +e
				"${SHARE}/mitigations/${MITIGATION}" status
				RETURN="${?}"
				set -e

				case "${RETURN}" in
					0)
						# fixed
						"${SHARE}/mitigations/${MITIGATION}" remove
						echo "  ${RED}removing         ${NORMAL}  $(basename "${MITIGATION}")  $(awk -F= '/^DATE=/ { print $2 }' "${SHARE}/mitigations/${MITIGATION}") $(awk -F= '/^NAME=/ { print $2 }' "${SHARE}/mitigations/${MITIGATION}")"
						;;

					*)
						# mitigated or vulnerable
						;;
				esac
			done
			;;
	esac
done
