#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2c).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2007-05-09 16:07 EDT by <root@DCOES01>.
# Source directory was `/root/lastlogin/cool-tool'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#   9586 -rwxr-xr-x lastlogin
#   3278 -rw-r--r-- lastlogin.conf
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
    shar_n= shar_c='
'
  else
    shar_n=-n shar_c=
  fi
else
  shar_n= shar_c='\c'
fi
if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$2 "$8"'
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
#
$echo $shar_n 'x -' 'lock directory' "\`_sh31953': "$shar_c
if mkdir _sh31953; then
  $echo 'created'
else
  $echo 'failed to create'
  exit 1
fi
# ============= lastlogin ==============
if test -f 'lastlogin' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'lastlogin' '(file already exists)'
else
  $echo 'x -' extracting 'lastlogin' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'lastlogin' &&
#!/bin/bash
X
##############################################################################
#
# This tool is most useful for those Novell customers who have per-user 
# license agreements.  During the annual "true-up" process, administrators 
# can run this tool to assist in the clean up of eDirectory and identify 
# those user objects that are no longer needed.
#
# Even those customers who have MLA or other "unlimited" user license
# agreements will find this tool useful in helping identify old user
# objects that are easily forgotten in a large environment.
# 
# NORMAL DISCLAIMER
#    This script is completely free to anyone who finds it useful and is
#    released "as-is" with no warranty, yada yada.
#
#    If you are somehow able to damage your environment through mis-use of 
#    this script, you probably need to find another line of work... ;)
#
# This tool is released as "postcard-ware".  If you find it useful or have
# any questions, please contact me at dcostello@ahcinc.com or 
# dcc1165@earthlink.net
#
#-----------------------------------------------------------------------------
#
# GETTING STARTED
#
# Using the script is very straight forward.  It can be run from any directory,
# but probably most useful when installed to /usr/local/bin (and that
# directory is part of the PATH).
#
# The script must first be configured for your environment.  Change the LDAP
# Parameters (and optionally the Script Parameters) section to customize for
# your environment.  You can experiment with different settings by changing 
# the values in the lastlogin.conf file.  The config file is really just a 
# sourced shell script.
#
# The list can optionally be sent to the recipient specified in "mailrcpt"
# (default is to not send an e-mail).
#
# RUNNING THE SCRIPT
#
# The script will retrieve a DN list from eDirectory via LDAP then generate a 
# report of users who have not logged in within a given timeframe (default is 
# greater than 45). It also generates an LDIF file which can optionally be fed
# into ldapmodify to delete those user objects.
#
# USAGE: lastlogin [ -x ] [ -f <config> ] [ -m ]
#
#                   -x:  Use an existing lastlogin.ldif file from a previous 
#                        run.  Useful when performing multiple runs (i.e. to
#                        generate different results based on min/max days).
#                        If "lastlogin.ldif" doesn't exist, the script will
#                        generate one automatically.
#
#          -f <config>:  Specify an optional config file to override script
#                        defaults (see "Config Variables" below).
#
#                   -m:  Turn off e-mail notification.
#
##############################################################################
#
# Source the standard functions file (if it exists).
X
[[ -f /usr/local/bin/funcs ]] && . /usr/local/bin/funcs
shopt -s xpg_echo
X
# The LDAP search command
lds() {
X   ldapsearch -H $ldapurl -D $admindn                        \
X              -w $adminpw -b "$basedn"                       \
X              -x -s sub "(objectclass=user)"                 \
X              -S $ldapattr | grep -v "#" | grep -v "^$"
}
X
# --------- Config Variables ==========================
#
# These variables can be overridden in a specified config file.  All
# variables are documented in the lastlogin.conf file.
#
# -- IMPORTANT -- Change these values to those specific to your organization
#
# LDAP Parameters
ldapattr="dn fullName LoginTime" 
basedn="o=myorg"
ldapurl="ldaps://ldap.myorg.com" 
admindn="cn=admin,o=myorg"
adminpw="adminpw"
X
# Script Parameters
progname="`basename $0`"
ldifFile="$progname.ldif"
rptfile="$progname.rpt"
delfile="delusers.ldif"
mindays=0
maxdays=45
config="Default"
mail=0
mailrcpt="usermgmt@mail.myorg.com"
nosearch=0
X
# "ignorelist" is used to skip user IDs (i.e. system accounts).  This is
# useful when determining what user accounts can be deleted.  Not useful
# when counting full eDirectory licenses, but nice to have when you're only
# interested in actual people-related user objects.
#
#ignorelist="ldapproxy nfauuser ifolder rprinter trackit sqlwork backup"
#ignorelist="$ignorelist publicuser msgproxy eGuidProxy"
#ignorelist="$ignorelist eolsupport ldapuser"
#
# ---------- End of Config Variables ------------------
X
#
# Parse command line parameters - Poor man's getopts :)
#
while [ $# -ne 0 ]
do
X   case $1 in
X       -x)  if [[ -f $ldifFile ]] 
X            then
X               nosearch=1
X            else
X               echo "$ldifFile does not exist.  Generating a new one."
X            fi
X            shift
X            ;;
X
X       -f)  shift
X            config=$1
X            [[ -f $config ]] && . $config
X            [[ ! -f $config ]] &&  echo "$config doesn't exist.  Assuming defaults"
X            shift
X            ;;
X
X        -m) mail=0
X            shift
X            ;;
X
X        *)  echo "Invalid option \"$1\"."
X            shift
X            ;;
X    esac
done
X
# check if this is the "canned" script with unmodified paramaters
if [[ "$basedn" == "o=myorg" ]]
then
X   echo "\n!!! ------------------------- ERROR -----------------------------!!!"
X   echo "  This script has not been customized for your environment!"
X   echo "\n  Please modify the LDAP Parameters and Script Paramaters sections"
X   echo "  in the \"lastlogin\" script -- OR -- customize the settings in the"
X   echo "  \"lastlogin.conf\" file.\n"
X   exit
fi
X
# Whack the old report file.
[[ -f $rptfile ]] && rm $rptfile
X
# List the operating parameters
echo "Login report running with the following parameters:"
echo "\nLDAP Search Parameters"
echo "---------------------------------------------------"
echo "  LDAP Attributes: $ldapattr"
echo "          Base DN: $basedn"
echo "         LDAP URI: $ldapurl\n\n"
echo "Script parameters:"
echo "---------------------------------------------------"
echo "  Config File: $config"
echo "    LDIF File: $ldifFile \c"
[[ $nosearch == 1 ]] && echo "(Existing)"
[[ $nosearch == 0 ]] && echo "(New)"
echo "  Report File: $rptfile"
echo "  Output LDIF: $delfile"
echo "     Min Days: $mindays days"
echo "     Max Days: $maxdays days"
[[ $mail -eq 1 ]] && echo "eMail Results: $mailrcpt"
echo "  Ignored CNs:\t`echo $ignorelist | sed -e 's/ /\n\t\t/g'`"
echo "---------------------------------------------------"
X
# Main
X
# If "-x" is specified on the command line, don't bother getting
# another LDAP list.
if [[ $nosearch -eq 0 ]]
then
X   echo "Getting user list from LDAP...\c"
X   lds >$ldifFile
X   echo "Done.  \nTotal DN lines in LDIF: `grep \"dn:\" $ldifFile | wc -l`"
fi
X
# These two lines set up today's date as number of seconds since 12:00:00am
# Jan 1, 1970.  Used to calculate how many days since the users' last login.
# The first call to the date command returns just the MM/DD/YY format of the
# date instead of the default date and time.  The "days since last logged in"
# calculation doesn't need to be accurate to within a second.
now="`date +'%m/%d/%Y'`"
nowsec="`date -d \"$now\" +'%s'`"
X
# Prepare the LDIF "deletion" file.
echo "Version: 1\n" >$delfile
echo "Processing $ldifFile..."
X
# Read the user-list LDIF file and find the last login time.
cat $ldifFile | while read curline
do
X   tt="`echo \"$curline\" | cut -d':' -f1 | tr -d [:space:]`"
X   vv="`echo \"$curline\" | cut -d':' -f2`"
X
X   [[ "$tt" == "dn" ]] && dn="`echo $vv | tr -d [:space:]`"
X   [[ "$tt" == "fullName" ]] && fn="$vv"
X   [[ -z "$fn" ]] &&  fn="<NO FULL NAME>"
X
X   if [[ "$tt" == "LoginTime" ]] 
X   then
X      lastlogin="`echo $vv | tr -d [:space:]`"
X      if [[ ! -z "$lastlogin" ]]
X      then
X         # Split up the LoginTime LDAP field
X         yy="`echo $lastlogin | cut -c1-4`"
X         mm="`echo $lastlogin | cut -c5-6`"
X         dd="`echo $lastlogin | cut -c7-8`"
X
X         # Convert the last login time to number of seconds since
X         # 1970 12:00:00am ("date +'%s'") and get the differnce between
X         # today and the last login date.
X         ddsec="`date -d \"$mm/$dd/$yy\" +'%s'`"
X         diffsec=`expr $nowsec - $ddsec`
X
X         # bar room trivia -- there are 86,400 seconds in one day.
X         daysago=`expr $diffsec / 86400`
X
X         cn="`echo $dn | cut -d'=' -f2 | cut -d',' -f1`"
X
X         # Skip this CN if it's in $ignorelist.
X         if [[ ! -z "`echo $ignorelist | grep -i $cn`" ]] 
X         then
X            continue
X         else
X            # Report that this user hasn't logged in within "$numdays"
X            # (default 45) and write an LDIF delete record for this DN
X            cond1="$daysago -ge $mindays"
X            cond2="$daysago -le $maxdays"
X            if [ $cond1 ] && [ $cond2 ]
X            then
X               echo "X\c"
X               msg="User: $fn ($dn)" 
X               echo "$msg" >>$rptfile
X               msg="Last Login ($lastlogin): $mm/$dd/$yy ($daysago days ago)"
X               echo "$msg\n" >>$rptfile
X               echo "dn: $dn" >>$delfile
X               echo "changetype: delete\n" >>$delfile
X            else
X               echo ".\c"
X            fi
X            unset fn
X         fi
X      fi
X   fi
X   unset lastlogin
done
X
# If the mail option is set (default), send the resultant file to the $mailrcpt
if [[ $mail == 1 ]]
then
X  [[ ! -f $rptfile ]] && exit
X  cat - << EOF $rptfile | mail -s "Report: Users not-logged-in between $mindays and $maxdays days" $mailrcpt
X
The following `grep "^User" $rptfile | wc -l` users have not logged in between $mindays and $maxdays days.
----------------------------------------------------------------------------------------------------------
X
EOF
fi
echo "Done. \n"
SHAR_EOF
  (set 20 07 05 09 15 34 26 'lastlogin'; eval "$shar_touch") &&
  chmod 0755 'lastlogin' ||
  $echo 'restore of' 'lastlogin' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'lastlogin': 'MD5 check failed'
ebad56df61b7f1ae7b01ab84e7f6b64d  lastlogin
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'lastlogin'`"
    test 9586 -eq "$shar_count" ||
    $echo 'lastlogin': 'original size' '9586,' 'current size' "$shar_count!"
  fi
fi
# ============= lastlogin.conf ==============
if test -f 'lastlogin.conf' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'lastlogin.conf' '(file already exists)'
else
  $echo 'x -' extracting 'lastlogin.conf' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'lastlogin.conf' &&
#!/bin/bash
#============ Config File for loginrpt  =======================
#
# These values will override the default set in the lastlogin
# script.  Uncomment the lines to override the default values.
#
#==============================================================
X
######################################################
#  LDAP Parameters -- These contol the LDAP search   #
######################################################
X
#------------------------------------------------
# LDAP Attributes to get from LDAPSearch.  Adding 
# attributes to this line will not change the 
# behavior of the script. Only the default 
# attributes are used for comparison, etc.
# so this is basically a silly option.
#------------------------------------------------
#ldapattr="dn fullName LoginTime" 
X
#------------------------------------------------
# Base DN where the LDAP search should start.
# OpenLDAP supports "t=XXX" for those trees that
# have multiple O's at the top
#------------------------------------------------
#basedn="o=myorg"
X
#------------------------------------------------
# URI of the LDAP server being searched
#------------------------------------------------
# ldapurl="ldaps://ldap.myorg.com" 
X
#------------------------------------------------
# LDAP bind dn and password for searches.
# NOTE:  This should be a user with sufficient
# rights to read all attributes from all classes, 
# but should not be a tree admin equivalent.  If
# this is not possible, this file should not be
# world readable.
#------------------------------------------------
#admindn="cn=admin,o=myorg"
#adminpw="superuser"
X
#################################################################
# Script Parameters - These control the way the script behaves
#################################################################
X
#------------------------------------------------
# File where the LDAP search results are stored.
# ldifFile="$progname.ldif"
#------------------------------------------------
#rptfile="$progname.rpt"
X
#------------------------------------------------
# LDIF file that can be used to batch-delete the 
# users who fall outside of $numdays
#------------------------------------------------
#delfile="delusers.ldif"
X
#------------------------------------------------
# Upper and lower range of days since the last 
# login.
#------------------------------------------------
# mindays=45
# maxdays=60
mindays=45
maxdays=9999
X
#------------------------------------------------
# Toggle e-Mailing the results.
#------------------------------------------------
#mail=1
X
#------------------------------------------------
# eMail address who receives the results.
#
# NOTE: Postfix or some other SMTP MTA must be
#       be running on this hose in order for this
#       feature to work.
#------------------------------------------------
#mailrcpt="someadmin@somedomain.com"
X
#------------------------------------------------
# List of CNs to ignore.  User ID's specified 
# here will not be considered in the day-range 
# check.  This list only has the CN portion of
# the DN to ignore.
#------------------------------------------------
ignorelist="ldapuser ldapproxy nfauuser ifolderProxy1075 ifolderProxy3984 rprinter publicuser msgproxy osc unifica eGuideProxy"
SHAR_EOF
  (set 20 07 05 09 16 06 19 'lastlogin.conf'; eval "$shar_touch") &&
  chmod 0644 'lastlogin.conf' ||
  $echo 'restore of' 'lastlogin.conf' 'failed'
  if ( md5sum --help </dev/null 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version </dev/null 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'lastlogin.conf': 'MD5 check failed'
6ad287338b459c3e2387993bf32d3fdf  lastlogin.conf
SHAR_EOF
  else
    shar_count="`LC_ALL=C wc -c < 'lastlogin.conf'`"
    test 3278 -eq "$shar_count" ||
    $echo 'lastlogin.conf': 'original size' '3278,' 'current size' "$shar_count!"
  fi
fi
$echo $shar_n 'x -' 'lock directory' "\`_sh31953': " $shar_c
if rm -fr _sh31953; then
  $echo 'removed'
else
  $echo 'failed to remove'
fi
exit 0
