#!/bin/bash

#< Script to check Red Hat Enterprise Linux AS 4 OS-level security for security risks

# Designed to be run whilst redirecting output to two files, thus:
# /path/to/chkhard.sh >/root/chkhard/listings.out 2>/root/chkhard/security_risks.out
# i.e. - file output is dumped to listings.out for analysis, whilst all checked
# security risks are output to security_risks.out.

# This script sticks a few "best" security principles from various sources (CISecurity.org, 
# and many others), customised for my environment. The script is VERY rigid. But you can
# just ignore problems that you're not concerned with

# ToDo: Make most settings user configurable
#       Create variables to hold paths to executables

# Function:	cleanup()
# Arguments:	None
# Returns:	Nothing
# Description:	Removes all /tmp/chkhard* files, if any exist

cleanup() {
   rm -rf /tmp/chkhard*
}

# Trap signals, cleanup and exit
trap 'cleanup(); exit 1' 1 2 3 15

# Function:	print_error()
# Arguments:	$@
# Returns:	Nothing
# Description:  Prints arguments to STDERR with prefix "ERROR: "

print_error() {
   echo "ERROR: $@" >&2
}

# Function:	print_warning()
# Arguments:	$@
# Returns:	Nothing
# Description:  Prints arguments to STDERR with prefix "WARNING: "

print_warning() {
   echo "WARNING: $@" >&2
}

# Function:	check_os()
# Arguments:	None
# Returns:	Exits on failure
# Description:  Ensures that the script is only executed on Red Hat Linux

check_os() {
   [[ `uname -s` == "Linux" ]] && {
      [[ -e /etc/redhat-release ]] || {
         print_error "Sorry, only Red Hat Linux supported"
         exit 1
      }
   }
}

# Function:	check_root()
# Arguments:	None
# Returns:	Exits on failure	
# Description:  Ensures that the script is only run as root

check_root() {
   [[ `id -u` -ne "0" ]] && {
      print_error "This script must be run as \"root\""
      exit 1
   }
}

# Function:	check_fstab()
# Arguments:	None
# Returns:	Nothing
# Description:  Goes through /etc/fstab and checks that various mount options are set
#		on various filesystems. These are currently hard coded.
# ToDo:		Make filesystems and mount options to check configurable

check_fstab() {
   [[ ! -e "/etc/fstab" ]] && {
       print_warning "/etc/fstab does not exist"
   } || {
       # First, check /boot filesystem
      egrep '^[^ 	]+[ 	]+/boot[ 	]+.*$' /etc/fstab >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         BOOT_FS_LINE=`egrep '^[^ 	]+[ 	]+/boot[ 	]+.*$' /etc/fstab`
         BOOT_FS_MOUNT_OPTIONS=`echo "${BOOT_FS_LINE}" | awk '{print $4}'`
         echo "${BOOT_FS_MOUNT_OPTIONS}" | awk -vRS=',' '1' | grep -v '^[ 	]*$' > /tmp/chkhard_boot_fs_options_$$
         BOOT_FS_REQUIRED_OPTIONS="defaults\nacl"
         echo -e "${BOOT_FS_REQUIRED_OPTIONS}" | while read OPTION; do
            grep "^${OPTION}$" /tmp/chkhard_boot_fs_options_$$ >/dev/null 2>&1 || {
               print_warning "${OPTION} mount option not set for /boot filesystem" 
            }
         done 
      } || {
         print_warning "Could not find /boot filesystem in /etc/fstab"
      } 
      # Next, root filesystem
      egrep '^[^ 	]+[ 	]+/[ 	]+.*$' /etc/fstab >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         ROOT_FS_LINE=`egrep '^[^ 	]+[ 	]+/[ 	]+.*$' /etc/fstab`
         ROOT_FS_MOUNT_OPTIONS=`echo "${ROOT_FS_LINE}" | awk '{print $4}'`
         echo "${ROOT_FS_MOUNT_OPTIONS}" | awk -vRS=',' '1' | grep -v '^[ 	]*$' > /tmp/chkhard_root_fs_options_$$
         ROOT_FS_REQUIRED_OPTIONS="defaults"
         echo -e "${ROOT_FS_REQUIRED_OPTIONS}" | while read OPTION; do
            grep "^${OPTION}$" /tmp/chkhard_root_fs_options_$$ >/dev/null 2>&1 || {
               print_warning "${OPTION} mount option not set for / filesystem" 
            }
         done 
      } || {
         print_warning "Could not find / filesystem in /etc/fstab"
      } 
      # Next, /var filesystem
      egrep '^[^ 	]+[ 	]+/var[ 	]+.*$' /etc/fstab >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         VAR_FS_LINE=`egrep '^[^ 	]+[ 	]+/var[ 	]+.*$' /etc/fstab`
         VAR_FS_MOUNT_OPTIONS=`echo "${VAR_FS_LINE}" | awk '{print $4}'`
         echo "${VAR_FS_MOUNT_OPTIONS}" | awk -vRS=',' '1' | grep -v '^[ 	]*$' > /tmp/chkhard_var_fs_options_$$
         VAR_FS_REQUIRED_OPTIONS="defaults\nnosuid\nacl\nnodev"
         echo -e "${VAR_FS_REQUIRED_OPTIONS}" | while read OPTION; do
            grep "^${OPTION}$" /tmp/chkhard_var_fs_options_$$ >/dev/null 2>&1 || {
               print_warning "${OPTION} mount option not set for /var filesystem" 
            }
         done 
      } || {
         print_warning "Could not find /var filesystem in /etc/fstab"
      } 
      # Next, /var/log filesystem
      egrep '^[^ 	]+[ 	]+/var/log[ 	]+.*$' /etc/fstab >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         VAR_LOG_FS_LINE=`egrep '^[^ 	]+[ 	]+/var/log[ 	]+.*$' /etc/fstab`
         VAR_LOG_FS_MOUNT_OPTIONS=`echo "${VAR_LOG_FS_LINE}" | awk '{print $4}'`
         echo "${VAR_LOG_FS_MOUNT_OPTIONS}" | awk -vRS=',' '1' | grep -v '^[ 	]*$' > /tmp/chkhard_var_log_fs_options_$$
         VAR_LOG_FS_REQUIRED_OPTIONS="defaults\nnosuid\nacl\nnodev"
         echo -e "${VAR_LOG_FS_REQUIRED_OPTIONS}" | while read OPTION; do
            grep "^${OPTION}$" /tmp/chkhard_var_log_fs_options_$$ >/dev/null 2>&1 || {
               print_warning "${OPTION} mount option not set for /var/log filesystem" 
            }
         done 
      } || {
         print_warning "Could not find /var/log filesystem in /etc/fstab"
      } 
      # Next, /tmp filesystem
      egrep '^[^ 	]+[ 	]+/tmp[ 	]+.*$' /etc/fstab >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         TMP_FS_LINE=`egrep '^[^ 	]+[ 	]+/tmp[ 	]+.*$' /etc/fstab`
         TMP_FS_MOUNT_OPTIONS=`echo "${TMP_FS_LINE}" | awk '{print $4}'`
         echo "${TMP_FS_MOUNT_OPTIONS}" | awk -vRS=',' '1' | grep -v '^[ 	]*$' > /tmp/chkhard_tmp_fs_options_$$
         TMP_FS_REQUIRED_OPTIONS="defaults\nnosuid\nacl\nnodev"
         echo -e "${TMP_FS_REQUIRED_OPTIONS}" | while read OPTION; do
            grep "^${OPTION}$" /tmp/chkhard_tmp_fs_options_$$ >/dev/null 2>&1 || {
               print_warning "${OPTION} mount option not set for /tmp filesystem" 
            }
         done 
      } || {
         print_warning "Could not find /tmp filesystem in /etc/fstab"
      } 
      # Finally, /home
      egrep '^[^ 	]+[ 	]+/home[ 	]+.*$' /etc/fstab >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         HOME_FS_LINE=`egrep '^[^ 	]+[ 	]+/tmp[ 	]+.*$' /etc/fstab`
         HOME_FS_MOUNT_OPTIONS=`echo "${HOME_FS_LINE}" | awk '{print $4}'`
         echo "${HOME_FS_MOUNT_OPTIONS}" | awk -vRS=',' '1' | grep -v '^[ 	]*$' > /tmp/chkhard_home_fs_options_$$
         HOME_FS_REQUIRED_OPTIONS="defaults\nnosuid\nacl\nnodev"
         echo -e "${HOME_FS_REQUIRED_OPTIONS}" | while read OPTION; do
            grep "^${OPTION}$" /tmp/chkhard_home_fs_options_$$ >/dev/null 2>&1 || {
               print_warning "${OPTION} mount option not set for /home filesystem" 
            }
         done 
      } || {
         print_warning "Could not find /home filesystem in /etc/fstab"
      } 
      # And simply check for the existance of a swap partition
      egrep '^[^ 	]+[ 	]+swap[ 	]+.*$' /etc/fstab >/dev/null 2>&1
      [[ "$?" -eq "0" ]] || {
         print_warning "Could not find swap partition in /etc/fstab"
      }
   }
}

# Function:	check_required_software()
# Arguments:	None
# Returns:	Nothing
# Description:  Check that various software packages are installed

check_required_software() {
   for RPM in sudo tcp_wrappers openssh sysstat; do
      rpm -qi ${RPM} >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "Package \"${RPM}\" not installed"
      }
   done
}

# Function:	check_banned_software()
# Arguments:	None
# Returns:	Nothing
# Description:  Check that various software packages are not installed

check_banned_software() {
   for RPM in tcpdump nmap netcat hotplug kernel-pcmcia-cs pcmcia-cs; do
      rpm -qi ${RPM} >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         print_warning "Package \"${RPM}\" is installed"
      }
  done
}

# Function:	display_messages()
# Arguments:	None
# Returns:	Nothing
# Description:  Dump contents of /etc/{motd,issue,issue.net} to STDOUT

display_messages() {
   echo "======================================================================="
   echo "Check the output of the following commands for message file compliance:"
   echo "======================================================================="
   [[ -e "/etc/motd" ]] && {
      echo "$ cat /etc/motd"
      cat /etc/motd
   } || {
      print_warning "/etc/motd does not exist"
   }
   [[ -e "/etc/issue" ]] && {
      echo "$ cat /etc/issue"
      cat /etc/issue
   } || {
      print_warning "/etc/issue does not exist"
   }
   [[ -e "/etc/issue.net" ]] && {
      echo "$ cat /etc/issue.net"
      cat /etc/issue.net
   } || {
      print_warning "/etc/issue.net does not exist"
   }
}

# Function:	display_services()
# Arguments:	None
# Returns:	Nothing
# Description:  Show listening network services, and services enabled via chkconfig

display_services() {
   echo "======================================================================="
   echo "Check the output of the following commands to ensure appropriate"
   echo "service lockdown has been applied:"
   echo "======================================================================="
   echo "$ netstat -anlp | grep LISTEN"
   netstat -anlp | grep LISTEN
   echo "$ chkconfig --list | grep on"
   chkconfig --list | grep on
}

# Function:	check_system_accounts()
# Arguments:	None
# Returns:	Nothing
# Description:  Check for accounts that should be removed or locked

check_system_accounts() {
   ACCOUNTS_TO_REMOVE="smtp\nlisten\nuucp\nnuucp\ngames\ngopher\nftp\nnetdump\nnfsnobody\npcap"
   echo -e "${ACCOUNTS_TO_REMOVE}" | while read ACCOUNT; do
      grep "^${ACCOUNT}:.*$" /etc/passwd >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         print_warning "System account ${ACCOUNT} exists and should be removed"
      }
   done
   ACCOUNTS_TO_DISABLE="nobody4\ndaemon\nbin\nadm\nlp\nnobody\nnoaccess\nsmmsp\nsync\nshutdown"
   ACCOUNTS_TO_DISABLE="${ACCOUNTS_TO_DISABLE}\nhalt\nmail\nnews\noperator\ndbus\nvcsa\nnscd"
   ACCOUNTS_TO_DISABLE="${ACCOUNTS_TO_DISABLE}\nrpm\nhaldaemon\nsshd\nrpc\nrpcuser\nmailnull"
   echo -e "${ACCOUNTS_TO_DISABLE}" | while read ACCOUNT; do
      grep "^${ACCOUNT}:.*$" /etc/passwd >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         egrep "^${ACCOUNT}:(!!|\*):.*$" /etc/shadow >/dev/null 2>&1
         [[ "$?" -eq "0" ]] || {
            print_warning "System account ${ACCOUNT} exists and is NOT locked"
         }
      }
   done
}

# Function:	check_syslog_conf()
# Arguments:	None
# Returns:	Nothing
# Description:  Display syslog.conf file on STDOUT for checking

check_syslog_conf() {
   echo "======================================================================="
   echo "Check the output of the following commands to ensure that the syslog"
   echo "configuration has been set correctly"
   echo "======================================================================="
   [[ ! -e "/etc/syslog.conf" ]] && {
      print_warning "/etc/syslog.conf does not exist. Maybe check your syslog-ng config?"
   } || {
      echo "$ cat /etc/syslog.conf"
      cat /etc/syslog.conf
   }
}

# Function:	check_sysctl_conf()
# Arguments:	None
# Returns:	Nothing
# Description:  Check that various parameters are set correctly in /etc/sysctl.conf

check_sysctl_conf() {
   grep '^net\.ipv4\.tcp_max_syn_backlog[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.tcp_max_syn_backlog[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "4096" ]] && {
         print_warning "net.ipv4.tcp_max_syn_backlog NOT set to 4096 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.tcp_max_syn_backlog NOT defined in /etc/sysctl.conf" 
   }
   grep '^net\.ipv4\.tcp_syncookies[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.tcp_syncookies[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "1" ]] && {
         print_warning "net.ipv4.tcp_max_syncookies NOT set to 1 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.tcp_max_syncookies NOT defined in /etc/sysctl.conf" 
   }
   grep '^net\.ipv4\.conf\.all\.rp_filter[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.conf\.all\.rp_filter[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "1" ]] && {
         print_warning "net.ipv4.conf.all.rp_filter NOT set to 1 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.conf.all.rp_filter NOT defined in /etc/sysctl.conf" 
   }
   grep '^net\.ipv4\.conf\.all\.accept_source_route[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.conf\.all\.accept_source_route[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "0" ]] && {
         print_warning "net.ipv4.conf.all.accept_source_route NOT set to 0 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.conf.all.accept_source_route NOT defined in /etc/sysctl.conf" 
   }
   grep '^net\.ipv4\.conf\.all\.accept_redirects[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.conf\.all\.accept_redirects[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "0" ]] && {
         print_warning "net.ipv4.conf.all.accept_redirects NOT set to 0 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.conf.all.accept_redirects NOT defined in /etc/sysctl.conf" 
   }
   grep '^net\.ipv4\.conf\.all\.secure_redirects[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.conf\.all\.secure_redirects[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "0" ]] && {
         print_warning "net.ipv4.conf.all.secure_redirects NOT set to 0 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.conf.all.secure_redirects NOT defined in /etc/sysctl.conf" 
   }
   grep '^net\.ipv4\.conf\.default\.rp_filter[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.conf\.default\.rp_filter[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "1" ]] && {
         print_warning "net.ipv4.conf.default.rp_filter NOT set to 1 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.conf.default.rp_filter NOT defined in /etc/sysctl.conf" 
   }
   grep '^net\.ipv4\.conf\.default\.accept_redirects[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.conf\.default\.accept_redirects[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "0" ]] && {
         print_warning "net.ipv4.conf.default.accept_redirects NOT set to 0 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.conf.default.accept_redirects NOT defined in /etc/sysctl.conf" 
   }
   grep '^net\.ipv4\.conf\.default\.secure_redirects[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.conf\.default\.secure_redirects[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "0" ]] && {
         print_warning "net.ipv4.conf.default.secure_redirects NOT set to 0 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.conf.default.secure_redirects NOT defined in /etc/sysctl.conf" 
   }
   grep '^net\.ipv4\.icmp_echo_ignore_broadcasts[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.icmp_echo_ignore_broadcasts[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "1" ]] && {
         print_warning "net.ipv4.icmp_echo_ignore_broadcasts NOT set to 1 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.icmp_echo_ignore_broadcasts NOT defined in /etc/sysctl.conf" 
   }
   grep '^net\.ipv4\.ip_forward[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.ip_forward[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "0" ]] && {
         print_warning "net.ipv4.ip_forward NOT set to 0 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.ip_forward NOT defined in /etc/sysctl.conf" 
   }
   grep '^net\.ipv4\.conf\.all\.send_redirects[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.conf\.all\.send_redirects[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "0" ]] && {
         print_warning "net.ipv4.conf.all.send_redirects NOT set to 0 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.conf.all.send_redirects NOT defined in /etc/sysctl.conf" 
   }
   grep '^net\.ipv4\.conf\.default\.send_redirects[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^net\.ipv4\.conf\.default\.send_redirects[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "0" ]] && {
         print_warning "net.ipv4.conf.default.send_redirects NOT set to 0 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "net.ipv4.conf.default.send_redirects NOT defined in /etc/sysctl.conf" 
   }
}

# Function:	display_host_access()
# Arguments:	None
# Returns:	Nothing
# Description:  Display contents of hosts.{allow,deny} for checking

display_host_access() {
   echo "======================================================================="
   echo "Check the output of the following commands to ensure that the TCP"
   echo "wrappers configuration has been set correctly"
   echo "======================================================================="
   [[ ! -e "/etc/hosts.allow" ]] && {
      print_warning "/etc/hosts.allow does not exist"
   } || {
      echo "$ cat /etc/hosts.allow"
      cat /etc/hosts.allow
   }
   [[ ! -e "/etc/hosts.deny" ]] && {
      print_warning "/etc/hosts.deny does not exist"
   } || {
      echo "$ cat /etc/hosts.deny"
      cat /etc/hosts.deny
   }
}

# Function:	check_sendmail()
# Arguments:	None
# Returns:	Nothing
# Description:  Check some basic sendmail configuration parameters

check_sendmail() {
   # If either of these files do not exist, don't worry about it
   [[ -e "/etc/mail/sendmail.cf" ]] && {
      grep '^O SmtpGreetingMessage.*$' /etc/mail/sendmail.cf >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         SETTING=`sed -n 's/^O SmtpGreetingMessage[ 	]*=[ 	]*\(.*\)$/\1/p' /etc/mail/sendmail.cf`
         echo "${SETTING}" | grep "^mailer ready$" >/dev/null 2>&1
         [[ "$?" -ne "0" ]] && {
            print_warning "O SmtpGreetingMessage not set to \"mailer ready\" in /etc/mail/sendmail.cf"
         } || { :; }
      } || {
         print_warning "O SmtpGreetingMessage not defined in /etc/mail/sendmail.cf"
      }
   } 
   [[ -e "/etc/sysconfig/sendmail" ]] && {
      grep '^DAEMON.*$' /etc/sysconfig/sendmail >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         SETTING=`sed -n 's/^DAEMON[ 	]*=[ 	]*\(.*\)$/\1/p' /etc/sysconfig/sendmail`
         echo "${SETTING}" | grep "^no$" >/dev/null 2>&1
         [[ "$?" -ne "0" ]] && {
            print_warning "DAEMON not set to \"no\" in /etc/sysconfig/sendmail"
         } || { :; }
      } || {
         print_warning "DAEMON not defined in /etc/sysconfig/sendmail"
      }
      grep '^QUEUE.*$' /etc/sysconfig/sendmail >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         SETTING=`sed -n 's/^QUEUE[ 	]*=[ 	]*\(.*\)$/\1/p' /etc/sysconfig/sendmail`
         echo "${SETTING}" | grep "^15m$" >/dev/null 2>&1
         [[ "$?" -ne "0" ]] && {
            print_warning "QUEUE not set to \"15m\" in /etc/sysconfig/sendmail"         
         } || { :; }
      } || { 
         print_warning "QUEUE not defined in /etc/sysconfig/sendmail"
      }
   }
}

# Function:	check_sshd_config()
# Arguments:	None
# Returns:	Nothing
# Description:  Check that lockdown has been applied to /etc/ssh/sshd_config

check_sshd_config() {
   [[ -e "/etc/ssh/sshd_config" ]] && {
      # get IP of primary interface, we'll assume bond0 
      INTERFACE="bond0"
      INET_ADDR=`ifconfig ${INTERFACE} | sed -n '/^[ 	]*inet addr.*$/ s/^.*inet addr:\([^ 	]*\).*$/\1/p'`
      PORT="22"
      grep "^ListenAddress[ 	]*${INET_ADDR}$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "ListenAddress not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^Port[ 	]*${PORT}$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "Port not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^Protocol[ 	]*2$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "Protocol not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^Banner[ 	]*/etc/issue\.net$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "Banner not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^UsePrivilegeSeparation[ 	]*yes$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "UsePrivilegeSeparation not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^ChallengeResponseAuthentication[ 	]*no$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "ChallengeResponseAuthentication not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^PAMAuthenticationViaKbdInt[ 	]*no$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "PAMAuthenticationViaKbdInt not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^X11Forwarding[ 	]*no$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "X11Forwarding not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^AllowTcpForwarding[ 	]*no$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "AllowTcpForwarding not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^Ciphers[ 	]*aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "Ciphers not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^ClientAliveInterval[ 	]*10$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "ClientAliveInterval not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^ClientAliveCountMax[ 	]*5$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "ClientAliveCountMax not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^HostbasedAuthentication[ 	]*no$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "HostbasedAuthentication not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^IgnoreRhosts[ 	]*no$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "IgnoreRhosts not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^KeepAlive[ 	]*yes$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "KeepAlive not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^PermitEmptyPasswords[ 	]*no$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "PermitEmptyPasswords not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^PermitRootLogin[ 	]*no$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "PermitRootLogin not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^PermitUserEnvironment[ 	]*no$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "PermitUserEnvironment not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^RhostsAuthentication[ 	]*no$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "RhostsAuthentication not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^RhostsRSAAuthentication[ 	]*no$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "RhostsRSAAuthentication not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^StrictModes[ 	]*yes$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "StrictModes not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^UseLogin[ 	]*no$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "UseLogin not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^VerifyReverseMapping[ 	]*yes$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "VerifyReverseMapping not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^KeyRegenerationInterval[ 	]*30m$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "KeyRegenerationInterval not correctly defined in /etc/ssh/sshd_config"
      } || :
      grep "^ServerKeyBits[ 	]*1024$" /etc/ssh/sshd_config >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "ServerKeyBits not correctly defined in /etc/ssh/sshd_config"
      } || :
   } || {
      print_warning "/etc/ssh/sshd_config does not exist"
   }
}

# Function:	check_su()
# Arguments:	None
# Returns:	Nothing
# Description:  Ensure that su has correct ownership and permissions

check_su() {
   SU_PATHS="/bin/su\n/usr/bin/su\n/sbin/su.static"
   echo -e "${SU_PATHS}" | while read SU_PATH; do
      [[ -e "${SU_PATH}" ]] && {
         LONG_LISTING=`ls -ld "${SU_PATH}"`
         SU_PERM=`echo "${LONG_LISTING}" | awk '{print $1}'` 
         SU_OWNER=`echo "${LONG_LISTING}" | awk '{print $3}'`
         SU_GROUP=`echo "${LONG_LISTING}" | awk '{print $3}'`
         [[ "${SU_PERM}" != "-rws--x---" ]] && {
            print_warning "${SU_PATH} permission incorrect"
         } || :
         [[ "${SU_OWNER}" != "root" ]] && {
            print_warning "${SU_PATH} ownership incorrect"
         } || :
         [[ "${SU_GROUP}" != "wheel" ]] && {
            print_warning "${SU_PATH} group ownership incorrect"
         } || :
      }
   done
   grep '^auth.*required.*pam_wheel.so.*use_uid' /etc/pam.d/su >/dev/null 2>&1
   [[ "$?" -ne "0" ]] && {
      print_warn "/etc/pam.d/su not correctly configured"
   }
}

# Function:	check_symlinks()
# Arguments:	None
# Returns:	Nothing
# Description:  Ensure that hosts.equiv is linked to /dev/null

check_symlinks() {
   [[ -e "/etc/hosts.equiv" ]] && {
      LONG_LISTING=`ls -ld /etc/hosts.equiv` 
      LAST_FIELD=`echo "${LONG_LISTING}" | awk '{print $NF}'`
      [[ "${LAST_FIELD}" != "/dev/null" ]] && {
         print_warning "/etc/hosts.equiv not linked to /dev/null"
      } || :
   } || {
      print_warning "/etc/hosts.equiv does not exist"
   }
   [[ -e "/etc/shosts.equiv" ]] && {
      LONG_LISTING=`ls -ld /etc/shosts.equiv` 
      LAST_FIELD=`echo "${LONG_LISTING}" | awk '{print $NF}'`
      [[ "${LAST_FIELD}" != "/dev/null" ]] && {
         print_warning "/etc/shosts.equiv not linked to /dev/null"
      } || :
   } || {
      print_warning "/etc/shosts.equiv does not exist"
   }
}

# Function:	check_stack_protection()
# Arguments:	None
# Returns:	Nothing
# Description:  Ensure that stack protection is enabled in /etc/sysctl.conf

check_stack_protection() {
   grep '^kernel\.exec-shield[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^kernel\.exec-shield[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "1" ]] && {
         print_warning "kernel.exec-shield NOT set to 0 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "kernel.exec-shield NOT defined in /etc/sysctl.conf" 
   }
   grep '^kernel\.exec-shield-randomize[ 	]*=.*$' /etc/sysctl.conf >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      NUM=`sed -n 's/^kernel\.exec-shield-randomize[ 	]*\=[ 	]*\(.*\)$/\1/p' /etc/sysctl.conf`
      [[ "${NUM}" -ne "1" ]] && {
         print_warning "kernel.exec-shield-randomize NOT set to 0 in /etc/sysctl.conf (value: ${NUM})"
      } || { :; }
   } || {
      print_warning "kernel.exec-shield-randomize NOT defined in /etc/sysctl.conf" 
   }
}

# Function:	check_umask()
# Arguments:	None
# Returns:	Nothing
# Description:  Check that umaks is adequately restrictive

check_umask() {
   grep '^[ 	]*umask 027$' /etc/init.d/functions >/dev/null 2>&1
   [[ "$?" -ne "0" ]] && {
      print_warning "umask not correctly set in /etc/init.d/functions"
   }
   for INITFILE in /etc/profile /etc/.login/etc/profile /etc/csh.login /etc/csh.cshrc /etc/bashrc; do
      [[ -e "${INITFILE}" ]] && {
         grep "^[	]*umask 077$" ${INITFILE} >/dev/null 2>&1
          [[ "$?" -ne "0" ]] && {
             print_warning "umask not correctly set in ${INITFILE}"
          } || { :; }
      }
   done
}

# Function:	check_mesg()
# Arguments:	None
# Returns:	Nothing
# Description:  mesg n!

check_mesg() {
   for INITFILE in /etc/profile /etc/.login/etc/profile /etc/csh.login /etc/csh.cshrc /etc/bashrc; do
      [[ -e "${INITFILE}" ]] && {
         grep "^[	]*mesg n$" ${INITFILE} >/dev/null 2>&1
          [[ "$?" -ne "0" ]] && {
             print_warning "mesg not correctly set in ${INITFILE}"
          } || { :; }
      }
   done
}

# Function:	check_system_auth()
# Arguments:	None
# Returns:	Nothing
# Description:  Check that pam_tally is configured to lock out accounts after 3 incorrect
#		password attempts. Of course, ignore root!

check_system_auth() {
   grep '^auth.*required.*pam_tally.so.*onerr=fail.*no_magic_root$' /etc/pam.d/system-auth >/dev/null 2>&1
   [[ "$?" -ne "0" ]] && {
      print_warning "auth required line for pam_tally not correctly defined in /etc/pam.d/system-auth"
   } 
   grep '^account.*required.*pam_tally.so.*deny=3.*reset.*no_magic_root$' /etc/pam.d/system-auth >/dev/null 2>&1
   [[ "$?" -ne "0" ]] && {
      print_warning "account required line for pam_tally not correctly defined in /etc/pam.d/system-auth"
   } 
}

# Function:	check_securetty()
# Arguments:	None
# Returns:	Nothing
# Description:  Ensure that root can only log in on specified consoles/terminals

check_securetty() {
   cat <<EoF >/tmp/chkhard_securetty.$$
console
vc/1
vc/2
vc/3
vc/4
vc/5
vc/6
vc/7
vc/8
vc/9
vc/10
vc/11
tty1
tty2
tty3
tty4
tty5
tty6
tty7
tty8
tty9
tty10
tty11
EoF
   [[ -e "/etc/securetty" ]] && {
      diff /etc/securetty /tmp/chkhard_securetty.$$ >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "/etc/securetty not correctly populated"
      } || :
   } || {
      print_warning "/etc/securetty does not exist"
   }
}

# Function:	check_cron_access()
# Arguments:	None
# Returns:	Nothing
# Description:  Check for cron/at restrictions. This function assumes a lot, i.e. that you
#		only want "root" to access cron and at. However, you can just check the output
#		and ignore the warnings if other users require access to these facilities

check_cron_access() {
   [[ -e "/etc/at.allow" ]] && {
      NUM_LINES=`grep -v 'root' /etc/at.allow | wc -l`
      [[ "${NUM_LINES}" -ne "0" ]] && {
         print_warning "users other than root exist in /etc/at.allow"
      } || :
   } || {
      print_warning "/etc/at.allow does not exist"
   }
   [[ -e "/etc/cron.allow" ]] && {
      NUM_LINES=`grep -v 'root' /etc/cron.allow | wc -l`
      [[ "${NUM_LINES}" -ne "0" ]] && {
         print_warning "users other than root exist in /etc/cron.allow"
      } || :
   } || {
      print_warning "/etc/cron.allow does not exist"
   }
   [[ -e "/etc/cron.deny" ]] && {
      cut -d: -f1 /etc/passwd | grep -v root | sort > /tmp/chkhard_cron_deny.$$
      sort /etc/cron.deny > /tmp/chkhard_cron_deny_compare.$$
      diff /tmp/chkhard_cron_deny.$$ /tmp/chkhard_cron_deny_compare.$$ >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "/etc/cron.deny not in sync with current system accounts"
      } || :
   } || {
      print_warning "/etc/cron.deny does not exist"
   }
   [[ -e "/etc/at.deny" ]] && {
      cut -d: -f1 /etc/passwd | grep -v root | sort > /tmp/chkhard_at_deny.$$
      sort /etc/at.deny > /tmp/chkhard_at_deny_compare.$$
      diff /tmp/chkhard_at_deny.$$ /tmp/chkhard_at_deny_compare.$$ >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "/etc/at.deny not in sync with current system accounts"
      } || :
   } || {
      print_warning "/etc/at.deny does not exist"
   }
}

# Function:	check_rhosts_pam()
# Arguments:	None
# Returns:	Nothing
# Description:  No rhosts support in pam, thanks!

check_rhosts_pam() {
   for PAM_FILE in /etc/pam.d/*; do
      grep "^[^#]*rhosts_auth" ${PAM_FILE} >/dev/null 2>&1
      [[ "$?" -eq "0" ]] && {
         print_warning "rhosts_auth enabled in ${PAM_FILE}"
      }
   done
}

# Function:	check_passwd_files()
# Arguments:	None
# Returns:	Nothing
# Description:  Check for correct ownership and permissions on user database files

check_passwd_files() {
   PASSWD_PERMS=`stat /etc/passwd | grep '^Access: (' | sed -n 's/^Access: (\([0-7][0-7]*\)\/.*$/\1/p'`
   SHADOW_PERMS=`stat /etc/shadow | grep '^Access: (' | sed -n 's/^Access: (\([0-7][0-7]*\)\/.*$/\1/p'`
   GROUP_PERMS=`stat /etc/group | grep '^Access: (' | sed -n 's/^Access: (\([0-7][0-7]*\)\/.*$/\1/p'`
   PASSWD_OWNER=`ls -ld /etc/passwd | awk '{print $3}'`
   PASSWD_GROUP=`ls -ld /etc/passwd | awk '{print $4}'`
   SHADOW_OWNER=`ls -ld /etc/shadow | awk '{print $3}'`
   SHADOW_GROUP=`ls -ld /etc/shadow | awk '{print $4}'`
   GROUP_OWNER=`ls -ld /etc/group | awk '{print $3}'`
   GROUP_GROUP=`ls -ld /etc/group | awk '{print $4}'`
   [[ "${PASSWD_PERMS}" != "0644" ]] && {
      print_warning "/etc/passwd has incorrect permissions"
   }
   [[ "${PASSWD_OWNER}" != "root" ]] && {
      print_warning "/etc/passwd has incorrect ownership"
   }
   [[ "${PASSWD_GROUP}" != "root" ]] && {
      print_warning "/etc/passwd has incorrect group ownership"
   }
   [[ "${SHADOW_PERMS}" != "0400" ]] && {
      print_warning "/etc/shadow has incorrect permissions"
   }
   [[ "${SHADOW_OWNER}" != "root" ]] && {
      print_warning "/etc/shadow has incorrect ownership"
   }
   [[ "${SHADOW_GROUP}" != "root" ]] && {
      print_warning "/etc/shadow has incorrect group ownership"
   }
   [[ "${GROUP_PERMS}" != "0644" ]] && {
      print_warning "/etc/group has incorrect permissions"
   }
   [[ "${GROUP_OWNER}" != "root" ]] && {
      print_warning "/etc/group has incorrect ownership"
   }
   [[ "${GROUP_GROUP}" != "root" ]] && {
      print_warning "/etc/group has incorrect group ownership"
   }
}

# Function:	check_crontab_permissions()
# Arguments:	None
# Returns:	Nothing
# Description:  Check that all crontab files are heavily locked down

check_crontab_permissions() {
   ETC_CRONTAB_PERMS=`stat /etc/crontab | grep '^Access: (' | sed -n 's/^Access: (\([0-7][0-7]*\)\/.*$/\1/p'`
   ETC_CRONTAB_OWNER=`ls -ld /etc/crontab | awk '{print $3}'`
   ETC_CRONTAB_GROUP=`ls -ld /etc/crontab | awk '{print $4}'`
   [[ "${ETC_CRONTAB_PERMS}" != "0400" ]] && {
      print_warning "/etc/crontab has incorrect permissions"
   }
   [[ "${ETC_CRONTAB_OWNER}" != "root" ]] && {
      print_warning "/etc/crontab has incorrect ownership"
   }
   [[ "${ETC_CRONTAB_GROUP}" != "root" ]] && {
      print_warning "/etc/crontab has incorrect group ownership"
   }
   CRONTAB_DIR_PERMS=`stat /var/spool/cron | grep '^Access: (' | sed -n 's/^Access: (\([0-7][0-7]*\)\/.*$/\1/p'`
   CRONTAB_DIR_OWNER=`ls -ld /var/spool/cron | awk '{print $3}'`
   CRONTAB_DIR_GROUP=`ls -ld /var/spool/cron | awk '{print $4}'`
   [[ "${CRONTAB_DIR_PERMS}" != "0400" ]] && {
      print_warning "/var/spool/cron has incorrect permissions"
   }
   [[ "${CRONTAB_DIR_OWNER}" != "root" ]] && {
      print_warning "/var/spool/cron has incorrect ownership"
   }
   [[ "${CRONTAB_DIR_GROUP}" != "root" ]] && {
      print_warning "/var/spool/cron has incorrect group ownership"
   }
   for CRONTAB in /var/spool/cron/*; do
      CRONTAB_PERMS=`stat ${CRONTAB} | grep '^Access: (' | sed -n 's/^Access: (\([0-7][0-7]*\)\/.*$/\1/p'`
      CRONTAB_OWNER=`ls -ld ${CRONTAB} | awk '{print $3}'`
      CRONTAB_GROUP=`ls -ld ${CRONTAB} | awk '{print $4}'`
      [[ "${CRONTAB_PERMS}" != "0400" ]] && {
         print_warning "${CRONTAB} has incorrect permissions"
      }
      [[ "${CRONTAB_OWNER}" != "root" ]] && {
         print_warning "${CRONTAB} has incorrect ownership"
      }
      [[ "${CRONTAB_GROUP}" != "root" ]] && {
         print_warning "${CRONTAB} has incorrect group ownership"
      }
   done
}

# Function:	check_ftpusers()
# Arguments:	None
# Returns:	Nothing
# Description:  Ensure that FTP access is locked down

check_ftpusers() {
   for FTPFILE in /etc/ftpusers /etc/vsftpd.users; do
      [[ -e "${FTPFILE}" ]] && {
         diff <(sort ${FTPFILE}) <(cut -d: -f1 /etc/passwd | sort) >/dev/null 2>&1
         [[ "$?" -ne "0" ]] && {
            print_warning "${FTPFILE} not in sync with system accounts"
         } || :
      } || {
         print_warning "${FTPFILE} does not exist"
      }
   done
}

# Function:	check_xserver()
# Arguments:	None
# Returns:	Nothing
# Description:  If X is installed, ensure it is not listening for tcp connections

check_xserver() {
   for XFILE in /etc/X11/xdm/Xservers /etc/X11/gdm/gdm.conf /etc/X11/xinit/xserverrc; do
      [[ -e "${XFILE}" ]] && {
         print_warning "${XFILE} exists - X servers are NOT permitted"
         grep '^[^#]*-nolisten tcp' ${XFILE} >/dev/null 2>&1
         [[ "$?" -ne "0" ]] && {
            print_warning "${XFILE} does not contain -nolisten tcp"
         } || :
      } || :
   done 
}

# Function:	check_core_dumps()
# Arguments:	None
# Returns:	Nothing
# Description:  Ensure that core dumping is disabled

check_core_dumps() {
   [[ -e "/etc/security/limits.conf" ]] && {
      grep '^.*\*.*soft.*core.*0' /etc/security/limits.conf >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "soft core limit not set in /etc/security/limits.conf"
      } || :
      grep '^.*\*.*hard.*core.*0' /etc/security/limits.conf >/dev/null 2>&1
      [[ "$?" -ne "0" ]] && {
         print_warning "hard core limit not set in /etc/security/limits.conf"
      } || :
   } || {
      print_warning "/etc/security/limits.conf does NOT exist"
   }
}

# Function:	check_pam_other()
# Arguments:	None
# Returns:	Nothing
# Description:  Check that /etc/pam.d/other contains required lockdown

check_pam_other() {
   [[ -e "/etc/pam.d/other" ]] && {
      # Very rough check... assumes a lot
      LINECOUNT=`grep '^[^#]' /etc/pam.d/other | grep -v '^[ 	]$' | wc -l`
      [[ "${LINECOUNT}" -ne "8" ]] && {
         print_warning "/etc/pam.d/other does not have the eight required rules"
      } || : 
   } || {
     print_warning "/etc/pam.d/other does not exist"
   }
}

# Function:	check_ctrl_alt_del()
# Arguments:	None
# Returns:	Nothing
# Description:  Check that CTRL-ALT-DEL sequence won't reboot our server!

check_ctrl_alt_del() {
   grep '^ca::ctrlaltdel.*$' /etc/inittab >/dev/null 2>&1
   [[ "$?" -eq "0" ]] && {
      print_warning "CTRL-ALT-DEL sequence still enabled in /etc/inittab"
   }
}

# Function:	check_sulogin()
# Arguments:	None
# Returns:	Nothing
# Description:  Make sure that single user login will require a password

check_sulogin() {
   grep '^~~:S:wait:/sbin/sulogin$' /etc/inittab >/dev/null 2>&1
   [[ "$?" -ne "0" ]] && {
      print_warning "sulogin not configured in /etc/inittab"
   }
}

# main()
check_os
check_root
check_fstab
check_required_software
display_messages
display_services
check_system_accounts
check_syslog_conf
check_sysctl_conf
check_sendmail
check_sshd_config
check_su
check_symlinks
check_stack_protection
check_umask
check_mesg
check_system_auth
check_securetty
check_cron_access
check_rhosts_pam
check_passwd_files
check_ftpusers
check_xserver
check_core_dumps
check_pam_other
check_ctrl_alt_del
check_sulogin

cleanup

# ToDo:
#  -  setuid/setgid/world-writable files
#  -  check home directory permissions

exit 0