#!/bin/bash
set -e

# This script is run during installation of the main server inside Debian Installer.
# Don't ever use it manually! You will definitely ruin your main server!

# If you intend to re-create the LDAP data base, use the dedicated tool:
# Run '/usr/share/debian-edu-config/tools/edu-ldap-from-scratch'

################# fetch LDAP password from debconf ################
#export DEBCONF_DEBUG='developer'
. /usr/share/debconf/confmodule
db_get debian-edu-config/ldap-password
ROOTPWDCLEAR="$RET"
RESTARTSLAPD=false

if db_get debian-edu-config/first-user-name && [ "$RET" ] ; then
    FIRSTUSERNAME="$RET"
else
    echo "error: no value in first-user-name, passing debconf values fail?  Creating localadmin user instead" 1>&2
    FIRSTUSERNAME="localadmin"
    db_set debian-edu-config/first-user-name "$FIRSTUSERNAME"
fi
if db_get debian-edu-config/first-user-fullname && [ "$RET" ] ; then
    # Last word
    FIRSTUSERLASTNAME="$(echo "$RET" | awk '{print $NF}')"
    # Everything extept the last word
    FIRSTUSERGIVENNAME="$(echo "$RET" | awk '{for (i=1; i<NF; i++) printf("%s ",$i);print ""}')"
    if [ -z "$FIRSTUSERGIVENNAME" ] ; then
	FIRSTUSERGIVENNAME="$FIRSTUSERLASTNAME"
    fi
    # GECOS in LDAP must be ASCII (IA5String), convert to this
    FIRSTUSERGECOS="$(echo $RET | iconv -t ASCII//TRANSLIT)"
else
    echo "error: no value in first-user-fullname, passing debconf values fail?" 1>&2
    FIRSTUSERGECOS="LDAP initial admin user"
    db_set debian-edu-config/first-user-fullname "$FIRSTUSERGECOS"
    FIRSTUSERLASTNAME="LDAP"
    FIRSTUSERGIVENNAME="initial admin user"
fi
if db_get debian-edu-config/first-user-password && [ "$RET" ] ; then
    FIRSTUSERPWD="$RET"
else
    echo "error: no value in first-user-password, passing debconf values fail?" 1>&2
    FIRSTUSERPWD="$ROOTPWD"
    db_set debian-edu-config/first-user-password "$FIRSTUSERPWD"
fi

echo "info: Creating first user <$FIRSTUSERNAME> '$FIRSTUSERGECOS'."

FIRSTUSERPWDHASH=$(slappasswd -s "$FIRSTUSERPWD" -h {SSHA})

## Make sure to ask for the password if it is not available
if [ -f /etc/debian-edu/config ] && grep -q Main-Server /etc/debian-edu/config \
    && [ ! -f /var/lib/ldap/__db.001 ] && [ -z "$ROOTPWDCLEAR" ]; then
    loop=0
    while [ $loop -lt 50 ]; do
        loop=$(($loop+1))
        db_input critical debian-edu-config/ldap-password || true
        db_input critical debian-edu-config/ldap-password-again || true
        db_go
        ## Check if password is non-empty:
        db_get debian-edu-config/ldap-password
        ROOTPWDCLEAR="$RET"
        if [ -z "$ROOTPWDCLEAR" ]; then
            db_set debian-edu-config/ldap-password ""
            db_set debian-edu-config/ldap-password-again ""
            db_fset debian-edu-config/ldap-password-empty seen false
            db_input critical debian-edu-config/ldap-password-empty
            db_fset debian-edu-config/ldap-password seen false
            db_fset debian-edu-config/ldap-password-again seen false
            continue
        fi
        ## Check if both entered passwords are identical:
        db_get debian-edu-config/ldap-password-again
        if [ "$ROOTPWDCLEAR" != "$RET" ]; then
            db_set debian-edu-config/ldap-password ""
            db_set debian-edu-config/ldap-password-again ""
            db_fset debian-edu-config/ldap-password-mismatch seen false
            db_input critical debian-edu-config/ldap-password-mismatch
            db_fset debian-edu-config/ldap-password seen false
            db_fset debian-edu-config/ldap-password-again seen false
        else
            break
        fi
    done
else
    echo "To initialize a brand new LDAP+KDC: " 1>&2
    echo "rm /var/lib/ldap/__db* /var/lib/ldap/*.bdb" 1>&2
    echo "rm /etc/krb5kdc/stash /etc/krb5.keytab*" 1>&2
fi

## clear passwords in the database:
db_set debian-edu-config/ldap-password ''
db_set debian-edu-config/ldap-password-again ''
## reset all questions/templates:
db_fset debian-edu-config/ldap-password seen false
db_fset debian-edu-config/ldap-password-mismatch seen false
db_fset debian-edu-config/ldap-password-again seen false
db_fset debian-edu-config/ldap-password-empty seen false
echo "LDAP passwords cleared from debconf database."

## check if the provided LDAP password is non-empty:
if [ -z "$ROOTPWDCLEAR" ]; then
    echo "The provided LDAP password is empty: Skipping LDAP setup."
    exit 1
else
    echo "The provided LDAP password is valid."
fi

################# password available now ##################

lookup_mac_addrs() {
    PATH=/sbin:$PATH LANG=C ifconfig 2>/dev/null | grep -i hwaddr | awk '{print $5}' | sort -u
}

slapd_stop() {
  # Check if slapd is running.  Use pidfile to avoid detecting the wrong
  # daemon when running in a chroot.
  if [ -f /var/run/slapd/slapd.pid ] &&
    kill -0 $(cat /var/run/slapd/slapd.pid) ; then
    RESTARTSLAPD=true
    service slapd stop

    # Make sure slapd is really stopped
    SLAPPIDS=$(pidof slapd || /bin/true)
    if [ "$SLAPPIDS" ] ; then
      echo -n "warning: slapd is still running, trying to TERM it"
      for SLAPPID in $SLAPPIDS ; do
        kill $SLAPPID || /bin/true
      done
    fi

    # Not sure why, but it seems like slapd takes some time to shut down
    LOOP=0
    while [ $LOOP -lt 10 ] ; do
      SLAPPIDS=$(pidof slapd || /bin/true)
      if [ "$SLAPPIDS" ] ; then
        LOOP=$(($LOOP + 1))
        sleep 1
        echo -n "."
      else
  	LOOP=10
      fi
    done
    echo
    if [ "$SLAPPIDS" ] ; then
      echo -n "error: slapd is still running, I'll KILL it"
      for SLAPPID in $SLAPPIDS ; do
        kill -9 $SLAPPID || /bin/true
      done
    fi

    # Not sure why, but it seems like slapd takes some time to shut down
    LOOP=0
    while [ $LOOP -lt 10 ] ; do
      SLAPPIDS=$(pidof slapd || /bin/true)
      if [ "$SLAPPIDS" ] ; then
        LOOP=$(($LOOP + 1))
        sleep 1
        echo -n "."
      else
  	LOOP=10
      fi
    done
    echo
    if [ "$SLAPPIDS" ] ; then
      echo "error: Critical: slapd is still running, I'm giving up"
      exit 9
    fi
  fi
}

dns_stop() {
    # make sure to stop DNS service, to avoid hanging installer.
    PID=`pidof named || /bin/true`
    if [ -n "$PID" ]; then
        echo "info: stopping named with pid $PID"
       service named stop
    fi
}

# Init tree
init_ldap () {

  rm -f /var/lib/ldap/*

  if [ -f /etc/shadow ] ; then
      FILE=/etc/shadow
  else
      FILE=/etc/passwd
  fi
  ROOTPWDHASH=`grep ^root: < $FILE | cut -d':' -f2`

  # Calculate the ssha hash
  ROOTPWDSSHAHASH=$(slappasswd -h {ssha} -s "$ROOTPWDCLEAR")

  HOSTNAME=`hostname -s`

  ## Create and distribute a random password and
  ## its hash for the ldap gosa-admin account:
  GOSAPWD=`slappasswd -g -h {CLEARTEXT}`
  GOSAPWDHASH=`slappasswd -s "$GOSAPWD" -h {SSHA}`
  GOSACONFDIR="/etc/gosa/"
  GOSACONF="gosa.conf"
  GOSAADMINSDN=$(awk '/dn: cn=gosa-admins,/ { print $2 }' /etc/ldap/gosa.ldif)
  GOSAADMINSDN64=$(echo -n "$GOSAADMINSDN" | base64 -w0)
  ADMINROLEDN=$(awk '/dn: cn=admin-role,/ { print $2 }' /etc/ldap/gosa.ldif)
  ADMINROLEDN64=$(echo -n "$ADMINROLEDN" | base64 -w0)
  JRADMINROLEDN=$(awk '/dn: cn=jradmin-role,/ { print $2 }' /etc/ldap/gosa.ldif)
  JRADMINROLEDN64=$(echo -n "$JRADMINROLEDN" | base64 -w0)
  TEACHERSDN=$(awk '/dn: cn=teachers,/ { print $2 }' /etc/ldap/gosa.ldif)
  TEACHERSDN64=$(echo -n "$TEACHERSDN" | base64 -w0)
  MAC=$(lookup_mac_addrs|head -1)

  ## Set LTSP chroot related DHCPD values (rootpath and filename):
  LTSPARCH=$(/usr/bin/dpkg --print-architecture)

  ## query debconf data base for time zone and locale:
  AREA=`debconf-show tzdata | grep "^* tzdata/Areas:" | \
      sed "s/.*:[[:space:]]*\([[:alpha:]]*\)$/\1/"`
  ZONE=`debconf-show tzdata | grep "^* tzdata/Zones/$AREA:" | \
      sed "s/.*:[[:space:]]*\([[:alpha:]]*\)$/\1/"`
  TIMEZONE=$AREA/$ZONE
  LANGUAGE=`debconf-show locales | grep "^* locales/default_environment_locale:" | \
      sed "s/.*:[[:space:]]*\([^[:space:]]*\)$/\1/"`

  ## cp gosa.conf.template to the right place and name: /etc/gosa/gosa.conf
  cp /usr/share/debian-edu-config/gosa.conf.template /etc/gosa/gosa.conf
  if [ -f $GOSACONFDIR$GOSACONF ] && grep -q \$GOSAPWD $GOSACONFDIR$GOSACONF ; then
      sed -i "s:\$GOSAPWD:$GOSAPWD:g" $GOSACONFDIR$GOSACONF
      sed -i "s:\$TIMEZONE:$TIMEZONE:g" $GOSACONFDIR$GOSACONF
      sed -i "s:\$LANGUAGE:$LANGUAGE:g" $GOSACONFDIR$GOSACONF
      rm -f $GOSACONFDIR/gosa.random_secret
      chown root:www-data $GOSACONFDIR$GOSACONF
      chmod 0640 $GOSACONFDIR$GOSACONF
      ## run gosa-encrypt-passwords:
      rm -f /etc/gosa/gosa.secrets
      gosa-encrypt-passwords > /dev/null
  else
      mkdir -p $GOSACONFDIR
      touch $GOSACONFDIR/gosa.random_secret
      chmod 0600 $GOSACONFDIR/gosa.random_secret
      cat > $GOSACONFDIR/gosa.random_secret <<EOF
## The gosa configuration file "$GOSACONFDIR$GOSACONF" has
## been missing during bootstrap of the ldap database or
## does not contain the string \$GOSAPWD.
## The password used by the gosa-admin in ldap is:
##                 $GOSAPWD
## Make sure to use this password in "$GOSACONFDIR$GOSACONF".
## Finally, run 'gosa-encrypt-passwords' if everything
## works fine and remove this file.
EOF
  fi

  ## Create and distribute a random password and its hash
  ## for the kdc service accounts kadmin and kdc-service:
  KDCPWD=`slappasswd -g -h {CLEARTEXT}`
  KDCPWDHASH=`slappasswd -s "$KDCPWD" -h {SSHA}`
  KDCCONFDIR="/etc/krb5kdc/"
  KEYFILE="service.keyfile"
  ## convert to {HEX} encoding:
  KDCPWDHEX=`echo "$KDCPWD" | xxd -g0 -ps | sed "s/0a$//"`
  KRB_CONT_DN=`awk '/dn: cn=kerberos,/ { print $2 }' /etc/ldap/krb5.ldif`

  mkdir -p $KDCCONFDIR
  touch $KDCCONFDIR$KEYFILE
  chmod 0600 $KDCCONFDIR$KEYFILE
  cat > $KDCCONFDIR$KEYFILE <<EOF
cn=kdc-service,$KRB_CONT_DN#{HEX}$KDCPWDHEX
cn=kadmin-service,$KRB_CONT_DN#{HEX}$KDCPWDHEX
EOF

  ## bootstrap ldap with passwords inserted:
  for ldif in \
    /etc/ldap/root.ldif \
    /etc/ldap/ipnetworks.ldif \
    /etc/ldap/netgroup.ldif \
    /etc/ldap/autofs.ldif \
    /etc/ldap/sudo.ldif \
    /etc/ldap/gosa.ldif \
    /etc/ldap/gosa-server.ldif \
    /etc/ldap/ltsp.ldif \
    /etc/ldap/firstuser.ldif \
    /etc/ldap/krb5.ldif
  do
      if cat $ldif | sed -e "s:\$ROOTPWDHASH:$ROOTPWDHASH:" \
	-e "s/\$MAC/$MAC/" \
	-e "s:\$GOSAPWDHASH:$GOSAPWDHASH:" \
	-e "s:\$GOSAADMINSDN64:$GOSAADMINSDN64:" \
	-e "s:\$ADMINROLEDN64:$ADMINROLEDN64:" \
	-e "s:\$JRADMINROLEDN64:$JRADMINROLEDN64:" \
	-e "s:\$TEACHERSDN64:$TEACHERSDN64:" \
	-e "s:\$KDCPWDHASH:$KDCPWDHASH:" \
	-e "s:\$ROOTPWDSSHAHASH:$ROOTPWDSSHAHASH:" \
        -e "s:\$FIRSTUSERNAME:$FIRSTUSERNAME:" \
        -e "s:\$FIRSTUSERGECOS:$FIRSTUSERGECOS:" \
        -e "s:\$FIRSTUSERLASTNAME:$FIRSTUSERLASTNAME:" \
        -e "s:\$FIRSTUSERGIVENNAME:$FIRSTUSERGIVENNAME:" \
        -e "s:\$FIRSTUSERPWDHASH:$FIRSTUSERPWDHASH:" \
        -e "s:\$LTSPARCH:$LTSPARCH:" \
	  | /usr/sbin/slapadd ; then
	  echo "info: added '$ldif' to ldap database."
      else
	  echo "error: Unable to load '$ldif'"
	  exit 1
      fi
  done

  # the database must be owned by openldap
  if getent passwd openldap | grep  -q openldap ; then
     chown -R openldap:openldap /var/lib/ldap
  fi

  # For some lines of code, we need LDAP up and running again
  ## check if slapd is running:
  if [ -x /sbin/start-stop-daemon.REAL ] ; then
      ## needed to start slapd during installation:
      mv /sbin/start-stop-daemon /sbin/start-stop-daemon.FAKE
      cp /sbin/start-stop-daemon.REAL /sbin/start-stop-daemon
  fi

  PID=`pidof slapd || /bin/true`
  if [ -z "$PID" ]; then
      echo "The LDAP server slapd seems not to be running. Trying to start slapd." 1>&2
      service slapd start
      slapd_started=true
  fi
  # again: the database must be owned by openldap
  if getent passwd openldap | grep  -q openldap ; then
     chown -R openldap:openldap /var/lib/ldap
  fi
}

# Create ldap-tree on the initial install
#$MTAINIT stop
slapd_stop

if slapcat 2> /dev/null | grep -q "dn: cn=all-hosts" ; then
  echo "info: found existing data (cn=all-hosts): skipping initalization"
  echo "info: use rm /var/lib/ldap/__db* /var/lib/ldap/*.bdb to reinitialize"
else
  init_ldap

  ## initialize Kerberos KDC, use gosa-admin account to access ldap:
  if [ -x /usr/share/debian-edu-config/tools/kerberos-kdc-init ] ; then
      if /usr/share/debian-edu-config/tools/kerberos-kdc-init "$GOSAPWD" ; then
          :
      else
          echo "error: critical: setting up Kerberos failed"
      fi
  fi
fi

# Restart ldap server if we stopped it and it aint already running
SLAPPIDS=$(pidof slapd || /bin/true)
if [ true = "$RESTARTSLAPD" ] && [ -z "$SLAPPIDS" ] ; then
  service slapd start
fi

# Create PKI nssdb files for first user.
if [ -x /usr/bin/certutil ] ; then
  mkdir -p /skole/tjener/home0/"$FIRSTUSERNAME"/.pki/nssdb
  chmod -R 700 /skole/tjener/home0/"$FIRSTUSERNAME"/.pki/nssdb
  certutil  -A -d sql:/skole/tjener/home0/"$FIRSTUSERNAME"/.pki/nssdb/ -t "CT,CT," -n "DebianEdu" -i /etc/ssl/certs/Debian-Edu_rootCA.crt
  chown -R 2000:2000 /skole/tjener/home0/"$FIRSTUSERNAME"/
  echo "info: created PKI nssdb files for first-user"
fi

