#!/bin/bash
#
# Create user in LDAP and add a password using Kerberos.  This script
# is for testing purposes only, and will fail if several systems add
# users at the same time to LDAP, as the uid and gid values will
# conflict.

set -e

function usage {
    cat >&2 <<EOF
Usage: $0 [-u uid] [-g gid] [-G group[,group]...] [-d department] <username> <gecos>
  Create a user with a personal group and configure its kerberos
  principal.
EOF
}

if [[ $(id -u) -ne 0 ]]; then
    printf "error: this script needs to be run as root\n" >&2
    exit 1
fi

NEWUID=
NEWGID=
ADDITIONAL_GROUPS=
DEPT=
while getopts "d:hg:G:u:" arg; do
    case $arg in
    d)
        DEPT="${OPTARG}"
        ;;
    g)
        NEWGID="${OPTARG}"
        ;;
    G)
        ADDITIONAL_GROUPS="${OPTARG}"
        ;;
    u)
        NEWUID="${OPTARG}"
        ;;
    h)
        usage
        exit 0
        ;;
    *)
        usage
        exit 2
    esac
done
shift $((OPTIND - 1))

USERNAME="$1"

# posixAccount only accept ASCII in the gecos attribute.  Make sure
# any non-ascii characters are converted apprpropriately.
GECOS="$(echo $2 | iconv -t ASCII//TRANSLIT)"

if [[ $# -ne 2 || -z "$USERNAME" || -z "$GECOS" ]]; then
    usage
    exit 1
fi

read -rs -p "new user password: " PASSWORD
echo
read -rs -p "confirm password: " CONFIRM
if [[ "${CONFIRM}" != "${PASSWORD}" ]]; then
    echo "passwords do not match" >&2
    exit 1
fi

if [[ -n $DEPT ]]; then
    BASE="$(ldapsearch -x -LLL -o ldif-wrap=no "(&(objectClass=gosaDepartment)(ou:dn:=${DEPT}))" 2>/dev/null | awk '/^dn: / {print $2}' | sort | head -1)"
else
    # Put users in first gosaDepartment
    BASE=$(ldapsearch -x -LLL -o ldif-wrap=no "(objectClass=gosaDepartment)" 2>/dev/null | awk '/^dn: / {print $2}' | sort | head -1)
fi

if [ -z "$BASE" ] ; then
    BASE="$(debian-edu-ldapserver -b)"
fi

GROUPBASE="ou=group,$BASE"
USERBASE="ou=people,$BASE"

ADMINUSER="admin";

# Locate the LDAP admin DN
admindn=$(ldapsearch -x "(&(cn=$ADMINUSER)(objectClass=simpleSecurityObject))" 2>/dev/null | perl -p0e 's/\n //g' | awk '/^dn: / {print $2}')

HOMEDIR=/skole/tjener/home0/$USERNAME
KRB5DOMAIN=INTERN
PWLASTCHANGE=$(( $(date +%s) / (60 * 60 * 24) ))

LASTID="$(ldapsearch -x -LLL -o ldif-wrap=no '(|(&(objectclass=posixaccount)(uidNumber>=2000)(uidNumber<=10000))(&(objectclass=posixgroup)(gidNumber>=2000)(gidNumber<=10000)))' uidnumber gidnumber 2>/dev/null | awk '/^[ug]idNumber: / {if (max < $2) { max = $2; } } END { print max}')"

# If no ID was found, use LASTID=2000-1 to get uid/gid=2000
if [ -z "$LASTID" ] ; then
    LASTID=1999
fi

NEWUID=$(( $LASTID + 1 ))

# Look up group DN
NEWGID=$(ldapsearch -x "(&(cn=$USERNAME)(objectClass=posixGroup))" 2>/dev/null | perl -p0e 's/\n //g' | awk '/^gidNumber: / {print $2}')
if [ -z "$NEWGID" ] ; then
    NEWGID=$NEWUID
    ldif="$ldif

dn: cn=$USERNAME,$GROUPBASE
changetype: add
objectClass: top
objectClass: posixGroup
cn: $USERNAME
description: Private group of user $USERNAME
gidNumber: $NEWGID
"
fi

USER_PASSWORD="$(slappasswd -h '{CRYPT}' -c '$y$j9T$%.16s$' -T /dev/stdin <<<"${PASSWORD}")"

ldif="$ldif

dn: uid=$USERNAME,$USERBASE
changetype: add
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: gosaAccount
objectClass: posixAccount
objectClass: shadowAccount
objectClass: krbPrincipalAux
objectClass: krbTicketPolicyAux
sn: $GECOS
givenName: $GECOS
uid: $USERNAME
cn: $GECOS
userPassword: $USER_PASSWORD
homeDirectory: $HOMEDIR
loginShell: /bin/bash
uidNumber: $NEWUID
gidNumber: $NEWGID
gecos: $GECOS
shadowLastChange: $PWLASTCHANGE
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
krbPwdPolicyReference: cn=users,cn=${KRB5DOMAIN},cn=kerberos,$(debian-edu-ldapserver -b)
krbPrincipalName: $USERNAME@$KRB5DOMAIN
"

oIFS="${IFS}"
IFS=","
set -- $ADDITIONAL_GROUPS
IFS="${oIFS}"
for group; do
    group_dn="$(ldapsearch -x -LLL -o ldif-wrap=no "(&(objectClass=posixGroup)(cn=$group))" '')"
    if [ -z "${group_dn}" ]; then
        echo "group not found: ${group}" >&2
        continue
    fi
    ldif="$ldif

$group_dn
changetype: modify
add: memberUid
memberUid: $USERNAME
"
done

echo "$ldif"

if echo "$ldif" | ldapmodify -ZZ -D "$admindn" -W -v -x ; then

    # Set the kerberos password
    kadmin.local <<EOF
change_password $USERNAME@$KRB5DOMAIN
${PASSWORD}
${PASSWORD}
EOF

    # Create home directory
    if [ ! -d $HOMEDIR ] ; then
        cp -r /etc/skel $HOMEDIR
        mkdir -p $HOMEDIR/.pki/nssdb
        chmod -R 700 $HOMEDIR/.pki/nssdb
        certutil  -A -d sql:$HOMEDIR/.pki/nssdb/ -t "CT,CT," -n "DebianEdu" -i /etc/ssl/certs/Debian-Edu_rootCA.crt
        chown -R $NEWUID:$NEWGID $HOMEDIR
    fi

    # add Samba user
    smbpasswd -a -n -s $USERNAME

    # Send welcome mail in order to create maildir for dovecot
    /usr/lib/sendmail "${USERNAME}@postoffice.intern" <<EOF
Subject: Welcome to the mail-system

Hello $GECOS,

welcome to the mail-system.

Your userID is $USERNAME, and your email address is:

    $USERNAME@postoffice.intern

Regards,

    Debian-Edu SysAdmin

EOF
fi
