#!/bin/sh

# Copyright (C) 2025-2026 Daniel Baumann <daniel@debian.org>
#
# SPDX-License-Identifier: GPL-3.0+
#
# 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 <https://www.gnu.org/licenses/>.

set -e

PROJECT="bfh"
SOFTWARE="bfh-tools"
PROGRAM="bfh"
COMMAND="$(basename ${0})"

HOOKS="/etc/${PROJECT}/${PROJECT}.hooks"

Parameters ()
{
	GETOPT_LONGOPTIONS="type:,department:,name:,simulate,dry-run,verbose,quiet,help,"
	GETOPT_OPTIONS="t:,d:,n:,v,q,h,"

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

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

	eval set -- "${PARAMETERS}"

	while true
	do
		case "${1}" in
			-t|--type)
				SHARE_TYPE="${2}"
				shift 2
				;;

			-d|--department)
				SHARE_DEPARTMENT="${2}"
				shift 2
				;;

			-n|--name)
				SHARE_NAME="${2}"
				shift 2
				;;

			--simulate|--dry-run)
				SIMULATE="true"
				shift 1
				;;

			-v|--verbose)
				VERBOSE="true"
				shift 1
				;;

			-q|--quiet)
				QUIET="true"
				shift 1
				;;

			-h|--help)
				Usage
				exit 0
				;;

			--)
				shift 1
				break
				;;

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

Usage ()
{
	echo "Usage: ${PROGRAM} ${COMMAND} -t|--type {group|user} [-d|--departement {AHB|BFH|G|HAFL|HKB|S|Services|TI|W}] -n|--name NAME [--simulate|--dry-run] [-v|--verbose] [-q|--quiet]" >&2
	echo "Usage: ${PROGRAM} ${COMMAND} -h|--help" >&2
	echo
	echo "See ${PROGRAM}_${COMMAND}(1), ${PROGRAM}(1) and ${SOFTWARE}(7) for more information."

	exit 1
}

Parameters "${@}"

if [ -z "${SHARE_TYPE}" ] || [ -z "${SHARE_NAME}" ]
then
	Usage
else
	case "${SHARE_TYPE}" in
		group)
			if [ -z "${SHARE_DEPARTMENT}" ]
			then
				Usage
			fi
			;;
	esac
fi

case "${SHARE_TYPE}" in
	group|user)
		;;

	*)
		Usage
		;;
esac

if [ -n "${SHARE_DEPARTMENT}" ]
then
	case "${SHARE_DEPARTMENT}" in
		AHB|BFH|G|HAFL|HKB|S|Services|TI|W)
			;;

		*)
			Usage
			;;
	esac
fi

# group name is subset of ascii only
case "${SHARE_NAME}" in
	*[![a-z][A-Z][0-9]'-']*)
		echo "E: group name contains non-allowed characters" >&2
		exit 1
		;;
esac

# FIXME
# group name is always lower case
#SHARE_NAME="$(echo ${SHARE_NAME} | tr '[A-Z]' '[a-z]')"

case "${SHARE_TYPE}" in
	user)
		SHARE="user/home/${SHARE_NAME}"
		;;

	group)
		SHARE="group/${SHARE_DEPARTMENT}/${SHARE_NAME}"
		;;
esac

# FIXME
# share path needs to be <= 64 characters for LDAP/AD compatibility
if [ "$(echo ${SHARE} | wc -m)" -ge 65 ]
then
	echo "E: share name exceeds 64 characters" >&2
	exit 1
fi

if [ ! -e /usr/bin/ssh ]
then
	echo "E: openssh-client missing - please 'sudo apt install openssh-client'" >&2
	exit 1
fi

SSH_OPTIONS="-qqq -o HashKnownHosts=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"

# Pre hooks
for FILE in "${HOOKS}/${COMMAND}.pre"* "${HOOKS}/pre.${COMMAND}".* "${HOOKS}/all.pre"* "${HOOKS}/pre.all".*
do
	if [ -x "${FILE}" ]
	then
		"${FILE}"
	fi
done

################################################################################
# Run command
################################################################################

for CONFIG in ceph ldap
do
	if [ ! -e "/etc/bfh/bfh.conf.d/${CONFIG}.conf" ]
	then
		echo "E: ${CONFIG} missing - please 'sudo dpkg-reconfigure bfh-tools'" >&2
		exit 1
	else
		. "/etc/bfh/bfh.conf.d/${CONFIG}.conf"
	fi
done

BFH_CEPH_MOUNT="/mnt/data"

Run ()
{
	case "${SIMULATE}" in
		true)
			echo ${@}
			;;

		*)
			"${@}"
			;;
	esac
}

if Run ssh ${SSH_OPTIONS} -i "${BFH_CEPH_PRIMARY_SECRET}" "${BFH_CEPH_PRIMARY_USER}@${BFH_CEPH_PRIMARY_HOST}" \
	"cd $(dirname ${BFH_CEPH_MOUNT}/${SHARE}) && ls * -d" | grep -qsi "^${SHARE_NAME}$"
then
	echo "I: already exists (names are case-insensitive and must be unique)"
	exit 0
fi

Run ssh ${SSH_OPTIONS} -i "${BFH_CEPH_PRIMARY_SECRET}" "${BFH_CEPH_PRIMARY_USER}@${BFH_CEPH_PRIMARY_HOST}" \
	"sudo mkdir ${BFH_CEPH_MOUNT}/${SHARE} && \
	 sudo bfh-ceph-permissions --directory ${BFH_CEPH_MOUNT}/${SHARE} --quiet"

# cleanup on exit
Clean ()
{
	rm -f "${_TMPFILE}"
}

trap 'Clean' EXIT HUP INT QUIT TERM

# check group is existing
OBJECTS=""

case "${SHARE_TYPE}" in
	user)
		# FIXME: use ldap primary
		OBJECTS="$(ldapsearch -LLL -o ldif_wrap=no -H ldaps://ldap.bfh.info:636 -x -b dc=bfh -s sub uid=${SHARE_NAME} | awk '/^dn: / { print $2 }')"
		CEPH_DIRECTORY="Users/${SHARE_NAME}"
		;;

	group)
		# FIXME: use ldap primary
		GROUPS="$(ssh ${SSH_OPTIONS} -i "${BFH_CEPH_PRIMARY_SECRET}" "${BFH_CEPH_PRIMARY_USER}@${BFH_CEPH_PRIMARY_HOST}" getfacl -c -p ${BFH_CEPH_MOUNT}/${SHARE} | awk -F: '/default:group:IDM.perm.storage/ { print $3 }')"

		for GROUP in ${GROUPS}
		do
			OBJECTS="${OBJECTS} $(ldapsearch -LLL -o ldif-wrap=no -H ldaps://ldap.bfh.info:636 -x -b dc=bfh -s sub cn=${GROUP} | awk '/^dn: / { print $2 }')"
		done

		CEPH_DIRECTORY="${SHARE_DEPARTMENT}/${SHARE_NAME}"
		;;
esac

if [ -z "${OBJECTS}" ]
then
	echo "E: user or group doesn't exist in LDAP" >&2
	exit 1
fi

# write ldif
for OBJECT in ${OBJECTS}
do

	_TMPFILE="$(mktemp -t ${PROGRAM}_$(basename ${0}).XXXXXXXX)"

cat > "${_TMPFILE}" << EOF
dn: ${OBJECT}
changetype: modify
replace: bfhCephDirectory
bfhCephDirectory: ${CEPH_DIRECTORY}
EOF

	# apply ldif
	case "${SIMULATE}" in
		true)
			# do nothing
			echo "SIMULATE"
			cat "${_TMPFILE}"
			echo "SIMULATE"
			;;

		*)
			case "${QUIET}" in
				true)
					ldapmodify -x -D ${BFH_LDAP_PRIMARY_USER} -w ${BFH_LDAP_PRIMARY_SECRET} -H ldaps://${BFH_LDAP_PRIMARY_HOST}:636 -f "${_TMPFILE}" > /dev/null 2>&1 || echo "something went wrong" >&2
					;;

				*)
					ldapmodify -x -D ${BFH_LDAP_PRIMARY_USER} -w ${BFH_LDAP_PRIMARY_SECRET} -H ldaps://${BFH_LDAP_PRIMARY_HOST}:636 -f "${_TMPFILE}" || echo "something went wrong" >&2
					;;
			esac
			;;
	esac

	rm -f "${_TMPFILE}"
done

################################################################################

# Post hooks
for FILE in "${HOOKS}/${COMMAND}.post"* "${HOOKS}/post.${COMMAND}".* "${HOOKS}/all.post"* "${HOOKS}/post.all".*
do
	if [ -x "${FILE}" ]
	then
		"${FILE}"
	fi
done
