#!/bin/sh -e
#
# The useradd wrapper for the hasher-priv project.
#
# Copyright (C) 2003-2022  Dmitry V. Levin <ldv@altlinux.org>
# All rights reserved.
#
# SPDX-License-Identifier: GPL-2.0-or-later
#

PROG="${0##*/}"

Info()
{
	printf >&2 '%s\n' "${0##*/}: $*"
}

Fatal()
{
	Info "$*"
	exit 1
}

show_usage()
{
	[ -z "$*" ] || Info "$*"
	echo >&2 "Try \`$PROG --help' for more information."
	exit 1
}

show_help()
{
	cat <<EOF
hasher-useradd - adds hasher satellite users for already existing user,
and creates hasher-priv config file.

Usage: $PROG [options] <user>

Valid options are:
  --names=USER1:USER2   names for satellite users;
  --number=NUMBER       subconfig identifier;
  -r, --system          pass this option to useradd(8);
  -V, --version         print program version and exit;
  -h, --help            show this text and exit.

By default, satellite user names will be chosen based on <user>.
EOF
	exit
}

print_version()
{
	cat <<EOF
hasher-useradd version 2.0.14
Written by Dmitry V. Levin <ldv@altlinux.org>

Copyright (C) 2003-2019  Dmitry V. Levin <ldv@altlinux.org>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
EOF
	exit
}

opt_check_number()
{
	[ -n "${2##0*}" -a -n "${2##*[!0-9]*}" ] &&
		[ "$2" -ge 1 ] 2>/dev/null ||
		Fatal "$1: $2: invalid number."
	printf %s "$2"
}

svrc_booted() {
	[ -n "$(find /var/lock/subsys -maxdepth 0 -type d -not -empty 2>/dev/null)" ]
}

TEMP=`getopt -n $PROG -o f,r,h,V -l names:,number:,force,system,help,version -- "$@"` ||
	show_usage
eval set -- "$TEMP"

force=
names=
number=
system=
while :; do
	case "$1" in
		--names) shift; names="$1"
			;;
		--number)
			number="$(opt_check_number "$1" "$2")"
			shift
			;;
		-r|--system) system=1
			;;
		-f|--force) force=1
			;;
		-h|--help) show_help
			;;
		-V|--version) print_version
			;;
		--) shift; break
			;;
		*) Fatal "unrecognized option: $1"; exit 1
			;;
	esac
	shift
done

# Exactly one argument.
[ "$#" -ge 1 ] || show_usage 'Insufficient arguments.'
[ "$#" -le 1 ] || show_usage 'Too many arguments.'

caller="$1"
shift

if [ -n "$names" ]; then
	user1="${names%%:*}"
	user2="${names##*:}"
	if [ -z "$user1" -o -z "$user2" -o "$user1" = "$user2"  -o "$caller" = "$user1"  -o "$caller" = "$user2" ]; then
		Fatal "invalid names for satellite users: $names"
	fi
else
	user1="${caller}_a$number"
	user2="${caller}_b$number"
fi

caller_id="$(id "$caller")"
caller_uid="$(printf %s "$caller_id" |sed -ne 's/^uid=\([0-9]\+\)(.*/\1/p')"
[ -n "$force" ] || [ "$caller_uid" -gt 0 ] ||
	Fatal "user \""$caller"\" is too privileged"

! id "$user1" >/dev/null 2>&1 ||
	Fatal "error creating satellite users: $user1 already exists"
! id "$user2" >/dev/null 2>&1 ||
	Fatal "error creating satellite users: $user2 already exists"

min_uid="$(sed -ne 's/^UID_MIN[[:space:]]\+\([1-9][0-9]*\)[[:space:]]*$/\1/p' /etc/login.defs)"
[ -n "$min_uid" ] || min_uid=500
[ "$caller_uid" -ge "$min_uid" ] &&
	useradd_system_option= ||
	useradd_system_option=-r
[ -z "$system" ] || useradd_system_option=-r

cd /etc/hasher-priv/user.d

if [ -z "$number" ]; then
	config="$caller_uid"
	old_config="$caller"
else
	config="$caller_uid:$number"
	old_config="$caller:$number"
fi

[ ! -e "$config" ] ||
	Fatal "config file '$config' for user '$caller' already exists"

[ ! -e "$old_config" ] ||
	Fatal "config file '$old_config' for user '$caller' already exists"

# First satellite.
useradd $useradd_system_option -M -d /dev/null -s /dev/null \
	-c "1st hasher satellite for $caller" "$user1" ||
	Fatal "error creating satellite user $user1"

# Second satellite.
useradd $useradd_system_option -M -d /dev/null -s /dev/null \
	-c "2nd hasher satellite for $caller" "$user2" ||
	Fatal "error creating satellite user $user2"

# Add caller to hashman and satellite groups.
gpasswd -a "$caller" "$(id -gn "$user1")" &&
gpasswd -a "$caller" "$(id -gn "$user2")" &&
gpasswd -a "$caller" hashman ||
	Fatal "error updating groups for user $caller"

# Create config.
umask 037
cat >"$config" <<__EOF__
user1=$user1
user2=$user2
__EOF__

chgrp -- "$(id -g "$caller")" "$config"

# If we have successfully added the satellite users, enable the hasher-privd
# service. If the main daemon was socket-activated instead, that would
# translate to "least surprise" better, but we have to support service managers
# which cannot socket-activate.
Info 'enabling hasher-privd'
chkconfig hasher-privd on
if [ -d /run/systemd/system ] || svrc_booted; then
	Info 'starting hasher-privd'
	service hasher-privd start
fi
