#!/bin/sh
#
# SccsId[] = "%W% %G% (shell script)"
#
#----------------------------------------------------------------------#
# janitor.sh #
# -------------------------------------------------------------------- #
# Program documentation and notes located at the bottom of script. #
#----------------------------------------------------------------------#
#--------------------------------------------------------------#
# Assignments for name_root and script_name are necessary if #
# there exists the possibility that this process may be run #
# by the 'at' command. Run via 'at' and the `basename $0` used #
# in /usr/local/scripts/defaults.sh to assign $script_name, #
# simply returns the name, 'sh' (hardly desirable). #
#--------------------------------------------------------------#
name_root="janitor"
script_name=$name_root.sh
args=`echo "$@" | sed 's/-/\\-/g'` # Escape dashes
prelims="`date '+%Y-%m-%d %T'` $script_name (v%I%)" # SCCS keyword
#--------------------------------------------------------------#
# Make sure we can find all necessary commands and libraries. #
#--------------------------------------------------------------#
PATH=/usr/bin:/sbin:/bin:/usr/sbin:/usr/ucb:$PATH; export PATH
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/include:/usr/local/lib:/usr/lib:/lib
export LD_LIBRARY_PATH
program_start=`date '+%Y-%m-%d %T'`
#--------------------------------------------------------------#
# Use nawk or gawk, et al, depending on the OS. #
#--------------------------------------------------------------#
OZ=`uname -s 2> /dev/null | tr '[A-Z]' '[a-z]' 2> /dev/null`
if [ ."$OZ" != ."linux" ]; then
bin_dir=/usr/bin
AWK=nawk
MAIL=$bin_dir/mailx
DF=$bin_dir/df
ECHO=$bin_dir/echo
else # Linux
bin_dir=/bin
AWK=gawk
MAIL=$bin_dir/mail
DF=$bin_dir/df
ECHO="$bin_dir/echo -e"
fi
df_opt="-lk"
rm=$bin_dir/rm
host=`hostname || uname -n`
HOST=`echo $host | $AWK '{sub(/\..*/,"");print toupper($0)}'`
#======================================================================#
# I N T E R N A L F U N C T I O N S #
#----------------------------------------------------------------------#
MAIL_ERROR() # Requires $subject and $msg to be assigned. #
#----------------------------------------------------------------------#
{
$ECHO "`date '+%Y-%m-%d %T'` $subject\n$msg" 1>&2
$ECHO "`date '+%Y-%m-%d %T'` $msg" \
| $MAIL -s "$subject" "Bob@OrlandoKuntao.com"
}
#======================================================================#
# L I B R A R Y F U N C T I O N S #
# (in alphabetical order) #
#----------------------------------------------------------------------#
cwd=`pwd`
if [ .${SHLIB} = . ]; then SHLIB=/usr/local/scripts; export SHLIB; fi
if [ .${SHBIN} = . ]; then SHBIN=/usr/local/bin; export SHBIN; fi
#----------------------------------------------------------------#
# If we can't get to shell library, call for help and exit. #
#----------------------------------------------------------------#
`cd $SHLIB 2>&1`
status=$?
if [ $status -ne 0 ]; then
syslog_msg1="Problems cd'ng to $SHLIB."
syslog_msg2="Chdir status=$status. $script_name ($$) terminated."
subject="FATAL ERROR $HOST: CD SHLIB Failure"
msg="$syslog_msg1\n$syslog_msg2"
MAIL_ERROR
exit 1
fi
cd $SHLIB 2>&1
#----------------------------------------------------------------#
# We do this first. Set it up so that when we receive a signal #
# (CTL-C, kill, whatever) we echo the signal we received and #
# exit accordingly. We expand this once we get into 'M A I N'. #
# We skip some signals including CTL-Z and BG (for backgrounding #
# an interactive process). #
#----------------------------------------------------------------#
prelims="$prelims\n`date '+%Y-%m-%d %T'` Assign signal traps."
n=0
for sig in `kill -l`
do
n=`expr $n + 1`
[ ".$sig" = ".EXIT" -o ".$sig" = ".SEGV" \
-o ".$sig" = ".CHLD" -o ".$sig" = ".CLD" \
-o ".$sig" = ".TSTP" -o ".$sig" = ".CONT" \
] && continue
trap "echo Exit $sig \($n\) 1>&2; exit $n" $n
done
prelims="$prelims\n`date '+%Y-%m-%d %T'` Load library functions."
. ./chdir_exit_err.sh ; status=$?
. ./chmod_exit_err.sh ; status=`expr $status + $?`
. ./chmod_exit_err_nomail.sh ; status=`expr $status + $?`
. ./chown_exit_err.sh ; status=`expr $status + $?`
. ./cleanup_work_files.sh ; status=`expr $status + $?`
. ./cp_dev_null_exit_err.sh ; status=`expr $status + $?`
. ./cp_dev_null_exit_err_nomail.sh; status=`expr $status + $?`
. ./cp_exit_err.sh ; status=`expr $status + $?`
. ./elapsed_time.sh ; status=`expr $status + $?`
. ./email_msg.sh ; status=`expr $status + $?`
. ./exit.sh ; status=`expr $status + $?`
. ./exit_if_already_running.sh ; status=`expr $status + $?`
. ./format_num_with_commas.sh ; status=`expr $status + $?`
. ./get_file_perms.sh ; status=`expr $status + $?`
. ./isint.sh ; status=`expr $status + $?`
. ./mv_exit_err.sh ; status=`expr $status + $?`
. ./parse_parameters.sh ; status=`expr $status + $?`
. ./print_vars.sh ; status=`expr $status + $?`
. ./prune_files.sh ; status=`expr $status + $?`
. ./range_nums.sh ; status=`expr $status + $?`
. ./rm_exit_err.sh ; status=`expr $status + $?`
. ./show_documentation.sh ; status=`expr $status + $?`
. ./terminate.sh ; status=`expr $status + $?`
. ./terminate_subprocesses.sh ; status=`expr $status + $?`
. ./touch_exit_err.sh ; status=`expr $status + $?`
. ./touch_exit_err_nomail.sh ; status=`expr $status + $?`
. ./trap_exit.sh ; status=`expr $status + $?`
. ./verify_num_vars.sh ; status=`expr $status + $?`
. ./verify_vars.sh ; status=`expr $status + $?`
# This one last.
. ./defaults.sh ; status=`expr $status + $?`
#--------------------------------------------------------------#
# If anything fails to load, fuss about it and exit. #
#--------------------------------------------------------------#
if [ $status -ne 0 ]; then
syslog_msg1="Function load problems (status=$status)."
syslog_msg2="$script_name '$args' ($$) terminated."
subject="FATAL ERROR $HOST: SHLIB LOAD Failure"
msg="$syslog_msg1\n$syslog_msg2"
MAIL_ERROR
exit 1
fi
prelims="$prelims\n`date '+%Y-%m-%d %T'` Function load complete."
#--------------------------------------------------------------#
# Problems changing to $cwd? Fuss about it and split. #
#--------------------------------------------------------------#
`cd $cwd 2>&1`
status=$?
if [ $status -ne 0 ]; then
syslog_msg1="Problems cd'ng to $cwd!"
syslog_msg2="Chdir status=$status. $script_name ($$) terminated."
subject="FATAL ERROR $HOST: SHLIB LOAD Failure"
msg="$syslog_msg1\n$syslog_msg2"
MAIL_ERROR
exit 1
fi
cd $cwd
#======================================================================#
# U S E R F U N C T I O N S #
# (in alphabetical order) #
#----------------------------------------------------------------------#
BROKEN_SYMBOLIC_LINKS() # Global variables: $broken_links, broken_ln. #
#----------------------------------------------------------------------#
{
if [ $opt_b -ne 1 ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Skipping broken symbolic links check (_BSL_)." | $teelog
broken_links="Link check skipped."
broken_ln=0
echo "${sp}$dashes" | $teelog
return
fi
echo "`date '+%Y-%m-%d %T'`" \
"Checking/removing broken symbolic links (_BSL_)." | $teelog
_BSL_max_time=`expr $max_proc_time \* 3` # This can take a while.
#--------------------------------------------------------#
# Run this in background. #
#--------------------------------------------------------#
_BSL_cmd="/usr/local/bin/linkcheck.pl -lr /"
echo "${sp}$_BSL_cmd"
$_BSL_cmd > $tmpwrk 2>&1 &
[ $opt_v -eq 1 ] \
&& echo "${sp}TERMINATE $! $pidfil $_BSL_max_time"
TERMINATE $! $pidfil $_BSL_max_time
wait # For BG job to complete normally or be TERMINATEd
broken_links=`grep -i 'Found [0-9].* broken links' $tmpwrk`
broken_links=`expr "$broken_links" : '.*: \(.*\)'` # Strip hostname
[ ."$broken_links" = . ] && broken_links="No report from '$_BSL_cmd'!"
broken_ln=`expr "$broken_links" : 'Found \([0-9][0-9]*\) *.*'`
sed "s/^/$sp/" $tmpwrk | $teelog
echo "${sp}$dashes" | $teelog
} # "_BSL_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
CHECK_CRITICAL_ID_MAIL()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'`" \
"Checking critical ID mail (_CCM_)." | $teelog
_CCM_fail_n=0
_CCM_vxvm_n=0
_CCM_mail_n=0
#--------------------------------------------------------------------#
# Check for process failures (by looking for mail to critical users).#
# Use the 'case' construct to add any others we might want checked. #
#--------------------------------------------------------------------#
_CCM_purge_logins="" # List of users no longer having mail
for _CCM_login in $logins
do
[ ."`$AWK '/^'$_CCM_login':/' /etc/passwd`" = . ] && continue
echo "`date '+%Y-%m-%d %T'`" \
"Checking mail for $_CCM_login." | $teelog
_CCM_login_mail=$mail_dir/$_CCM_login
if [ -s "$_CCM_login_mail" ]; then
#----------------------------------------------------------#
# It's really tough to get a count on e-mails. We've tried #
# counting subject and sender lines. Now we're trying #
# Message-Id lines. We may have to divide that tally by 2. #
#----------------------------------------------------------#
# _CCM_mail_n=`grep "Subject: " $_CCM_login_mail | wc -l`
# _CCM_mail_n=`grep "Sender: " $_CCM_login_mail | wc -l`
_CCM_mail_n=`grep -i "^Message-Id: " $_CCM_login_mail | wc -l`
mail_files_n=`expr $mail_files_n + $_CCM_mail_n`
echo "$_CCM_login" >> $notice_list
#------------------------------------------------#
# If this is root we're talking about here, then #
# check for veritas (sparc storage array) errors.#
#------------------------------------------------#
if [ $_CCM_login = "root" ]; then
_CCM_fail_n=`grep "Subject: Volume Manager failures" \
$_CCM_login_mail | wc -l`
_CCM_vxvm_n=`grep "Subject: Attempted VxVM recovery" \
$_CCM_login_mail | wc -l`
_CCM_mail_n=`expr \`grep "Subject: " $_CCM_login_mail|wc -l\` \
- $_CCM_fail_n - $_CCM_vxvm_n`
if [ $_CCM_fail_n -gt 0 ]; then
EMAIL_MSG "URGENT!! Volume Manager Failures" \
"${sp}Check mail on $HOST for details"
elif [ $_CCM_vxvm_n -gt 0 ]; then
EMAIL_MSG "URGENT!! Attempted VxVM Recovery" \
"${sp}Check mail on $HOST for details"
fi
[ $_CCM_mail_n -eq 0 ] && $continue # Iterate our for-loop
fi
#----------------------------------------------------------#
# For all users including root (unless it has iterated our #
# for-loop) do the following: Just being here means that #
# the user has mail. The question remains, do they have #
# one entry in $notice_list (the only other possibility is #
# more than one--can't get here with zero). #
#----------------------------------------------------------#
if [ `grep "$_CCM_login" $notice_list | wc -l` -eq 1 ]; then
_CCM_mail_n=`grep "Subject: " $_CCM_login_mail | wc -l`
if [ $_CCM_mail_n -gt 0 ]; then
grep -i '^Subject: ' $_CCM_login_mail \
| sort -u | sed "s/^/$sp/" 1> $stderr 2>&1
EMAIL_MSG "MAIL FOUND for $_CCM_login." \
"${sp}'Subject:' lines follow:" \
"${sp}$dashes" \
"FILE=$stderr"
fi
else # No mail notification, but log it anyway
grep -i '^Subject: ' $_CCM_login_mail \
| sort | uniq | sed "s/^/$sp/" 1> $stderr 2>&1
echo "`date '+%Y-%m-%d %T'`" \
"MAIL FOUND for $_CCM_login." | $teelog
echo "${sp}'Subject:' lines follow:" | $teelog
echo "${sp}$dashes" | $teelog
cat $stderr | $teelog
fi
else # No mail? OK, add $_CCM_login to our purge list.
_CCM_purge_logins="$_CCM_purge_logins $_CCM_login"
fi # if [ -s "$_CCM_login_mail" ]; then
done # for _CCM_login in $logins
#----------------------------------------------------------#
# Purge any logins from $notice_list (if they're in there) #
# that had no mail (perhaps it's already been read). #
#----------------------------------------------------------#
if [ `echo $_CCM_purge_logins | wc -w` -gt 0 ]; then
PURGE_MAIL_NOTICE_LIST $_CCM_purge_logins
fi
echo "${sp}$dashes" | $teelog
} # "_CCM_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
CHECK_DEV_NULL_PERMS()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'` Checking /dev/null permissions."| $teelog
_CNP_str_perms="crw-rw-rw-"
_CNP_dev_null='/dev/null'
_CNP_null_perms=`ls -al $_CNP_dev_null | $AWK '{print $1}'`
if [ $_CNP_null_perms = "lrwxrwxrwx" ]; then
#-----------------------------------------------#
# If /dev/null is actually a link, then check #
# the permissions of the file to which it links.#
#-----------------------------------------------#
_CNP_null_perms=`ls -alL $_CNP_dev_null | $AWK '{print $1}'`
ls -al $_CNP_dev_null \
| $AWK -v sp="$sp" '{gsub(/[\t ]+/," ");print sp""$0}' | $teelog
fi
ls -alL $_CNP_dev_null \
| $AWK -v sp="$sp" '{gsub(/[\t ]+/," ");print sp""$0}' | $teelog
if [ "$_CNP_null_perms" = "$_CNP_str_perms" ]; then
$ECHO "${sp}$_CNP_dev_null Permissions OK ($_CNP_str_perms)." \
| $teelog
else
EMAIL_MSG "WARNING: /dev/null Permissions Problem" \
"${sp}$_CNP_dev_null permissions NOT '$_CNP_str_perms'!" \
"${sp}Permissions are: '$_CNP_null_perms'"
fi
echo "${sp}$dashes" | $teelog
} # "_CNP_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
CHECK_PARFILE_FOR_UPDATES() # Note: Since this function is expected #
#---------------------------# to be the very first function called, #
# it assigns all its output to $prelims where it will be printed later #
# (assuming all goes well--$prelims will print sooner if anything goes #
# amuck). Only this function behaves in this manner. #
#----------------------------------------------------------------------#
{
ctlfile=$script_home/$name_root.ctl
#--------------------------------------------------------------#
# If janitor.master_par is in use (possibly being FTP'd here) #
# or a control file is found (meaning janitor parameter file #
# update is in progress), notify all that we're skipping this #
# janitor run. #
#--------------------------------------------------------------#
if [ ."`fuser $parfile_master 2> /dev/null`" != . -o -f $ctlfile ]
then
$ECHO "$prelims" 1>&2
EMAIL_MSG "NOTICE $script_name" \
"${sp}Parameter file ($parfile) being updated." \
"${sp}Skipping $0 $args. $script_name terminated."
EXIT 1
fi
prelims="$prelims\n`date '+%Y-%m-%d %T'` Checking parameter file updates."
#--------------------------------------------------------------#
# Compare timestamps in $parfile and $parfile_master. If they #
# differ, then create a new in $parfile from the master and #
# continue. If they are identical, then run as usual. #
#--------------------------------------------------------------#
_CPF_awk_out=`$AWK -v sp="$sp" -v verbose=$opt_v \
'BEGIN {
if (ARGC != 3) exit 4
p = 1
f[1] = ARGV[1]; time[1] = ""; n[1] = 0
f[2] = ARGV[2]; time[2] = ""; n[2] = 0
target = "^[\t ]*\043[\t ]*JANITOR_PARFILE_TIME[\t ]*=[\t ]*"
yyyy_mm_dd = "20[0-9][0-9]\-[01][0-9]\-[0-3][0-9]"
hh_mi_ss = "[0-2][0-9]:[0-5][0-9]:[0-5][0-9]"
pattern = target""yyyy_mm_dd" "hh_mi_ss
if (verbose) print sp"pattern=|"pattern"|"
}
#-----------------------------------------------------------#
# For lines matching our timestamp pattern, .. #
#-----------------------------------------------------------#
$0 ~ pattern \
{
sub(/[\t ]+=[\t ]+/,"=") # Remove whitespace around =-sign
if (verbose) print sp"\$0=|"$0"|"
p = (FILENAME == ARGV[1]) ? 1 : 2 # Processing file 1 or 2?
n[p]++
match($0, yyyy_mm_dd" "hh_mi_ss)
time[p] = substr($0,RSTART,RLENGTH) # Save timestamp
if (verbose) print sp"==> time["p"]=|"time[p]"|"
}
END {
if (ARGC != 3)
{
print sp"Insufficient args for parameter file check."
exit 6
}
if (n[1] > 1 || n[2] > 1)
{
if (n[1] > 1)
{
print sp"Too many timestamps in "ARGV[1]"!"
exit 5
}
if (n[2] > 1)
{
print sp"Too many timestamps in "ARGV[2]"!"
exit 4
}
}
if (n[1] == 0 || n[2] == 0)
{
if (n[1] == 0)
{ # Not found in janitor.master_par
print sp"Timestamp not found in "ARGV[1]"!"
exit 3
}
if (n[2] == 0)
{ # Not found in janitor.par
print sp"Timestamp not found in "ARGV[2]"!"
exit 2
}
}
if (time[1] != time[2])
{
print sp"Updated parameter file detected.",
"\n"sp""ARGV[1]"=|"time[1]"|",
"\n"sp""ARGV[2]"=|"time[2]"|"
exit 1
}
print sp"Parameter file up to date."
exit 0 # Timestamps identical.
}' $parfile_master $parfile`
_CPF_status=$?
prelims="$prelims\n$_CPF_awk_out"
#----------------------------------------------------------------#
# If awk status indicates a change, then create new $parfile. #
#----------------------------------------------------------------#
if [ $_CPF_status -eq 1 -o $_CPF_status -eq 2 ]; then
#-------------------------------------------------------------#
# Check this one more time (to minimize multiple simultaneous #
# creations of this file). #
#-------------------------------------------------------------#
if [ ."`fuser $parfile_master 2> /dev/null`" != . -o -f $ctlfile ]
then
$ECHO "$prelims" 1>&2
EMAIL_MSG "NOTICE $script_name" \
"${sp}Parameter file ($parfile) being updated." \
"${sp}Skipping $0 $args. $script_name terminated."
EXIT 1
fi
echo $$ > $ctlfile
prelims="$prelims\n`date '+%Y-%m-%d %T'` Creating new $parfile."
#-----------------------------------------------------------#
# If one exists, save the current parameter file. #
#-----------------------------------------------------------#
if [ -s "$parfile" ]; then
prelims="$prelims\n`CP_EXIT_ERR $parfile ${parfile}'_bak'`"
[ $? -ne 0 ] && EXIT 1
fi
#-----------------------------------------------------------#
# Create new $parfile, extracting config info from master. #
# Note the #=> MUST be separated from configuration text by #
# whitespace. #
#-----------------------------------------------------------#
$AWK -v sp="$sp" \
-v verbose=$opt_v \
-v hostname=`uname -n` \
'BEGIN {
p = q = 1
export = ""
all = "[\t ]+#=> [Aa][Ll][Ll][\t ]*.*"
host = "[\t ]+#=> [A-Za-z0-9.\t ]*[\!]*"hostname"[\t ]*.*"
exclude = "[\t ]+#=> .*\!"hostname
pattern = all"|"host
if (verbose) # Print to stderr
{
print "2> all =|"all "|" | "cat 1>&2"
print "2> host =|"host "|" | "cat 1>&2"
print "2> exclude=|"exclude"|" | "cat 1>&2"
print "2> pattern=|"pattern"|" | "cat 1>&2"
}
}
# / T E S T / { print "=> " $0 | "cat 1>&2" } ## T E S T ##
$0 ~ pattern \
{
if (match($0,all) && match($0,exclude)) next
# print "==>" $0 | "cat 1>&2" ## T E S T ##
sub(pattern,"") # Remove the pattern from line.
line[p++] = $0 # Save the line as is, even if blank.
}
END {
for (q=1; q<=p; q++) {print line[q]}
}' $parfile_master > $parfile
CPF_status=$?
[ $opt_v -eq 1 ] && cat $parfile
#-----------------------------------------------------------#
# Check the creation status. Restore saved config file #
# if there was a problem. #
#-----------------------------------------------------------#
if [ $CPF_status -eq 0 ]; then
prelims="$prelims\n`date '+%Y-%m-%d %T'` New $parfile creation successful."
else
$ECHO "$prelims" 1>&2
EMAIL_MSG "ALERT $script_name" \
"${sp}$parfile creation completed with $CPF_status status." \
"${sp}Restoring last good $parfile."
MV_EXIT_ERR ${parfile}"_bak" $parfile
fi
RM_EXIT_ERR $ctlfile
elif [ $_CPF_status -ne 0 ]; then
EMAIL_MSG "ERROR $script_name:$_CPF_name()" \
"${sp}Parameter file timestamp problems." \
"${sp}$_CPF_awk_out" \
"${sp}$script_name terminated."
EXIT 1
fi # if [ $_CPF_status -eq 1 -o $_CPF_status -eq 2 ]; then
} # "_CPF_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
CHECK_N_ROLL_CRON_LOG() # Report /var/cron/log size, optionally #
# pruning log if it exceeds $cronlog_size by rolling #
# it over (akin to what happens to /var/adm/messages). #
#----------------------------------------------------------------------#
{
_CRC_name='CHECK_N_ROLL_CRON_LOG'
_CRC_rollovers="None" # Default
echo "`date '+%Y-%m-%d %T'`" \
"Check $cronlog for excessive growth (_CRC_)." | $teelog
if [ ! -f "$cronlog" ]; then # $cronlog a global var
EMAIL_MSG "ERROR $script_name:$_CRC_name()" \
"${sp}$cronlog missing! Killing and restarting cron." \
"${sp}$script_name continues."
CRON_STOP && sleep 5 && CRON_START # ()
_CRC_status=$?
elif [ ! -s "$cronlog" ]; then
EMAIL_MSG "ERROR $script_name:$_CRC_name()" \
"${sp}$cronlog is zero length! Killing and restarting cron." \
"${sp}$script_name continues."
CRON_STOP && sleep 5 && CRON_START # ()
_CRC_status=$?
else
_CRC_bytes=`expr \`wc -c < $cronlog\` + 0`
_CRC_fmt_bytes=`FORMAT_NUM_WITH_COMMAS $_CRC_bytes`
if [ $_CRC_bytes -gt $cronlog_size ]; then
echo "`date '+%Y-%m-%d %T'`" \
"$cronlog has grown to $_CRC_fmt_bytes bytes." | $teelog
_CRC_rollovers="$_CRC_rollovers $cronlog"
if [ $opt_r -eq 1 ]; then
echo "${sp}Rolling over $cronlog." | $teelog
CRON_STOP # ()
_CRC_status=$?
if [ $_CRC_status -eq 0 ]; then
for _CRC_q in `RANGE_NUMS $cronlog_num-1`
do
[ ."$_CRC_q" = . ] && break
_CRC_p=`expr $_CRC_q - 1`
if [ -f "$cronlog.$_CRC_p" ]; then
MV_EXIT_ERR $cronlog.$_CRC_p $cronlog.$_CRC_q
elif [ -f "$cronlog.${_CRC_p}.Z" ]; then
MV_EXIT_ERR $cronlog.$_CRC_p".Z" \
$cronlog.$_CRC_q".Z"
fi
done
MV_EXIT_ERR $cronlog $cronlog".0"
CRON_START # ()
_CRC_status=$?
fi
_CRC_rollovers="$_CRC_rollovers (status=$_CRC_status)"
fi
else
cronlog_size=`FORMAT_NUM_WITH_COMMAS $cronlog_size`
echo "`date '+%Y-%m-%d %T'`" \
"$cronlog size ($_CRC_fmt_bytes)" \
"within acceptable $cronlog_size byte limit." | $teelog
fi
fi
#----------------------------------------------------#
# Compress any uncompressed rolled-over files. If a #
# compressed file exists already, remove it first. #
#----------------------------------------------------#
for _CRC_file in `ls $cronlog.? 2> /dev/null \
| $AWK '/\.[0-9]+$/ {print}'`
do
[ -f "${_CRC_file}$suffix" ] && RM_EXIT_ERR ${_CRC_file}$suffix
echo "`date '+%Y-%m-%d %T'`" \
"$compress -v $_CRC_file" | $teelog
$compress -v $_CRC_file 2>&1 | sed "s/^/$sp/" | $teelog
done
ls -al $cronlog* | sed "s/^/$sp/" | $teelog
echo "${sp}$dashes" | $teelog
return $_CRC_status
} # "_CRC_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
CHECK_N_ROLL_WTMP_FILESIZES() # Report /var/adm/wtmp* file sizes, #
# optionally pruning the log if it exceeds $wtmp_size by rolling #
# it over (like what happens to /var/adm/messages does). #
#----------------------------------------------------------------------#
{
_CRW_rollovers="None"
#------------------------------------------------------#
# The following 'ls' lists only /var/adm/wtmp*.[0-9]+ #
# files, and excludes compressed (.Z) files. #
#------------------------------------------------------#
for _CRW_file in `ls $wtmp_dir/wtmp* 2> /dev/null \
| $AWK '! /\.[0-9]+/ {print}'`
do
echo "`date '+%Y-%m-%d %T'`" \
"Check $_CRW_file for excessive growth (_CRW_)." | $teelog
_CRW_bytes=`expr \`wc -c < $_CRW_file\` + 0`
_CRW_fmt_bytes=`FORMAT_NUM_WITH_COMMAS $_CRW_bytes`
if [ $_CRW_bytes -gt $wtmp_size ]; then
echo "`date '+%Y-%m-%d %T'`" \
"$_CRW_file has grown to $_CRW_fmt_bytes bytes." | $teelog
if [ $opt_r -eq 1 ]; then
_CRW_rollovers="$_CRW_rollovers $_CRW_file"
echo "${sp}Rolling over $_CRW_file." | $teelog
_CRW_perms=`GET_FILE_PERMS $_CRW_file`
for _CRW_q in `RANGE_NUMS $wtmp_num-1`
do
[ ."$_CRW_q" = . ] && break
_CRW_p=`expr $_CRW_q - 1`
if [ -f "$_CRW_file.$_CRW_p" ]; then
MV_EXIT_ERR $_CRW_file"."$_CRW_p \
$_CRW_file"."$_CRW_q
elif [ -f "$_CRW_file.${_CRW_p}.Z" ]; then
MV_EXIT_ERR $_CRW_file"."$_CRW_p".Z" \
$_CRW_file"."$_CRW_q".Z"
elif [ -f "$_CRW_file.${_CRW_p}.gz" ]; then
MV_EXIT_ERR $_CRW_file"."$_CRW_p".gz" \
$_CRW_file"."$_CRW_q".gz"
fi
done
#-----------------------------------------------------#
# After rolling over the log, touch it and restore #
# the file's original permissions. #
#-----------------------------------------------------#
# CP_EXIT_ERR $_CRW_file $_CRW_file".0"
# CP_DEV_NULL_EXIT_ERR $_CRW_file
MV_EXIT_ERR $_CRW_file $_CRW_file".0"
TOUCH_EXIT_ERR $_CRW_file
CHMOD_EXIT_ERR $_CRW_perms "$_CRW_file"
fi
else
echo "`date '+%Y-%m-%d %T'`" \
"$_CRW_file size ($_CRW_fmt_bytes)" \
"within acceptable limit ($wtmp_size)." | $teelog
fi
done
#----------------------------------------------------#
# Compress any uncompressed rolled-over files. If a #
# compressed file exists already, remove it first. #
#----------------------------------------------------#
for _CRW_file in `ls $wtmp_dir/wtmp* 2> /dev/null \
| $AWK '/\.[0-9]+$/ {print}'`
do
[ -f "${_CRW_file}$suffix" ] && RM_EXIT_ERR ${_CRW_file}$suffix
echo "`date '+%Y-%m-%d %T'`" \
"$compress -v $_CRW_file" | $teelog
$compress -v $_CRW_file 2>&1 | sed "s/^/$sp/" | $teelog
done
ls -al $wtmp_dir/wtmp* | sed "s/^/$sp/" | $teelog
echo "${sp}$dashes" | $teelog
} # "_CRW_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
CHECK_PASSWD_FOR_UID_0()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'`" \
"Checking /etc/passwd for UID 0." | $teelog
_CPU_ids=`$AWK -v sp="$sp" \
'BEGIN {
FS=":"
p=0
}
{
if ($3 == 0 && $1 != "root")
{
p++
line[p] = $0
}
}
END {
if (p == 0)
{
print sp"None found."
exit p
}
print sp"UID 0 found for the following non-root ",
"users (_CPU_):"
for (q=0; q<=p; q++) {print sp" "line[q]}
exit p
}' /etc/passwd`
zero_uid_n=$?
zero_uids=`echo $_CPU_ids | $AWK 'BEGIN {FS=":"} {print $2}'`
echo "$_CPU_ids" | $teelog
echo "${sp}$dashes" | $teelog
} # "_CPU_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
CHECK_ROOT_DIR_PERMS()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'`" \
"Checking / (root) directory permissions." | $teelog
_CRP_oct_perms="0755" # Octal value permissions
_CRP_str_perms="drwxr-xr-x" # String (ls) permissions
_CRP_root_perms=`expr "\`ls -ald /\`" : '\(d.........\) .*'`
if [ "$_CRP_root_perms" = "$_CRP_str_perms" ]; then
echo "${sp}/ (root) permissions OK ($_CRP_str_perms)." \
| $teelog
else
CHMOD_EXIT_ERR $_CRP_oct_perms /
_CRP_new_perms=`expr "\`ls -ald /\`" : '\(d.........\) .*'`
EMAIL_MSG "NOTICE: / (root) Permissions Problem" \
"${sp}/ (root) permissions NOT $_CRP_oct_perms!!" \
"${sp}Permissions are currently: '$_CRP_root_perms'" \
"${sp}Changed'em to $_CRP_oct_perms ($_CRP_str_perms)." \
"${sp}Permissions after chmod are: '$_CRP_new_perms'"
fi
} # "_CRP_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
CHECK_TMP_DIR_PERMS()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'`" \
"Checking /tmp and /var/tmp directory permissions." | $teelog
_CTP_oct_perms="1777" # Octal value permissions.
_CTP_1777_perms="drwxrwxrwt" # String perms (ls) with sticky bit.
_CTP_0777_perms="drwxrwxrwx" # String permissions without sticky bit.
_CTP_fil_perms="" # Just so you know what variabls we use.
_CTP_new_perms="" # Assignment asts as a flag as well.
#----------------------------------------------------------------#
# I use the sticky bit on these temp directories because they #
# are world-writable (meaning others can trash your temp files). #
# Using the sticky bit limits file renaming/removal ability to #
# the file's owner, the directory owner, and superuser (root). #
#----------------------------------------------------------------#
for _CTP_dir in /tmp /var/tmp
do
_CTP_fil_perms=`expr "\`ls -ald $_CTP_dir\`" : '\(d.........\) .*'`
if [ "$_CTP_fil_perms" = "$_CTP_1777_perms" ]; then
echo "${sp}$_CTP_dir permissions OK ($_CTP_fil_perms)." \
| $teelog
continue # Iterate the loop
elif [ "$_CTP_fil_perms" = "$_CTP_0777_perms" ]; then
CHMOD_EXIT_ERR $_CTP_oct_perms "$_CTP_dir"
_CTP_new_perms=`expr "\`ls -ald $_CTP_dir\`" : '\(d.........\) .*'`
else
CHMOD_EXIT_ERR $_CTP_oct_perms "$_CTP_dir"
_CTP_new_perms=`expr "\`ls -ald $_CTP_dir\`" : '\(d.........\) .*'`
fi
#-------------------------------------------------------#
# If $_CTP_new_perms is assigned anything, then some #
# discrepency was found. so notify responsible persons. #
#-------------------------------------------------------#
if [ .$_CTP_new_perms != . ]; then
EMAIL_MSG "NOTICE: $_CTP_dir Permissions Incorrect" \
"${sp}$_CTP_dir permissions NOT $_CTP_oct_perms!!" \
"${sp}Permissions are currently: '$_CTP_fil_perms'" \
"${sp}Changed'em to $_CTP_oct_perms ($_CTP_1777_perms)." \
"${sp}Permissions after chmod are: '$_CTP_new_perms'"
_CTP_new_perms=""
fi
done
} # "_CTP_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
CHECK_VAR_MSGS_PERMS()
#----------------------------------------------------------------------#
{
_CVM_dir=`dirname $messages`
echo "`date '+%Y-%m-%d %T'`" \
"Checking $messages* file permissions." | $teelog
_CVM_oct_perms="0644" # Octal value permissions
_CVM_str_perms="-rw-r--r--" # String (ls) permissions
_CVM_cwd=`pwd`
_CVM_status=0
_CVM_find_cmd="find $_CVM_dir -xdev -type f"
_CVM_find_cmd="$_CVM_find_cmd -name 'messages*'"
_CVM_find_cmd="$_CVM_find_cmd ! -perm $_CVM_oct_perms -ls"
echo "`date '+%Y-%m-%d %T'` eval $_CVM_find_cmd" # No $teelog
eval $_CVM_find_cmd | $AWK '{sub(/\.\//,"",$NF);print $3, $NF}' \
| while read _CVM_fil_perms _CVM_file
do
CHMOD_EXIT_ERR $_CVM_oct_perms "$_CVM_file"
_CVM_new_perms=`ls -al $_CVM_file | $AWK '{print $1}'`
EMAIL_MSG "NOTICE: $_CVM_file Permissions Problem" \
"${sp}$_CVM_file permissions NOT $_CVM_oct_perms!!" \
"${sp}Permissions are currently: '$_CVM_fil_perms'" \
"${sp}Changed'em to $_CVM_oct_perms ($_CVM_str_perms)." \
"${sp}Permissions after chmod are: '$_CVM_new_perms'"
_CVM_status=1
done
if [ $_CVM_status -eq 0 ]; then
echo "${sp}$messages* permissions A-OK" \
"($_CVM_str_perms)." | $teelog
fi
CHDIR_EXIT_ERR $_CVM_cwd
echo "${sp}$dashes" | $teelog
} # "_CVM_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
CHMOD_SPECIFIC_FILES() # $1 = fileid of file containing files & perms. #
# # (primarily from janitor.fileperms). #
# # $chmod_m = Global variable #
#----------------------------------------------------------------------#
{
_CSF_name='CHMOD_SPECIFIC_FILES'
if [ $# -lt 1 ]; then
echo "FATAL ERROR $script_name:$_CSF_name()" 1>&2
echo "${sp}Insufficient args." 1>&2
echo "${sp}Usage: $_CSF_name fileid" 1>&2
echo "${sp}$script_name terminated." 1>&2
EXIT 1
fi
if [ -f "$1" ]; then
_CSF_n=`$AWK '{sub(/#+*/,"");if (NF) print}' $1 | wc -l`
[ $_CSF_n -lt 1 ] && return # None listed in the file? Return.
echo "`date '+%Y-%m-%d %T'`" \
"Checking select file permissions from list in $1 (_CSF_)." \
| $teelog
echo 0 > $tmpwrk2 # Initial count (saved outside while-loop)
$AWK '{sub(/#.*/,"");if (NF) print}' $1 \
| while read _CSF_file _CSF_perms
do
if [ -f "$_CSF_file" ]; then
#------------------------------------------------------#
# Don't chmod symbolic links. #
# ---------------------------------------------------- #
_CSF_1st_char=`expr "\`ls -al $_CSF_file\`" : '\(.\).*'`
if [ ."$_CSF_1st_char" = .'l' ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Skipping $_CSF_file -- it's a link." | $teelog
continue # Iterate while loop
fi
# #
#------------------------------------------------------#
[ $verbose -eq 1 ] \
&& echo "${sp}Checking $_CSF_file" | $teelog
_CSF_curr_perms=`GET_FILE_PERMS $_CSF_file`
_CSF_adj_perms=`$AWK \
-v curr_perms="$_CSF_curr_perms" \
-v desired_perms="$_CSF_perms" \
"$awk_perms_script"`
#------------------------------------------------------#
# If adjusted perms != desired perms (even if they're #
# less than the desired), report the difference anyway.#
#------------------------------------------------------#
if [ $_CSF_curr_perms -ne $_CSF_perms ]; then
if [ $opt_c -eq 1 ]; then
if [ $_CSF_adj_perms -ne $_CSF_perms ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Recommended permissions for $_CSF_file" \
"are $_CSF_perms (current =" \
"$_CSF_curr_perms)." | $teelog
fi
ls -al $_CSF_file | sed "s/^/$sp/" | $teelog
fi # if [ $opt_c -eq 1 ]; then
fi
if [ $_CSF_curr_perms -ne $_CSF_adj_perms ]; then
if [ $opt_c -eq 1 ]; then
#------------------------------------------#
# The following changes file permissions: #
#------------------------------------------#
eval echo "`date '+%Y-%m-%d %T'`" \
"Changing $_CSF_file permissions from," \
"$_CSF_curr_perms to $_CSF_adj_perms." | $teelog
ls -al $_CSF_file | sed "s/^/$sp/" | $teelog
$ECHO "`date '+%Y-%m-%d %T'`" \
"eval chmod -f $_CSF_adj_perms $_CSF_file" | $teelog
eval chmod -f $_CSF_adj_perms $_CSF_file
_CSF_status=$?
if [ $_CSF_status -ne $success ]; then
$ECHO "`date '+%Y-%m-%d %T'`" \
"Failure changing $_CSF_file permissions" \
"to $1." | $teelog
else
chmod_m=`expr $chmod_m + 1`
fi
else
#------------------------------------------#
# Following recommends changing file perms #
#------------------------------------------#
echo "`date '+%Y-%m-%d %T'`" \
"Recommend changing $_CSF_file permissions" \
"from, $_CSF_curr_perms to $_CSF_perms." | $teelog
fi # if [ $opt_c -eq 1 ]; then
ls -al $_CSF_file | sed "s/^/$sp/" | $teelog
fi # if [ $_CSF_curr_perms -ne $_CSF_perms ]; then
else
#----------------------------------------------------#
# This should help to keep list current. When files #
# are routinely missing, this reminds us to purge #
# them from our list. HOWEVER, it is only to show #
# up when this process is run interactively. #
#----------------------------------------------------#
if [ ."$TERM" != . ]; then
$ECHO "${sp}List file !found: $_CSF_file."
fi
fi # if [ -f $_CSF_file ]; then
echo $chmod_m > $tmpwrk2 # Pass this count outside for-loop
done # while read _CSF_file _CSF_perms
chmod_m=`cat $tmpwrk2` # Pick up passed count
#-----------------------------------------------------------#
# If nothing was changed, then for the record, show'em what #
# we're using (from our list). #
#-----------------------------------------------------------#
if [ $chmod_m -eq 0 ]; then
$ECHO "`date '+%Y-%m-%d %T'`" \
"All files match or exceed (are more restrictive" \
"\n${sp}than) the following permission list:" | $teelog
$AWK -v sp="$sp" \
'{
gsub(/#.*/ ,"")
gsub(/^[\t ]*/,"")
if ($0 !~ /^$/)
{
gsub(/^/,sp)
print
}
}' $1 | $teelog
fi
echo "${sp}$dashes" | $teelog
fi # if [ -f $1 ]; then
} # "_CSF_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
CRON_START()
#----------------------------------------------------------------------#
{
_CRS_process=`QUERY_PROCESS "$cron_demon"` # ()
_CRS_status=$?
#---------------------------------------------------------#
# There should be none. Period. If there are, then fuss #
# about and return. #
#---------------------------------------------------------#
if [ $_CRS_status -gt 0 ]; then
ps $ps_opts > $tmpwrk 2>&1
EMAIL_MSG "ERROR $script_name:$_CRS_name()" \
"${sp}$cron_demon process running! 'ps' list follows." \
"${sp}Cron NOT started. $script_name continues." \
"`sed \"s/^/$sp/\" $tmpwrk`"
return $_CRS_status
fi
echo "`date '+%Y-%m-%d %T'` $cron_start" | $teelog
$cron_start > $tmpwrk 2>&1
sleep 10 # Give it some time to complete.
_CRS_process=`QUERY_PROCESS "$cron_demon"` # ()
_CRS_status=$?
if [ $_CRS_status -eq 0 ]; then # Cron ! started
echo "${sp}'$cron_start' failed to start cron!" | $teelog
#-------------------------------------------#
# If running SunOs and cron fails to start, #
# then remove cron FIFO file and try again. #
#-------------------------------------------#
if [ ."$OZ" = ."sunos" ]; then
echo "${sp}Attempting restart." | $teelog
echo "`date '+%Y-%m-%d %T'`" \
"$rm -f /etc/cron.d/FIFO" | $teelog
$rm -f /etc/cron.d/FIFO 2>&1 | $teelog
echo "`date '+%Y-%m-%d %T'`" \
"$cron_start" | $teelog
$cron_start > $tmpwrk 2>&1
fi # if [ ."$OZ" = ."sunos" ]
sleep 10 # Give it more time to complete.
_CRS_process=`QUERY_PROCESS "$cron_demon"` # ()
_CRS_status=$?
if [ $_CRS_status -eq 0 ]; then
ps $ps_opts > $tmpwrk 2>&1
EMAIL_MSG "ERROR $script_name:$_CRS_name()" \
"${sp}'$cron_start' failed to start cron!" \
"${sp}Check it out. $script_name continues." \
"`sed \"s/^/$sp/\" $tmpwrk`"
fi
else
[ -s "$tmpwrk" ] && sed "s/^/$sp/" $tmpwrk | $teelog
[ -f "$cronlog" ] && tail -20 $cronlog | sed "s/^/$sp/" | $teelog
fi # if [ $_CRS_status -eq 0 ]
#------------------------------------------------------------#
# Return success (0) if status > 0, else return failure (1). #
#------------------------------------------------------------#
[ $_CRS_status -gt 0 ] && return 0 || return 1
} # "_CRS_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
CRON_STOP()
#----------------------------------------------------------------------#
{
_CSTP_process=`QUERY_PROCESS "$cron_demon"` # ()
_CSTP_status=$?
#------------------------------------------------------------#
# There should be only 1, max. If more, then fuss about it #
# and return. If only one, try shutting it down properly. #
#------------------------------------------------------------#
if [ $_CSTP_status -gt 1 ]; then
ps $ps_opts > $tmpwrk 2>&1
EMAIL_MSG "ERROR $script_name:$_CSTP_name()" \
"${sp}Found multiple cron processes! List follows." \
"${sp}$script_name continues." \
"`sed \"s/^/$sp/\" $tmpwrk`"
fi
echo "`date '+%Y-%m-%d %T'` $cron_stop" | $teelog
$cron_stop > $tmpwrk 2>&1
sleep 10 # Give it some time to complete.
_CSTP_process=`QUERY_PROCESS "$cron_demon"` # ()
_CSTP_status=$?
echo "${sp}2. \$_CSTP_status =|$_CSTP_status|" | $teelog
echo "${sp}2. \$_CSTP_process=|$_CSTP_process|" | $teelog
if [ $_CSTP_status -gt 0 ]; then
ps $ps_opts > $tmpwrk 2>&1
EMAIL_MSG "ERROR $script_name:$_CSTP_name()" \
"${sp}'$cron_stop' returned $_CSTP_status!" \
"${sp}Check it out. $script_name continues." \
"`sed \"s/^/$sp/\" $tmpwrk`"
else
[ -s "$tmpwrk" ] && sed "s/^/$sp/" $tmpwrk | $teelog
[ -f "$cronlog" ] && tail -20 $cronlog | sed "s/^/$sp/" | $teelog
fi
#--------------------------------------------------#
# Return number of processes found (0 = success). #
#--------------------------------------------------#
return $_CSTP_status
} # "_CSTP_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
DISPLAY_TMPWRK()
#----------------------------------------------------------------------#
{
wait # for any errant BG jobs
[ -s "$tmpwrk" ] && cat $tmpwrk
echo "${sp}$dashes"
$rm -f $tmpwrk 2>&1 | $teelog
}
#----------------------------------------------------------------------#
DISPLAY_SETUID_SCRIPTS()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'`" \
"Looking for set[ug]id executable scripts (perm 4000)." | $teelog
_DSS_n=0
_DSS_found=0
#--------------------------------------------------------------#
# NOTE: "/etc/lp/alerts/printer" is the only executable shell #
# script having setuid/setgid file permissions allowed. #
#--------------------------------------------------------------#
CP_DEV_NULL_EXIT_ERR $stderr $tmpwrk $tmpwrk1
for _DSS_fs in $fs /tmp
do
echo "`date '+%Y-%m-%d %T'` Checking $_DSS_fs." | $teelog
#---------------------------------------------------------#
# If we're searching root (/), then use -xdev to keep the #
# search local (hopefully it won't descend into subdirs). #
#---------------------------------------------------------#
if [ $_DSS_fs = '/' ]; then
_DSS_opt="-xdev"
else # Not root dir and
if [ ."$OZ" != ."linux" ]; then # not Linux? (SunOS),
_DSS_opt="-local" # so use -local.
else # Else Linux, so don't use
_DSS_opt="" # -local option (doesn't
fi # know -local).
fi
#-----------------------------------------------------------------#
# Display the command before running it so anyone can cut-n-paste #
# it as needed. Note: the '\;' must remain outside the $_..._find #
# assignment or the find fails for incomplete statement. #
#-----------------------------------------------------------------#
_DSS_find="find $_DSS_fs $exclude_fs $_DSS_opt -type f"
_DSS_find="$_DSS_find -perm -4000 -exec file {}"
if [ $opt_v -eq 1 ]; then
echo "`date '+%Y-%m-%d %T'` $_DSS_find \;" | $teelog
fi
#---------------------------------------#
# Run this in background. #
#---------------------------------------#
eval $_DSS_find '\;' 2>&1 \
| egrep -vi "permission denied|timed out|cannot open" \
>> $stderr &
[ $opt_v -eq 1 ] \
&& echo "${sp}TERMINATE $! $pidfil $max_proc_time"
TERMINATE $! $pidfil $max_proc_time
wait # For BG job to complete normally or be TERMINATEd
#---------------------------------------#
# If we snagged anything, then report. #
#---------------------------------------#
if [ -s "$stderr" ]; then
$AWK -v sp="$sp" \
'{
file=tolower($0)
if (! \
( \
match(file,/executable shell script/) \
|| \
match(file,/commands text/) \
) \
) {next}
if (match(file,/\/etc\/lp\/alerts\/printer/)) {next}
gsub(/^[\t ]+/,"",$0)
gsub(/[\t ]+$/,"",$0)
sub(/:.*/,"",$0)
"/usr/bin/ls -al " $0 | getline ls_out
print sp""ls_out
}' $stderr | sort -u +8 > $tmpwrk1 # Sort drops dup lines
fi
_DSS_found=`expr \`wc -l < $stderr\` + 0`
_DSS_n=`expr $_DSS_found - $_DSS_n`
echo "${sp}Files found in $_DSS_fs = $_DSS_n" | $teelog
_DSS_n=$_DSS_found
done # for _DSS_fs in $fs /tmp
#--------------------------------------------#
# Since these are hot, mail this list ASAP. #
#--------------------------------------------#
echo "${sp}Total files found = $_DSS_found" | $teelog
_DSS_found=`expr \`wc -l < $tmpwrk1\` + 0`
if [ $_DSS_found -gt 0 -o -s "$tmpwrk1" ]; then
if [ $opt_m -eq 1 ]; then
EMAIL_MSG "$_DSS_found Set[UG]id files found (_DSS_)!" \
"${sp}List follows:" \
"${sp}$dashes" \
"FILE=$tmpwrk1"
else
echo "`date '+%Y-%m-%d %T'`" \
"$_DSS_found Set[UG]id files found (_DSS_)!" | $teelog
echo "${sp}List follows:" | $teelog
echo "${sp}$dashes" | $teelog
cat $tmpwrk1 | $teelog
fi
suid_scripts_n=$_DSS_found
else
$ECHO "${sp}No set[ug]id scripts among the files.\n" | $teelog
fi
echo "${sp}$dashes" | $teelog
} # "_DSS_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
ENSURE_GNUPG_PERMS()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'`" \
"Ensuring GnuPG perms (_EGP_)." | $teelog
[ -d /.gnupg ] && CHOWN_EXIT_ERR root /.gnupg
FIND_AND_CHMOD -f 4755 gpg # ()
echo "${sp}$dashes" | $teelog
} # "_EGP_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
EXAMINE_NETRC_FILES()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'`" \
"Examining all .netrc files (_ENF_)." | $teelog
CP_DEV_NULL_EXIT_ERR $stderr $tmpwrk $tmpwrk1 $tmpwrk2
for _ENF_fs in $fs
do
echo "`date '+%Y-%m-%d %T'` Checking $_ENF_fs." | $teelog
cp /dev/null $stderr 2>&1
#---------------------------------------------------------#
# If we're searching root (/), then use -xdev to keep the #
# search local (hopefully it won't descend into subdirs). #
#---------------------------------------------------------#
if [ $_ENF_fs = '/' ]; then
_ENF_opt="-xdev"
else # Not root dir and
if [ ."$OZ" != ."linux" ]; then # not Linux? (SunOS),
_ENF_opt="-local" # so use -local.
else # Else Linux, so don't use
_ENF_opt="" # -local option (doesn't
fi # know -local).
fi
#---------------------------------------------------------#
# Run find command in background. #
#---------------------------------------------------------#
_ENF_find="find $_ENF_fs $exclude_fs $_ENF_opt"
_ENF_find="$_ENF_find -name .netrc -print"
if [ $opt_v -eq 1 ]; then
echo "`date '+%Y-%m-%d %T'` $_ENF_find" | $teelog
fi
eval $_ENF_find 2>&1 \
| egrep -vi "permission denied|timed out|cannot open" \
> $tmpwrk1 &
[ $opt_v -eq 1 ] \
&& echo "${sp}TERMINATE $! $pidfil $max_proc_time"
TERMINATE $! $pidfil $max_proc_time
status=$?
wait # For BG job to complete normally or be TERMINATEd
[ -s "$stderr" ] && sed "s/^/$stderr_sp/" $stderr | $teelog
if [ -s "$tmpwrk1" ]; then
$AWK -v sp="$sp" -v opt_n=$opt_n \
'! /^\+? ?find / \
{ # Print filename, and if $opt_n, the contents as well.
print sp""$0
if (opt_n == 1)
while ("/bin/cat "$0 | getline out != 0)
if (out !~ /^[\t\n\r ]*$/) # Skip blank lines.
print sp" "out
close("/bin/cat "$0)
}' $tmpwrk1 | $teelog
fi
cat $tmpwrk1 >> $tmpwrk # This is that we, indeed, have files.
done # for _ENF_fs in $fs
if [ ! -s "$tmpwrk" ]; then
echo "`date '+%Y-%m-%d %T'` No .netrc files found!" | $teelog
fi
CP_DEV_NULL_EXIT_ERR $stderr $tmpwrk $tmpwrk1 $tmpwrk2
echo "${sp}$dashes" | $teelog
} # "_ENF_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
EXAMINE_RHOSTS_FILES()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'`" \
"Examining all rhosts files (_ERF_)." | $teelog
unsafe_m=0 # Global variable
CP_DEV_NULL_EXIT_ERR $stderr $tmpwrk $tmpwrk1 $tmpwrk2
for _ERF_fs in $fs
do
echo "`date '+%Y-%m-%d %T'` Checking $_ERF_fs." | $teelog
cp /dev/null $stderr 2>&1
#---------------------------------------------------------#
# If we're searching root (/), then use -xdev to keep the #
# search local (hopefully it won't descend into subdirs). #
#---------------------------------------------------------#
if [ $_ERF_fs = '/' ]; then
_ERF_opt="-xdev"
else # Not root dir and
if [ ."$OZ" != ."linux" ]; then # not Linux? (SunOS),
_ERF_opt="-local" # so use -local.
else # Else Linux, so don't use
_ERF_opt="" # -local option (doesn't
fi # know -local).
fi
#-----------------------------------------------#
# Run find command in background. #
#-----------------------------------------------#
if [ $opt_v -eq 1 ]; then
echo "`date '+%Y-%m-%d %T'`" \
"find $_ERF_fs $exclude_fs $_ERF_opt $rhost_pr" | $teelog
fi
#-----------------------------------------------#
# Run this in background and must have 'eval'. #
#-----------------------------------------------#
eval find $_ERF_fs $exclude_fs $_ERF_opt $rhost_pr \
> $tmpwrk1 2> $tmpwrk2 &
[ $opt_v -eq 1 ] \
&& echo "${sp}TERMINATE $! $pidfil $max_proc_time"
TERMINATE $! $pidfil $max_proc_time
status=$?
wait # For BG job to complete normally or be TERMINATEd
[ -s "$stderr" ] && sed "s/^/$stderr_sp/" $stderr | $teelog
[ -s "$tmpwrk2" ] && sed "s/^/$tmpwrk2_sp/" $tmpwrk2 \
| egrep -vi "permission denied|timed out|cannot open" | $teelog
if [ -s "$tmpwrk1" ]; then
for _ERF_fil in `cat $tmpwrk1`
do
$AWK -v sp="$sp" \
'BEGIN {
n=0
print sp""ARGV[1]
}
# Print "unsafe" lines here
/^[\t ]*(\+[\t ]*$|\+[\t ]+\+[\t ]*$)/ \
{
n++
print sp" !! UNSAFE => "$0
next
}
# All other lines print here
{
print sp" "$0
}
END {exit n}' $_ERF_fil > $tmpwrk2 # Reusing $tmpwrk2
unsafe_m=`expr $unsafe_m + $?`
cat $tmpwrk2 | $teelog
done
fi
cat $tmpwrk1 >> $tmpwrk # This is how I know if there are any files
done # for _ERF_fs in $fs
if [ ! -s "$tmpwrk" ]; then
echo "`date '+%Y-%m-%d %T'` No .rhosts files found!" | $teelog
fi
CP_DEV_NULL_EXIT_ERR $stderr $tmpwrk $tmpwrk1 $tmpwrk2
echo "${sp}$dashes" | $teelog
} # "_ERF_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
FIND_AND_CHMOD() # Args = [-f] mode fileid(s) (e.g. .rhosts .forward) #
# # $unsafe_n = Global variable #
#----------------------------------------------------------------------#
{
_FAC_name='FIND_AND_CHMOD'
if [ ."$1" = ."-f" ]; then
_FAC_opt_f=1
shift
else
_FAC_opt_f=0
fi
if [ $# -lt 2 ]; then
EMAIL_MSG "FATAL ERROR $script_name:$_FAC_name" \
"${sp}Insufficient args." \
"${sp}Usage: $_FAC_name perms fileid ..." \
"${sp}$script_name terminated."
EXIT 1
fi
#----------------------------------------------#
# Parse and verify perms are at least numeric. #
#----------------------------------------------#
ISINT $1
if [ $? -ne 1 ]; then
EMAIL_MSG "FATAL ERROR $script_name:$_FAC_name" \
"${sp}'$1' not an integer!" \
"${sp}Usage: $_FAC_name perms fileid ..." \
"${sp}$script_name continues."
return 1
fi
_FAC_perms=$1
shift
#--------------------------------------------------------------------#
_FAC_CHMOD() # Function within FIND_AND_CHMOD() to change perms. #
#--------------------------------------------------------------------#
{
eval echo "`date '+%Y-%m-%d %T'`" \
"Changing $_FAC_found_file permissions from," \
"$_FAC_curr_perms to $1." | $teelog
$ECHO "`date '+%Y-%m-%d %T'`" \
"eval chmod -f $1 $_FAC_found_file" | $teelog
eval chmod -f $1 $_FAC_found_file
_FAC_status=$?
ls -al $_FAC_found_file | sed "s/^/$sp/" | $teelog
if [ $_FAC_status -ne $success ]; then
$ECHO "`date '+%Y-%m-%d %T'`" \
"Failure changing $_FAC_found_file permissions" \
"to $1." | $teelog
else
unsafe_n=`expr $unsafe_n + 1`
fi
} # _FAC_CHMOD()
CP_DEV_NULL_EXIT_ERR $stderr
#--------------------------------------------------------------#
# Seek out files, changing weaker (less safe) perms as needed. #
#--------------------------------------------------------------#
echo 0 > $tmpwrk2 # Initial count (saved outside while-loop)
for _FAC_file in $*
do
CP_DEV_NULL_EXIT_ERR $tmpwrk1
_FAC_file=`echo $_FAC_file | sed 's/^.*\///'`
echo "`date '+%Y-%m-%d %T'`" \
"Searching for $_FAC_file file(s) with unsafe permissions (_FAC_)." \
| $teelog
#-----------------------------------------------------------#
# First, find all target files bearing $_FAC_file name. #
#-----------------------------------------------------------#
_FAC_list=""
for _FAC_fs in $fs
do
echo "`date '+%Y-%m-%d %T'` Checking $_FAC_fs." | $teelog
#----------------------------------------------------------#
# If we're searching root (/), then use -xdev to keep the #
# search local (hopefully it won't descend into subdirs). #
#----------------------------------------------------------#
if [ $_FAC_fs = '/' ]; then
_FAC_opt="-xdev"
else # Not root dir and
if [ ."$OZ" != ."linux" ]; then # not Linux? (SunOS),
_FAC_opt="-local" # so use -local.
else # Else Linux, so don't use
_FAC_opt="" # -local option (doesn't
fi # know -local).
fi
#----------------------------------#
# Run find command in background. #
#----------------------------------#
_FAC_find="find $_FAC_fs $exclude_fs $_FAC_opt -type f"
_FAC_find="$_FAC_find -type f -name \"$_FAC_file\" -print"
if [ $opt_v -eq 1 ]; then
echo "`date '+%Y-%m-%d %T'` $_FAC_find" | $teelog
fi
#----------------------------------#
# Run this in background. #
#----------------------------------#
eval $_FAC_find 2>&1 \
| egrep -vi "permission denied|timed out|cannot open" \
> $tmpwrk1 &
[ $opt_v -eq 1 ] \
&& echo "${sp}TERMINATE $! $pidfil $max_proc_time"
TERMINATE $! $pidfil $max_proc_time
status=$?
wait # For BG job to complete normally or be TERMINATEd
done # for _FAC_fs in $fs
[ -s "$stderr" ] && sed "s/^/$stderr_sp/" $stderr | $teelog
#---------------------------------------------------------#
# Run the list of files found, changing weaker files. #
#---------------------------------------------------------#
for _FAC_found_file in `cat $tmpwrk1`
do
#----------------------------------------------------#
# Just in case it's part of an error msg that slips #
# thru from the 'find' above, test file's existance. #
#----------------------------------------------------#
if [ ! -f "$_FAC_found_file" ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Skipping '$_FAC_found_file' -- not found!" | $teelog
continue # Iterate while loop
fi
#------------------------------------------------------#
# Don't chmod symbolic links (this is insurance -- the #
# above find command should exclude symbolic links). #
_FAC_1st_char=`expr "\`ls -al $_FAC_found_file 2> /dev/null\`" : '\(.\).*'`
if [ ."$_FAC_1st_char" = .'l' ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Skipping $_FAC_found_file -- it's a link." | $teelog
continue # Iterate while loop
fi
# #
#------------------------------------------------------#
ls -al $_FAC_found_file | sed "s/^/$sp/" | $teelog
_FAC_curr_perms=`GET_FILE_PERMS $_FAC_found_file`
_FAC_adj_perms=`$AWK \
-v curr_perms="$_FAC_curr_perms" \
-v desired_perms="$_FAC_perms" \
"$awk_perms_script"`
#------------------------------------------------------#
# If adjusted perms != desired perms (even if they're #
# less than the desired), report the difference anyway.#
#------------------------------------------------------#
if [ $_FAC_curr_perms -ne $_FAC_perms ]; then
if [ $opt_c -eq 1 ]; then
if [ $_FAC_adj_perms -ne $_FAC_perms ]; then
if [ $_FAC_opt_f -eq 1 ]; then
_FAC_CHMOD $_FAC_perms
else
echo "`date '+%Y-%m-%d %T'`" \
"Recommended permissions for $_FAC_found_file" \
"are $_FAC_perms (current=$_FAC_curr_perms)." \
| $teelog
fi
fi
fi # if [ $opt_c -eq 1 ]; then
fi # if [ $_FAC_curr_perms -ne $_FAC_perms ]; then
if [ $_FAC_curr_perms -ne $_FAC_adj_perms ]; then
if [ $opt_c -eq 1 -o $_FAC_opt_f -eq 1 ]; then
_FAC_CHMOD $_FAC_adj_perms
else
#--------------------------------------------------#
# Following recommends changing file permissions: #
#--------------------------------------------------#
echo "`date '+%Y-%m-%d %T'`" \
"Recommend changing $_FAC_found_file permissions" \
"from, $_FAC_curr_perms to $_FAC_perms." | $teelog
fi # if [ $opt_c -eq 1 -o $_FAC_opt_f -eq 1 ]; then
fi # if [ $_FAC_curr_perms -ne $_FAC_perms ]; then
echo $unsafe_n > $tmpwrk2 # Pass this count outside for-loop
done # for _FAC_found_file in `cat $tmpwrk1`
done # for _FAC_file in $*
unsafe_n=`cat $tmpwrk2`
} # "_FAC_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
FIND_ERRORS_IN_SYSLOGS() # Scan for errors newer than $msgs_back #
#----------------------------------------------------------------------#
{
#------------------------------------------------------------------#
# 1st, create an array of days back dates in the form 'Mmm dd ...' #
#------------------------------------------------------------------#
_FES_mmm_dd_array=""
_FES_limit=20
#------------------------------------------------------------------#
# $syslogs contains /var/adm/messages and /var/log/syslog, however,#
# /var/log/syslog* is excluded because its files are too big. #
#------------------------------------------------------------------#
for _FES_syslog in "${syslog_dir}messages"
do
#---------------------------------------------------------#
# Reduce the number of logs we scan by getting only those #
# with file dates more recent than our oldest date. #
#---------------------------------------------------------#
_FES_fname=`basename $_FES_syslog`
_FES_yyyymmdd=`/usr/local/bin/dateplus -5`
_FES_mmdd=`echo $_FES_yyyymmdd | cut -c5-8`
_FES_logs=`ls -alr $_FES_syslog* \
| $AWK '/'$_FES_fname'\.*[0-9]*$/ {print $6,$7,$NF}' \
| $AWK -v mmdd=$_FES_mmdd \
'BEGIN {
logs=""
Mon["Jan"]="01" ; Mon["Jul"]="07"
Mon["Feb"]="02" ; Mon["Aug"]="08"
Mon["Mar"]="03" ; Mon["Sep"]="09"
Mon["Apr"]="04" ; Mon["Oct"]="10"
Mon["May"]="05" ; Mon["Nov"]="11"
Mon["Jun"]="06" ; Mon["Dec"]="12"
}
/'$_FES_fname'\.*[0-9]*$/ \
{
ls_mmdd=Mon[$1]sprintf("%02d",$2)
if (ls_mmdd >= mmdd)
logs = logs" "$NF
}
END {print logs}'`
if [ ."$_FES_logs" = . ]; then
echo "`date '+%Y-%m-%d %T'`" \
"No messages files found in $syslog_dir!" | $teelog
continue
fi
echo "`date '+%Y-%m-%d %T'`" \
"Last $msgs_back days 'error's ($_FES_limit lines worth)" \
"from $_FES_logs" | $teelog
#-----------------------------------------------------------------#
# Now here's s really tricky part. First, I require that the file #
# list just handed to me be in oldest to newest order because we #
# concatonate them to maintain their chronology. Then we number #
# their lines and sort those lines in reverse order by the line #
# number. We feed all that into $AWK which returns no more than #
# the number of lines in $_FES_limit ($AWK does that last part #
# for us). Essentially, we're tailing the last nn lines of just #
# the errors we find, listing them in LIFO order. #
#-----------------------------------------------------------------#
cat $_FES_logs | nl | sort -r +0 -1 \
| $AWK -v days_back=$msgs_back \
-v line_limit=$_FES_limit \
-v sp="$sp" \
-v dateplus="$dateplus" \
'BEGIN {
#------------------------------------------------#
# Create Mon[] hash with month numbers by name. #
#------------------------------------------------#
Mon["Jan"]="01" ; Mon["Feb"]="02" ; Mon["Mar"]="03"
Mon["Apr"]="04" ; Mon["May"]="05" ; Mon["Jun"]="06"
Mon["Jul"]="07" ; Mon["Aug"]="08" ; Mon["Sep"]="09"
Mon["Oct"]="10" ; Mon["Nov"]="11" ; Mon["Dec"]="12"
#---------------------------------------------#
# Add month names by number to the Mon[] hash #
# (so we can look-em up either way). #
#---------------------------------------------#
Mon["01"]="Jan" ; Mon["02"]="Feb" ; Mon["03"]="Mar"
Mon["04"]="Apr" ; Mon["05"]="May" ; Mon["06"]="Jun"
Mon["07"]="Jul" ; Mon["08"]="Aug" ; Mon["09"]="Sep"
Mon["10"]="Oct" ; Mon["11"]="Nov" ; Mon["12"]="Dec"
#---------------------------------------------#
# Target error strings #
#---------------------------------------------#
t1="[Ee][Rr][Rr][Oo][Rr]"
t2="[Pp][Aa][Nn][Ii][Cc]"
t3="core dumped"
t4="syncing file systems"
#---------------------------------------------#
# Assign today (Mon, mm, and dd) to arrays[1].#
#---------------------------------------------#
"/bin/date +%h%m%d" | getline MonMmDd
Mon_dd[1] = substr(MonMmDd,1,3)
mm = substr(MonMmDd,4,2)
dd = substr(MonMmDd,6,2)
mmdd[1] = mm""dd
Mon_dd[1] = Mon_dd[1]" "dd
Mon_dd_hash[Mon[mm]" "sprintf("%02d",dd)] = 1
#----------------------------------------------#
# Now assign all the dates back to arrays[n]. #
#----------------------------------------------#
for (n=days_back;n>1;n--)
{
dateplus" -"(n-1) | getline yyyymmdd
mm = substr(yyyymmdd,5,2)
dd = substr(yyyymmdd,7,2)
mmdd[n] = mm""dd
Mon_dd[n] = Mon[mm]" "sprintf("%02d",dd)
Mon_dd_hash[Mon[mm]" "sprintf("%02d",dd)] = n
}
n=0
} # End of BEGIN Section
{
if (n > line_limit)
exit # User only wanted so many lines.
sub(/^[\t ]*[0-9]+[\t ]*/,"")
}
/^[ADFJMNOS][aceopu][bcglnprtvy] [1-3 ][0-9] / \
{
line_Mon_dd = sprintf("%s %2d",$1, $2)
line_mmdd = Mon[$1]sprintf("%02d",$2)
##--------------------------------------------------##
## Redo this logic -- fails at EOY ##
## if (line_mmdd < mmdd[days_back]) ##
## exit # We are done when we find older record ##
##--------------------------------------------------##
if (line_Mon_dd in Mon_dd_hash)
{
if ($0 ~ /STDERR=/) {next} # Skip these
if (match($0,t1)||match($0,t2)||match($0,t3)||match($0,t4))
{
print sp""$0
n++
}
}
}' | $teelog
echo "${sp}$dashes" | $teelog
# Now, go look at the next set of logs #
done # for _FES_syslog in $syslogs
} # "_FES_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
LAST_20_LINES_SYSLOGS()
#----------------------------------------------------------------------#
{
for _L2L_syslog in $syslogs
do
if [ -s "$_L2L_syslog" ]; then
echo "`date '+%Y-%m-%d %T'`" \
"LAST 20 LINES of $_L2L_syslog:" | $teelog
tail -20 $_L2L_syslog | sort -rM \
| sed "s/^ *//;/^$/d;s/^/$sp/" > $tmpwrk 2>&1
DISPLAY_TMPWRK | $teelog
fi
done
[ -f "$tmpwrk" ] && RM_EXIT_ERR $tmpwrk
} # "_L2L_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
LIST_ALL_WW_FILES() # Showem all world writable files #
# $ww_files_n = Global variable #
#----------------------------------------------------------------------#
{
if [ $opt_w -ne 1 ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Skipping ALL WW-files list (_LWW_)." | $teelog
echo "${sp}$dashes" | $teelog
return
fi
$ECHO "`date '+%Y-%m-%d %T'`" \
"Look for world-writable files (perm 0002)" \
"\n${sp}found anywhere." | $teelog
_LWW_n=0
_LWW_found=0
CP_DEV_NULL_EXIT_ERR $stderr
for _LWW_fs in $fs /tmp
do
echo "`date '+%Y-%m-%d %T'` Checking $_LWW_fs." | $teelog
#---------------------------------------------------------#
# If we're searching root (/), then use -xdev to keep the #
# search local (hopefully it won't descend into subdirs). #
#---------------------------------------------------------#
if [ $_LWW_fs = '/' ]; then
_LWW_opt="-xdev"
else # Not root dir and
if [ ."$OZ" != ."linux" ]; then # not Linux? (SunOS),
_LWW_opt="-local" # so use -local.
else # Else Linux, so don't use
_LWW_opt="" # -local option (doesn't
fi # know -local).
fi
#-----------------------------------------------------------------#
# Display the command before running it so anyone can cut-n-paste #
# it as needed. Note: the '\;' must remain outside the $_LWW_find #
# assignment or the find fails for incomplete statement. #
#-----------------------------------------------------------------#
_LWW_find="find $_LWW_fs $exclude_fs $_LWW_opt -type f"
_LWW_find="$_LWW_find -perm -0002 ! -perm -0003 -exec ls -al {}"
if [ $opt_v -eq 1 ]; then
echo "`date '+%Y-%m-%d %T'` $_LWW_find \;" | $teelog
fi
#-------------------------#
# Run this in background. #
#-------------------------#
eval $_LWW_find '\;' 2>&1 \
| egrep -vi "permission denied|timed out|cannot open" \
>> $stderr &
[ $opt_v -eq 1 ] \
&& echo "${sp}TERMINATE $! $pidfil $max_proc_time"
TERMINATE $! $pidfil $max_proc_time
wait # For BG job to complete normally or be TERMINATEd
_LWW_found=`expr \`wc -l < $stderr\` + 0`
_LWW_n=`expr $_LWW_found - $_LWW_n`
echo "${sp}Files found in $_LWW_fs = $_LWW_n" | $teelog
_LWW_n=$_LWW_found
done # for _LWW_fs in ..
echo "${sp}Total files found = $_LWW_found (_LWW_)" | $teelog
#------------------------------------------#
# OK, show'em what we found (if anything). #
#------------------------------------------#
ww_files_n=$_LWW_found
if [ $_LWW_found -gt 0 -o -s "$stderr" ]; then
echo "`date '+%Y-%m-%d %T'`" \
"$_LWW_found WORLD WW files found (_LWW_)!" | $teelog
$AWK -v sp="$sp" \
'! /^$/ {sub(/^[\t ]+/,"");print sp"|"$0"|"}' $stderr | $teelog
else
echo "${sp}None found" | $teelog
fi
echo "${sp}$dashes" | $teelog
} # "_LWW_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
LIST_CORE_DUMP_FILES()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'`" \
"List core dump files (_LCD_)." | $teelog
CP_DEV_NULL_EXIT_ERR $stderr $tmpwrk $tmpwrk1
for _LCD_fs in $fs
do
echo "`date '+%Y-%m-%d %T'` Checking $_LCD_fs." | $teelog
cp /dev/null $stderr 2>&1
#---------------------------------------------------------#
# If we're searching root (/), then use -xdev to keep the #
# search local (hopefully it won't descend into subdirs). #
#---------------------------------------------------------#
if [ $_LCD_fs = '/' ]; then
_LCD_opt="-xdev"
else # Not root dir and
if [ ."$OZ" != ."linux" ]; then # not Linux? (SunOS),
_LCD_opt="-local" # so use -local.
else # Else Linux, so don't use
_LCD_opt="" # -local option (doesn't
fi # know -local).
fi
#---------------------------------#
# Run find command in background. #
#---------------------------------#
if [ $opt_v -eq 1 ]; then
echo "`date '+%Y-%m-%d %T'`" \
"find $_LCD_fs $exclude_fs $_LCD_opt" \
"-name core -type f -ls" | $teelog
fi
#---------------------------------#
# Run this in background. #
#---------------------------------#
eval find $_LCD_fs $exclude_fs $_LCD_opt -name core -type f -ls \
| egrep -vi "permission denied|timed out|cannot open" \
>> $tmpwrk1 2>> $stderr &
[ $opt_v -eq 1 ] \
&& echo "${sp}TERMINATE $! $pidfil $max_proc_time"
TERMINATE $! $pidfil $max_proc_time
wait # For BG job to complete normally or be TERMINATEd
done # for _LCD_fs in $fs
_LCD_n=`wc -l < $tmpwrk1`
if [ $_LCD_n -gt 0 ]; then
$AWK -v sp="$sp" '$1 != "" {print sp""$0}' $tmpwrk1 > $tmpwrk
RM_EXIT_ERR $tmpwrk1
if [ -s "$tmpwrk" ]; then
sed "s/^/$stderr_sp/" $stderr >> $tmpwrk
DISPLAY_TMPWRK | $teelog
fi
else
echo "`date '+%Y-%m-%d %T'` No core dump files found." | $teelog
sed "s/^/$stderr_sp/" $stderr | $teelog
echo "${sp}$dashes" | $teelog
fi
return $_LCD_n
} # "_LCD_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
LIST_OLD_TMP_FILES()
#----------------------------------------------------------------------#
{
if [ $opt_t -ne 1 ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Skipping old /tmp files list (_LTF_)." | $teelog
echo "${sp}$dashes" | $teelog
return
fi
echo "`date '+%Y-%m-%d %T'`" \
"List old /tmp files (_LTF_)." | $teelog
_LTF_users='-user 0 -o -user 1 -o -user 2 -user 3 -o -user 4'
#------------------------------------------------------------#
# Display the names of regular files in /tmp that have not #
# been accessed in 3 days, then remove them from there. #
# FYI: _LTF_users= 0/root, 1/daemon, 2/bin, 3/sys and 4/adm. #
#------------------------------------------------------------#
echo "`date '+%Y-%m-%d %T'`" \
"Report /tmp files untouched in 7 days." | $teelog
_LTF_old_f=`find /tmp -type f -atime +7 \
! \\( $_LTF_users \\) -print | wc -l`
if [ $_LTF_old_f -gt 0 ]; then
CP_DEV_NULL_EXIT_ERR $tmpwrk1 $tmpwrk $stderr
echo "`date '+%Y-%m-%d %T'`" \
"Recommend removing the following files:" | $teelog
find /tmp -type f -atime +7 ! \( $_LTF_users \) \
-exec ls -al {} \; >> $tmpwrk1 2>> $stderr
$AWK -v sp="$sp" '$1 != "" {print sp""$0}' $tmpwrk1 > $tmpwrk
sed "s/^/$stderr_sp/" $stderr >> $tmpwrk # Append stderr.
RM_EXIT_ERR $tmpwrk1 $tmpwrk $stderr
fi # if [ $_LTF_old_f -gt 0 ]
echo "${sp}$dashes" | $teelog
#------------------------------#
# Show-em what's left in /tmp #
#------------------------------#
_LTF_remain_n=`find /tmp -ls \
| $AWK 'BEGIN {n=0} {n++} END {print n}'`
if [ $_LTF_remain_n -gt 0 ]; then
echo "`date '+%Y-%m-%d %T'` Here's a list of /tmp:" | $teelog
eval find /tmp -ls | $AWK -v sp="$sp" \
'!/^[\t ]*$/ {
sub(/^ *[0-9]* *[0-9]* */,"")
sub(/^ */,"")
sub(/^/,sp)
print
}' | $teelog
fi
echo "${sp}$dashes" | $teelog
} # "_LTF_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
LIST_SU_FILES()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'`" \
"Looking for any executable 'su' files (_LSU_)." | $teelog
_LSU_n=0
_LSU_found=0
CP_DEV_NULL_EXIT_ERR $stderr
for _LSU_fs in $fs
do
echo "`date '+%Y-%m-%d %T'` Checking $_LSU_fs." | $teelog
#---------------------------------------------------------#
# If we're searching root (/), then use -xdev to keep the #
# search local (hopefully it won't descend into subdirs). #
#---------------------------------------------------------#
if [ $_LSU_fs = '/' ]; then
_LSU_opt="-xdev"
else # Not root dir and
if [ ."$OZ" != ."linux" ]; then # not Linux? (SunOS),
_LSU_opt="-local" # so use -local.
else # Else Linux, so don't use
_LSU_opt="" # -local option (doesn't
fi # know -local).
fi
#-----------------------------------------------------------------#
# Display the command before running it so anyone can cut-n-paste #
# it as needed. Note: the '\;' must remain outside the $_LSU_find #
# assignment or the find fails for incomplete statement. #
#-----------------------------------------------------------------#
_LSU_find="find $_LSU_fs $exclude_fs $_LSU_opt -name su -type f"
_LSU_find="$_LSU_find -perm -0001 -exec ls -al {}"
if [ $opt_v -eq 1 ]; then
echo "`date '+%Y-%m-%d %T'` $_LSU_find \;" | $teelog
fi
#-------------------------#
# Run this in background. #
#-------------------------#
eval $_LSU_find '\;' 2>&1 \
| egrep -vi "permission denied|timed out|cannot open" \
>> $stderr &
[ $opt_v -eq 1 ] \
&& echo "${sp}TERMINATE $! $pidfil $max_proc_time"
TERMINATE $! $pidfil $max_proc_time
wait # For BG job to complete normally or be TERMINATEd
_LSU_found=`expr \`wc -l < $stderr\` + 0`
_LSU_n=`expr $_LSU_found - $_LSU_n`
echo "${sp}Files found in $_LSU_fs = $_LSU_n" | $teelog
_LSU_n=$_LSU_found
done # for _LSU_fs in $fs
#------------------------------------------#
# OK, show'em what we found (if anything). #
#------------------------------------------#
su_files_n=$_LSU_found
if [ $_LSU_found -gt 0 -o -s "$stderr" ]; then
echo "`date '+%Y-%m-%d %T'`" \
"$_LSU_found executable 'su' files found!" | $teelog
$AWK -v sp="$sp" \
'! /^$/ {sub(/^[\t ]+/,"");print sp"|"$0"|"}' $stderr | $teelog
else
echo "${sp}None found" | $teelog
fi
echo "${sp}$dashes" | $teelog
} # "_LSU_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
LIST_WORLD_WX_FILES() # World writable and executable files!! #
# $wx_files_n = Global variable #
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'`" \
"Looking for world-wx files (perm 0003)." | $teelog
_LWX_n=0
_LWX_found=0
CP_DEV_NULL_EXIT_ERR $stderr
for _LWX_fs in $fs
do
echo "`date '+%Y-%m-%d %T'` Checking $_LWX_fs." | $teelog
#---------------------------------------------------------#
# If we're searching root (/), then use -xdev to keep the #
# search local (hopefully it won't descend into subdirs). #
#---------------------------------------------------------#
if [ $_LWX_fs = '/' ]; then
_LWX_opt="-xdev"
else # Not root dir and
if [ ."$OZ" != ."linux" ]; then # not Linux? (SunOS),
_LWX_opt="-local" # so use -local.
else # Else Linux, so don't use
_LWX_opt="" # -local option (doesn't
fi # know -local).
fi
#-----------------------------------------------------------------#
# Display the command before running it so anyone can cut-n-paste #
# it as needed. Note: the '\;' must remain outside the $_LWX_find #
# assignment or the find fails for incomplete statement. #
#-----------------------------------------------------------------#
_LWX_find="find $_LWX_fs $exclude_fs $_LWX_opt -type f"
_LWX_find="$_LWX_find -perm -0003 -exec ls -al {}"
if [ $opt_v -eq 1 ]; then
echo "`date '+%Y-%m-%d %T'` $_LWX_find \;" | $teelog
fi
#-------------------------#
# Run this in background. #
#-------------------------#
eval $_LWX_find '\;' 2>&1 \
| egrep -vi "permission denied|timed out|cannot open" \
>> $stderr &
[ $opt_v -eq 1 ] \
&& echo "${sp}TERMINATE $! $pidfil $max_proc_time"
TERMINATE $! $pidfil $max_proc_time
wait # For BG job to complete normally or be TERMINATEd
_LWX_found=`expr \`wc -l < $stderr\` + 0`
_LWX_n=`expr $_LWX_found - $_LWX_n`
echo "${sp}Files found in $_LWX_fs = $_LWX_n" | $teelog
_LWX_n=$_LWX_found
done # for _LWX_fs in $fs
#------------------------------------------#
# OK, show'em what we found (if anything). #
#------------------------------------------#
wx_files_n=$_LWX_found
if [ $_LWX_found -gt 0 -o -s "$stderr" ]; then
echo "`date '+%Y-%m-%d %T'`" \
"$_LWX_found WORLD WX files found (_LWX_)!" | $teelog
$AWK -v sp="$sp" \
'! /^$/ {sub(/^[\t ]+/,"");print sp"|"$0"|"}' $stderr | $teelog
else
echo "${sp}None found" | $teelog
fi
echo "${sp}$dashes" | $teelog
} # "_LWX_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
PURGE_MAIL_NOTICE_LIST()
#----------------------------------------------------------------------#
{
_PMN_name="PURGE_MAIL_NOTICE_LIST"
if [ $# -lt 1 ]; then
EMAIL_MSG "FATAL ERROR $_PMN_name($script_name)" \
"${sp}Insufficient arguments passed to $_PMN_name()." \
"${sp}Usage: $_PMN_name login [...]" \
"${sp}$script_name terminted."
EXIT $failure
fi
_PMN_purged=0
if [ -s "$notice_list" ]; then
for _PMN_login in $*
do
_PMN_n=`expr \`grep "$_PMN_login" $notice_list | wc -l\` + 0`
if [ $_PMN_n -gt 0 ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Removing $_PMN_login from notice list." | $teelog
sed "/$_PMN_login/d" $notice_list > $tmpwrk
if [ $? -ne 0 ]; then
EMAIL_MSG "ERROR $_PMN_name($script_name)" \
"${sp}Failure removing $_PMN_login from \c" \
"\$notice_list," \
"${sp}$notice_list. $script_name terminated."
EXIT $failure
fi
MV_EXIT_ERR $tmpwrk $notice_list >> $log 2>&1
_PMN_purged=1
fi
done
fi
#------------------------------------------------------------------#
# If, after removing preceding logins from $notice_list, we still #
# have logins in the file, then prune them to just a single entry. #
#------------------------------------------------------------------#
if [ -s "$notice_list" ]; then
$AWK '{sub(/^[\t ]+/,"",$0);if ($0 ~ /^$/) next}' $notice_list \
| sort | uniq > $tmpwrk
if [ $? -ne 0 ]; then
EMAIL_MSG "ERROR $_PMN_name($script_name)" \
"${sp}Failure removing duplicate logins from\c" \
"${sp}$notice_list. $script_name terminated."
EXIT $failure
fi
[ $_PMN_purged -gt 0 ] && MV_EXIT_ERR $tmpwrk $notice_list >> $log 2>&1
fi
} # "_PMN_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
QUERY_PROCESS() # $1 = process argument string we seek #
#----------------------------------------------------------------------#
{
ps $ps_opts | $AWK -v ps_opts="$ps_opts" -v target="$@" \
'BEGIN \
{
if (target == "")
{
n = "-1"
exit
}
n=0 # Found counter.
pattern="^.*:.*("target"[\t ]*$)" # target[whitespace|linend]
}
#------------------------------------------------------------#
# Match our pattern (basically "target[whitespace|linend]"), #
# but exclude any "awk " and "vi " lines. #
#------------------------------------------------------------#
match($0,pattern) && ! /awk |vi / \
{
gsub( /[\t ]+/," ",$0) # Squeeze whitespace,
gsub(/^[\t ]+/,"", $0) # strip leading whitespace
print $0 # and print the dog.
n++
}
END \
{
if (n > 255) n=255
if (n == "-1")
{
print "Target string not supplied!"
n=255
}
else if (n == 0)
print "\""target"\"" " not_found in \047ps\047 query!"
exit n # Return number of cron demons found in exit status.
}'
return $?
} # "_QP_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
REMOVE_OLD_CORE_DUMPS()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'`" \
"Remove core dump files unchanged in $old_core days." | $teelog
CP_DEV_NULL_EXIT_ERR $tmpwrk1 $tmpwrk $stderr
for _RCD_fs in $fs
do
echo "`date '+%Y-%m-%d %T'` Checking $_RCD_fs." | $teelog
find $_RCD_fs -xdev -name core -type f -mtime +$old_core \
-exec echo "rm -f " {} \; -exec ls -al {} \; \
-exec $rm -f {} \; >> $tmpwrk1 2>> $stderr
$AWK -v sp="$sp" '$1 != "" {print sp""$0}' $tmpwrk1 > $tmpwrk
done
RM_EXIT_ERR $tmpwrk1
if [ -s "$tmpwrk" ]; then
sed "s/^/$stderr_sp/" $stderr >> $tmpwrk
DISPLAY_TMPWRK | $teelog
else
echo "`date '+%Y-%m-%d %T'` No old core dump files." | $teelog
sed "s/^/$stderr_sp/" $stderr | $teelog
echo "${sp}$dashes" | $teelog
fi
} # "_RCD_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
REMOVE_WORLD_FILE_PERMS() # [-m nnn] = mtime +days #
# # $1 = World bits to turn off [wxr] #
# # $2 = Target perms (e.g. 0002|0003) #
# # $3-$n = Target directories #
# # $chmod_n = Global variable #
#----------------------------------------------------------------------#
{
if [ $1 = "-m" ]; then
_RWP_mtime="-mtime $2"
shift 2
else
_RWP_mtime=""
fi
_RWP_flag=""
_RWP_bits=$1
_RWP_perms=$2
shift 2
if [ $opt_c -eq 0 ]; then
_RWP_dirs=`echo "$*" \
| $AWK -v sp="$sp" '{
print ""
for (i=1;i<=NF;i++)
{
print sp""$i;
}
}'`
$ECHO "`date '+%Y-%m-%d %T'`" \
"Skipping 'chmod o-$_RWP_bits' for files having" \
"'$_RWP_perms' perms in directories: $_RWP_dirs." | $teelog
echo "${sp}$dashes" | $teelog
return
fi
for _RWP_fs in $*
do
if [ -d $_RWP_fs ]; then
$ECHO "`date '+%Y-%m-%d %T'`" \
"Removing world-$_RWP_bits permission from world-xxx" \
"files (perm $_RWP_perms)\n${sp}found in $_RWP_fs." | $teelog
CP_DEV_NULL_EXIT_ERR $stderr $tmpwrk $tmpwrk1
#----------------------------------------------------------#
# If we're searching root (/), then use -xdev to keep the #
# search local (hopefully it won't descend into subdirs). #
#----------------------------------------------------------#
if [ $_RWP_fs = '/' ]; then
_RWP_local="-xdev"
else # Not root dir and
if [ ."$OZ" != ."linux" ]; then # not Linux? (SunOS),
_RWP_local="-local" # so use -local.
else # Else Linux, so don't use
_RWP_local="" # -local option (doesn't
fi # know -local).
fi
echo "${sp}find $_RWP_fs $exclude_fs $_RWP_local" \
"-type f" \
"-perm" \
"-$_RWP_perms" \
"$_RWP_mtime" \
'-exec ls -al {} \;' \
"| $AWK -v exclude='$ww_excl_dirs'" \
"-v bits='$_RWP_bits'" | $teelog
#------------------------------------------------#
# Run this in background. #
#------------------------------------------------#
find $_RWP_fs $exclude_fs $_RWP_local \
-type f \
-perm \
-$_RWP_perms \
$_RWP_mtime \
-print 2>&1 \
| $AWK -v exclude="$ww_excl_dirs" \
-v bits="$_RWP_bits" \
'BEGIN {
ls = "ls -al "
chmod = "chmod o-"bits" "
gsub(/ /,"|",exclude)
}
/cannot open|cannot read/ {next}
/[Pp]ermission denied|[Tt]imed out/ {next}
{
if (match($0,exclude)) next
#-----------------------------------------#
# If the fileid has a double quote in it, #
# then escape it. #
#-----------------------------------------#
if (match($0,/\042/))
gsub(/\042/,"\\\042",$0)
ls "\042"$0"\042" | getline ls_out
close(ls "\042"$0"\042")
cmd=chmod "\042"$0"\042"
print "Before: "ls_out
printf("%s\n", cmd)
status = system(cmd); close(cmd)
if (status == 0)
{
ls "\042"$0"\042" | getline ls_out
close(ls "\042"$0"\042")
print "After: "ls_out
}
else
{
print " (status="status")"
}
}' >> $tmpwrk1 2>> $stderr &
[ $opt_v -eq 1 ] \
&& echo "${sp}TERMINATE $! $pidfil $max_proc_time"
TERMINATE $! $pidfil $max_proc_time
wait # For BG job to complete normally or be TERMINATEd
$AWK -v sp="$sp" '$1 != "" {print sp$0}' $tmpwrk1 > $tmpwrk
sed "s/^/$stderr_sp/" $stderr >> $tmpwrk
_RWP_chmod_n=`$AWK 'BEGIN {n=0 }
/After:/ {n++ }
END {print n}' $tmpwrk`
chmod_n=`expr $chmod_n + $_RWP_chmod_n`
[ $_RWP_chmod_n -gt 0 ] && _RWP_flag=' (_RWP_)'
echo "${sp}Changed $_RWP_chmod_n files$_RWP_flag." >> $tmpwrk
DISPLAY_TMPWRK | $teelog
fi
done # for _RWP_fs in $*
[ -f "$tmpwrk1" ] && $rm -f $tmpwrk1
} # "_RWP_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
REPORT_RECENT_LOGIN_ACTIVITY()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'` Report recent login activity." | $teelog
_RRL_Mmm_dd=`date | cut -c5-10` # Any activity from today? #
#------------------------------------------------------#
# Place all rlogins to root on top. Then add the rest. #
# Begin with today's. #
#------------------------------------------------------#
last | $AWK -v sp="$sp" -v Mon_dd="$_RRL_Mmm_dd" \
'match($0,Mon_dd) && /^root/ {print sp""$0}' > $tmpwrk1
last | $AWK -v sp="$sp" -v Mon_dd="$_RRL_Mmm_dd" \
'match($0,Mon_dd) && ! /^root/ {print sp""$0}' > $tmpwrk2
#------------------------------------------------------#
# Now do the same for previous days. #
#------------------------------------------------------#
_RRL_msgs_back=2
_RRL_n=1
while [ $_RRL_n -lt $_RRL_msgs_back ]
do
_RRL_yyyymmdd=`$dateplus -$_RRL_n`
_RRL_dd=`echo $_RRL_yyyymmdd | cut -c7-8`
_RRL_mm=`echo $_RRL_yyyymmdd | cut -c5-6`
#-----------------------------------------------------------#
# Using a date $msgs_back from today, display 'last' output.#
# Awk note: Printf's "+=0" (in the "Mmm[($1+=0)]") strips #
# leading zeros (it can't find Mmm[06]). The "%2d" right- #
# justifies (padding with spaces) the dd value. #
#-----------------------------------------------------------#
_RRL_Mmm_dd=`echo $_RRL_mm $_RRL_dd | $AWK '
{
split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec", Mmm)
printf("%s %2d\n", Mmm[($1+=0)], $2)
}'`
#-------------------------------------------------------#
# Place all rlogins to root on top. Then add the rest. #
#-------------------------------------------------------#
last | $AWK -v Mon_dd="$_RRL_Mmm_dd" -v sp="$sp" \
'match($0,Mon_dd) && /^root/ {print sp""$0}' >> $tmpwrk1
last | $AWK -v Mon_dd="$_RRL_Mmm_dd" -v sp="$sp" \
'match($0,Mon_dd) && ! /^root/ {print sp""$0}' \
| sort +0 -1 >> $tmpwrk2
_RRL_n=`expr $_RRL_n + 1`
done
#------------------------------------------------------#
# If they exist, combine $tmpwrk1 and 2 into $tmpwrk. #
# (I'm NOT using MV_EXIT_ERR here because I only want #
# to see errors; not the move command itself.) #
#------------------------------------------------------#
if [ -s "$tmpwrk1" ]; then
mv $tmpwrk1 $tmpwrk > $tmplog 2>&1
_RRL_status=$?
if [ $_RRL_status -ne $success ]; then
EMAIL_MSG "FATAL ERROR $script_name" \
"${sp}Moving \$tmpwrk1 to $tmpwrk failed!" \
"${sp}Status=$_RRL_status. $script_name terminated."
EXIT $failure
fi
else
CP_DEV_NULL_EXIT_ERR $tmpwrk1 $tmpwrk
fi
if [ -s "$tmpwrk2" ]; then
echo "" >> $tmpwrk
cat $tmpwrk2 >> $tmpwrk
fi
RM_EXIT_ERR -f $tmpwrk1 $tmpwrk2
if [ -s "$tmpwrk" ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Login activity for last $msgs_back days." | $teelog
DISPLAY_TMPWRK | $teelog
else
echo "`date '+%Y-%m-%d %T'`" \
"No login activity for last $msgs_back days." | $teelog
echo "${sp}$dashes" | $teelog
fi
} # "_RRL_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
REPORT_SU_TO_ROOT_ACTIVITY() # Report recent su to root activity. #
#----------------------------------------------------------------------#
{
_RSR_sulog=/var/adm/sulog
if [ ! -f "$_RSR_sulog" ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Skipping scan -- No $_RSR_sulog found!" | $teelog
echo "${sp}$dashes" | $teelog
return
fi
_RSR_tail_n=100 # last 100 lines; report only last 20 'su - root'
_RSR_su_n=`tail -$_RSR_tail_n $_RSR_sulog | grep "\-root" | wc -l`
if [ $_RSR_su_n -gt 0 ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Tail of $_RSR_sulog's 'su' to root follows:" | $teelog
tail -$_RSR_tail_n $_RSR_sulog \
| $AWK -v sp="$sp" 'BEGIN {p=0;q=20}
/-root/ {n++; if (n <= q) print sp""$0}' | sort -r | $teelog
else
echo "`date '+%Y-%m-%d %T'`" \
"No su's to root found in the last $_RSR_tail_n lines" \
"of $_RSR_sulog." | $teelog
fi
echo "${sp}$dashes" | $teelog
} # "_RSR_" prefix identifies this function's variables.
#----------------------------------------------------------------------#
ROOT_DASH_I_FILE() # Accidents happen and sometimes root level files #
# are deleted. Creating a '/-i' file adds one more #
# layer of protection for securing root files and #
# saving the kernel from accidental deletion by #
# causing any errant 'rm' command to treat this #
# file as rm's interactive confirmation option. #
# (The file is easily removed with '\rm - -i'.) #
#----------------------------------------------------------------------#
{
if [ $opt_b -ne 1 ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Skipping '/-i' file create/check." | $teelog
echo "${sp}$dashes" | $teelog
return
fi
if [ ! -f '/-i' ]; then
echo "`date '+%Y-%m-%d %T'` Creating '/-i' file." | $teelog
echo "Safeguard against removing root-level files" > '/-i'
fi
CHMOD_EXIT_ERR 0000 '/-i'
ls -al '/-i' | sed "s/^/$sp/" | $teelog
echo "${sp}$dashes" | $teelog
}
#----------------------------------------------------------------------#
SNAPSHOT_SYSTEM()
#----------------------------------------------------------------------#
{
echo "`date '+%Y-%m-%d %T'` System snapshot." | $teelog
echo "${sp}`uname -a`" | $teelog
echo "${sp}hostid=`/usr/bin/hostid`" | $teelog
echo "${sp}umask=`umask`" | $teelog
#----------------------------------------#
# Run commands specified in $operations. #
#----------------------------------------#
for _SS_op in $operations
do
_SS_op_cmdstring=`$AWK -v cmd="$_SS_op" \
'BEGIN {
gsub(/_DASH_/," -",cmd)
gsub(/_SP_/ ," " ,cmd)
print cmd
}'`
_SS_op_cmd=`echo "$_SS_op_cmdstring" | sed 's/ .*//'`
if [ ! -f "$_SS_op_cmd" ]; then
echo "`date '+%Y-%m-%d %T'` '$_SS_op_cmd' not found!" \
| $teelog
echo "${sp}$dashes" | $teelog
continue # Iterate for-loop
fi
if [ ! -x $_SS_op_cmd ]; then
echo "`date '+%Y-%m-%d %T'` '$_SS_op_cmd' not executable!" \
| $teelog
echo "${sp}`ls -alL $_SS_op_cmd`" | $teelog
echo "${sp}$dashes" | $teelog
continue # Iterate for-loop
fi
#-----------------------------------------------------------#
# Since janitor is run by root, we will not run any command #
# that is world-writable. Moreover, such a command is #
# reported to support personnel. #
#-----------------------------------------------------------#
ls -alL $_SS_op_cmd \
| $AWK '{if (substr($1,9,1) == "w") exit 1; else exit 0}'
if [ $? -eq 1 ]; then
EMAIL_MSG "WARNING $script_name" \
"${sp}Skipping '$_SS_op_cmd' -- command world-writable!" \
"${sp}`ls -alL $_SS_op_cmd`"
echo "${sp}$dashes" | $teelog
continue # Iterate for-loop
fi
echo "`date '+%Y-%m-%d %T'` Running '$_SS_op_cmdstring'" | $teelog
eval $_SS_op_cmdstring > $stdout 2> $stderr
_SS_status=$?
[ -s "$stderr" ] && sed "s/^/$stderr_sp/" $stderr | $teelog
[ -s "$stdout" ] && sed "s/^/$sp/" $stdout | $teelog
echo "`date '+%Y-%m-%d %T'`" \
"'$_SS_op_cmdstring' completed with $_SS_status status." \
| $teelog
echo "${sp}$dashes" | $teelog
done # for _SS_op in $operations
} # "_SS_" prefix identifies this function's variables.
#======================================================================#
# I N I T I A L I Z A T I O N #
#======================================================================#
#------------------------------------------------------------------#
# The following is an attempt to extract the path to our #
# $par_file. Under interactive and cron execution (not "at" #
# execution), this works fine. We want the path for those cases #
# when this script is run from a directory other than this one. #
# This does not, however, work during batch (at) execution, for #
# there $0 is always /bin/sh. I haven't figured a way around #
# that problem yet. #
#------------------------------------------------------------------#
[ $0 = "/bin/sh" -o `dirname $0` = "." ] \
&& script_home=`pwd` || script_home=`dirname $0`
#----------------------------------------------------#
# Command line options come before other arguments. #
#----------------------------------------------------#
opt_b=0; opt_m=0
opt_c=0; opt_n=0
opt_g=0; opt_r=0
opt_h=0; opt_s=0
opt_H=0; opt_T=0
opt_h=0; opt_t=0
opt_i=0; opt_v=0
opt_l=0; opt_w=0
invalid_opt=0
GO_root=$tmp/$name_root"_"$LOGNAME"_GO_err"
GO_err=$GO_root"."$Xtimestamp
GO_opts='bcgHhilmnrsTtvw'
while getopts $GO_opts GO_opt 2> $GO_err
do
case $GO_opt in
b ) opt_b=1;;
c ) opt_c=1;;
g ) opt_g=1;;
H ) opt_H=1;;
h ) opt_h=1;;
i ) opt_i=1;;
l ) opt_l=1;;
m ) opt_m=1;;
n ) opt_n=1;;
r ) opt_r=1;;
s ) opt_s=1;;
T ) opt_T=1;;
t ) opt_t=1;;
v ) opt_v=1; verbose=1;;
w ) opt_w=1;;
\? ) echo "$script_name Invalid Option: $GO_opt" \
"-`sed 's/^.*-- //' $GO_err`"
invalid_opt=1;;
esac
done
shift `expr $OPTIND - 1` # Shift past options to remaining args
#------------------------------------------------------------#
# Must reset this dog if getopts is apt to be called again #
OPTIND=1 # (try finding this fact documented anywhere else). #
#------------------------------------------------------------#
[ ."$GO_root" != . ] && $rm -f $GO_root* > /dev/null 2>&1
cleanup_files="$log $stdout_root $stderr_root $tmpwrk_root"
cleanup_files="$cleanup_files $tmplog_root $mailmsg_root"
for file in $cleanup_files
do
[ -f "$file" ] && chmod 0640 $file
done
#--------------------------------------------------------------#
# Check for presence of parameter and master parameter files. #
# While we're at it, check their file permissions as well. #
#--------------------------------------------------------------#
parfile=$script_home/$name_root.par
parfile_master=$script_home/$name_root.master_par
parfile_perms="0644"
for file in $parfile_master $parfile
do
if [ ! -f "$file" ]; then # If $file is missing ..
if [ $file = $parfile_master ]; then # If it's the master file
$ECHO "$prelims" 1>&2
EMAIL_MSG "FATAL ERROR $script_name" \
"Unable to locate '$file'! $script_name terminated."
EXIT 1 # We MUST at least have the master parameter file.
else # Missing file is the working, janitor.par file.
prelims="$prelims\n`date '+%Y-%m-%d %T'` Unable to locate $file!"
prelims="$prelims\n${sp}Creating temporary (dummy) par file."
TOUCH_EXIT_ERR $file
continue # Iterate for-loop--don't care about permissions.
fi
fi
curr_perms=`GET_FILE_PERMS $file`
status=$?
if [ $status -eq 0 ]; then
if [ $curr_perms -ne $parfile_perms ]; then
ls_parfile=`ls -al $file | sed 's/ */ /g'`
CHMOD_EXIT_ERR $parfile_perms "$file"
EMAIL_MSG "WARNING $script_name $args" \
"${sp}$file perms ($curr_perms) wrong!" \
"${sp}$dashes" \
"${sp}$ls_parfile" \
"${sp}$dashes" \
"FILE=$file" \
"${sp}$dashes" \
"${sp}Resetting perms to $parfile_perms." \
"${sp}$dashes" \
"${sp}`ls -al $file | sed 's/ */ /g'`"
fi
else
$ECHO "$prelims" 1>&2
EMAIL_MSG "FATAL ERROR $script_name" \
"${sp}Unable to get $file file permissions!" \
"${sp}$script_name terminated."
EXIT 1
fi
done # for file in $parfile $parfile_master
#----------------------------------------------------------#
# Compare timestamp lines in janitor parameter and master #
# parameter files, creating new parameter file from master #
# if the timestamps differ. #
#----------------------------------------------------------#
CHECK_PARFILE_FOR_UPDATES # ()
#------------------------------------------------------------------#
# Reaching this point (not having exited because of a fatal error #
# already) means that our parameter file exists and its perms are #
# [now, at least] intact. Read and parse parameter file variables.#
#------------------------------------------------------------------#
prelims="$prelims\n`date '+%Y-%m-%d %T'` Assign $parfile parameters."
working_dir=` PARSE_PARAMETERS WORKING_DIR $parfile`;status=$?
log_dir=` PARSE_PARAMETERS LOG_DIR $parfile`;status=`expr $status + $?`
tmp=` PARSE_PARAMETERS TMP $parfile`;status=`expr $status + $?`
support=` PARSE_PARAMETERS SUPPORT $parfile`;status=`expr $status + $?`
active_status_file=`PARSE_PARAMETERS STATUS_FILE $parfile`;status=`expr $status + $?`
keep_logs=` PARSE_PARAMETERS KEEP_LOGS $parfile`;status=`expr $status + $?`
max_proc_time=` PARSE_PARAMETERS FIND_MAX_TM $parfile`;status=`expr $status + $?`
rhosts_files=` PARSE_PARAMETERS RHOSTS_FILES $parfile`;status=`expr $status + $?`
perm_600_files=` PARSE_PARAMETERS 0600_PERMS $parfile`;status=`expr $status + $?`
mail_dir=` PARSE_PARAMETERS MAIL_DIR $parfile`;status=`expr $status + $?`
file_perms=` PARSE_PARAMETERS FILE_PERMS $parfile`;status=`expr $status + $?`
ww_dirs=` PARSE_PARAMETERS WW_DIRS $parfile`;status=`expr $status + $?`
ww_30_dirs=` PARSE_PARAMETERS WW_30_DIRS $parfile`;status=`expr $status + $?`
ww_excl_dirs=` PARSE_PARAMETERS WW_EXCL_DIRS $parfile`;status=`expr $status + $?`
mtime=` PARSE_PARAMETERS MTIME $parfile`;status=`expr $status + $?`
old_core=` PARSE_PARAMETERS OLD_CORE $parfile`;status=`expr $status + $?`
msgs_back=` PARSE_PARAMETERS MSGS_BACK $parfile`;status=`expr $status + $?`
ps_opts=` PARSE_PARAMETERS PS_OPTS $parfile`;status=`expr $status + $?`
cron_demon=` PARSE_PARAMETERS CRON_DEMON $parfile`;status=`expr $status + $?`
cron_stop=` PARSE_PARAMETERS CRON_STOP $parfile`;status=`expr $status + $?`
cron_start=` PARSE_PARAMETERS CRON_START $parfile`;status=`expr $status + $?`
cronlog=` PARSE_PARAMETERS CRONLOG $parfile`;status=`expr $status + $?`
cronlog_size=` PARSE_PARAMETERS CRONLOG_SIZE $parfile`;status=`expr $status + $?`
cronlog_num=` PARSE_PARAMETERS CRONLOG_NUM $parfile`;status=`expr $status + $?`
wtmp_dir=` PARSE_PARAMETERS WTMP_DIR $parfile`;status=`expr $status + $?`
wtmp_size=` PARSE_PARAMETERS WTMP_SIZE $parfile`;status=`expr $status + $?`
wtmp_num=` PARSE_PARAMETERS WTMP_NUM $parfile`;status=`expr $status + $?`
syslog_dir=` PARSE_PARAMETERS SYSLOG_DIR $parfile`;status=`expr $status + $?`
syslogs=` PARSE_PARAMETERS SYSLOGS $parfile`;status=`expr $status + $?`
logins=` PARSE_PARAMETERS LOGINS $parfile`;status=`expr $status + $?`
messages=` PARSE_PARAMETERS MESSAGES $parfile`;status=`expr $status + $?`
exclude_fs=` PARSE_PARAMETERS EXCLUDE_FS $parfile`;status=`expr $status + $?`
operations=` PARSE_PARAMETERS OPERATIONS $parfile`;status=`expr $status + $?`
[ $opt_T -eq 1 ] && support="Bob@OrlandoKuntao.com"
notify="$support"
#------------------------------------------------------#
# If anything fails to parse, fuss about it and exit. #
#------------------------------------------------------#
if [ $status -ne 0 ]; then
syslog_msg1="Parameter parsing problem (status=$status)."
syslog_msg2="$script_name '$args' ($$) terminated."
$ECHO "$prelims" 1>&2
subject="FATAL ERROR $HOST: SHLIB PARSE Failure"
msg="$syslog_msg1\n$syslog_msg2"
MAIL_ERROR
if [ $opt_l = 1 -a ."$TERM" = . ]; then
logger -p "user.emerg" -t "$USER[$$]_EMER" \
"$script_name: $syslog_msg1 $syslog_msg2" 1>&2
fi
exit 1
fi
prelims="$prelims\n`date '+%Y-%m-%d %T'` Assignment complete."
#----------------------------------------------------------------#
# If our log already has something in it. If it does, then this #
# is NOT our first run today. (We'll use this indicator later #
# to see if we prune the logs or no.) #
#----------------------------------------------------------------#
[ -s "$log" ] && first_run=0 || first_run=1
#------------------------------------------------#
# If the user wants help, find the documentation #
# section and print everything from there down. #
#------------------------------------------------#
if [ $opt_H -eq 1 ]; then
SHOW_DOCUMENTATION
exit $failure
elif [ $# -gt 0 -o $opt_h -eq 1 -o $invalid_opt -eq 1 ]; then
#------------------------------------#
# Showem basic command usage/syntax. #
#------------------------------------#
echo "" 1>&2
$ECHO " Name: $script_name (v%I%)\n" 1>&2
echo "Usage: $script_name -$GO_opts" 1>&2
echo " -b = Broken symbolic link cleanup." 1>&2
echo " -c = Change errant file permissions." 1>&2
echo " -g = Ensures root ownership of ./gnupg" 1>&2
echo " and 4755 permissions for gpg program." 1>&2
echo " -H = Detailed process documentation." 1>&2
echo " -h = Usage brief." 1>&2
echo " -i = Install '-i' file in root filesystem." 1>&2
echo " -n = Display contents of .netrc files." 1>&2
echo " -m = Mail SUID scripts found notification." 1>&2
echo " -r = Rollover cron and wtmp logs." 1>&2
echo " -s = Scan and list tail of syslogs." 1>&2
echo " -T = Test mode (notify Bob Orlando only)" 1>&2
echo " -t = List old files in /tmp." 1>&2
echo " -v = Verbose mode (somewhat nosier output)." 1>&2
echo " -w = Report all world-writable files." 1>&2
echo "" 1>&2
echo "Purpose: Perform various SysAdmin functions." 1>&2
echo "" 1>&2
exit $failure
fi
#----------------------------------------------------------------#
# If our host name is among WW_30_DIRS parameters (myhost:/home),#
# then isolate the directory and remove that directory from the #
# directory list in our WW_DIRS parameter. #
#----------------------------------------------------------------#
if [ ."$ww_30_dirs" = . ]; then
# Note: $host in Awk script below must be lowercase (not $HOST).
ww_30_dirs=`echo $ww_30_dirs \
| $AWK \
'BEGIN {RS=" "; list=""}
/^'$host':/ \
{
sub(/^.*:/,"") # Remove "host:"
gsub(/\n/ ,"") # and newline.
list = list" "$1
}
END {
sub(/^ +/,"",list) # Strip leading whitespace.
print list
}'`
ww_dirs=`echo "$ww_dirs" \
| $AWK -v ww_30_dirs="$ww_30_dirs" \
'BEGIN {
RS = " "
list = ""
#-------------------------------#
# Assemble pattern for matching #
#-------------------------------#
gsub(/ +/,"|",ww_30_dirs) # Insert "or" (stiles)
ww_30_dirs="^("ww_30_dirs")$" # beg- and end-lines
}
$0 !~ ""ww_30_dirs"" \
{
gsub(/\n/,"") # Remove any newlines
list=list" "$0
}
END {
sub(/^ +/,"",list) # Strip leading whitespace.
print list
}'`
fi # if [ ."$ww_30_dirs" = . ]; then
#----------------------------------------------------------------#
# Prefer gzip, but we'll use "compress" if gzip is unavailable. #
#----------------------------------------------------------------#
gzip1="/usr/bin/gzip"
gzip2="/usr/local/bin/gzip"
if [ -x $gzip1 ]; then
compress=$gzip1
suffix=".gz"
elif [ -x $gzip2 ]; then
compress=$gzip2
suffix=".gz"
else
compress="$bin_dir/compress"
suffix=".Z"
fi
#------------------------------------------------------------------#
# Insure all the critical variables just taken from parfile are #
# assigned. If any are unassigned, then fuss at the user and exit. #
# ** Be sure they DO NOT HAVE dollar-signs ($) in front of'em. ** #
# ** Only '$variables' may have the dollar-sign. ** #
#------------------------------------------------------------------#
variables="working_dir log_dir tmp notify active_status_file"
variables="$variables parfile parfile_master ctlfile" ## T E S T ##
variables="$variables rhosts_files perm_600_files mail_dir"
variables="$variables file_perms ww_dirs ww_excl_dirs ps_opts"
variables="$variables cron_demon cron_stop cron_start cronlog"
variables="$variables wtmp_dir syslog_dir syslogs logins messages"
variables="$variables compress"
prelims="$prelims\n`date '+%Y-%m-%d %T'` Verify critical variables."
#--------------------------------------------------------------#
# operations and ww_30_vars are not verified because they are #
# strictly optional parameters. #
#--------------------------------------------------------------#
VERIFY_VARS $variables # Exits on error
variables="args $variables operations exclude_fs ww_30_dirs"
num_variables="keep_logs max_proc_time msgs_back mtime old_core"
num_variables="$num_variables cronlog_size cronlog_num"
num_variables="$num_variables wtmp_size wtmp_num"
num_variables="$num_variables opt_b opt_c opt_H opt_h opt_i opt_l"
num_variables="$num_variables opt_m opt_n opt_r opt_s opt_T opt_t"
num_variables="$num_variables opt_v opt_w"
VERIFY_NUM_VARS $num_variables # Exits on error
prelims="$prelims\n`date '+%Y-%m-%d %T'` Verification complete."
#--------------------------------------------------------------#
# Change multiple slashes to single, forcing a trailing slash. #
# (I don't usually do it this way, but it resolves problems #
# // problems that arise when / is the home directory.) #
#--------------------------------------------------------------#
wtmp_dir=` echo "$wtmp_dir" | sed 's|//.*|/|g'`
working_dir=`echo "$working_dir" | sed 's|//.*|/|g'`
log_dir=` echo "$log_dir" | sed 's|//.*|/|g'`
tmp=` echo "$tmp" | sed 's|//.*|/|g'`
syslog_dir=` echo "$syslog_dir" | sed 's|//.*|/|g'`
#------------------------------------------------------------------#
# While we're at it, verify the permissions of our parameter file. #
#------------------------------------------------------------------#
prelims="$prelims\n`date '+%Y-%m-%d %T'` Verifying $parfile file permissions."
pars_perms=`GET_FILE_PERMS $parfile`
if [ $parfile_perms -ne $pars_perms ]; then
CHMOD_EXIT_ERR $parfile_perms $parfile
EMAIL_MSG "WARNING $script_name" \
"${sp}Parameter file ($parfile) perms are $pars_perms!" \
"${sp}They should have been $parfile_perms." \
"${sp}Resetting perms now (check the following 'ls')." \
"${sp}Processing continues." \
"${sp}$dashes" \
"${sp}`ls -al $parfile | sed 's/ */ /g'`" \
"${sp}$dashes"
fi
prelims="$prelims\n`date '+%Y-%m-%d %T'` Assign additional variables."
tmplog_root=$tmp/$name_root"_tl_"$id_hex"."
tmplog=${tmplog_root}$Xtimestamp
teetmp="tee -ai $tmplog"
cleanup_files="$cleanup_files $tmplog_root"
#------------------#
mailmsg_root=$tmp/$name_root"_m0_"$id_hex"." # EMAIL_MSG #
mailmsg=${mailmsg_root}$Xtimestamp # uses this file. #
teemail="tee -ai $mailmsg" #------------------#
cleanup_files="$cleanup_files $mailmsg_root"
stdout_root=$tmp/$name_root"_s1_"$id_hex"."
stdout=${stdout_root}$Xtimestamp
cleanup_files="$cleanup_files $stdout_root"
stderr_root=$tmp/$name_root"_s2_"$id_hex"."
stderr=${stderr_root}$Xtimestamp
cleanup_files="$cleanup_files $stderr_root"
tmpwrk_root=$tmp/$name_root"_t0_"$id_hex"."
tmpwrk=${tmpwrk_root}$Xtimestamp
cleanup_files="$cleanup_files $tmpwrk_root"
tmpwrk_sp=" tmpwrk="
tmpwrk1_root=$tmp/$name_root"_t1_"$id_hex"." #------------------#
tmpwrk1=${tmpwrk1_root}$Xtimestamp # Add'l work file. #
cleanup_files="$cleanup_files $tmpwrk1_root" #------------------#
tmpwrk1_sp=" tmpwrk1="
tmpwrk2_root=$tmp/$name_root"_t2_"$id_hex"." #------------------#
tmpwrk2=${tmpwrk2_root}$Xtimestamp # And another. #
cleanup_files="$cleanup_files $tmpwrk2_root" #------------------#
tmpwrk2_sp=" tmpwrk2="
pidfil_root=$tmp/$name_root"_PI_"$id_hex"."
pidfil=${pidfil_root}$Xtimestamp
cleanup_files="$cleanup_files $pidfil_root"
log_root=$log_dir/$name_root"_log"
log=$log_root"."$yymmdd
teelog="tee -ai $log"
notice_list=$working_dir/$name_root.mail_files
variables="$variables notice_list"
cleanup_files="$cleanup_files $tmp/$name_root"
dateplus=$SHBIN/dateplus # For aged dates (figs, if you like)
Mmms="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
#--------------------------------------------------------------#
# Assign $rhosts_files and convert that list into 'find' args. #
#--------------------------------------------------------------#
rhost_pr=`$AWK -v hosts_files="$rhosts_files" \
'BEGIN \
{
q = split(hosts_files,files)
for (p = 1; p <= q; p++)
{
if (p > 1)
find_args=find_args" -name \""files[p]"\" -print"
else
find_args="-name \""files[p]"\" -print"
if (p < q)
find_args=find_args" -o"
}
print find_args
}'`
unsafe_n=0 # Unsafe (open invite) rhosts files
chmod_m=0 # System files changed
chmod_n=0 # User files changed
zero_uids=""
zero_uid_n=0
suid_scripts_n=0
su_files_n=0
mail_files_n=0
wx_files_n=0
ww_files_n=0
#----------------------------------------------------------------#
# Since I use this awk code in a couple of places, the following #
# variable assignment saves having it coded multiple times. #
#----------------------------------------------------------------#
awk_perms_script='BEGIN \
{ new_perms=""
#------------------------------------------#
# For each octet, if the current value is #
# less desired perm or less than or equal #
# to zero, then use desired value, else #
# retain the current permission. #
#------------------------------------------#
for (i=1;i<=4;i++)
{
c_perm=substr(curr_perms ,i,1);
d_perm=substr(desired_perms,i,1);
r_perm=c_perm - d_perm;
if (r_perm >= 0)
new_perms=new_perms""d_perm;
else
new_perms=new_perms""c_perm;
}
print new_perms;
}'
#------------------------------------------------------------------#
# If our log already has something in it, then this is NOT our 1st #
# run today. (We'll use this indicator later to see if we prune #
# the logs or no.) Since this is an accumulating log, we really #
# only want to view its activity from this operation (skipping any #
# previous operatione), which is why we need the last line number. #
#------------------------------------------------------------------#
if [ -s "$log" ]; then
first_run=0
log_pointer=`wc -l < $log`
else
first_run=1
log_pointer=1
fi
#------------------------------------------------------------------#
# Now print all the stuff we were saving. This way, if the user #
# wanted usage brief or documentation, he doesn't see see all the #
# preliminary stuff and mistakenly think he's started the program. #
#------------------------------------------------------------------#
$ECHO "$prelims" | $teelog
#----------------------------------------------------------#
# $fs is a critical variable -- exit on assignment failure.#
#----------------------------------------------------------#
echo "`date '+%Y-%m-%d %T'`" \
"Assign file system variable, \$fs." | $teelog
fs=`$DF $df_opt|$AWK 'NR > 1 && $NF !~ /\/cdrom|\/proc/ {print $NF}'`
if [ $? -ne 0 ]; then
echo "`date '+%Y-%m-%d %T'`" \
"Assign file system variable failed! $0 terminated." | $teelog
EXIT 1
fi
echo "`date '+%Y-%m-%d %T'` Variable assignment complete." | $teelog
#======================================================================#
# M A I N #
#======================================================================#
#--------------------------------------------------------------#
# If we receive a hangup, interrupt, or are killed (with the #
# default 'kill' or 'kill 15'), then run TRAP_EXIT(). This is #
# important because by exiting gracefully, we cleanup before #
# exiting. #
#--------------------------------------------------------------#
n=0
for sig in `kill -l`
do
n=`expr $n + 1`
[ ".$sig" = ".EXIT" -o ".$sig" = ".SEGV" \
-o ".$sig" = ".CHLD" -o ".$sig" = ".CLD" \
-o ".$sig" = ".TSTP" -o ".$sig" = ".CONT" \
] && continue
trap "echo Exit $sig \($n\) 1>&2; \
TERMINATE_SUBPROCESSES; TRAP_EXIT $n" $n
done
#----------------------------------------------------#
# If unable to touch or chmod $log, fuss at the user #
# (the function does this via stderr) and exit. #
#----------------------------------------------------#
TOUCH_EXIT_ERR_NOMAIL $log # Touch because we'll append to it.
CP_DEV_NULL_EXIT_ERR_NOMAIL $stdout $stderr
CP_DEV_NULL_EXIT_ERR $tmpwrk $tmplog
CHMOD_EXIT_ERR_NOMAIL 0600 $log $stdout $stderr \
$tmpwrk $tmplog $mailmsg
echo "`date '+%Y-%m-%d %T'`" \
"Begin `uname -n`:$script_name (PID=$$)" | $teelog
#------------------------------------#
# Display process variables. #
#------------------------------------#
echo "`date '+%Y-%m-%d %T'` Listing $script_name variables." | $teelog
var_list="bin_dir awk mail df kill rm echo" # Binaries
var_list="$var_list fs log teelog stdout stderr mailmsg tmplog"
var_list="$var_list tmpwrk tmpwrk1 tmpwrk2"
var_list="$var_list dateplus log_pointer"
var_list="$var_list rhost_pr script_home"
#------------------------------------#
# Print a sorted (-s) variable list. #
#------------------------------------#
PRINT_VARS -s $variables $var_list $num_variables
#------------------------------------------------------------------#
# If a this script is already running, then don't start a new one. #
# However, if $active_status file is more than a day old, then #
# notify support and remove the dog. #
# #
# Else, write our current process ID ($$) to $active_status_file #
# (the file is removed on exiting this process via EXIT function). #
#------------------------------------------------------------------#
if [ ."$active_status_file" != . ]; then
active_filename=`basename $active_status_file`
find="find $working_dir -name $active_filename -mtime +1 -print"
echo "`date '+%Y-%m-%d %T'` $find" | $teelog
old_active_file=`$find`
if [ ."$old_active_file" != . ]; then
EMAIL_MSG "Old Active Status File Found" \
"${sp}Found old active status file!" \
"${sp}($old_active_file)" \
"${sp}Removing file and continuing."
echo "`date '+%Y-%m-%d %T'`" \
"rm -f $active_status_file" | $teelog
rm -f $active_status_file 2>&1 | $teelog
fi
fi
EXIT_IF_ALREADY_RUNNING
ELAPSED_TIME start $program_start # $program_start captured above.
#--------------------------#
# How long we've been up. #
#--------------------------#
/usr/bin/uptime \
| $AWK -v sp="$sp" -v dashes=$dashes \
'{
"date \047+%Y-%m-%d %T\047" | getline timestamp
uptime=timestamp" Uptime = "$3" "$4" "$5
if ($6 ~ /min/) uptime=uptime" "$6
sub(/,$/,"",uptime) # Remove any trailing comma
print uptime"\n"sp""dashes
exit
}' | $teelog
#--------------------------------------------------------------#
# The '()' in the following lines is simply to make it easy to #
# find ALL function declaration and function calls. #
#--------------------------------------------------------------#
ROOT_DASH_I_FILE # ()
CHECK_DEV_NULL_PERMS # ()
CHECK_ROOT_DIR_PERMS # ()
CHECK_TMP_DIR_PERMS # ()
CHECK_VAR_MSGS_PERMS # ()
[ $opt_g -eq 1 ] && ENSURE_GNUPG_PERMS # ()
CHECK_CRITICAL_ID_MAIL # ()
CHECK_N_ROLL_WTMP_FILESIZES # ()
CHECK_N_ROLL_CRON_LOG # ()
FIND_AND_CHMOD 0600 $perm_600_files # ()
EXAMINE_NETRC_FILES # ()
EXAMINE_RHOSTS_FILES # ()
LIST_SU_FILES # ()
CHECK_PASSWD_FOR_UID_0 # ()
DISPLAY_SETUID_SCRIPTS # ()
REPORT_SU_TO_ROOT_ACTIVITY # ()
REPORT_RECENT_LOGIN_ACTIVITY # ()
LIST_CORE_DUMP_FILES; [ $? -gt 0 ] && REMOVE_OLD_CORE_DUMPS # ()
CHMOD_SPECIFIC_FILES $file_perms # ()
REMOVE_WORLD_FILE_PERMS "w" 0003 $ww_dirs # ()
REMOVE_WORLD_FILE_PERMS -m +$mtime "w" 0003 $fs # () W-execute
if [ ."$ww_30_dirs" != . ]; then
REMOVE_WORLD_FILE_PERMS -m +30 "w" 0003 $ww_30_dirs # ()
fi
LIST_WORLD_WX_FILES # ()
REMOVE_WORLD_FILE_PERMS "w" 0002 $ww_dirs # ()
REMOVE_WORLD_FILE_PERMS -m +$mtime "w" 0002 $fs # () W-write
if [ ."$ww_30_dirs" != . ]; then
REMOVE_WORLD_FILE_PERMS -m +30 "w" 0002 $ww_30_dirs # ()
fi
LIST_ALL_WW_FILES # ()
BROKEN_SYMBOLIC_LINKS # ()
LIST_OLD_TMP_FILES # ()
if [ $opt_s -eq 1 ]; then
FIND_ERRORS_IN_SYSLOGS # ()
LAST_20_LINES_SYSLOGS # ()
fi
SNAPSHOT_SYSTEM # ()
#----------------------------------------------------------------#
# Only on the first run of the day do we prune our process logs. #
#----------------------------------------------------------------#
[ $first_run -eq 1 ] && PRUNE_FILES $keep_logs $log_root
CLEANUP_WORK_FILES $cleanup_files 2>&1 | $teelog
#--------------------------------------------------------#
elapsed_time=`ELAPSED_TIME stop` # OK, let's clock out. #
#--------------------------------------------------------#
unsafe_m=` printf "%5d" $unsafe_m`
unsafe_n=` printf "%5d" $unsafe_n`
zero_uid_n=` printf "%5d" $zero_uid_n`
suid_scripts_n=`printf "%5d" $suid_scripts_n`
chmod_m=` printf "%5d" $chmod_m`
chmod_n=` printf "%5d" $chmod_n`
su_files_n=` printf "%5d" $su_files_n`
mail_files_n=` printf "%5d" $mail_files_n`
wx_files_n=` printf "%5d" $wx_files_n`
ww_files_n=` printf "%5d" $ww_files_n`
broken_ln=` printf "%5d" $broken_ln`
if [ ."$_CRC_rollovers" != ."None" ]; then
_CRC_rollovers=`echo "$_CRC_rollovers" | sed 's/^None //'`
fi
_CRC_rollovers="Cron Log Rollovers: $_CRC_rollovers"
if [ ."$_CRW_rollovers" != ."None" ]; then
_CRW_rollovers=`echo "$_CRW_rollovers" | sed 's/^None //'`
fi
_CRW_rollovers="WTMP Log Rollovers: $_CRW_rollovers"
if [ ."$TERM" = . ]; then
sed -n "$log_pointer,$ p" $log > $tmplog
EMAIL_MSG "$script_name" \
"${sp}$script_name completed in $elapsed_time." \
"${sp} Search" \
"${sp}Count String Category." \
"${sp}----- ------- -----------------------------------" \
"${sp}$unsafe_m (_ERF_) Unsafe .rhosts file contents found." \
"${sp}$unsafe_n (_FAC_) Unsafe .rhosts file perms found." \
"${sp}$zero_uid_n (_CPU_) Non-root UID=0 found: $zero_uids" \
"${sp}$su_files_n (_LSU_) Executable 'su' files found." \
"${sp}$suid_scripts_n (_DSS_) SUID script(s) found." \
"${sp}$mail_files_n (_CCM_) Critical ID mail files found." \
"${sp}$chmod_m (_CSF_) System file permissions changed." \
"${sp}$chmod_n (_RWP_) User file permissions changed." \
"${sp}$wx_files_n (_LWX_) World-WX files remain." \
"${sp}$ww_files_n (_LWW_) World-WW files remain." \
"${sp}$broken_ln (_BSL_) $broken_links" \
"${sp} (_CRW_) $_CRW_rollovers." \
"${sp} (_CRC_) $_CRC_rollovers." \
"${sp}$dashes" \
"NO_LOG" \
"${sp}Log ($log) follows:" \
"${sp}$ddashes" \
"FILE=$tmplog"
else
$ECHO "`date '+%Y-%m-%d %T'`" \
"$script_name completed in $elapsed_time." \
"\n${sp} Search" \
"\n${sp}Count String Category." \
"\n${sp}----- ------- -----------------------------------" \
"\n${sp}$unsafe_m (_ERF_) Unsafe .rhosts file contents found." \
"\n${sp}$unsafe_n (_FAC_) Unsafe .rhosts file perms found." \
"\n${sp}$zero_uid_n (_CPU_) Non-root UID=0 found: $zero_uids" \
"\n${sp}$su_files_n (_LSU_) Executable 'su' files found." \
"\n${sp}$suid_scripts_n (_DSS_) SUID script(s) found." \
"\n${sp}$mail_files_n (_CCM_) Critical ID mail files found." \
"\n${sp}$chmod_m (_CSF_) System file permissions changed." \
"\n${sp}$chmod_n (_RWP_) User file permissions changed." \
"\n${sp}$wx_files_n (_LWX_) World-WX files remain." \
"\n${sp}$ww_files_n (_LWW_) World-WW files remain." \
"\n${sp}$broken_ln (_BSL_) $broken_links" \
"\n${sp} (_CRW_) $_CRW_rollovers." \
"\n${sp} (_CRC_) $_CRC_rollovers." | $teelog
fi
CLEANUP_WORK_FILES $tmplog_root 2>&1 | $teelog
TERMINATE_SUBPROCESSES # Just in case we have any hanging around.
EXIT $success
#======================================================================#
# D O C U M E N T A T I O N #
#----------------------------------------------------------------------#
# #
# Author: Bob Orlando <Bob@OrlandoKuntao.com> #
# #
# Date: June 19, 1995 #
# #
# Program id: janitor.sh #
# #
# Usage: janitor.sh -bcgHhilmnrsTtvw #
# -b = Broken symbolic link cleanup. #
# -c = Change errant file permissions. #
# -g = Ensures root ownership of ./gnupg #
# and 4755 permissions for gpg program. #
# -H = Displays process documentation. #
# -h = Displays usage brief. #
# -i = Install '-i' file in root filesystem. #
# -l = Also use 'logger' for error reporting. #
# -m = Mail SUID scripts found notification. #
# -n = Display contents of .netrc files. #
# -r = Rollover cron and wtmp logs. #
# -s = Scan and list tail of syslogs. #
# -T = Test mode (notify Bob Orlando only) #
# -t = List old files in /tmp. #
# -v = Verbose mode (somewhat noisier output). #
# -w = Report all world-writable files. #
# #
# Code Contrl: aphrodite:~dmc/SCCS. #
# #
# Purpose: Perform various sysadmin functions. #
# #
# Description: Normally called by cron, this script performs the #
# following: #
# #
# * Compares timestamps in master parameter file, #
# janitor.master_par and runtime parameter file, #
# janitor.par, updating runtime version when the #
# master is found with a different timestamp. #
# * Checks /dev/null, / (root directory), /tmp and #
# /var/tmp directory, and /var/adm/messages* file #
# permissions. #
# * Optionally ensures gpg file permissions are 4755. #
# * Reports mail found for system IDs such as root, #
# bin, daemon, lp, etc. #
# * Informs when cronlog and wtmp* file sizes exceed #
# sizes specified in the program's parameter file #
# and optionally rolls over these files when they #
# exceed the size specified in the program's #
# parameter file (at this time this option is used #
# on all of the hosts under DMC monitoring). #
# * Scans and reports .rhosts files that pose security #
# risks (e.g. files having '+' or '+ +' entries #
# in them, as well as having file permissions other #
# than 0600). Also displays contents of all .rhosts #
# and hosts.equiv files. #
# * Changes .forward and .netrc file permissions to #
# 0600. #
# * Displays recent 'su' to root and rlogin activity. #
# * Reports and changes specific files (listed in #
# janitor.perms) that have other than the desired #
# or recommended permissions. #
# * Reports files having world-write and #
# world-write-execute permissions. Optionally, WW #
# and WX files in home can have the WW permission #
# removed from files in /home (at this time, this #
# option is used on all of the hosts under DMC #
# monitoring). #
# * Lists all core files found and removes those not #
# modified in $old_core days. #
# * Lists /tmp files not accessed in last 7 days. #
# * Reports recent "errors" from /var/adm/messages* #
# and /var/log/syslog* files. #
# * Report UIDs in /etc/passwd that have a UID of #
# zero but are some other ID other than root. #
# (It reported smtp as being one such user.) #
# * Report all executable root-SUID files. For example, #
# on ibesdev, in addition to /usr/bin/su, we found #
# /platform/sun4u/kernel/drv/su (-rwxr-xr-x 1 root sys #
# 26552 Jul 15 1997 /platform/sun4u/kernel/drv/su). #
# * Optionally, create (if absent) a '-i' file in root. #
# Such a file adds one more layer of protection for #
# securing root files and saving the kernel from #
# accidental deletion by causing errant interactive #
# 'rm' commands in root to treat this file as rm's #
# interactive confirmation option. This file only #
# affects interactive "removes" and is easily removed #
# with '\rm - -i', should globbing be absolutely #
# necessary. #
# * Displays system snapshot (e.g. uname -a, hostid, #
# umask, and command operations like df -lk, mount, #
# and others specified in the OPERATIONS parameter). #
# This snapshot can handle most any command line #
# operation. Here is a sample list: #
# #
# /usr/sbin/mount -p #
# /usr/bin/df -lk #
# /usr/local/etc/prtvtoc.sh # format, prtdiag/prtconf #
# /usr/sbin/vxprint -l #
# /usr/local/bin/sar.sh #
# /bin/cat /etc/profile #
# /bin/cat /etc/passwd /etc/shadow #
# #
# Files: /usr/local/etc/janitor.par #
# = CRITICAL runtime parameter file. Won't run home #
# without it. #
# /usr/local/etc/janitor.master_par #
# = CRITICAL parameter file master. Won't run home #
# without it. #
# /usr/local/etc/janitor.fileperms #
# = List of specific files and their desired perms. #
# /var/logs/janitor_log.yymmdd #
# = Process log file pruned to $keep_logs. #
# #
# Externals: /usr/local/bin/dateplus #
# = Returns aged dates for looking back through #
# message logs. #
# #
# Notes: You will find numerous lines with '# ()' appended to #
# them. This allows location of all function calls #
# (the function declarations already have '()' -- adding #
# '# ()' to calls makes it possible to grep all '()' and #
# see both declarations and calls). #
# #
# You will see many 'find' commands with assassin code #
# to terminate them if they exceed 5 minutes. We do not #
# diagnose the problem, simply terminate the find, report #
# said termination, and continue. #
# #
# Modified: 2006-09-28 Bob Orlando #
# v2.43 * Migrate from root SCCS ownership to DMC. #
# #
# 2006-02-02 Bob Orlando #
# v2.42 * Added the following echo for -T operation in #
# CHMOD_SPECIFIC_FILES() #
# #
# [ $verbose -eq 1 ] \ #
# && echo "${sp}Checking $_CSF_file" ... #
# #
#----------------------------------------------------------------------#