#!/bin/bash
#
# ::copy::
# ::maintainer::
#
CMD=$(basename $0)
CMDVER="1.4"
CMDSTR="$CMD v$CMDVER (2020/09)"

set -e -u

export CONFDIR=/etc/kusa
export LANG="C"

usage()
{
	echo "
=== $CMDSTR == create/update LDAP user/group structure ===

usage: $CMD [options]

options:
  -D	debug
" >&2
	exit 1
}


cleanup()
{
	trap '' EXIT
	$DEBUG || rm -rf $tmpdir
	pdebug "not removing tmpdir=$tmpdir"
	trap EXIT
}

pdebug()
{
	$DEBUG || return 0
	echo -n "@D: " >&2
	echo "$@" >&2
}



#################################################
# functions
#################################################

create_base_struct()
{
	echo "checking base struct ..."

	base=`kusa-conf ldap.base` || exit 1
	admin=`kusa-conf ldap.admin` || exit 1
	admin_name=`echo $admin | sed -e 's/,.*//' -e 's/.*=//'`

	conf=/etc/ldap/ku-rootdn.conf

	[ -f $conf -a -r $conf ] && {
		passwd=`sed -e 's/#.*//' -e 's/^[ ,	]*//' $conf | \
			grep '^rootpw[ ,	]' | \
			sed -e 's/^rootpw[ ,	]*//'`
	}
	if [ -s /etc/ldap.secret ]
	then
		echo "INFO: using admin password stored in /etc/ldap.secret"
		passwd=`cat /etc/ldap.secret`
	else
		if [ "$passwd" ]
		then
			echo "INFO: using admin dn and password as stored in $conf"
		else
			if passwd=`kusa-conf ldap.admin_password 2>/dev/null`
			then
				echo "INFO: using admin password as declared in ldap.admin_password"
			else
				passwd=$admin_name
				echo "WARNING: creating admin entry $admin with password $passwd"
				echo "         change the password to place this server in production"
			fi
		fi
	fi

	# la ricerca usando un 'dn' (che non e` un attributo) non si puo` fare
	# con un filtro, ma specificando che si cerca la base (il dn specifico)
	# e che lo scope della ricerca si deve limitare alla base passata
	#
	ldap_exists -s base -b $base || {
		template=/etc/ldap/ldap-template-base
		out=$tmpdir/base.ldif
		org=`kusa-conf customer.name 2>/dev/null` || org="ORGANIZATION NAME"
		orgdc=`echo $base | sed -e 's/,.*//' -e 's/.*=//'`

		sed -e "s/BASE/$base/g" -e "s/ORGDESC/$org/g" -e "s/ORGDC/$orgdc/g" \
			$template > $out
		
		ku-ldapupdate $out || exit $?
	}

	ldap_exists -s base -b $admin || {
		template=/etc/ldap/ldap-template-secrole
		out=$tmpdir/admin.ldif
		desc="LDAP administrator"


		sed -e "s/BASE/$base/g" -e "s/NAME/$admin_name/g" -e "s/PASSWD/$passwd/g" \
			-e "s/DESC/$desc/g" \
			$template > $out
		
		ku-ldapupdate $out || exit $?
	}


	# replicator user
	#
	user=`kusa-conf ldap.repl_user` || exit 1
	passwd=`kusa-conf ldap.repl_password` || exit 1
	user_name=`echo $user | sed -e 's/,.*//' -e 's/.*=//'`
	ldap_exists -s base -b $user || {
		template=/etc/ldap/ldap-template-secrole
		out=$tmpdir/replicator.ldif
		desc="LDAP replicator"


		sed -e "s/BASE/$base/g" -e "s/NAME/$user_name/g" -e "s/PASSWD/$passwd/g" \
			-e "s/DESC/$desc/g" \
			$template > $out
		
		ku-ldapupdate $out || exit $?
	}

	return 0
}


create_slots()
{
	template=/etc/ldap/ldap-template-slot
	out=$tmpdir/slots.ldif
	cp /dev/null $out

	echo "checking slots ..."

	for slot in `kusa-conf --listvars ldap | grep "^slot_" | sed -e 's/slot_//'`
	do
		slot=`kusa-conf ldap.slot_$slot` || exit 1
		ldap_exists ou=$slot && continue
		sed -e "s/NAME/$slot/g" -e "s/BASE/$BASE/g" $template >>$out
	done
	ku-ldapupdate $out || exit $?
}

create_groups()
{
	local template=/etc/ldap/ldap-template-group
	local out=$tmpdir/groups.ldif
	local role=
	local roles=
	local slot=
	local gid=
	local desc=
	local group=
	local groups=
	local exists=
	local has_errors=false

	cp /dev/null $out
	cp /dev/null $tmpdir/groups

	echo "checking groups ..."

	roles=`kusa-conf --list "role."`
	slot=`kusa-conf ldap.slot_groups` || exit 1

	for role in $roles
	do
		echo "  processing $role"
		groups=`kusa-conf $role.groups` || exit 1
		for group in $groups
		do
			if echo "$group" | grep -q '='
			then
				exists=$(echo "$group" | sed -e 's/=.*//')
				exists=$(grep "^$group=" $tmpdir/groups) && {
					echo "  WARN: skip duplicate/conflicting entry for $group: $exists"
					continue
				}
			else
				exists=$(grep "^$group=" $tmpdir/groups) && {
					echo "   using $exists"
					continue
				}
			fi
			echo $group >> $tmpdir/groups
		done
	done
	sort -u -o $tmpdir/groups $tmpdir/groups
	set `wc -l $tmpdir/groups`
	echo "  $1 groups found"

	for group in `cat $tmpdir/groups`
	do
		desc=$group
		if echo $group | grep -q "="
		then
			gid=`echo $group | cut -d'=' -f2`
			group=`echo $group | cut -d'=' -f1`
			echo "$gid" | grep -q "," && {
				desc=`echo $gid | cut -d',' -f2`
				gid=`echo $gid | cut -d',' -f1`
			}
		else
			gid=`grep "^$group:" /etc/group | cut -d':' -f3`
		fi
		[ "$gid" ] || {
			echo "group '$group' not in /etc/group or not defined with '=gid' !"
			has_errors=true
			continue
		}
		ldap_exists "(&(gidNumber=$gid)(objectClass=posixGroup))" && continue
		sed	-e "s/NAME/$group/g" \
			-e "s/SLOT/ou=$slot/g" \
			-e "s/BASE/$BASE/g" \
			-e "s/GID/$gid/g" \
			-e "s/DESC/$desc/g" \
			$template >>$out
	done
	$has_errors && return 1

	ku-ldapupdate $out || return 1
}


create_sysusers()
{
	template=/etc/ldap/ldap-template-sysuser
	out=$tmpdir/sysusers.ldif
	cp /dev/null $out

	echo "checking system users ..."

	slot=`kusa-conf ldap.slot_sysusers` || exit 1
	users=`kusa-conf ldap.sysusers` || exit 1

	for user in $users
	do
		###echo ">> processing user $user"
		ldap_exists uid=$user && continue

		entry=`grep "^$user:" /etc/passwd` || {
			echo "user '$user' not found in /etc/passwd!"
			exit 1
		}
		uid=`echo $entry | cut -d':' -f3`
		gid=`echo $entry | cut -d':' -f4`
		gecos=`echo $entry | cut -d':' -f5`
		home=`echo $entry | cut -d':' -f6`
		shell=`echo $entry | cut -d':' -f7`
		passwd=
		passwd=`grep "^$user:" /etc/shadow` && {
			passwd=`echo "$passwd" | cut -d':' -f2`
		}
		case "$passwd" in
			""|"!") passwd=$user ;;
		esac

		sed	-e "s/LOGIN/$user/g" \
			-e "s/BASE/$BASE/g" \
			-e "s/SLOT/ou=$slot/g" \
			-e "s/UID/$uid/g" \
			-e "s/GID/$gid/g" \
			-e "s/NAME/$gecos/g" \
			-e "s#HOMEDIR#$home#g" \
			-e "s#SHELL#$shell#g" \
			-e "s/PASSWORD/$passwd/g" \
			$template >>$out || exit $?
	done
	ku-ldapupdate $out || exit $?
}


ldap_exists()
{
	pdebug "ldap_exists($*)"
	result=`ldapsearch -x $*`
	pdebug "ldap_exists() result: $result"
	set `echo "$result" | grep "^# numEntries: "` 0
	[ $1 = 0 ] && return 1
	return 0
}


# (MAIN)

DEBUG=false

while [ $# != 0 ]
do
  case $1 in
    -D|--debug)	DEBUG=true ;;
    *)		usage ;;
  esac
  shift
done

BASE=$(kusa-conf ldap.base) || exit 1
tmpdir=

trap "echo '*INTR*'; cleanup; exit 255" 1 2 3
trap 'echo -e "\nunexpected error $? at $LINENO\n"' ERR
trap "cleanup" EXIT

if $DEBUG
then
	tmpdir="/tmp/${CMD}-debug"
	rm -rf $tmpdir
	mkdir $tmpdir
else
	tmpdir=$(mktemp -d /tmp/${CMD}-XXXXXXXXX)
fi

create_base_struct
create_slots
create_groups
create_sysusers

exit 0
