#!/bin/sh -e

. alterator-kdc-princ-functions
. alterator-openldap-functions

# Read default configuration
set_ldap_config

[ -n "$DN_CONF" ] || fatal "DN_CONF not set"

Usage()
{
    cat <<EOF
Usage:

    $0 [-n <first_name>] [-f <surname>]
       [-c <common_name>]
       [-w] [-i]
       [-d <home_dir>] [-s <shell>] [-p <passwd>]
       [-G <group[,...]] <user>

Arguments:
    -n first_name  LDAP attribute givenName (first or given name)
    -f surname     LDAP attribute surname (surname of family name)
    -c common_name LDAP attribute commonName (surname first_name patronym)
    -w             is a Windows Workstation
    -i             is a trust account (Windows Workstation)
    -d home_dir    new user home dir location (by default /home/<user>)
    -s shell       name of the user login shell (by default /bin/bash)
    -p passwd      password for new user
    -G group,...   a list of LDAP groups which the user is also a member of
    user        new user name in LDAP
    -h, --help  show this help
    --version   show version

EOF
    exit
}

[ $# -ne 0 ] || Usage

# Default values
first_name=
surname=
common_name=
is_workstation="no"
is_trusted="no"
home_dir=
shell="/bin/bash"
passwd=
groups=

# Parse arguments
export OPTERR=1
while getopts "hwi-:n:f:c:d:s:p:G:" c
do
    [ "$DEBUG" = "1" ] && echo "param: -$c '$OPTARG'" >&2
    case "$c" in
	n) first_name="$OPTARG";;
	f) surname="$OPTARG";;
	c) common_name="$OPTARG";;
	w) is_workstation="yes";;
	i) is_trusted="yes";;
	d) home_dir="$OPTARG";;
	s) shell="$OPTARG";;
	p) passwd="$OPTARG";;
	G) groups="$OPTARG";;
	h) Usage;;
	-) case "$OPTARG" in
		help) Usage;;
		version) get_ldap_version; exit;;
		*) fatal "Invalid option \"-$OPTARG\"";;
	   esac;;
	\?) fatal "Invalid option \"$1\"";;
    esac
done

# Set user name
shift $(( OPTIND - 1 ))
user="$1"

# Fallback values
[ -z "$surname" ] && surname="$user"
[ -z "$common_name" ] && common_name="$user"
[ -z "$home_dir" ] && home_dir="/home/$user"

# Add $ to username if -i is passed and $ miss at the end
[ "$is_workstation" = "yes" -a "$is_trusted" = "yes" -a "${user#${user%?}}" != "$" ] && user="$user$"

[ "$DEBUG" = "1" ] && cat >&2 <<DEBUGOUT

user=$user
first_name=$first_name
surname=$surname
common_name=$common_name
is_workstation=$is_workstation
is_trusted=$is_trusted
home_dir=$home_dir
shell=$shell
passwd=$passwd
groups=$groups
DEBUGOUT

# Check for username has only lowercase latin letters, digits, dot and '_'
echo "$user" | egrep '^[a-z][\.a-z0-9_-]*\$?$' >/dev/null ||
    fatal "only small latin letters, digits, dot, '-' and '_' are allowed in username"

#check for name
ldap-getent passwd "$user" >/dev/null &&
    fatal "user with same name already exists"

#calculate uid
uid_avail="$((ldap-getent passwd;ldap-getent ws)| cut -f3 -d: |sort -unr|head -1)"

uid=$(( $uid_avail + 1 ))

[ "$uid" -le "$uid_max" ] || fatal "not free uid available"
[ "$uid" -lt "$uid_min" ] && uid="$uid_min"

#add group and calculate gid
ldap-getent group "$user" >/dev/null &&
    fatal "same name in group database already exists"
ldap-groupadd "$user"
gid="$(ldap-getent group "$user"|cut -f3 -d:)"

# getting sid
get_sid >/dev/null
user_sid="$SID-$(($uid*2+1000))"

# Add workstation
if [ "$is_workstation" = "yes" ]
then
    # Create ou=Computers if it is not exist
    container="Computers"
    section=$(ldapsearch -LLL -b "$base" -x \
		-H "ldap://${host:-127.0.0.1}" \
		"(&(objectClass=organizationalUnit)(ou=$container))")
    if [ -z "$section" ]; then
	ldapadd -a -D "$rootdn" $rootpw -x \
		-H "ldap://${host:-127.0.0.1}" >/dev/null <<EOS
dn: ou=$container,$base
objectClass: organizationalUnit
ou: $container
EOS
    fi

    # fill content
    content="$(cat <<EOC
dn: uid=$user,ou=$container,$base
cn: $user
objectClass: top
objectClass: account
objectClass: posixAccount
uidNumber: $uid
gidNumber: $gid
homeDirectory: /dev/null
loginShell: /bin/false
description: Computer
gecos: Computer
EOC
)"
fi

# Add user
if [ "$is_workstation" != "yes" ]
then
    # Check Kerberos is ready
    if [ -n "$ENABLE_KRB" ]; then
	kdc_status=
	service krb5kdc status &>/dev/null || kdc_status="fail"

	# Add principal to Kerberos database
	addprinc "+requires_preauth $user" &>/dev/null || kdc_status="fail"

	# Error reaction
        if [ "$kdc_status" = "fail" ]; then
	    ldap-groupdel "$user" &>/dev/null ||:
	    fatal "unable to create user in Kerberos. Check krb5kdc service is running."
        fi
    fi

    #edit ldap
    content="$(cat <<EOF
dn: uid=$user,ou=People,$base
uid: $user
cn: $common_name
sn: $surname
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: sambaSamAccount
loginShell: $shell
userPassword: {crypt}x
uidNumber: $uid
gidNumber: $gid
homeDirectory: $home_dir
sambaAcctFlags: [U          ]
sambaSID: $user_sid
sambaPwdLastSet: 2147483647
sambaLogonTime: 0
sambaLogoffTime: 2147483647
sambaKickoffTime: 2147483647
sambaPwdCanChange: 0
sambaPwdMustChange: 0
EOF
)"

    [ -n "$first_name" ] && content="${content}
GivenName: $first_name"
fi

[ "$DEBUG" = "1" ] && echo "$content" >&2

# Put record in LDAP database
echo "$content" | ldapadd -a -D "$rootdn" $rootpw -x \
				-H "ldap://${host:-127.0.0.1}" >/dev/null

# Additional action for ordinary user
if [ "$is_workstation" != "yes" ]
then
    # Create user homedir
    su - "$user" -s /bin/true &>/dev/null

    # Create user mail spool file
    touch /var/spool/mail/"$user" &&
    chmod 0660 /var/spool/mail/"$user" &&
    chown "$user":mail /var/spool/mail/"$user"

    # Set password if it is not empty
    [ -n "$passwd" ] && ldap-passwd "$user" "$passwd"

    # Join to supplementary LDAP groups
    export IFS=","
    for g in $groups; do
	[ "$DEBUG" = "1" ] && echo "add group $g" >&2
	[ -n "$(ldap-getent group "$g")" ] &&
	    printf 'memberUid:%s\n' "$user" |
		ldap-groupmod add "$g" >/dev/null
    done
fi

