#  runtime : this file is used by the ldapscripts, it sould not be used independently

#  Copyright (C) 2005 Ganal LAPLANCHE - Linagora
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
#  USA.

### Useful functions ###

# Tests a string
# Input : string to test ($1)
# Output : true or false
is_yes () {
  echo "$1" | grep -qi '^yes$'
}

# Tests a string
# Input : string to test ($1)
# Output : true or false
is_no () {
  echo "$1" | grep -qi '^no$'
}

# Logs a string to $LOGFILE
# Input : string to log ($1)
# Output : nothing
log_only () {
  if [ -n "$1" ]
  then
    if [ -n "$LOGFILE" ]
    then
      if [ ! -w "$LOGFILE" ]
      then
        touch "$LOGFILE" 2>/dev/null
        if [ $? -ne 0 ]
        then
          echo "Unable to create $LOGFILE, exiting..." && exit 1
        fi
      fi
      echo "$1" >> "$LOGFILE"
    fi
  fi
}

# Echoes and logs a string to $LOGFILE
# Input : string to echo and log ($1)
# Output : nothing
echo_log () {
  [ -n "$1" ] && echo "$1"
  [ -n "$1" ] && log_only "$1"
}

# Echoes/logs $1, exits and returns 0
# Input : string to echo and log ($1)
# Output : 0
end_ok () {
  [ -n "$1" ] && echo_log "$1"
  exit 0
}

# Echoes/logs $1, exits and returns 1
# Input : string to echo and log ($1)
# Output : 1
end_die () {
  [ -n "$1" ] && echo_log "$1"
  exit 1
}

### LDAP functions ###

# Performs a search in the LDAP directory
# Input : base ($1), filter ($2), attribute to display ($3)
# Output : entry/entries found (stdout)
_ldapsearch () {
  if [ -z "$2" ] && [ -z "$3" ]
  then
    $LDAPSEARCHBIN -w "$BINDPWD" -D "$BINDDN" -b "${1:-$SUFFIX}" -xH "ldap://$SERVER" -s sub -LLL 2>>"$LOGFILE"
  else
    $LDAPSEARCHBIN -w "$BINDPWD" -D "$BINDDN" -b "${1:-$SUFFIX}" -xH "ldap://$SERVER" -s sub -LLL "$2" "$3" 2>>"$LOGFILE"
  fi
}

# Adds an entry to the LDAP directory
# Input : LDIF - entry to add (stdin)
# Output : nothing
_ldapadd () {
  $LDAPADDBIN -w "$BINDPWD" -D "$BINDDN" -xH "ldap://$SERVER" 2>>"$LOGFILE" 1>/dev/null
}

# Modifies an entry in the LDAP directory
# Input : LDIF - modification information (stdin)
# Output : nothing
_ldapmodify () {
  $LDAPMODIFYBIN -w "$BINDPWD" -D "$BINDDN" -xH "ldap://$SERVER" 2>>"$LOGFILE" 1>/dev/null
}

# Renames an entry in the LDAP directory
# Input : old dn ($1), new rdn ($2)
# Output : nothing
_ldaprename () {
  if [ -z "$1" ] || [ -z "$2" ]
  then
    end_die "_ldaprename : missing argument(s)"
  else
    $LDAPMODRDNBIN -w "$BINDPWD" -D "$BINDDN" -xH "ldap://$SERVER" -r "$1" "$2" 2>>"$LOGFILE" 1>/dev/null
  fi
}

# Deletes an entry in the LDAP directory
# Input : dn to delete ($1)
# Output : nothing
_ldapdelete () {
  [ -z "$1" ] && end_die "_ldapdelete : missing argument"
  $LDAPDELETEBIN -w "$BINDPWD" -D "$BINDDN" -xH "ldap://$SERVER" -r "$1" 2>>"$LOGFILE" 1>/dev/null
}

# Extracts LDIF information from $0 (the current script itself)
# Input : nothing
# Output : extracted LDIF data (stdout)
_extractldif () {
  grep -E '^##' "$0" | sed -e 's|^##||' 2>>"$LOGFILE"
}

# Filters LDIF information
# Input : Data to filter (stdin)
# Output : Filtered data (stdout)
_filterldif () {
  sed -e "s|<group>|$_GROUP|g" -e "s|<user>|$_USER|g" -e "s|<uid>|$_UID|g" -e "s|<gid>|$_GID|g" \
      -e "s|<suffix>|$SUFFIX|g" -e "s|<_suffix>|$_SUFFIX|g" -e "s|<usuffix>|$USUFFIX|g" -e "s|<_usuffix>|$_USUFFIX|g" \
      -e "s|<msuffix>|$MSUFFIX|g" -e "s|<_msuffix>|$_MSUFFIX|g" -e "s|<gsuffix>|$GSUFFIX|g" -e "s|<_gsuffix>|$_GSUFFIX|g" \
      -e "s|<home>|$_HOMEDIR|g"  -e "s|<shell>|$USHELL|g" -e "s|<entry>|$_ENTRY|g" 2>>"$LOGFILE"
}

### Nsswitch functions

# Converts to gid any group passed in as name/gid
# Input : the name or gid to convert ($1)
# Output : the result of the conversion ($_GID)
_grouptogid () {
  [ -z "$1" ] && end_die "_grouptogid : missing argument"
  _GID=`$GETENTGRCMD "$1" 2>/dev/null | head -n 1 | cut -d ":" -f 3`
  if [ -z "$_GID" ]
  then
    _GID=`echo "$1" | grep '^[0-9]\+$'` # Check if group is a gid
    [ -z "$_GID" ] && end_die "Cannot resolve group $1 to gid : groupname not found"
    echo_log "Warning : gid $2 not resolved, using it anyway..."
  fi
}

# Converts to name any group passed in as name/gid
# Input : the name or gid to convert ($1)
# Output : the result of the conversion ($_GID)
_gidtogroup () {
  [ -z "$1" ] && end_die "_gidtogroup : missing argument"
  _GID=`$GETENTGRCMD "$1" 2>/dev/null | head -n 1 | cut -d ":" -f 1`
  if [ -z "$_GID" ]
  then
    _GID="$1"
    echo_log "Warning : group $1 not resolved, using it anyway..."
  fi
}

# Converts to uid any user passed in as name/uid
# Input : the name or uid to convert ($1)
# Output : the result of the conversion ($_UID)
_usertouid () {
  [ -z "$1" ] && end_die "_usertouid : missing argument"
  _UID=`$GETENTPWCMD "$1" 2>/dev/null | head -n 1 | cut -d ":" -f 3`
  if [ -z "$_UID" ]
  then
    _UID=`echo "$1" | grep '^[0-9]\+$'` # Check if user is a UID
    [ -z "$_UID" ] && end_die "Cannot resolve user $1 to uid : username not found"
    echo_log "Warning : uid $1 not resolved, using it anyway..."
  fi
}

# Converts to name any user passed in as name/uid
# Input : the name or uid to convert ($1)
# Output : the result of the conversion ($_UID)
_uidtouser () {
  [ -z "$1" ] && end_die "_uidtouser : missing argument"
  _UID=`$GETENTPWCMD "$1" 2>/dev/null | head -n 1 | cut -d ":" -f 1`
  if [ -z "$_UID" ]
  then
    _UID="$1"
    echo_log "Warning : user $1 not resolved, using it anyway..."
  fi
}

### LDAP advanced functions

# Finds the last group id used in LDAP
# Input : nothing
# Output : the last gid used + 1 (so the first useable gid) ($_GID)
_findlastgroup () {
  _GID=`_ldapsearch "$GSUFFIX,$SUFFIX" '(objectClass=posixGroup)' gidNumber | grep "gidNumber: " | sed -e "s|gidNumber: ||" | uniq | sort -g | tail -n 1`
  if [ -z "$_GID" ] || [ ! "$_GID" -gt "$GIDSTART" ]
  then
    _GID="$GIDSTART"
  fi
  _GID=`expr "$_GID" + 1`
}

# Finds the last machine id used in LDAP
# Input : nothing
# Output : the last machine id used + 1 (so the first useable machine id) ($_UID)
_findlastmachine () {
  _UID=`_ldapsearch "$SUFFIX" '(objectClass=posixAccount)' uidNumber | grep "uidNumber: " | sed -e "s|uidNumber: ||" | uniq | sort -g | tail -n 1`
  if [ -z "$_UID" ] || [ ! "$_UID" -gt "$MIDSTART" ]
  then
    _UID="$MIDSTART"
  fi
  _UID=`expr "$_UID" + 1`
}

# Finds the last user id used in LDAP
# Input : nothing
# Output : the last user id used + 1 (so the first useable user id) ($_UID)
_findlastuser () {
  _UID=`_ldapsearch "$SUFFIX" '(objectClass=posixAccount)' uidNumber | grep "uidNumber: " | sed -e "s|uidNumber: ||" | uniq | sort -g | tail -n 1`
  if [ -z "$_UID" ] || [ ! "$_UID" -gt "$UIDSTART" ]
  then
    _UID="$UIDSTART"
  fi
  _UID=`expr "$_UID" + 1`
}

# Finds a particular entry in the LDAP directory
# Input : base ($1), filter ($2)
# Output : the dn of the first matching entry found ($_ENTRY)
_findentry () {
  _ENTRY=`_ldapsearch "$1" "$2" dn | grep "dn: " | head -n 1 | sed -e "s|dn: ||"`
}

### Other functions ###

# Generates a password using the $PASSWORDGEN variable
# Input : the username related to the generation ($1)
# Output : the generated password ($_PASSWORD)
_genpassword () {
  PASSWORDGEN=`echo "$PASSWORDGEN" | sed -e "s|%u|$1|g"`
  _PASSWORD=`eval $PASSWORDGEN`
}

# Changes a password for a particular DN
# Input : the new password ($1), the user DN ($2)
# Output : nothing
_changepassword () {
  if [ -z "$1" ] || [ -z "$2" ]
  then
    end_die "_changepassword : missing argument(s)"
  else
    if is_yes "$RECORDPASSWORDS"
    then
      echo "$2 : $1" >> "$PASSWORDFILE"
    fi
    $LDAPPASSWDBIN -w "$BINDPWD" -D "$BINDDN" -xH "ldap://$SERVER" -s "$1" "$2" 2>>"$LOGFILE" 1>/dev/null
  fi
}

### Source configuration file

_CONFIGFILE="/etc/ldapscripts/ldapscripts.conf"
. "$_CONFIGFILE" || end_die "Unable to source configuration file ($_CONFIGFILE), exiting..."

### Checks and defaults ###

# Check if ldap client tools are correctly configured
if [ ! -x "$LDAPADDBIN" ] || [ ! -x "$LDAPDELETEBIN" ] || [ ! -x "$LDAPSEARCHBIN" ] || [ ! -x "$LDAPMODIFYBIN" ] || [ ! -x "$LDAPPASSWDBIN" ] || [ ! -x "$LDAPMODRDNBIN" ]
then
  end_die "You must have OpenLDAP client commands installed before running these scripts"
fi

# Check homes, shell and logfile
UHOMES=${UHOMES:-"/dev/null"}
USHELL=${USHELL:-"/bin/false"}
LOGFILE=${LOGFILE:-"/var/log/ldapscripts.log"}

# Check password file if password recording set
if is_yes "$RECORDPASSWORDS"
then
  PASSWORDFILE=${PASSWORDFILE:-"/var/log/ldapscripts_passwd.log"}
  if [ ! -w "$PASSWORDFILE" ]
  then
    touch "$PASSWORDFILE" 2>/dev/null || end_die "Unable to create password log file $PASSWORDFILE, exiting..."
  fi
fi

# Guess what kind of getent command to use
if [ -z "$GETENTPWCMD" ] || [ -z "$GETENTGRCMD" ]
then
  case "`uname`" in
    Linux*)
      GETENTPWCMD="getent passwd"
      GETENTGRCMD="getent group"
      ;;
    FreeBSD*)
      GETENTPWCMD="pw usershow"
      GETENTGRCMD="pw groupshow"
      ;;
    *)
      GETENTPWCMD="getent passwd"
      GETENTGRCMD="getent group"
      ;;
  esac
fi

# Record command call into logfile
_NOW=`date "+%D - %R"`
log_only ">> $_NOW : Command : $0 $*"

