#!/bin/bash
#
# Import a list of users to GOsa.  Based on the ldapscripts package.
#

set -e

umask 0022

sync_nscd(){
    if pidof nscd 1>&2 > /dev/null ; then
        ## Clear tables to have database up to date:
        nscd -i passwd
        nscd -i group
    fi
}

mk_uname() {
    GNAME=${1,,}
    FNAME=${2,,}
    echo ${GNAME::4}${FNAME::4}
    #echo ${GNAME}_${FNAME}
}

ou2LDAP() {
    OU=$1
    # Add ou to LDAP
    _extractldif 3 | sed -e "s|<ORGUNIT>|$OU|g" | _filterldif | _utf8encode | _ldapadd
    [ $? -eq 0 ] || end_die "Error adding '$OU' to '$SUFFIX'."
    echo_log "Successfully added '$OU' to '$SUFFIX'."
}

user2LDAP() {
    set +e
    GNAME=$1
    FNAME=$2
    _USER="$3"
    _GROUP="$_USER"

    # Group GID
    _GID=$(_findnextgid)
    [ -z "_GID" ] && end_die "Cannot guess next free group ID."

    # Add group to LDAP
    _extractldif 4 | _filterldif | _utf8encode | _ldapadd
    [ $? -eq 0 ] || end_die "Error adding group '$_GROUP' to LDAP."
    echo_log "Successfully added group '$_GROUP' to LDAP."

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

    # User UID
    _UID=$(_findnextuid)
    [ -z "_UID" ] && end_die "Cannot guess next free user ID."

    # Compute homedir
    _HOMEDIR=$(echo "$UHOMES" | sed "s|%u|$_USER|g")

    # Add user to LDAP
    _extractldif 5 | \
        sed -e "s|<GNAME>|$GNAME|g" \
        -e "s|<FNAME>|$FNAME|g" \
        -e "s|<PWHASH>|$PWHASH|g" \
        | _filterldif | _utf8encode | _ldapadd
    [ $? -eq 0 ] || end_die "Error adding user '$_USER' to LDAP."
    echo_log "Successfully added user '$_USER' to LDAP."

    # Create Home dir
    if [ -e "$_HOMEDIR" ] ; then
        warn_log "Skipped home directory creation for user '$_USER' (already exists)."
    else
        if [ -d "$HOMESKEL" ] ; then
            mkdir -p $(dirname "$_HOMEDIR") 2>>"$LOGFILE" 1>/dev/null
            cp -pR "$HOMESKEL/" "$_HOMEDIR" 2>>"$LOGFILE" 1>/dev/null
        else
            mkdir -p "$_HOMEDIR" 2>>"$LOGFILE" 1>/dev/null
        fi
        chmod "$HOMEPERMS" "$_HOMEDIR" 2>>"$LOGFILE" 1>/dev/null
        chown -R "$_UID":"$_GID" "$_HOMEDIR" 2>>"$LOGFILE" 1>/dev/null
        echo_log "Successfully created home directory '$_HOMEDIR' for user '$_USER'."
    fi
    set -e
}

checkPASSWD (){
    PASSWD="$1"
    local NUM=0
    if [ $(expr length "$PASSWD") -ge $MINLEN ] ; then
        [ -n "${PASSWD//[![:lower:]]/}" ] && NUM=$(($NUM+1))
        [ -n "${PASSWD//[![:upper:]]/}" ] && NUM=$(($NUM+1))
        [ -n "${PASSWD//[![:digit:]]/}" ] && NUM=$(($NUM+1))
        [ -n "${PASSWD//[![:punct:]]/}" ] && NUM=$(($NUM+1))
    fi
    echo $NUM
}

createPASSWD (){
    local NUM=0
    while [ $NUM -lt $MINCLS ] ; do
        PASSWD=$(slappasswd -g)
        NUM=$(checkPASSWD "$PASSWD")
    done
    echo "$PASSWD"
}

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

FILE=$1
GOSAOU=$2

# Source runtime file
_RUNTIMEFILE="/usr/share/ldapscripts/runtime"
. "$_RUNTIMEFILE"

# We need to overwrite variables defined in the configuration
# and sourced in the runtime file above:
SUFFIX="$GOSAOU,ou=gosa,dc=intern"
SUFFIX=${SUFFIX#,} # remove ',' if $GOSAOU=""
GIDSTART="10000"
UIDSTART="10000"

## Map LDAP structure on the home directory tree if not switched off:
if [ -n "$GOSAOU" ] && [ "$3" != "--no-map" ] ; then
    HSUFFIX=$(echo -n "${GOSAOU}," | tac -s "," | sed -e "s|ou=||g" -e "s|,|\/|g" )
    UHOMES=${UHOMES/\%u/${HSUFFIX}%u}
fi

## Password restrictions (compliant with kerberos policy):
MINLEN=4  # minimal password length (max 8 with slappasswd as password generator)
MINCLS=2  # minimal number of character classes

if [ ! -r "$FILE" ] ; then
    cat <<EOF
Usage: add2gosa <file> [ou=<GOsa Department>[,ou=...] [--no-map]]
Where <file> contains rows of first and last names:

    <First Name> <Last Name>
         ...        ...

Empty lines or lines starting with a '#' will be ignored.  The
generated password is appended to the line during processing, the line
commented.

Optionally it is possible to specify an organizational unit within the
GOsa tree.  The users will be added to that department.  The location
of the home directory created will map the structure of the
organizational units in LDAP.  This feature can be switched off with
the --no-map option.

Examples:

  * add users to GOsa base, home directory: '/<default>/<username>':

           add2gosa <file>

  * add users to department 'ou=2013,ou=students', home directory
    '/<default>/students/2013/<username>':

           add2gosa <file> ou=2013,ou=students

The department has to be created in GOsa before adding users.
EOF
    exit 1
fi

sync_nscd
# Test if dn exists:
_ldapsearch "$SUFFIX" "(objectClass=organizationalUnit)" "dn" \
    | grep -q "$SUFFIX" || end_die "No Department '$SUFFIX' found.  Create it in GOsa first."
# Create ou=groups if missing:
_ldapsearch "$GSUFFIX,$SUFFIX" "(objectClass=organizationalUnit)" "dn" \
    | grep -q "$GSUFFIX,$SUFFIX" || ou2LDAP $GSUFFIX
# Create ou=people if missing:
_ldapsearch "$USUFFIX,$SUFFIX" "(objectClass=organizationalUnit)" "dn" \
    | grep -q "$USUFFIX,$SUFFIX" || ou2LDAP $USUFFIX
echo

chmod 600 $FILE
IFS=$'\n'
for LINE in $(grep -Ev "^(#|[[:space:]]*$)" $FILE | sed "s/\#.*//g" | awk '{print $1, $2, $3}') ; do
    GNAME=`echo "$LINE" | cut -d " " -f1`
    FNAME=`echo "$LINE" | cut -d " " -f2`
    USERNAME=$(mk_uname ${GNAME} ${FNAME})
    echo "---------------- $USERNAME ----------------"
    PASSWD=$(createPASSWD)
    PWHASH=$(slappasswd -s $PASSWD -h {SSHA})
    echo "Password and hash created."
    sed -i "s|\($GNAME[[:space:]]\+$FNAME\)|\# \1:\t $USERNAME\t ${PASSWD}|" $FILE
    user2LDAP "$GNAME" "$FNAME" "$USERNAME" "$PWHASH"
    USERDN="dn=uid=$USERNAME,$USUFFIX,$SUFFIX"
    kadmin.local -q "add_principal -pw "$PASSWD" -x $USERDN $USERNAME"
    echo
done

cat <<EOF
   ===================== IMPORTANT NOTICE =====================
    Make sure to keep '$FILE' save or remove it!
    Advice users to change their password immediately in GOsa.
   ============================================================
EOF

end_ok

# Ldif ou template ##################################
###dn: <ORGUNIT>,<suffix>
###objectClass: top
###objectClass: organizationalUnit
###ou: <ORGUNIT>

# Ldif group template ###############################
####dn: cn=<group>,<gsuffix>,<suffix>
####objectClass: <gclass>
####cn: <group>
####gidNumber: <gid>
####description: Group of user <group>

# Ldif user template ################################
#####dn: uid=<user>,<usuffix>,<suffix>
#####objectClass: person
#####objectClass: organizationalPerson
#####objectClass: inetOrgPerson
#####objectClass: gosaAccount
#####objectClass: posixAccount
#####objectClass: shadowAccount
#####sn: <FNAME>
#####givenName: <GNAME>
#####cn: <GNAME> <FNAME>
#####gecos: <GNAME> <FNAME>
#####uid: <user>
#####homeDirectory: <home>
#####loginShell: <shell>
#####uidNumber: <uid>
#####gidNumber: <gid>
#####userPassword: <PWHASH>
