#!/bin/bash

###############################################################################
#### Hardening Script for RHEL, CentOS, Rocky, Alma, Oracle and Ubuntu.   ####
#### Author: Phil Connor 02/10/2020                                        ####
#### Contact: contact@mylinux.work                                         ####
#### Version 4.00.03.06.26                                                 ####
####                                                                       ####
#### Supported: RHEL 7/8/9, CentOS 7, Rocky 8/9, Alma 8/9,               ####
####            Oracle Linux 7/8, Ubuntu 20.04/22.04/24.04                 ####
####                                                                       ####
#### To Use chmod to 755 or simply type bash <SecureIt.sh>                 ####  
###############################################################################

clear
export TERM=xterm-256color

############################
#### User Configuration ####
############################
RSWP=8 # <-- Set the required swap size
TCPPORTS=( 22 53 1521 5666 7001 7002 8000 9090 10000 ) # <-- Firwall ports that you need open, don't remove 22 unless you will only contecting with a console
TCP6PORTS=( 22 ) # <-- IPv6 is disabled but Nessus scans requires it configured
UDPPORTS=( 53 ) # <-- Gotta have DNS
UDP6PORTS=( 53 ) # <-- Gotta have DNS

##########################
#### System Variables ####
##########################
BACKUP="/root/config_Backups"
BOOTLD="/boot/grub2/user.cfg"
BOOTLDCE="/boot/efi/EFI/centos/"
BOOTLDRH="/boot/efi/EFI/redhat/"
BOOTLDUB="/boot/grub/user.cfg"
CRON_RH="/var/spool/cron/root"
CRON_UB="/var/spool/cron/crontab/root"
FIREIP=""
IPTBL="/etc/sysconfig/iptables"
IP6TBL="/etc/sysconfig/ip6tables"
IPTBLUB="/etc/iptables/rules.v4"
IP6TBLUB="/etc/iptables/rules.v6"
GRUBCFG="/boot/grub2/grub.cfg"
GRUBCFGCE="/boot/efi/EFI/centos/grub.cfg"
GRUBCFGRH="/boot/efi/EFI/redhat/grub.cfg"
GRUBCFGUB="/boot/grub/grub.cfg"
HOSTNAME=$(uname -n)
LOG=${BACKUP}/install.log
MODPRO="/etc/modprobe.d/cis.conf"
MYIP=$(ss -tnp 2>/dev/null | awk '/:22 / && /ESTAB/ {split($5,result,":"); print result[1]}' | head -1)
OS=$(. /etc/os-release && echo "${ID}")
OSVER=$(. /etc/os-release && echo "${VERSION_ID%%.*}")
SSHD_FILE='/etc/ssh/sshd_config'
TMPMNT="/usr/lib/systemd/system"

########################
#### Menu Variables ####
########################
H1=20
R1=3
R2=6
R3=11
W1=80

###########################################################
#### Detect Package Manger from OS and OSVer Variables ####
########################################################### 
if [[ ${OS} = ubuntu || ${OS} = debian ]]; then
	PAKMGR="apt-get -y"
elif [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux || ${OS} = fedora ]]; then
	if [ "${OSVER}" = 7 ]; then
		PAKMGR="yum -y"
	fi
	if [ "${OSVER}" = 8 ] || [ "${OSVER}" = 9 ]; then
		PAKMGR="dnf -y"
	fi
fi

##############################################
#### Check to see if running as Root User ####
##############################################
function check_root() {
	{
		if [ $EUID -ne 0 ]; then
			echo ""
			echo "Script Installation has been Halted!"
			echo ""
			echo "You Must Run This Script as the \"ROOT\" User"
			exit
		fi
	}
}

#################################
#### Config backup directory ####
#################################
function backup() {
	{
		for dir in ${BACKUP}; do
		[[ ! -d "$dir" ]] && mkdir "$dir"
		touch ${BACKUP}/install.log
		done
	}
}

#######################
#### Copy Function ####
#######################
function no_show() {
	{
		expand | awk 'NR == 1 {match($0, /^ */); l = RLENGTH + 1}
			{print substr($0, l)}'
	}
}

##########################
#### Spinner Function ####
##########################
function _spinner() {
    {
		local on_success="COMPLETE"
		local on_fail="ERROR"
		local green="\e[1;32m"
		local red="\e[1;31m"
		local nc="\e[0m"
		case $1 in
			start)
				((column=$(tput cols)-${#2}-8)) 
				echo -ne "\e[7m ${2} \e[0m \n"
				printf "%${column}s"
				i=1
				sp='/-\|/-\:'
				delay=${SPINNER_DELAY:-0.15}
				while :
				do
					printf "\b%s${sp:i++%${#sp}:1}"
					sleep "$delay"
				done
				;;
			stop)
				if [[ -z ${3} ]]; then
					echo "spinner is not running.."
					exit 1
				fi
				kill "$3" > /dev/null 2>&1
				echo -en "\b["
				if [[ $2 -eq 0 ]]; then
					echo -en "${green}${on_success}${nc}"
				else
					echo -en "${red}${on_fail}${nc}"
				fi
				echo -e "]"
				;;
			*)
				echo "invalid argument, try {start/stop}"
				exit 1
				;;
		esac
	}
}

#######################
#### Spinner Start ####
#######################
function start_spinner {
	{
		echo ""
		_spinner "start" "${1}" &
		_sp_pid=$!
		echo ""
		disown
	}
}

######################
#### Spinner Stop ####
######################
function stop_spinner {
	{
		echo ""
		_spinner "stop" "$1" $_sp_pid
		unset _sp_pid
		echo ""
	}
}

#########################
#### Warning Message ####
#########################
function warn_message() {
	{
		whiptail --backtitle "SecureIt contact@mylinux.work" --title "*** WARNING ***" --yes-button "CONFIRM" --no-button "Exit" --defaultno --yesno "   Running this script will harden this server to CIS Benchmark settings.
		It will change server configuration and will affect server operation


			ONLY RUN THIS SCRIPT IF YOU KNOW WHAT YOU ARE DOING!

			
							You must select CONFIRM to continue." ${H1} ${W1}
			exitstatus=$?
		if [ ${exitstatus} = 0 ]; then
			private_ip
		else
			exit
		fi
	}

}

#############################
#### Get VLAN IP address ####
#############################
function private_ip() {
	{
		VLANIP=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Server Connect IP" --ok-button "Continue" --cancel-button "Exit" --inputbox "     What is the IP/Sub or VLAN/Sub you use to connect to this server?
				
										Examples are 192.168.0.0/24
											or   192.168.1.21/32
											or   10.0.10.0/16

	Your current SSH Connection IP is Shown and can be changed if required" ${H1} ${W1} "${MYIP}"/32 3>&1 1>&2 2>&3) 
			exitstatus=$?
		if [ ${exitstatus} = 0 ]; then
			FIREIP="${VLANIP//[[:space:]]/}"
			time_zone
		else
			exit
		fi
	}
}

######################
#### Get TimeZone ####
######################
function time_zone() {
	{
		# shellcheck disable=SC2046	
		TIMEZONE=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Server TimeZone" --ok-button "Continue" --cancel-button "Exit" --menu "                      What is your Server Timezone?

													Example Central" ${H1} ${W1} ${R3} $(find /usr/share/zoneinfo/US/* | cut -d '/' -f 6 | sort | sed "s/$/ ./" | tr '\n' ' ';)  3>&1 1>&2 2>&3)
			exitstatus=$?
		if [ ${exitstatus} = 0 ]; then
			max_count
		else
			exit
		fi
	}
}

##################################
#### Get Auto Disconnect Time ####
##################################
function max_count() {
	{
		MAXCOUNT=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Server Disconnect" --ok-button "Continue" --cancel-button "Exit" --radiolist "             What is the MAX time you want before auto disconnect?" ${H1} ${W1} ${R1} \
						"1" "5 mins"  OFF \
						"2" "10 mins" OFF \
						"3" "15 mins" ON  3>&1 1>&2 2>&3)
		exitstatus=$?
		if [ ${exitstatus} = 0 ]; then
				max_logs
		else
				exit
		fi
	}
}

################################
#### Get Audit logs Setting ####
################################
function max_logs() {
	{
		MAXLOGS=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Audit Logs" --ok-button "Continue" --cancel-button "Exit" --inputbox "        If you plan on archiving the audit logs leave \"ignore\" here
						If you have tons of room change this to \"KEEP_LOGS\"" ${H1} ${W1} ignore  3>&1 1>&2 2>&3)
			exitstatus=$?
		if [ ${exitstatus} = 0 ]; then
			syslog_server
		else
			exit
		fi
	}
}

###########################
#### Get Syslog Server ####
###########################
function syslog_server() {
	{
		SYSLOG=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "SysLog Server" --ok-button "Continue" --cancel-button "Exit" --inputbox "               What is the Name or IP of your SysLog Server?" ${H1} ${W1}  3>&1 1>&2 2>&3)
			exitstatus=$?
		if [ ${exitstatus} = 0 ]; then
			srv_type
		else
			exit
		fi
	}
}

##########################
#### Get Server Usage ####
##########################
function srv_type() {
	{
		SRVTYPE=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Server Disconnect" --ok-button "Continue" --cancel-button "Exit" --radiolist "             What is the use or purpose of this server?" ${H1} ${W1} ${R1} \
						"1" "EBS Server"  OFF      \
						"2" "Weblogic Server" OFF \
						"3" "Regular Server" ON  3>&1 1>&2 2>&3)
		exitstatus=$?
		if [ ${exitstatus} = 0 ]; then
			grub_password
		else
				exit
		fi
	}
}

#########################
#### Get Grub Passwd ####
#########################
function grub_password() {
	{
		GPASS=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Grub Password" --ok-button "Continue" --cancel-button "Exit" --inputbox "                  What do you want your Grub Password to be?" ${H1} ${W1} 3>&1 1>&2 2>&3)
			exitstatus=$?
		if [ ${exitstatus} = 0 ]; then
			if [ "${OS}" = ubuntu ]; then
				G2PASSWD="$(echo -e "${GPASS}\n$GPASS" | grub-mkpasswd-pbkdf2 2>/dev/null | tail --lines=1 | awk -F " " '{print $7}')"
				main_menu
			else
				G2PASSWD="$(echo -e "${GPASS}\n$GPASS" | grub2-mkpasswd-pbkdf2 2>/dev/null | tail --lines=1 | awk -F " " '{print $7}')"
				main_menu
			fi
		else
			exit
		fi
	}
}

#############################
#### OS Select Main Menu ####
#############################
function main_menu() {
	{
		while true; do
			CHOICE=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "OS Select Main" --ok-button "Continue" --cancel-button "Exit" --menu "                     Please Select Your Linux Distro" ${H1} ${W1} ${R2} \
				"1)" "Oracle Linux"                 \
				"2)" "RedHat/CentOS/Rocky/Alma"     \
				"3)" "Ubuntu"                       3>&2 2>&1 1>&3)
		exitstatus=$?
		if [ ${exitstatus} = 0 ]; then
			case ${CHOICE} in
			"1)")
				oracle_menu
			;;

			"2)")
				redhat_menu
			;;

			"3)")
				ubuntu_menu
			;;

			"4)")
				
			;;

			esac
		else
			exit
		fi
		done
	}
}

#####################
#### Oracle Menu ####
#####################
function oracle_menu() {
	{
		while true; do
			CHOICE=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Oracle Linux" --ok-button "Install" --cancel-button "Exit" --menu "                     Please Select Your Oracle Version" ${H1} ${W1} ${R2} \
				"1)" "OCI Oracle Linux 7"    \
				"2)" "OCI Oracle Linux 8"    \
				"3)" "Oracle Linux 7"        \
				"4)" "Oracle Linux 8"        3>&2 2>&1 1>&3)
		exitstatus=$?
		if [ ${exitstatus} = 0 ]; then
			case ${CHOICE} in
			"1)")
				oci_oracle_ebs_setup
				oci_rh_ub_common
				oci_only
				complete
			;;

			"2)")
				oci_oracle_ebs_setup
				oci_rh_ub_common
				oci_only
				complete
			;;

			"3)")
				oci_rh_ub_common
				complete
			;;

			"4)")
				oci_rh_ub_common
				complete
			;;

			esac
		else
			exit
		fi
		done
	}
}

#####################
#### Redhat Menu ####
#####################
function redhat_menu() {
	{
		while true; do
			CHOICE=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Redhat/Centos Linux" --ok-button "Install" --cancel-button "Exit" --menu "                 Please Select Your Redhat/CentOS Version" ${H1} ${W1} ${R2} \
				"1)" "OCI CentOS 7"               \
				"2)" "OCI CentOS 8"               \
				"3)" "AWS Redhat/Centos 7"        \
				"4)" "AWS Redhat/Centos 8"        \
				"5)" "Redhat/CentOS/Rocky/Alma 7" \
				"6)" "Redhat/CentOS/Rocky/Alma 8" \
				"7)" "Redhat/Centos/Rocky/Alma 9" 3>&2 2>&1 1>&3)
		exitstatus=$?
		if [ ${exitstatus} = 0 ]; then
			case ${CHOICE} in
			"1)")
				oci_rh_ub_common
				oci_only
				complete
			;;

			"2)")
				oci_rh_ub_common
				oci_only
				complete
			;;

			"3)")
				oci_rh_ub_common
				aws_only
				complete
			;;

			"4)")
				oci_rh_ub_common
				aws_only
				complete
			;;

			"5)")
				oci_rh_ub_common
				complete
			;;

			"6)")
				oci_rh_ub_common
				complete
			;;

			"7)")
				oci_rh_ub_common
				complete
			;;

			esac
		else
			exit
		fi
		done
	}
}

#####################
#### Ubuntu Menu ####
#####################
function ubuntu_menu() {
        {
			while true; do
					CHOICE=$(whiptail --backtitle "SecureIt contact@mylinux.work" --title "Ubuntu Linux" --ok-button "Install" --cancel-button "Exit" --menu "                     Please Select Your Ubuntu Version" ${H1} ${W1} ${R2} \
							"1)" "OCI Ubuntu"   \
							"2)" "AWS Ubuntu"   \
							"3)" "Ubuntu"       3>&2 2>&1 1>&3)
			exitstatus=$?
			if [ ${exitstatus} = 0 ]; then
					case ${CHOICE} in
					"1)")
							oci_rh_ub_common
							oci_only
							complete
					;;

					"2)")
							oci_rh_ub_common
							aws_only
							complete
					;;

					"3)")
							oci_rh_ub_common
							complete
					;;

					esac
			else
					exit
			fi
			done
        }
}

##########################
#### Install Complete ####
##########################
function complete() {
	{
		whiptail --backtitle "SecureIt contact@mylinux.work" --title "Configuration Complete" --msgbox "              This script has configured and hardened this server to
		
						CIS Level 1 Benchmark settings.
							
			It is recommended that you try to ssh to the sever as any user
		or root to make sure you can connect and once you know all is working
			properly the system should be rebooted.

			
								Please select \"OK\" to EXIT." ${H1} ${W1} 3>&1 1>&2 2>&3
			exitstatus=$?
		if [ ${exitstatus} = 0 ]; then
			exit
		fi
	}	
}
					#####################################################################
					### The following is in line with the CIS BenchMark Manual v3.0.0 ###
					#####################################################################

#############################
#### Make Swap if Needed ####
#############################
function make_swap() {
	{
		start_spinner 'Configuring Additional Swap Space...'
		echo ""
		if [ "${SRVTYPE}" -ne 3 ]; then
			# size of swapfile in gigabytes
			swpsize="$RSWP"
			# how large the swap needs to be total in mb's
			swpneed=$((swpsize * 1024))
			# / part dir file list
			dir=$(ls -la --block-size=M /)
			# does the swap file already exist?
			swpexist=$(echo "$dir" | grep -i swap | awk '{ print $5 }' | tr -d 'M"')
			# what is the name of the swap file if it exist 
			swpname=$(echo "$dir" | grep -i swap | awk '{ print $9 }')
			# Is there any swap present if yes what size is it
			swppres=$(free -m | sed -n '3 p' | awk '{ print $2 }')
			# If the swap file already exist is it large enough?
			if (( swpneed < swpexist )) || (( swpneed < swppres )); then
				echo -e '\e[01;37m ======================================================================='
				echo -e '\e[01;32m  ====================================================================='
				echo -e '\e[01;32m   ==== \e[01;37m A Large Enough Swapfile was Found! No Changes Needed... \e[01;32m ===='
				echo -e '\e[01;32m  ====================================================================='
				echo -e '\e[01;37m ======================================================================='
			elif (( swpneed > swpexist )) || (( swpneed > swppres )); then
				echo -e '\e[01;37m =================================================================================='
				echo -e '\e[01;31m  ================================================================================'
				echo -e '\e[01;31m   ==== \e[01;37m A Large Enough Swapfile was not found! Creating Larger SwapFile... \e[01;31m ===='
				echo -e '\e[01;31m  ================================================================================'
				echo -e '\e[01;37m =================================================================================='
				# Turn off existing swap if needing replacement 
				if echo "$dir" | grep -i swap; then
					swapoff /"${swpname}"
					rm -f /"$swpname"
				fi
			# Create the swapfile and make it active
				fallocate -l ${swpsize}g /.SwapFile
				chmod 600 /.SwapFile
				mkswap /.SwapFile
				swapon /.SwapFile
				echo -e '\e[01;37m =============================================================================='
				echo -e '\e[01;32m  ============================================================================'
				echo -e '\e[01;32m   ==== \e[01;37m Checking whether the swap space was mounted and active or not! \e[01;32m ===='
				echo -e '\e[01;32m  ============================================================================'
				echo -e '\e[01;37m =============================================================================='
				R=$(swapon -s)
				if [ -n "$R" ]; then
					echo -e '\e[01;32m                                ============'
					echo -e '\e[01;32m                                ============'
					echo -e '\e[01;32m  ============================================================================'
					echo -e "\e[01;37m$R"
					echo -e '\e[01;32m  ============================================================================'
					echo -e '\e[01;37m =============================================================================='
				else
					echo -e '\e[01;31m                                ============'
					echo -e '\e[01;31m                                ============'
					echo -e '\e[01;31m  ============================================================================'
					echo -e "\e[01;37m                  Something Went Wrong no Swap was Loaded"
					echo -e '\e[01;31m  ============================================================================'
					echo -e '\e[01;37m =============================================================================='
				fi
				# Check to see if the created swap is losted in the fstab file
				if ! grep -q "SwapFile" /etc/fstab; then
					echo "/.SwapFile               swap                                      swap    defaults                        0 0" >> /etc/fstab
				fi
			fi
		fi
		stop_spinner $?
	} | tee -a $LOG
}

############################
#### Set Sever TimeZone ####
############################
function time_set() {
	{
		start_spinner 'Setting System TimeZone...'
		echo ""
		timedatectl set-timezone US/"${TIMEZONE}"
		stop_spinner $?
	} | tee -a $LOG
}

########################################
### 1.1.1 Disable Unused Filesystems ###
########################################
function disable_filesystems() {
	{
		start_spinner 'Disabling Unused Filesystems...'
		echo ""
		touch ${MODPRO}
		#### 1.1.1.1 Ensure mounting of cramfs is disabled ####
		echo "install cramfs /bin/true" > ${MODPRO}
		lsmod | grep -qi cramfs
		if [ $? != 1  ]; then
			rmmod cramfs
		fi
		#### 1.1.1.2 Ensure mounting of freevxf filesystem 1s disabled ####
		echo "install freevxfs /bin/true" >> ${MODPRO}
		lsmod | grep -qi freevxfs
		if [ $? != 1  ]; then
			rmmod freevxfs
		fi
		#### 1.1.1.3 Ensure mounting of jiffs2 filesystem is disabled ####
		echo "install jffs2 /bin/true" >> ${MODPRO}
		lsmod | grep -qi jffs2
		if [ $? != 1  ]; then
			rmmod jffs2
		fi
		#### 1.1.1.4 Ensure mounting of hfs filesystem is disabled ####
		echo "install hfs /bin/true" >> ${MODPRO}
		lsmod | grep -qi hfs
		if [ $? != 1  ]; then
			rmmod hfs
		fi
		#### 1.1.1.5 Ensure mounting of hfsplus filesystem is disabled ####
		echo "install hfsplus /bin/true" >> ${MODPRO}
		lsmod | grep -qi hfsplus
		if [ $? != 1  ]; then	
			rmmod hfsplus
		fi
		#### 1.1.1.6 Ensure mounting of squashfs filesystem is disabled ####
		echo "install squashfs /bin/true" >> ${MODPRO}
		lsmod | grep -qi squashfs
		if [ $? != 1  ]; then	
			rmmod squashfs
		fi
		#### 1.1.1.7 Ensure mounting of udf filesystem is disabled ####
		echo "install udf /bin/true" >> ${MODPRO}
		lsmod | grep -qi udf
		if [ $? != 1  ]; then
			rmmod udf
		fi
		#### 1.1.1.8 Ensure mounting of FAT filesystem is disabled #### 
		echo "install fat /bin/true" >> ${MODPRO}
		lsmod | grep -qi fat 
		if [ $? != 1  ]; then	
			rmmod fat
		fi
		#####################################
		#### Additonal Unsed Filesystems ####
		#####################################
		echo "install cifs /bin/true" >> ${MODPRO}
		lsmod | grep -qi cifs
		if [ $? != 1  ]; then	
			rmmod cifs
		fi
		echo "install nfs /bin/true" >> ${MODPRO}
		lsmod | grep -qi nfs
		if [ $? != 1  ]; then	
			rmmod nfs
		fi
		echo "install nfsv3 /bin/true" >> ${MODPRO}
		lsmod | grep -qi nfsv3
		if [ $? != 1  ]; then	
			rmmod nfsv3
		fi
		echo "install nfsv4 /bin/true" >> ${MODPRO}
		lsmod | grep -qi nfsv4
		if [ $? != 1  ]; then	
			rmmod nfsv4
		fi
		echo "install gfs2 /bin/true" >> ${MODPRO}
		lsmod | grep -qi gfs2
		if [ $? != 1  ]; then	
			rmmod gfs2
		fi
		echo "install usb-storage /bin/true" >> ${MODPRO}
		lsmod | grep -qi usb-storage
		if [ $? != 1  ]; then	
			rmmod usb-storage
		fi
		echo "install bnep /bin/true" >> ${MODPRO}
		lsmod | grep -qi bnep
		if [ $? != 1  ]; then	
			rmmod bnep
		fi
		echo "install bluetooth /bin/true" >> ${MODPRO}
		lsmod | grep -qi bluetooth
		if [ $? != 1  ]; then	
			rmmod bluetooth
		fi
		echo "install btusb /bin/true" >> ${MODPRO}
		lsmod | grep -qi btusb
		if [ $? != 1  ]; then	
			rmmod btusb
		fi
		echo "install net-pf-31 /bin/true" >> ${MODPRO}
		lsmod | grep -qi  net-pf-31
		if [ $? != 1  ]; then	
			rmmod net-pf-31
		fi
		echo "install appletalk /bin/true" >> ${MODPRO}
		lsmod | grep -qi appletalk
		if [ $? != 1  ]; then	
			rmmod appletalk
		fi
		{
		echo "blacklist  usb-storage" 
		echo "blacklist firewire-core"
		echo "options ipv6 disable=1" 
		} >> ${MODPRO}
		stop_spinner $?
	} | tee -a $LOG
}

######################################################
#### 1.1.2 Ensure seprate partion exists for /tmp ####
######################################################
function tmp_directory() {
	{
		start_spinner 'Ensuring a Seprate Partion Exists for /tmp...'
		echo ""
		#### Copy Conf Files for Backup #### 
		xargs -n 1 cp -v /etc/fstab <<< ""${BACKUP} /etc/fstab.bak""
		#### Check to see if /tmp is a mount ####
		if mount | grep -q /tmp; then
			umount /tmp
		fi
		#### /tmp Mount Changes Ubuntu ####
		if [ "${OS}" = ubuntu ]; then
			xargs -n 1 cp -v /usr/share/systemd/tmp.mount <<< ""${BACKUP} /usr/share/systemd/tmp.mount.bak""
			if grep -q nosuid /usr/share/systemd/tmp.mount; then
				sed -i 's/Options=mode=1777,strictatime,nosuid,nodev/Options=mode=1777,strictatime,nosuid,nodev,noexec/g' /usr/share/systemd/tmp.mount
			else
				sed -i 's/Options=mode=1777,strictatime/Options=mode=1777,strictatime,nosuid,nodev,noexec/g' /usr/share/systemd/tmp.mount
			fi
		#### /tmp Mount Changes RedHat ####
		elif [ "${OS}" = ol ]; then 
			xargs -n 1 cp -v /usr/lib/systemd/system/tmp.mount <<< ""${BACKUP} /usr/lib/systemd/system/tmp.mount.bak""
			if [ "${OSVER}" = 7 ]; then
				sed -i 's/Options=mode=1777,strictatime/Options=mode=1777,strictatime,nosuid,nodev,noexec/g' $TMPMNT/tmp.mount	
			fi
			if [ "${OSVER}" = 8 ] || [ "${OSVER}" = 9 ]; then
				sed -i 's/Options=mode=1777,strictatime,nosuid,nodev/Options=mode=1777,strictatime,nosuid,nodev,noexec/g' $TMPMNT/tmp.mount
			fi
		elif [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
				if [ "${OSVER}" = 7 ]; then
					sed -i 's/Options=mode=1777,strictatime/Options=mode=1777,strictatime,nosuid,nodev,noexec/g' $TMPMNT/tmp.mount
				fi
				if [ "${OSVER}" = 8 ]; then
					sed -i 's/Options=mode=1777,strictatime,nosuid,nodev/Options=mode=1777,strictatime,nosuid,nodev,noexec/g' $TMPMNT/tmp.mount
				fi
				if [ "${OSVER}" = 9 ]; then
					sed -i 's/Options=mode=1777,strictatime,nosuid,nodev,size=50%,nr_inodes=1m/Options=mode=1777,strictatime,nosuid,nodev,noexec,size=50%,nr_inodes=1m/g' $TMPMNT/tmp.mount
				fi
		else
			xargs -n 1 cp -v /etc/systemd/system/local-fs.target.wants/tmp.mount <<< ""${BACKUP} /etc/systemd/system/local-fs.target.wants/tmp.mount.bak""
			no_show << 	EOF > /etc/systemd/system/local-fs.target.wants/tmp.mount
			[Mount]
			What=tmpfs
			Where=/tmp
			Type=tmpfs
			Options=mode=1777,strictatime,noexec,nodev,nosuid
EOF
		fi
		#### Setting /tmp to persist thru reboots ####
		if ! grep -w /tmp /etc/fstab; then 
				echo "tmpfs                   /tmp                                      tmpfs   defaults,nodev,nosuid,noexec     0 0" >> /etc/fstab
		fi
		mount /tmp
		#### 1.1.3, 1.1.4 & 1.1.5 Ensure noexec, nosuid and nodev option set on /tmp partition ####
		#### mount -o remount,noexec,nosuid,nodev /tmp
		#### Setting /var/tmp to persist thru reboots ####
		if ! grep -w /var/tmp /etc/fstab; then
			echo "/tmp                    /var/tmp                                   none    rw,noexec,nosuid,nodev,bind     0 0" >> /etc/fstab
		fi
		#### Binding mount /var/tmp directory to /tmp ####
		mount -o rw,noexec,nosuid,nodev,bind /tmp/ /var/tmp/
		#### 1.1.8, 1.1.9 & 1.1.10 Ensure noexec, nosuid and nodev option set on /var/tmp partition ####
		mount -o remount,noexec,nosuid,nodev /var/tmp
		#### Setting /dev/shm to persist thru reboots ####
		if [ "${SRVTYPE}" -ne 2 ]; then
			if ! grep -w /dev/shm /etc/fstab; then
				echo "tmpfs                   /dev/shm                                  tmpfs   defaults,nodev,nosuid,noexec,relatime     0 0" >> /etc/fstab
				#### 1.1.15, 1.1.16 and 1.1.17	Ensure noexec, nosuid and nodev option set on /dev/shm partition ####
				mount -o remount,noexec,nosuid,nodev,relatime /dev/shm
			fi
		fi
		#### Ensure noexec and nodev option set on /dev partition ####
		mount -o remount,noexec /dev
		#### Setting /dev to persist thru reboots ####
		if ! grep -w devtmpfs /etc/fstab; then
			echo "devtmpfs                /dev                                   devtmpfs    defaults,noexec                 0 0" >> /etc/fstab
		fi
		stop_spinner $?
	} | tee -a $LOG
}

#############################################################################
#### 1.1.21 Ensure Sticky Bit is set on "All" World-Writable Directories ####
#############################################################################
function stickybit() {
	{
		start_spinner 'Setting Sticky Bit on "All" World-Writable Directories...'
		echo ""
		df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type d -perm -0002 2>/dev/null | xargs chmod a+t
		stop_spinner $?
	} | tee -a $LOG
}

##############################################
#### 1.2.2 Ensure GPG Keys are Configured ####
##############################################
function gpgkeys() {
	{
		start_spinner 'Checking GPG Keys are Configured...'
		echo ""
		if [ "${OS}" = ubuntu ]; then
			apt-cache policy
			${PAKMGR} update 2>&1 1>/dev/null | sed -ne 's/.*NO_PUBKEY //p' |
			while read -r key; do
				echo 'Processing key:' "$key"
				apt-key adv --keyserver keyserver.ubuntu.com --recv-keys "$key"
			done
			apt-key adv --refresh-keys --keyserver keyserver.ubuntu.com
			apt-key list	
		else
			rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY*
			rpm -q gpg-pubkey --qf '%{name}-%{version}-%{release} --> %{summary}\n' 
			grep ^gpgcheck /etc/yum.repos.d/* >> ${LOG} 2>&1
			### 1.2.3 Verify that gpgcheck is Globally Activated ###
			grep -Eq "^(\s*)gpgcheck\s*=\s*\S+(\s*#.*)?\s*$" /etc/yum.conf && sed -ri "s/^(\s*)gpgcheck\s*=\s*\S+(\s*#.*)?\s*$/\1gpgcheck=1\2/" /etc/yum.conf || echo "gpgcheck=1" >> /etc/yum.conf
		fi
		stop_spinner $?
	} | tee -a $LOG
}

########################################
#### 1.3.1 Ensure Aide is Installed ####
########################################
function aide_install() {
	{
		start_spinner 'Installing and Configuring AIDE...'
		echo ""
		if [ "${OS}" = ubuntu ]; then
			debconf-set-selections <<< ""postfix postfix/mailname string "${HOSTNAME}"""
			debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'"
			${PAKMGR} install aide aide-common --assume-yes
			aideinit
			update-aide.conf
			if [ ! -f ${CRON_UB} ]; then
				touch ${CRON_UB}
				crontab ${CRON_UB}
			fi
			if ! grep -qi "aide" ${CRON_UB}; then
				echo "0 5 * * * /usr/bin/aide.wrapper --check" >> ${CRON_UB}
			fi
		else
			${PAKMGR} install aide 
			aide --init
			mv -f /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
			if [ ! -f ${CRON_RH} ]; then
				touch ${CRON_RH}
				crontab ${CRON_RH}
			fi
			if ! grep -qi "aide" ${CRON_RH}; then
				echo "0 5 * * * /usr/sbin/aide --check" >> ${CRON_RH}
			fi
		fi
		stop_spinner $?
	} | tee -a $LOG
}

###########################
#### 1.3 Sudo Commands ####
###########################
function sudo_changes() {
	{
		start_spinner 'Configuring Sudo Settings...'
		echo ""
		if [ ! -f /etc/sudoers.d/cis ]; then
			touch /etc/sudoers.d/cis
			chmod 440 /etc/sudoers.d/cis
		fi
		#### 1.3.2 Ensure Sudo Commands use Pty ####
		echo "Defaults use_pty" >> /etc/sudoers.d/cis
		#### 1.3.3 Ensure Sudo Log File Exists ####
		echo "Defaults logfile=\"/var/log/sudo.log\"" >> /etc/sudoers.d/cis
		stop_spinner $?
	} | tee -a $LOG
}

##################################
#### 1.4 Secure Boot Settings ####
##################################
function boot_load() {
	{
		start_spinner 'Securing Boot Settings...'
		echo ""
		#### 1.4.1 Ensure permissions on bootloader config are configured ####
		if [ "${OS}" = "ubuntu" ]; then
			touch ${BOOTLDUB}
			chmod 600 ${BOOTLDUB}
			chown root.root ${BOOTLDUB}
		else
			touch ${BOOTLD}
			chmod 600 ${BOOTLD}
			chown root.root ${BOOTLD}
		fi
		#### Config /boot/efi permissions in fstab !!! This is for OCI !!! I have not seen this on any other cloud provider ####
		mount | grep /boot/efi
		if [ $? != 1  ]; then
			umount /boot/efi
			if [ "${OS}" = ol ]; then
				if [ "${OSVER}" = 7 ]; then
					sed -i 's/defaults,uid=0,gid=0,umask=0077,shortname=winnt,_netdev,_netdev,x-initrd.mount/defaults,uid=0,gid=0,umask=0077,fmask=0177,shortname=winnt,_netdev,_netdev,x-initrd.mount/g' /etc/fstab
				elif [ "${OSVER}" = 8 ]; then
					sed -i 's/defaults,uid=0,gid=0,umask=077,shortname=winnt/defaults,uid=0,gid=0,umask=077,fmask=0177,shortname=winnt/g' /etc/fstab
				fi
			fi
			if [ "${OS}" = centos ]; then
				sed -i 's/vfat[[:blank:]]*defaults/vfat    defaults,uid=0,gid=0,umask=0077,fmask=0177/g' /etc/fstab
			fi
			mount /boot/efi
		fi
		#### 1.4.2 Ensure bootloader password is set ####
		if [ "${OS}" = centos ]; then
			echo GRUB2_PASSWORD="${G2PASSWD}" > ${BOOTLD}
			cp ${BOOTLD} ${BOOTLDCE}
		elif [ "${OS}" = ubuntu ]; then
			echo GRUB2_PASSWORD="${G2PASSWD}" > ${BOOTLDUB}
		else
			echo GRUB2_PASSWORD="${G2PASSWD}" > ${BOOTLD}
			cp ${BOOTLD} ${BOOTLDRH}
		fi
		stop_spinner $?
	} | tee -a $LOG
}

################################################
#### 1.5.1 Ensure core dumps are restricted ####
################################################
function core_dumps() {
	{
		start_spinner 'Restricting Core Dumps...'
		echo ""
		xargs -n 1 cp -v /etc/security/limits.conf <<<"${BACKUP} /etc/security/limits.conf.bak"
		echo '* hard core 0' >> /etc/security/limits.conf
		stop_spinner $?
	} | tee -a $LOG
}

###########################################################################
#### 1.5.3 Ensure address space layout randomization (ASLR) is enabled ####
###########################################################################
function sysctl_conf() {
	{
		start_spinner 'Configuring Sysctl and Tuning Kernel Parameters...'
		echo ""
		xargs -n 1 cp -v /etc/sysctl.conf <<< "${BACKUP} /etc/sysctl.conf.bak"
		no_show << "EOF" > /etc/sysctl.d/99-secureit.conf
		##################################################################################################
		####       Hardened SysCtl Configuration File edited to match CIS level 1 requirements        ####
		####       for questions or changles please contact Phil Connor contact@mylinux.work          ####
		##################################################################################################

		#### Controls the System Request debugging functionality of the kernel
		kernel.sysrq = 0

		#### Controls whether core dumps will append the PID to the core filename.
		#### Useful for debugging multi-threaded applications.
		kernel.core_uses_pid = 1

		##################################
		#### GENERAL SECURITY OPTIONS ####
		##################################

		#### Automatically Reboot Server 30 Seconds after a Kernel Panic
		vm.panic_on_oom = 1
		kernel.panic = 30
		kernel.panic_on_oops = 30

		#### Enable ExecShield
		#kernel.exec-shield = 1

		kernel.dmesg_restrict = 1
		kernel.kptr_restrict = 1
		kernel.yama.ptrace_scope = 1

		#### 1.5.3 Ensure address space layout randomization (ASLR) is enabled 
		kernel.randomize_va_space = 2

		#################################
		#### COMMUNICATIONS SECURITY ####
		#################################

		#### 3.1.1 Ensure IP forwarding is disabled
		net.ipv4.ip_forward = 0
		net.ipv4.conf.all.forwarding = 0
		net.ipv4.conf.default.forwarding = 0
		net.ipv6.conf.all.forwarding = 0
		net.ipv6.conf.default.forwarding = 0

		#### 3.1.2 Ensure packet redirect sending is disabled
		net.ipv4.conf.all.send_redirects = 0
		net.ipv4.conf.default.send_redirects = 0

		#### 3.2.1 Ensure source routed packets are not accepted
		net.ipv4.conf.all.accept_source_route = 0
		net.ipv4.conf.default.accept_source_route = 0

		#### 3.2.2 Ensure ICMP redirects are not accepted
		net.ipv4.conf.all.accept_redirects = 0
		net.ipv4.conf.default.accept_redirects = 0

		#### 3.2.3 Ensure secure ICMP redirects are not accepted
		net.ipv4.conf.all.secure_redirects = 0
		net.ipv4.conf.default.secure_redirects = 0

		#### 3.2.4 Ensure suspicious packets are logged
		net.ipv4.conf.all.log_martians = 1
		net.ipv4.conf.default.log_martians = 1

		#### 3.2.5 Ensure broadcast ICMP requests are ignored
		net.ipv4.icmp_echo_ignore_broadcasts = 1
		net.ipv4.tcp_timestamps = 0

		#### 3.2.6 Ensure bogus ICMP responses are ignored
		net.ipv4.icmp_ignore_bogus_error_responses = 1

		#### 3.2.7 Ensure Reverse Path Filtering is enabled
		net.ipv4.conf.all.rp_filter = 1
		net.ipv4.conf.default.rp_filter = 1

		#### 3.2.8 Ensure TCP SYN Cookies is enabled
		net.ipv4.tcp_syncookies = 1
		net.ipv4.tcp_syn_retries = 5
		net.ipv4.tcp_synack_retries = 2
		net.ipv4.tcp_max_syn_backlog = 4096

		#### 3.3.1 Ensure IPv6 router advertisements are not accepted
		net.ipv6.conf.all.accept_ra = 0
		net.ipv6.conf.default.accept_ra = 0

		#### 3.3.1.1 Ensure IPv6 router advertisements are not accepted
		net.ipv4.conf.all.accept_source_route=0
		net.ipv6.conf.all.accept_source_route=0
		net.ipv4.conf.default.accept_source_route=0
		net.ipv6.conf.default.accept_source_route=0

		#### 3.3.2 Ensure IPv6 redirects are not accepted
		net.ipv4.conf.all.accept_redirects = 0
		net.ipv6.conf.all.accept_redirects = 0
		net.ipv4.conf.default.accept_redirects = 0
		net.ipv6.conf.default.accept_redirects = 0

		#### 3.3.3 Ensure IPv6 is disabled
		net.ipv6.conf.all.disable_ipv6 = 1
		net.ipv6.conf.default.disable_ipv6 = 1
		net.ipv6.conf.lo.disable_ipv6 = 1

		#### Reduce KeepAlive
		net.ipv4.tcp_keepalive_time = 300
		net.ipv4.tcp_keepalive_probes = 5
		net.ipv4.tcp_keepalive_intvl = 15

		fs.suid_dumpable = 0
EOF
		#### Oracle EBS settings only applied for EBS/Weblogic servers ####
		if [ "${SRVTYPE}" != "3" ] 2>/dev/null; then
			no_show << "EOF" > /etc/sysctl.d/99-secureit-oracle.conf
			#########################
			#### Oracle Settings ####
			#########################

			# oracle-ebs-server-R12-preinstall setting for fs.file-max is 6815744
			fs.file-max = 6815744
			# oracle-ebs-server-R12-preinstall setting for kernel.sem is '256 32000 100 142'
			kernel.sem = 256 32000 100 142
			# oracle-ebs-server-R12-preinstall setting for kernel.shmmni is 4096
			kernel.shmmni=4096
			# oracle-ebs-server-R12-preinstall setting for kernel.shmall is 1073741824 on x86_64
			kernel.shmall=1073741824
			# oracle-ebs-server-R12-preinstall setting for kernel.shmmax is 4398046511104 on x86_64
			kernel.shmmax=4398046511104
			# oracle-ebs-server-R12-preinstall setting for kernel.panic_on_oops is 1
			kernel.panic_on_oops=1
			# oracle-ebs-server-R12-preinstall setting for kernel.msgmax is 8192
			kernel.msgmax = 8192
			# oracle-ebs-server-R12-preinstall setting for kernel.msgmni is 2878
			kernel.msgmni=2878
			# oracle-ebs-server-R12-preinstall setting for kernel.msgmnb is 65535
			kernel.msgmnb=65535
			# oracle-ebs-server-R12-preinstall setting for net.core.rmem_default is 262144
			net.core.rmem_default=262144
			# oracle-ebs-server-R12-preinstall setting for net.core.rmem_max is 4194304
			net.core.rmem_max=4194304
			# oracle-ebs-server-R12-preinstall setting for net.core.wmem_default is 262144
			net.core.wmem_default=262144
			# oracle-ebs-server-R12-preinstall setting for net.core.wmem_max is 1048576
			net.core.wmem_max=1048576
			# oracle-ebs-server-R12-preinstall setting for fs.aio-max-nr is 1048576
			fs.aio-max-nr = 1048576
			# oracle-ebs-server-R12-preinstall setting for net.ipv4.ip_local_port_range is 9000 65500
			net.ipv4.ip_local_port_range = 9000 65500
EOF
		fi
		sysctl --system >/dev/null 2>&1
		stop_spinner $?
	} | tee -a $LOG
}

##########################################
#### 1.5.4 Ensure prelink is disabled ####
##########################################
function pre_link() {
	{
		start_spinner 'Disabling and removing Prelink...'
		echo ""
		if [ -f /usr/sbin/prelink ]; then
			prelink -ua
			${PAKMGR} remove prelink
		fi
		stop_spinner $?
	} | tee -a $LOG
}

########################################################
#### 1.6.1.4 Ensure SETroubleshoot is not installed ####
########################################################
function se_troubleshoot_mcs() {
	{
		start_spinner 'Removing SE Troubleshoot and MCS Translation Service...'
		echo ""
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			if [ -f /usr/bin/setroubleshoot ]; then
				${PAKMGR} remove setroubleshoot 
			fi
		fi
		#### 1.6.1.5 Ensure the MCS Translation Service (mcstrans) is not installed ####
		if [ "${OS}" = ubuntu ]; then
			if systemctl list-units --type=service --all | grep -q mcstrans; then
				${PAKMGR} remove policycoreutils
			fi
		else
			if systemctl list-units --type=service --all | grep -q mcstrans; then
				${PAKMGR} remove mcstrans
			fi
		fi
		stop_spinner $?
	} | tee -a $LOG
}

######################################################
#### 1.6.1.6 Ensure no unconfigured daemons exist ####
######################################################
function unconf_daemons() {
	{
		start_spinner 'Ensuring no unconfigered daemons exist...'
		echo ""
		process=$(ps -eZ)
		echo "${process}" | grep -E "initrc" | grep -Evw "tr|ps|grep|bash|awk" | tr ':' ' ' | awk '{ print $NF }'
		stop_spinner $?
	} | tee -a $LOG
}

###########################################
#### 1.6.2 Ensure SELinux is installed ####
###########################################
function se_linux() {
	{
		start_spinner 'Ensuring MAC Security is installed...'
		echo ""
		if [ "${OS}" = ubuntu ]; then
			${PAKMGR} install apparmor apparmor-utils
			systemctl enable --now apparmor
		else
			if ! rpm -qa libselinux; then
				${PAKMGR} install libselinux
			fi
		fi
		stop_spinner $?
	} | tee -a $LOG
}

##################################################################
#### 1.7.1.1 Ensure message of the day is configured properly ####
##################################################################
function banners() {
	{
		start_spinner 'Configuring all Message Banners...'
		echo ""
		if [ "${OS}" = ubuntu ]; then
			chmod -x /etc/update-motd.d/*
			touch /etc/motd
		else
			xargs -n 1 cp -v /etc/motd <<< "${BACKUP} /etc/motd.bak"
		fi	
		echo "   All activities performed on this system will be monitored." > /etc/motd
		#### 1.7.1.2 Ensure local login warning banner is configured properly ####
		xargs -n 1 cp -v /etc/issue <<< "${BACKUP} /etc/issue.bak"
		echo "   All activities performed on this system will be monitored." > /etc/issue
		#### 1.7.1.3 Ensure remote login warning banner is configured properly ####
		xargs -n 1 cp -v /etc/issue.net <<< "${BACKUP} /etc/issue.net.bak"
		echo "   All activities performed on this system will be monitored." > /etc/issue.net
		#### 1.7.1.4 Ensure permissions on /etc/motd ore configured ####
		chmod 644 /etc/motd
		chown root.root /etc/motd
		#### 1.7.1.5 Ensure permissions on /etc/issue are configured ####
		chmod 644 /etc/issue
		chown root.root /etc/issue
		#### 1.7.1.6 Ensure permissions on /etc/issue.net are configured ####
		chmod 644 /etc/issue.net
		chown root.root /etc/issue.net
		stop_spinner $?
	} | tee -a $LOG
}

#####################################################################################
#### 1.8 ensure updates, patches, and additional security software are installed ####
#####################################################################################
function update_security() {
	{
		start_spinner 'Checking and Installing Security Updates...'
		echo ""
		if [ "${OS}" = ubuntu ]; then
			${PAKMGR} autoremove	
			${PAKMGR} update 
			${PAKMGR} upgrade
		else
			${PAKMGR} clean all
			${PAKMGR} check-update --security
			${PAKMGR} update --security 
		fi
		stop_spinner $?
	} | tee -a $LOG
}

############################
#### 2.1 inetd Services ####
############################
function inet_service() {
	{
		start_spinner 'Disabling Unused/Unsecure inetd Services...'
		echo ""
		#### 2.1.1 Ensure chargen services are not enabled ####
		if [ "${OS}" = ubuntu ]; then
			if grep -Rq "^chargen" /etc/inetd.* 2>/dev/null; then
				systemctl stop chargen 2>/dev/null
				systemctl disable chargen 2>/dev/null
			fi
		else
			if systemctl is-enabled chargen-dgram >/dev/null 2>&1; then
				systemctl stop chargen-dgram 
				systemctl disable chargen-dgram
			fi
			if systemctl is-enabled chargen-stream >/dev/null 2>&1; then
				systemctl stop chargen-stream 
				systemctl disable chargen-stream 
			fi
		fi
		#### 2.1.2 Ensure daytime services are not enabled ####
		if [ "${OS}" = ubuntu ]; then
			if grep -Rq "^daytime" /etc/inetd.* 2>/dev/null; then
				systemctl stop daytime 2>/dev/null
				systemctl disable daytime 2>/dev/null
			fi
		else
			if systemctl is-enabled daytime-dgram >/dev/null 2>&1; then
				systemctl stop daytime-dgram 
				systemctl disable daytime-dgram
			fi
			if systemctl is-enabled daytime-stream >/dev/null 2>&1; then
				systemctl stop daytime-stream 
				systemctl disable daytime-stream
			fi
		fi
		#### 2.1.3 Ensure discard services are not enabled ####
		if [ "${OS}" = ubuntu ]; then
			if grep -Rq "^discard" /etc/inetd.* 2>/dev/null; then
				systemctl stop discard 2>/dev/null
				systemctl disable discard 2>/dev/null
			fi
		else
			if systemctl is-enabled discard-dgram >/dev/null 2>&1; then
				systemctl stop discard-dgram 
				systemctl disable discard-dgram 
			fi
			if systemctl is-enabled discard-stream >/dev/null 2>&1; then
				systemctl stop discard-stream 
				systemctl disable discard-stream
			fi
		fi
		#### 2.1.4	Ensure echo services are not Enabled ####
		if [ "${OS}" = ubuntu ]; then
			if grep -Rq "^echo" /etc/inetd.* 2>/dev/null; then
				systemctl stop echo 2>/dev/null
				systemctl disable echo 2>/dev/null
			fi
		else
			if systemctl is-enabled echo-stream >/dev/null 2>&1; then
				systemctl stop echo-stream 
				systemctl disable echo-stream 
			fi
		fi
		#### 2.1.5 Ensure time services are not enabled ####
		if [ "${OS}" = ubuntu ]; then
			if grep -Rq "^time" /etc/inetd.* 2>/dev/null; then
				systemctl stop time 2>/dev/null
				systemctl disable time 2>/dev/null
			fi
		else
			if systemctl is-enabled time-dgram >/dev/null 2>&1; then
				systemctl stop time-dgram 
				systemctl disable time-dgram
			fi
			if systemctl is-enabled time-stream >/dev/null 2>&1; then
				systemctl stop time-stream 
				systemctl disable time-stream 
			fi
		fi
		#### 2.1.6 Ensure rsh server is not enabled Ubuntu ####
		if [ "${OS}" = ubuntu ]; then
			if grep -Rq "^shell" /etc/inetd.* 2>/dev/null; then
				systemctl stop shell 2>/dev/null
				systemctl disable shell 2>/dev/null
			fi
			if grep -Rq "^login" /etc/inetd.* 2>/dev/null; then
				systemctl stop login 2>/dev/null
				systemctl disable login 2>/dev/null
			fi
			if grep -Rq "^exec" /etc/inetd.* 2>/dev/null; then
				systemctl stop exec 2>/dev/null
				systemctl disable exec 2>/dev/null
			fi
		fi
		#### 2.1.6 Ensure tftp server is not enabled Others ####
		if systemctl is-enabled tftp >/dev/null 2>&1; then
			systemctl stop tftp 
			systemctl disable tftp
		fi
		#### 2.1.7 Ensure talk server is not enabled Ubuntu ####
		if [ "${OS}" = ubuntu ]; then
			if grep -Rq "^talk" /etc/inetd.* 2>/dev/null; then
				systemctl stop talk 2>/dev/null
				systemctl disable talk 2>/dev/null
			fi
			if grep -Rq "^ntalk" /etc/inetd.* 2>/dev/null; then
				systemctl stop ntalk 2>/dev/null
				systemctl disable ntalk 2>/dev/null
			fi
		fi
		#### 2.1.9 Ensure tftp server is not enabled Ubuntu ####
		if [ "${OS}" = ubuntu ]; then
			if grep -Rq "^tftp" /etc/inetd.* 2>/dev/null; then
				systemctl stop tftp 2>/dev/null
				systemctl disable tftp 2>/dev/null
			fi
		fi
		#### 2.1.8 Ensure telnet server is not enabled Ubuntu ####
		if [ "${OS}" = ubuntu ]; then
			if grep -Rq "^telnet" /etc/inetd.* 2>/dev/null; then
				systemctl stop telnet 2>/dev/null
				systemctl disable telnet 2>/dev/null
			fi
		fi
		#### 2.1.10 Ensure xinetd is not enabled All ####
		if systemctl is-enabled xinetd >/dev/null 2>&1; then
			systemctl stop xinetd 
			systemctl disable xinetd
		fi
		stop_spinner $?
	} | tee -a $LOG
}

#######################################################	
#### 2.2.1.1 Ensure time synchronization is in use ####
#######################################################

#### 2.2.1.2 Ensure ntp is configured ####
function ntp_config() {
	{
		start_spinner 'Configuring Time Sync Service...'
		echo ""
		local NTP_FILE="/etc/ntp.conf"
		#### Ubuntu uses chrony (handled in chrony_cfg), skip ntp ####
		if [ "${OS}" = ubuntu ]; then
			systemctl disable --now systemd-timesyncd 2>/dev/null
			stop_spinner $?
			return 0
		fi
		${PAKMGR} install ntp
		if [ "${OS}" = centos ]; then
			var1=${OS}
		else
			var1=rhel
		fi
		if [ "${OS}" = centos ]; then
			sed -i 's/OPTIONS="-g"/OPTIONS="-u ntp:ntp"/g' /etc/sysconfig/ntpd
			if ! grep -qi "server 127.127.1.0" ${NTP_FILE}; then
				echo "server  127.127.1.0  #local clock" >> ${NTP_FILE} 
				echo "fudge   127.127.1.0  stratum 10" >> ${NTP_FILE}
			fi
			if ! grep -qi "disable monitor" ${NTP_FILE}; then 
				echo "disable monitor" >> ${NTP_FILE} 
			fi
			systemctl enable --now ntpd 		
		else
			xargs -n 1 cp -v ${NTP_FILE} <<< ""${BACKUP} ${NTP_FILE}.bak""
			sed -i 's/restrict default nomodify notrap nopeer noquery/restrict default nomodify notrap nopeer noquery/p' ${NTP_FILE}
			sed -i '8 s/restrict default nomodify notrap nopeer noquery/restrict -4 default kod nomodify notrap nopeer noquery/g' ${NTP_FILE}
			sed -i '9 s/restrict default nomodify notrap nopeer noquery/restrict -6 default kod nomodify notrap nopeer noquery/g' ${NTP_FILE} 
			sed -i 's/OPTIONS="-g"/OPTIONS="-u ntp:ntp"/g' /etc/sysconfig/ntpd
			if ! grep -qi "server 127.127.1.0" "${NTP_FILE}"; then
				echo "server  127.127.1.0  #local clock" >> ${NTP_FILE} 
				echo "fudge   127.127.1.0  stratum 10" >> ${NTP_FILE}
			fi
			if ! grep -qi "disable monitor" ${NTP_FILE}; then 
				echo "disable monitor" >> ${NTP_FILE} 
			fi
			systemctl enable --now ntpd 
			systemctl restart ntpd   	
		fi
		sed -i "s/#server 0.$var1.pool.ntp.org iburst/server 0.$var1.pool.ntp.org iburst/g" ${NTP_FILE} 
		sed -i "s/#server 1.$var1.pool.ntp.org iburst/server 1.$var1.pool.ntp.org iburst/g" ${NTP_FILE}
		sed -i "s/#server 2.$var1.pool.ntp.org iburst/server 2.$var1.pool.ntp.org iburst/g" ${NTP_FILE}
		sed -i "s/#server 3.$var1.pool.ntp.org iburst/server 3.$var1.pool.ntp.org iburst/g" ${NTP_FILE}
		stop_spinner $?
	} | tee -a $LOG
}

#### 2.2.1.3 Ensure chrony is configured ####
function chrony_cfg() {
	{
		start_spinner 'Configuring Chrony Service...'
		echo ""
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			if [ "${OSVER}" = 8 ] || [ "${OSVER}" =  9 ]; then
					${PAKMGR} install chrony ntpstat
			fi
		elif [ "${OS}" = ubuntu ]; then
			DEBIAN_FRONTEND=noninteractive ${PAKMGR} install chrony
		else
			${PAKMGR} install chrony
		fi
		if [ "${OS}" = centos ]; then
			var1=${OS}
		else
			var1=rhel
		fi
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			if [ "${OSVER}" = 7 ]; then
				if ! grep $var1.pool.ntp.org /etc/chrony.conf; then
					echo '#################################################################'
					echo '####   Using public servers from the pool.ntp.org project.   ####'
					echo '####   Added for CIS Level 1 Compatibility for questions     ####'
					echo '####       Contact Phil Connor contact@mylinux.work          ####'
					echo '#################################################################'
					echo "server 0.$var1.pool.ntp.org iburst"
					echo "server 1.$var1.pool.ntp.org iburst"
					echo "server 2.$var1.pool.ntp.org iburst"
					echo "server 3.$var1.pool.ntp.org iburst"
					sed -i "s/#server 0.$var1.pool.ntp.org iburst/server 0.$var1.pool.ntp.org iburst/g" /etc/chrony.conf 
					sed -i "s/#server 1.$var1.pool.ntp.org iburst/server 1.$var1.pool.ntp.org iburst/g" /etc/chrony.conf
					sed -i "s/#server 2.$var1.pool.ntp.org iburst/server 2.$var1.pool.ntp.org iburst/g" /etc/chrony.conf
					sed -i "s/#server 3.$var1.pool.ntp.org iburst/server 3.$var1.pool.ntp.org iburst/g" /etc/chrony.conf
					sed -i 's/server 169.254.169.254 iburst/#server 169.254.169.254 iburst/g' /etc/chrony.conf
					sed -i 's/OPTIONS=""/OPTIONS="-u chrony"/g' /etc/sysconfig/chronyd
				fi	
			fi
		fi			
			if [ "${OSVER}" = 8 ] || [ "${OSVER}" =  9 ]; then
				if ! grep $var1.pool.ntp.org /etc/chrony.conf; then 
					chronyd -q 'server 2.rhel.pool.ntp.org iburst'
					sed -i 's/OPTIONS="-F 2"/OPTIONS="-u chrony"/g' /etc/sysconfig/chronyd
					chronyc sourcestats -v
				fi
			systemctl enable --now chronyd
			fi
		if [ "${OS}" = ubuntu ]; then
			DEBIAN_FRONTEND=noninteractive ${PAKMGR} install chrony
			systemctl disable --now systemd-timesyncd 2>/dev/null
			systemctl enable --now chrony
			chronyc sourcestats -v 2>/dev/null
		fi
		stop_spinner $?
	} | tee -a $LOG
}

#######################################################
#### 2.2.2 Ensure X Window System is not installed ####
#######################################################
function unsecure_services() {
	{
		start_spinner 'Removing X11 and Disabling Insecure Protocols...'
		echo ""
		if [ "${OS}" = ubuntu ]; then
			${PAKMGR} remove xorg*
			${PAKMGR} remove xserver-xorg*
		else
			${PAKMGR} remove xorg-x11* 
		fi
		a=( "$(systemctl list-units --type=service --all)" )
		#### 2.2.3 Ensure Avahi Server is not installed ####
		if echo "${a[@]}" | grep avahi-daemon.service; then	
			systemctl stop avahi-daemon 
			systemctl disable avahi-daemon
		fi
		### 2.2.4 Ensure CUPS is not enabled ###
		if echo "${a[@]}" | grep cups.service; then 
			systemctl stop cups
			systemctl disable cups
		fi
		#### 2.2.5 Ensure DHCP Server is not enabled ####
		if  [ "${OS}" = ubuntu ]; then
			if echo "${a[@]}" | grep isc-dhcp-server.service; then
				systemctl stop isc-dhcp-server
				systemctl disable isc-dhcp-server
			fi
		else
			if echo "${a[@]}" | grep dhcpd.service; then 
				systemctl stop dhcpd
				systemctl disable dhcpd
			fi
		fi
		#### 2.2.6 Ensure LDAP Server is not enabled ####
		if echo "${a[@]}" | grep slapd.service; then 
			systemctl stop slapd
			systemctl disable slapd
		fi
		#### 2.2.7 Ensure NFS and RPC are not enabled ####
		if [ "${OS}" = ubuntu ]; then
			if echo "${a[@]}" | grep nfs-kernel-server.service; then
				systemctl stop nfs-kernel-server
				systemctl disable nfs-kernel-server
			fi
		else
			if echo "${a[@]}" | grep nfs-server.service; then
				systemctl stop nfs-server
				systemctl disable nfs-server
			fi
			if echo "${a[@]}" | grep nfs.service; then
				systemctl stop nfs
				systemctl disable nfs
			fi		
		fi
		if echo "${a[@]}" | grep rpcbind.service; then 
			systemctl stop rpcbind
			systemctl disable rpcbind
		fi
		#### 2.2.8 Ensure DNS Server is not enabled ####
		if echo "${a[@]}" | grep named.service; then 
			systemctl stop named
			systemctl disable named
		fi
		if [ "${OS}" = ubuntu ]; then
			if echo "${a[@]}" | grep bind9.service; then 
				systemctl stop bind9
				systemctl disable bind9
			fi
		fi
		#### 2.2.9 Ensure FTP Server is not enabled ####
		if echo "${a[@]}" | grep vsftpd.service; then 
			systemctl stop vsftpd
			systemctl disable vsftpd
		fi
		#### 2.2.10 Ensure HTTP Server is not enabled ####
		if [ "${OS}" = ubuntu ]; then
			if echo "${a[@]}" | grep apache2.service; then 
				systemctl stop apache2
				systemctl disable apache2
			fi
		else
			if echo "${a[@]}" | grep httpd.service; then 
				systemctl stop httpd
				systemctl disable httpd
			fi
		fi
		#### 2.2.11 Ensure IMAP and POP3 server are not enabled ####
		if echo "${a[@]}" | grep dovecot.service; then 
			systemctl stop dovecot
			systemctl disable dovecot
		fi
		#### 2.2.12 Ensure Samba is not enabled ####
		if echo "${a[@]}" | grep smb.service; then 
			systemctl stop smb
			systemctl disable smb
		fi
		#### 2.2.13 Ensure HTTP Proxy Server is not enabled ####
		if echo "${a[@]}" | grep squid.service; then 
			systemctl stop squid
			systemctl disable squid
		fi
		#### 2.2.14 Ensure SNMP Server is not enabled ####
		if echo "${a[@]}" | grep snmpd.service; then 
			systemctl stop snmpd
			systemctl disable snmpd
		fi
		stop_spinner $?
	} | tee -a $LOG
}

#############################################################################
#### 2.2.15 Ensure mail transfer agent is configured for local-only mode ####
#############################################################################
function mail_config() {
	{
		start_spinner 'Configuring Postfix MTA...'
		echo ""
		if [ "${OS}" = ubuntu ]; then
			debconf-set-selections <<< ""postfix postfix/mailname string "${HOSTNAME}"""
			debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'"
			DEBIAN_FRONTEND=noninteractive ${PAKMGR} install postfix --assume-yes
			sed -i 's/inet_interfaces = all/inet_interfaces = localhost/g' /etc/postfix/main.cf
		else
			${PAKMGR} install postfix
			sed -i 's/inet_interfaces = localhost/inet_interfaces = loopback-only/g' /etc/postfix/main.cf
		fi
		# shellcheck disable=SC2016
		sed -i 's/#smtpd_banner = $myhostname ESMTP $mail_name/smtpd_banner = $myhostname ESMTP/g' /etc/postfix/main.cf
		# shellcheck disable=SC2016
		sed -i 's/smtpd_banner = $myhostname ESMTP ($mail_version)/#smtpd_banner = $myhostname ESMTP $mail_name ($mail_version)/g' /etc/postfix/main.cf
		if ! grep -qi "mailbox_size_limit" /etc/postfix/main.cf; then
			echo "mailbox_size_limit = 0" >> /etc/postfix/main.cf
		fi
		postconf -e message_size_limit=0
		postconf -e "mailbox_size_limit=0"
		systemctl enable --now postfix 
		stop_spinner $?
	} | tee -a $LOG
}

################################################
#### 2.2.x Disable Additional inet Services ####
################################################ 
function addon_inet_services() {
	{
		start_spinner 'Disabling Additional Unsecure Services...'
		echo ""
		a=( "$(systemctl list-units --type=service --all)" )
		### 2.2.16 Ensure NIS Server is not enabled ###
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			if echo "${a[@]}" | grep ypserv.service; then 
				systemctl stop ypserv 
				systemctl disable ypserv
			fi
		### 2.2.16 Ensure rsync service is not enabled Ubuntu ###
		elif [ "${OS}" = ubuntu ]; then
			if echo "${a[@]}" | grep rsync.service; then 
				systemctl stop rsync
				systemctl disable rsync
			fi		
		fi
		### 2.1.17 Ensure rsh server is not enabled ###
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol ]]; then
			if echo "${a[@]}" | grep rsh.socket.service; then 
				systemctl stop rsh.socket 
				systemctl disable rsh.socket
			fi
			if echo "${a[@]}" | grep rlogin.socket.service; then 
				systemctl stop rlogin.socket 
				systemctl disable rlogin.socket 
			fi
			if echo "${a[@]}" | grep rexec.socket.service; then 
				systemctl stop rexec.socket 
				systemctl disable rexec.socket
			fi
		### 2.2.17 Ensure NIS Server is not enabled Ubuntu ###
		elif [ "${OS}" = ubuntu ]; then
			if echo "${a[@]}" | grep nis.service; then 
				systemctl stop nis
				systemctl disable nis
			fi
		fi
		### 2.2.18 Ensure talk server is not enabled ###
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol ]]; then
			if echo "${a[@]}" | grep ntalk.service; then
				systemctl stop ntalk 
				systemctl disable ntalk 
			fi
			### 2.2.19 Ensure telnet server is not enabled ###
			if echo "${a[@]}" | grep telnet.socket.service; then 
				systemctl stop telnet.socket 
				systemctl disable telnet-socket
			fi
			### 2.2.20 Ensure tftp server is not enabled ###
			if echo "${a[@]}" | grep tftp.socket.service; then 
				systemctl stop tftp.socket 
				systemctl disable tftp-socket
			fi
			### 2.2.21 Ensure rsync service is not enabled ###
			if echo "${a[@]}" | grep rsyncd.service; then 
				systemctl stop rsyncd 
				systemctl disable rsyncd
			fi
		fi
		stop_spinner $?
	} | tee -a $LOG
}

###############################################################
#### 2.3 Ensure Insecure Service Clients are not Installed ####
###############################################################
function service_clients() {
	{
		start_spinner 'Removing Insecure Service Clients...'
		echo ""
		a=( "$(systemctl list-units --type=service --all)" )
		#### 2.3.1 Ensure NIS Client is not installed ####
		if [ "${OS}" = ubuntu ]; then
			if echo "${a[@]}" | grep nis.service; then 
				${PAKMGR} remove nis
			fi
		else
			if echo "${a[@]}" | grep ypbind.service; then 
				${PAKMGR} remove ypbind
			fi
		fi
		#### 2.3.2 Ensure rsh client is not installed ####
		if [ "${OS}" = ubuntu ]; then
			if echo "${a[@]}" | grep rsh-client.service; then 
				${PAKMGR} remove rsh-client rsh-redone-client
			fi
		else
			if echo "${a[@]}" | grep rsh.service; then 
				${PAKMGR} remove rsh
			fi
		fi
		#### 2.3.3 Ensure talk client is not installed ####
		if echo "${a[@]}" | grep talk.service; then 
			${PAKMGR} remove talk
		fi
		#### 2.3.4 Ensure telnet client is not installed ####
		if echo "${a[@]}" | grep telnet.service; then 
			${PAKMGR} remove telnet
		fi
		#### 2.3.5 Ensure LDAP client is not installed ####
		if [ "${OS}" = ubuntu ]; then
			if echo "${a[@]}" | grep libnss-ldap.service; then 
				${PAKMGR} remove libnss-ldap
			fi
			if echo "${a[@]}" | grep libpam-ldap.service; then 
				${PAKMGR} remove libpam-ldap
			fi
			if echo "${a[@]}" | grep ldap-utils.service; then 
				${PAKMGR} remove ldap-utils
			fi
		else
			if echo "${a[@]}" | grep openldap-clients.service; then 
				${PAKMGR} remove openldap-clients
			fi
		fi
		stop_spinner $?
	} | tee -a $LOG
}

##########################
#### 3.4 TCP Wrappers ####
##########################
function tcp_wrappers() {
	{
		start_spinner 'Configuring TCP Wrappers...'
		echo ""
		#### 3.4.1 Ensure TCP Wrappers is installed ####
		if [ "${OS}" = ubuntu ]; then
			echo "TCP Wrappers skipped on Ubuntu (deprecated)"
		else
			if ! ${PAKMGR} list installed tcp_wrappers 2>/dev/null | grep -q tcp_wrappers; then
				${PAKMGR} install tcp_wrappers
			fi
		fi
		#### 3.4.2 Ensure /etc/hosts.allow is configured ####
		echo ALL:"${VLANIP}" > /etc/hosts.allow
		#### 3.4.3 Ensure /etc/hosts.deny is configured ####
		echo "ALL:ALL" >> /etc/hosts.deny
		#### 3.4.4 Ensure permissions on /etc/hosts.allow are configured ####
		chown root.root /etc/hosts.allow
		chmod 644 /etc/hosts.allow
		#### 3.4.5 Ensure permissions on /etc/hosts.deny are configured ####
		chown root.root /etc/hosts.deny
		chmod 644 /etc/hosts.deny
		stop_spinner $?
	}
}

########################################
#### 3.5 Uncommon Network Protocols ####
########################################
function uncommon_protocols() {
	{
		start_spinner 'Disabling Uncommon Network Protocols...'
		echo ""
		MODPRO="/etc/modprobe.d/cis.conf"
		#### 3.5.1 Ensure DCCP is disabled ####
		echo "install dccp /bin/true" >> ${MODPRO}
		if lsmod | grep -qi dccp; then
			rmmod dccp 2>/dev/null
		fi
		#### 3.5.2 Ensure SCTP is disabled ####
		echo "install sctp /bin/true" >> ${MODPRO}
		if lsmod | grep -qi sctp; then
			rmmod sctp 2>/dev/null
		fi
		#### 3.5.3 ensure RDS is disabled ####
		echo "install rds /bin/true" >> ${MODPRO}
		if lsmod | grep -qi rds; then
			rmmod rds 2>/dev/null
		fi
		#### 3.5.4 Ensure TIPC is disabled ####
		echo "install tipc /bin/true" >> ${MODPRO}
		if lsmod | grep -qi tipc; then
			rmmod tipc 2>/dev/null
		fi
		stop_spinner $?
	} | tee -a $LOG
}

########################################
#### 3.6 Firewall Configuration AWS ####
########################################
function iptables_config() {
	{
		start_spinner 'Configuring IP Tables...'
		echo ""
		### 3.6.1 Ensure iptables is installed ###
		if [ "${OS}" = ubuntu ]; then
			ufw --force disable
			debconf-set-selections <<< "iptables-persistent iptables-persistent/autosave_v4 boolean true"
			debconf-set-selections <<< "iptables-persistent iptables-persistent/autosave_v6 boolean true"
			DEBIAN_FRONTEND=noninteractive ${PAKMGR} install iptables
			DEBIAN_FRONTEND=noninteractive ${PAKMGR} install iptables-persistent --assume-yes
			service netfilter-persistent start
			service netfilter-persistent save
		else
			systemctl stop firewalld.service 
			systemctl mask firewalld.service 
			systemctl daemon-reload 
			${PAKMGR} install iptables-utils iptables-services
		fi
		#### 3.6.2 Ensure default deny firewall policy ####
		#### Configure IPv4 #### 
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			systemctl enable --now iptables
			cp $IPTBL $BACKUP
			mv -f ${IPTBL} ${IPTBL}.bak
			touch ${IPTBL}
		fi
		# Flush Iptables rules
		iptables -F
		# Forcing SYN packets check
		iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
		# Forcing Fragments packets check
		iptables -A INPUT -f -j DROP
		# Dropping malformed XMAS packets
		iptables -A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
		# Drop all NULL packets
		iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
		# Limiting pings to 1 per second
		iptables -N PACKET
		iptables -A PACKET -p icmp -m limit --limit 3/sec --limit-burst 25 -j ACCEPT
		# Setup Connection Tracking
		iptables -N STATE_TRACK
		iptables -A STATE_TRACK -m state --state RELATED,ESTABLISHED -j ACCEPT
		iptables -A STATE_TRACK -m state --state INVALID -j DROP
		# Discouraging Port Scanning
		iptables -N PORTSCAN
		iptables -A PORTSCAN -p tcp --tcp-flags ACK,FIN FIN -j DROP
		iptables -A PORTSCAN -p tcp --tcp-flags ACK,PSH PSH -j DROP
		iptables -A PORTSCAN -p tcp --tcp-flags ACK,URG URG -j DROP
		iptables -A PORTSCAN -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
		iptables -A PORTSCAN -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
		iptables -A PORTSCAN -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
		iptables -A PORTSCAN -p tcp --tcp-flags ALL ALL -j DROP
		iptables -A PORTSCAN -p tcp --tcp-flags ALL NONE -j DROP
		iptables -A PORTSCAN -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
		iptables -A PORTSCAN -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP
		iptables -A PORTSCAN -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
		iptables -N COMMON
		iptables -A COMMON -j STATE_TRACK
		iptables -A COMMON -j PORTSCAN
		iptables -A COMMON -j PACKET
		iptables -A INPUT -j COMMON
		iptables -A OUTPUT -j COMMON
		iptables -A FORWARD -j COMMON
		iptables -A FORWARD -j PACKET
		# Ensure loopback traffic is configured
		iptables -A INPUT -i lo -j ACCEPT
		iptables -A INPUT -s 127.0.0.0/8 -j DROP
		iptables -A OUTPUT -o lo -j ACCEPT
		# Ensure outbound and established connections are configured
		iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
		iptables -A INPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
		iptables -A INPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
		iptables -A INPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
		iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
		iptables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
		iptables -A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
		iptables -A OUTPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
		iptables -A OUTPUT -j LOG --log-prefix "iptables_output "
		# Add Network Connection IP
		iptables -A INPUT -s "${FIREIP}" -d "${FIREIP}" -m state --state NEW,ESTABLISHED -j ACCEPT
		iptables -A OUTPUT -s "${FIREIP}" -d "${FIREIP}" -m state --state NEW,ESTABLISHED -j ACCEPT
		# Open inbound ssh(22) connections and linit connects to 10 every 10 seconds
		iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
		iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 10 --hitcount 10 -j DROP
		iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j ACCEPT
		# Default deny Firewall policy
		iptables -P INPUT DROP
		iptables -P OUTPUT DROP
		iptables -P FORWARD DROP
		for port in "${TCPPORTS[@]}"
		do
			echo "Opening TCP Port $port"
			/sbin/iptables -A INPUT -p tcp -m tcp --dport "$port" -j ACCEPT
		done
		# Open UDP Ports
		for port in "${UDPPORTS[@]}"
		do
			echo "Opening UDP Port $port"
			/sbin/iptables -A INPUT -p udp -m udp --dport "$port" -j ACCEPT
		done
		# Save and Start IPTables
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			iptables-save > ${IPTBL}
			systemctl restart iptables
		elif [ "${OS}" = ubuntu ]; then
			iptables-save > ${IPTBLUB}
			sed -i '/:ufw-/d' ${IPTBLUB}
			sed -i '/-j ufw-/d' ${IPTBLUB}
			iptables-restore < ${IPTBLUB}
		fi
		# Configure IPv6 Firewall Ensure Default Deny Policy
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			cp $IPTBL $BACKUP
			mv -f $IP6TBL $IP6TBL.bak
			touch $IP6TBL
			systemctl enable ip6tables
		fi
		# Flush Iptables rules
		ip6tables -F
		# Default deny Firewall policy
		ip6tables -P INPUT DROP
		ip6tables -P OUTPUT DROP
		ip6tables -P FORWARD DROP
		ip6tables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
		# Forcing Fragments packets check
		ip6tables -A INPUT -f -j DROP
		# Dropping malformed XMAS packets
		ip6tables -A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
		# Drop all NULL packets
		ip6tables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
		# Limiting pings to 1 per second
		ip6tables -N PACKET
		ip6tables -A PACKET -p icmp -m limit --limit 3/sec --limit-burst 25 -j ACCEPT
		# Setup Connection Tracking
		ip6tables -N STATE_TRACK
		ip6tables -A STATE_TRACK -m state --state RELATED,ESTABLISHED -j ACCEPT
		ip6tables -A STATE_TRACK -m state --state INVALID -j DROP
		# Discouraging Port Scanning
		ip6tables -N PORTSCAN
		ip6tables -A PORTSCAN -p tcp --tcp-flags ACK,FIN FIN -j DROP
		ip6tables -A PORTSCAN -p tcp --tcp-flags ACK,PSH PSH -j DROP
		ip6tables -A PORTSCAN -p tcp --tcp-flags ACK,URG URG -j DROP
		ip6tables -A PORTSCAN -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
		ip6tables -A PORTSCAN -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
		ip6tables -A PORTSCAN -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
		ip6tables -A PORTSCAN -p tcp --tcp-flags ALL ALL -j DROP
		ip6tables -A PORTSCAN -p tcp --tcp-flags ALL NONE -j DROP
		ip6tables -A PORTSCAN -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
		ip6tables -A PORTSCAN -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP
		ip6tables -A PORTSCAN -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
		ip6tables -N COMMON
		ip6tables -A COMMON -j STATE_TRACK
		ip6tables -A COMMON -j PORTSCAN
		ip6tables -A COMMON -j PACKET
		ip6tables -A INPUT -j COMMON
		ip6tables -A OUTPUT -j COMMON
		ip6tables -A FORWARD -j COMMON
		ip6tables -A FORWARD -j PACKET
		# Ensure loopback traffic is configured
		ip6tables -A INPUT -i lo -j ACCEPT
		ip6tables -A INPUT -s 127.0.0.0/8 -j DROP
		ip6tables -A OUTPUT -o lo -j ACCEPT
		# Ensure outbound and established connections are configured
		ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
		ip6tables -A INPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
		ip6tables -A INPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
		ip6tables -A INPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
		ip6tables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
		ip6tables -A OUTPUT -p tcp -m state --state NEW,ESTABLISHED -j ACCEPT
		ip6tables -A OUTPUT -p udp -m state --state NEW,ESTABLISHED -j ACCEPT
		ip6tables -A OUTPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
		ip6tables -A OUTPUT -j LOG --log-prefix "iptables_output "
		for port in "${TCP6PORTS[@]}"
		do
			echo "Opening TCP Port $port"
			ip6tables -A INPUT -p tcp -m tcp --dport "$port" -j ACCEPT
		done
		# Open UDP Ports
		for port in "${UDP6PORTS[@]}"
		do
			echo "Opening UDP Port $port"
			ip6tables -A INPUT -p udp -m udp --dport "$port" -j ACCEPT

		done
			# Save and Start IPTables
		if [[ ${OS} = ubuntu ]]; then
			ip6tables-save > ${IP6TBLUB}
			sed -i '/:ufw6-/d' ${IP6TBLUB}
			sed -i '/-j ufw6-/d' ${IPTBLUB}
			ip6tables-restore < ${IP6TBLUB}
		else 
			ip6tables-save > ${IP6TBL}
			systemctl restart ip6tables
		fi
		stop_spinner $?
	} | tee -a $LOG
}

##################################################
#### 3.6a Addional Firewall Configuration AWS ####
##################################################
function iptables_aws() {
	{
		start_spinner 'Adding AWS Required Rules to IP Tables...'
		echo ""
		iptables -t nat -A PREROUTING -p tcp -d 169.254.170.2 --dport 80 -j DNAT --to-destination 127.0.0.1:51679
		iptables -t nat -A OUTPUT -d 169.254.170.2 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 51679
		iptables-save > /etc/sysconfig/iptables
		systemctl restart iptables
		stop_spinner $?
	} | tee -a $LOG
}

##################################################
#### 3.6b Addional Firewall Configuration OCI ####
##################################################
function oci_iptables() {
	{
		start_spinner 'Adding OCI Required Rules to IP Tables...'
		echo ""
		iptables -A OUTPUT -d 169.254.0.0/16 -m state --state NEW,ESTABLISHED -p tcp -m tcp -j REJECT --reject-with tcp-reset -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.0.0/16 -m state --state NEW,ESTABLISHED -p udp -m udp -j REJECT -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.0.2/32 -m state --state NEW,ESTABLISHED -p tcp -m tcp --dport 80 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.0.2/32 -m state --state NEW,ESTABLISHED -p tcp -m owner --uid-owner root -m tcp --dport 3260 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.0.3/32 -m state --state NEW,ESTABLISHED -p tcp -m owner --uid-owner root -m tcp --dport 80  -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.0.4/32 -m state --state NEW,ESTABLISHED -p tcp -m tcp --dport 80  -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.2.0/24 -m state --state NEW,ESTABLISHED -p tcp -m owner --uid-owner root -m tcp --dport 3260 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.4.0/24 -m state --state NEW,ESTABLISHED -p tcp -m owner --uid-owner root -m tcp --dport 3260 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.5.0/24 -m state --state NEW,ESTABLISHED -p tcp -m owner --uid-owner root -m tcp --dport 3260 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.169.254/32 -m state --state NEW,ESTABLISHED -p tcp -m tcp --dport 53 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE" 
		iptables -A OUTPUT -d 169.254.169.254/32 -m state --state NEW,ESTABLISHED -p udp -m udp --dport 53 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.169.254/32 -m state --state NEW,ESTABLISHED -p udp -m udp --dport 67 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.169.254/32 -m state --state NEW,ESTABLISHED -p udp -m udp --dport 69 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.169.254/32 -m state --state NEW,ESTABLISHED -p udp -m udp --dport 80 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
		iptables -A OUTPUT -d 169.254.169.254/32 -m state --state NEW,ESTABLISHED -p udp -m udp --dport 123 -j ACCEPT -m comment --comment "OCI Required - DO NOT REMOVE"
		# Save and Start IPTables
		if [ "${OS}" = ubuntu ]; then
			iptables-save > ${IPTBLUB}
			sed -i '/:ufw-/d' ${IPTBLUB}
			sed -i '/-j ufw-/d' ${IPTBLUB}
			iptables-restore < ${IPTBLUB}
		else
			iptables-save > ${IPTBL}
			systemctl restart iptables
		fi
		stop_spinner $?
		} | tee -a $LOG
}

#########################################
#### 4.1 Configure System Accounting ####
#########################################
function auditd_accounting() {
	{
		start_spinner 'Configuring Auditd Service...'
		echo ""
		#### 4.1.1.1 Ensure audit log storage size is configured ####
		#### !!! Our current default configuration is 8MB !!! ####
		#### 4.1.1.2 Ensure system is disabled when audit logs are full ####
		if [ "${OS}" = ubuntu ]; then
			debconf-set-selections <<< ""postfix postfix/mailname string "${HOSTNAME}"""
			debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'"
			DEBIAN_FRONTEND=noninteractive ${PAKMGR} install auditd --assume-yes
		else
			${PAKMGR} install audit
		fi
		xargs -n 1 cp -v /etc/audit/auditd.conf <<< ""${BACKUP} /etc/audit/auditd.conf.bak""
		### 4.1.1.3 Ensure audit logs are not automaticlly deleted ###
		sed -i 's/^space_left_action.*$/space_left_action = email/' /etc/audit/auditd.conf
		sed -i 's/^action_mail_acct.*$/action_mail_acct = root/' /etc/audit/auditd.conf
		sed -i 's/^admin_space_left_action.*$/admin_space_left_action = halt/' /etc/audit/auditd.conf
		# shellcheck disable=SC2086
		sed -i ""s/max_log_file_action = ROTATE/max_log_file_action = \"${MAXLOGS}\"/g"" /etc/audit/auditd.conf
		### 4.1.2 Ensure auditd service is enabled ####
		service auditd reload
		if ! systemctl is-enabled auditd; then 
			systemctl enable --now auditd
		fi
		### 4.1.3 Ensure auditing for processes that start prior to auditd is enabled"
		xargs -n 1 cp -v /etc/default/grub <<< ""${BACKUP} /etc/default/grub.bak""
		if ! grep "audit=1" /etc/default/grub; then 
			sed -i '/^GRUB_CMDLINE_LINUX=/ s/\(\"[^\"]*\)$/ audit=1 &/' /etc/default/grub
		fi
		if [ "${OS}" = ubuntu ]; then
			grub-mkconfig -o ${BACKUP}/grub.cfg
		else
			grub2-mkconfig -o ${BACKUP}/grub.cfg
		fi
		if [[ ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			cp ${BACKUP}/grub.cfg ${GRUBCFGRH}
			cp ${BACKUP}/grub.cfg ${GRUBCFG} 
		elif [ "${OS}" = ubuntu ]; then
			cp ${BACKUP}/grub.cfg ${GRUBCFGUB}
		elif [ "${OS}" = centos ]; then
			cp ${BACKUP}/grub.cfg ${GRUBCFGCE}
			cp ${BACKUP}/grub.cfg ${GRUBCFG} 
		fi
		if ! dmesg | grep '[NX|DX]*Execute Disable'; then
			echo 0 > /proc/sys/kernel/exec-shield
		fi
		### 4.1.4 Ensure events that modify date and time information are collected ###
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			sed -i 's/RefuseManualStop=yes/RefuseManualStop=no/g' /lib/systemd/system/auditd.service
			systemctl daemon-reload
		fi
		xargs -n 1 cp -v /etc/audit/rules.d/audit.rules <<< ""${BACKUP} /etc/audit/rules.d/audit.rules.bak""
		sed -i 's/RefuseManualStop=yes/RefuseManualStop=no/g' /lib/systemd/system/auditd.service
		systemctl daemon-reload
		{
			echo '##################################################################################################'
			echo '####                Audit Rules File edited to match CIS level 1 requirements                 ####'
			echo '####        for questions or changes please contact Phil Connor contact@mylinux.work          ####'
			echo '##################################################################################################'
			echo ''
			echo '#### First rule - delete all rules ####'
			echo '-D'
			echo ''
			echo '#### 4.1.4 Ensure events that modify date and time information are collected ####'
			echo '-a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time-change'
			echo '-a always,exit -F arch=b32 -S adjtimex -S settimeofday -S stime -k time-change'
			echo '-a always,exit -F arch=b64 -S clock_settime -k time-change'
			echo '-a always,exit -F arch=b32 -S clock_settime -k time-change'
			echo '-w /etc/localtime -p wa -k time-change'
			echo ''
			echo '#### 4.1.5 Ensure events that modify user/group information are collected ####'
			echo '-w /etc/group -p wa -k identity'
			echo '-w /etc/passwd -p wa -k identity'
			echo '-w /etc/gshadow -p wa -k identity'
			echo '-w /etc/shadow -p wa -k identity'
			echo '-w /etc/security/opasswd -p wa -k identity'
			echo ''
			echo '#### 4.1.6 Ensure events that modify the system'\''s network environment are collected ####'
			echo '-a always,exit -F arch=b32 -S sethostname -S setdomainname -k system-locale'
			echo '-a always,exit -F arch=b64 -S sethostname -S setdomainname -k system-locale'
			echo '-w /etc/issue -p wa -k system-locale'
			echo '-w /etc/issue.net -p wa -k system-locale'
			echo '-w /etc/hosts -p wa -k system-locale'
			echo '-w /etc/network -p wa -k system-locale'
			echo '-w /etc/networks -p wa -k system-locale'
			echo ''
			echo '#### 4.1.7 Ensure events that modify the system'\''s Mandatory Access Controls (MAC'\''s) are collected ####'
			echo '-w /etc/selinux/ -p wa -k MAC-policy'
			echo '-w /etc/apparmor/ -p wa -k MAC-policy'
			echo '-w /etc/apparmor.d/ -p wa -k MAC-policy'
			echo ''
			echo '#### 4.1.8 Ensure login and logout events are collected ####'
			echo '-w /var/log/faillog -p wa -k logins'
			echo '-w /var/log/lastlog -p wa -k logins'
			echo '-w /var/log/tallylog -p wa -k logins'
			echo ''
			echo '#### 4.1.9 Ensure session initiation information is collected ###'
			echo '-w /var/run/utmp -p wa -k session'
			echo '-w /var/run/wtmp -p wa -k session'
			echo '-w /var/run/btmp -p wa -k session'
			echo ''
			echo '#### 4.1.10 Ensure discretionary access control permission modification events are collected ####'
			echo '-a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod'
			echo '-a always,exit -F arch=b32 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod'
			echo '-a always,exit -F arch=b64 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=4294967295 -k perm_mod'
			echo '-a always,exit -F arch=b32 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=4294967295 -k perm_mod'
			echo '-a always,exit -F arch=b64 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>=1000 -F auid!=4294967295 -k perm_mod'
			echo '-a always,exit -F arch=b32 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>=1000 -F auid!=4294967295 -k perm_mod'
			echo ''
			echo '#### 4.1.11 Ensure unsuccessful unauthorized file access attempts are collected ####'
			echo '-a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=4294967295 -k access'
			echo '-a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=4294967295 -k access'
			echo '-a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=4294967295 -k access'
			echo '-a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=4294967295 -k access'
			echo ''
			echo '#### 4.1.12 Ensure use of privileged commands is collected ####'
			echo "$RULES"
			echo ''
			echo '#### 4.1.13 Ensure successful file system mounts are collected ####'
			echo '-a always,exit -F arch=b64 -S mount -F auid>=1000 -F auid!=4294967295 -k mounts'
			echo '-a always,exit -F arch=b32 -S mount -F auid>=1000 -F auid!=4294967295 -k mounts'
			echo ''
			echo '#### 4.1.14 Ensure file deletion events by users are collected ####'
			echo '-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete'
			echo '-a always,exit -F arch=b32 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete'
			echo ''
			echo '#### 4.1.15 Ensure changes to system administration scope (sudoers) is collected ####'
			echo '-w /etc/sudoers -p wa -k scope'
			echo '-w /etc/sudoers.d -p wa -k scope'
			echo ''
			echo '#### 4.1.16 Ensure system administrator actions (sudolog) are collected ####'
			echo '-w /var/log/sudo.log -p wa -k actions'
			echo ''
			echo '#### 4.1.17 Ensure kernel module loading and unloading is collected ####'
			echo '-w /sbin/insmod -p x -k modules'
			echo '-w /sbin/rmmod -p x -k modules'
			echo '-w /sbin/modprobe -p x -k modules'
			echo '-a always,exit -F arch=b64 -S init_module -S delete_module -k modules'
			echo ''
			echo '#### 4.1.18 Ensure the audit configuration is immutable ####'
			echo '-e 2'
		} > /etc/audit/rules.d/audit.rules
		service auditd restart 
		stop_spinner $?
	} | tee -a $LOG
}

###############################################
#### 4.1.19 Compress and Rotate Audit Logs ####
###############################################
function compress_auditd() {
	{
		start_spinner 'Configuring Audit Log Compression...'
		echo ""
		if [ -f /etc/audit/auditd.conf ]; then
			sed -i 's/^num_logs.*$/num_logs = 10/' /etc/audit/auditd.conf
			sed -i 's/^max_log_file .*$/max_log_file = 20/' /etc/audit/auditd.conf
		fi
		service auditd reload 2>/dev/null
		stop_spinner $?
	} | tee -a $LOG
}

#################################
#### 4.2.1 Configure rsyslog ####
#################################
function rsyslog_service() {
	{
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			if [ "${OSVER}" = 7 ]; then
				os7_rsyslog	
			elif [[ ${OSVER} = 8 || ${OSVER} = 9 ]]; then 
				os8_rsyslog
			fi
		elif [ "${OS}" = ubuntu ]; then
				ub_rsyslog
			
		fi
	}
}

function os7_rsyslog() {
	{
		start_spinner 'Configuring Rsyslog Service...'
		echo ""
		### 4.2.1.1 Ensure rsyslog Service is enabled ###
		systemctl enable --now rsyslog
		### 4.2.1.2 Ensure logging is configured ###
		xargs -n 1 cp -v /etc/rsyslog.conf <<< ""${BACKUP} /etc/rsyslog.conf.bak""
		cat > /etc/rsyslog.conf << 'EOF'   
		##################################################################################################
		####     Hardened Rsyslog Configuration File edited to match CIS level 1 requirements         ####
		####      for questions or changles please contact Phil Connor contact@mylinux.work           ####
		##################################################################################################

		#################
		#### MODULES ####
		#################

		# The imjournal module bellow is now used as a message source instead of imuxsock.
		$ModLoad imuxsock # provides support for local system logging (e.g. via logger command)
		$ModLoad imjournal # provides access to the systemd journal
		#$ModLoad imklog # reads kernel messages (the same are read from journald)
		#$ModLoad immark  # provides --MARK-- message capability

		# Provides UDP syslog reception
		#$ModLoad imudp
		#$UDPServerRun 514

		# Provides TCP syslog reception
		#$ModLoad imtcp
		#$InputTCPServerRun 514

		# Enable non-kernel facility klog messages
		# $KLogPermitNonKernelFacility on

		###########################
		#### GLOBAL DIRECTIVES ####
		###########################

		# Reset UMASK
		$umask 0000

		# Set file creation pewrmissions
		$FileCreateMode 0640

		# Set previously cleared UMASK
		$umask 0177

		# Where to place auxiliary files
		$WorkDirectory /var/lib/rsyslog

		# Use default timestamp format
		$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

		# File syncing capability is disabled by default. This feature is usually not required,
		# not useful and an extreme performance hit
		#$ActionFileEnableSync on

		# Include all config files in /etc/rsyslog.d/
		$IncludeConfig /etc/rsyslog.d/*.conf

		# Turn off message reception via local log socket;
		# local messages are retrieved through imjournal now.
		$OmitLocalLogging on

		# File to store the position in the journal
		$IMJournalStateFile imjournal.state

		###############
		#### RULES ####
		###############

		#  ### Log Anything of Level WARN or Higher. ###
		*.warn;mail.none;news.none;authpriv.none;cron.none       /var/log/messages

		# ### Secure Logging Anything of Level WARN or Higher ###
		authpriv.*                                               /var/log/secure

		# ### All Mail Logs ###
		mail.*                                                  -/var/log/mail

		# ### Cron Log ###
		cron.*                                                   /var/log/cron

		# ### Everybody Gets Emergency Messages ###
		*.emerg                                                   :omusrmsg:*
		*.=warning;*.=err                                        -/var/log/warn
		*.crit                                                    /var/log/warn

		# ### News Error Logs ###
		news.crit                                                -/var/log/news/news.crit
		news.err                                                 -/var/log/news/news.err
		news.notice                                              -/var/log/news/news.notice

		# ### Local and Boot Messages ###
		local0,local1.*                                          -/var/log/localmessages
		local2,local3.*                                          -/var/log/localmessages
		local4,local5.*                                          -/var/log/localmessages
		local6.*                                                 -/var/log/localmessages
		local7.*                                                  /var/log/boot.log

		###############################
		#### Begin Forwarding Rule ####
		###############################

		# ### The Remote SysLog Server host is: name/ip:port, e.g. 192.168.0.1:514, port optional ###
		#*.* @@syslog
EOF
		echo "
		*.* @@${SYSLOG}

		####################################
		#### End of the Forwarding Rule ####
		####################################
			" >>  /etc/rsyslog.conf
		sed -i 's/^[\t]*//' /etc/rsyslog.conf
		touch /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
		chmod og-rwx /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
		chown root:root /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
		sed -i 's/*.* @@/#*.* @@/g' /etc/rsyslog.conf
		pkill -hup rsyslog
		stop_spinner $?
	}
}

function os8_rsyslog() {
	{
		start_spinner 'Configuring Rsyslog Service...'
		echo ""
		### 4.2.1.1 Ensure rsyslog Service is enabled ###
		systemctl enable rsyslog
		### 4.2.1.2 Ensure logging is configured ###
		xargs -n 1 cp -v /etc/rsyslog.conf <<< ""${BACKUP} /etc/rsyslog.conf.bak""
		cat > /etc/rsyslog.conf << 'EOF'
		##################################################################################################
		####     Hardened Rsyslog Configuration File edited to match CIS level 1 requirements         ####
		#### for questions or changles please contact Phil Connor contact@mylinux.work ####
		##################################################################################################

		#################
		#### MODULES ####
		#################

		module(load="imuxsock"       	# provides support for local system logging (e.g. via logger command)
		SysSock.Use="off")            	# Turn off message reception via local log socket;
										# local messages are retrieved through imjournal now.
		module(load="imjournal"      	# provides access to the systemd journal
		StateFile="imjournal.state") 	# File to store the position in the journal
		#module(load="imklog")       	# reads kernel messages (the same are read from journald)
		#module(load"immark")        	# provides --MARK-- message capability

		# Provides Rsyslog Forwarding
		module(load="omfwd")

		# Provides UDP syslog reception
		# for parameters see http://www.rsyslog.com/doc/imudp.html
		#module(load="imudp") # needs to be done just once
		#input(type="imudp" port="514")

		# Provides TCP syslog reception
		# for parameters see http://www.rsyslog.com/doc/imtcp.html
		#module(load="imtcp") # needs to be done just once
		#input(type="imtcp" port="514")

		###########################
		#### GLOBAL DIRECTIVES ####
		###########################

		# Reset UMASK
		$umask 0000

		# Set file creation pewrmissions
		$FileCreateMode 0640

		# Set previously cleared UMASK
		$umask 0177

		# Where to place auxiliary files
		global(workDirectory="/var/lib/rsyslog")

		# Use default timestamp format
		module(load="builtin:omfile" Template="RSYSLOG_TraditionalFileFormat")

		# Include all config files in /etc/rsyslog.d/
		include(file="/etc/rsyslog.d/*.conf" mode="optional")

		###############
		#### RULES ####
		###############

		#  ### Log Anything of Level WARN or Higher. ###
		*.warn;mail.none;news.none;authpriv.none;cron.none       /var/log/messages

		# ### Secure Logging Anything of Level WARN or Higher ###
		authpriv.*                                               /var/log/secure

		# ### All Mail Logs ###
		mail.*                                                  -/var/log/mail

		# ### Cron Log ###
		cron.*                                                   /var/log/cron

		# ### Everybody Gets Emergency Messages ###
		*.emerg                                                   :omusrmsg:*
		*.=warning;*.=err                                        -/var/log/warn
		*.crit                                                    /var/log/warn

		# ### News Error Logs ###
		news.crit                                                -/var/log/news/news.crit
		news.err                                                 -/var/log/news/news.err
		news.notice                                              -/var/log/news/news.notice

		# ### Local and Boot Messages ###
		local0,local1.*                                          -/var/log/localmessages
		local2,local3.*                                          -/var/log/localmessages
		local4,local5.*                                          -/var/log/localmessages
		local6.*                                                 -/var/log/localmessages
		local7.*                                                  /var/log/boot.log


		###############################
		#### Begin Forwarding Rule ####
		###############################

		#action(type="omfwd"
		# An on-disk queue is created for this action. If the remote host is
		# down, messages are spooled to disk and sent when it is up again.
		#queue.filename="fwdRule1"       # unique name prefix for spool files
		#queue.maxdiskspace="1g"         # 1gb space limit (use as much as possible)
		#queue.saveonshutdown="on"       # save messages to disk on shutdown
		#queue.type="LinkedList"         # run asynchronously
		#action.resumeRetryCount="-1"    # infinite retries if host is down
		# Remote Logging (we use TCP for reliable delivery)
		# remote_host is: name/ip, e.g. 192.168.0.1, port optional e.g. 10514
		# Target="remote_host" Port="XXX" Protocol="tcp")

EOF
		echo "
		Target=\"${SYSLOG}" Port="514" Protocol="tcp\"

		####################################
		#### End of the Forwarding Rule ####
		####################################
			" >> /etc/rsyslog.conf
		sed -i 's/^[\t]*//' /etc/rsyslog.conf
		touch /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
		chmod og-rwx /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
		chown root:root /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
		sed -i 's/Target="" Port="514" Protocol="tcp"/#Target="" Port="514" Protocol="tcp"/g' /etc/rsyslog.conf
		pkill -hup rsyslog
		stop_spinner $?
	}
}

function ub_rsyslog() {
	{
		start_spinner 'Configuring Rsyslog Service...'
		echo ""
		service rsyslog stop
		mknod -m 640 /dev/xconsole c 1 3
		chown syslog:adm /dev/xconsole
		### 4.2.1.1 Ensure rsyslog Service is enabled ###
		systemctl enable rsyslog
		### 4.2.1.2 Ensure logging is configured ###
		xargs -n 1 cp -v /etc/rsyslog.conf <<< ""${BACKUP} /etc/rsyslog.conf.bak""
		no_show << "EOF" >  /etc/rsyslog.conf
		##################################################################################################
		####     Hardened Rsyslog Configuration File edited to match CIS level 1 requirements         ####
		####       for questions or changles please contact Phil Connor contact@mylinux.work          ####
		##################################################################################################

		#################
		#### MODULES ####
		#################

		module(load="imuxsock") # provides support for local system logging
		#module(load="immark")  # provides --MARK-- message capability

		# provides UDP syslog reception
		#module(load="imudp")
		#input(type="imudp" port="514")

		# provides TCP syslog reception
		#module(load="imtcp")
		#input(type="imtcp" port="514")

		# provides kernel logging support and enable non-kernel klog messages
		module(load="imklog" permitnonkernelfacility="on")

		###########################
		#### GLOBAL DIRECTIVES ####
		###########################

		# Use default timestamp format
		$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

		# Use traditional timestamp format.
		# To enable high precision timestamps, comment out the following line.
		$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

		# Filter duplicated messages
		$RepeatedMsgReduction on

		# Reset UMASK
		$Umask 0000

		# Set the default permissions for all log files.
		$FileOwner syslog
		$FileGroup adm
		$FileCreateMode 0640
		$DirCreateMode 0755
		$Umask 0177
		$PrivDropToUser syslog
		$PrivDropToGroup syslog

		# Where to place spool and state files
		$WorkDirectory /var/spool/rsyslog

		# Include all config files in /etc/rsyslog.d/
		$IncludeConfig /etc/rsyslog.d/*.conf

		###############################
		#### Begin Forwarding Rule ####
		###############################
		$PreserveFQDN on
		$ActionQueueFileName queue
		$ActionQueueMaxDiskSpace 1g
		$ActionQueueSaveOnShutdown on
		$ActionQueueType LinkedList
		$ActionResumeRetryCount -1
		# ### The Remote SysLog Server host is: name/ip:port, e.g. 192.168.0.1:514, port optional ###
		#*.* @@syslog

EOF
		echo "
		*.* @@${SYSLOG}:514

		####################################
		#### End of the Forwarding Rule ####
		####################################
			" >> /etc/rsyslog.conf
		sed -i 's/^[\t]*//' /etc/rsyslog.conf
		xargs -n 1 cp -v /etc/rsyslog.d/50-default.conf <<< ""${BACKUP} /etc/rsyslog.d/50-default.conf.bak""
		no_show << "EOF" > /etc/rsyslog.d/50-default.conf
		##################################################################################################
		####     Hardened Rsyslog Configuration File edited to match CIS level 1 requirements         ####
		####      for questions or changles please contact Phil Connor contact@mylinux.work           ####
		##################################################################################################


		###############
		#### RULES ####
		###############

		#  Default rules for rsyslog.
		#
		#                       For more information see rsyslog.conf(5) and /etc/rsyslog.conf

		#
		# First some standard log files.  Log by facility.
		#
		auth,authpriv.*                 /var/log/auth.log
		*.*;auth,authpriv.none          -/var/log/syslog
		#cron.*                         /var/log/cron.log
		#daemon.*                       -/var/log/daemon.log
		kern.*                          -/var/log/kern.log
		#lpr.*                          -/var/log/lpr.log
		mail.*                          -/var/log/mail.log
		#user.*                         -/var/log/user.log

		#
		# Logging for the mail system.  Split it up so that
		# it is easy to write scripts to parse these files.
		#
		#mail.info                      -/var/log/mail.info
		#mail.warn                      -/var/log/mail.warn
		mail.err                        /var/log/mail.err

		#
		# Logging for INN news system.
		#
		news.crit                       /var/log/news/news.crit
		news.err                        /var/log/news/news.err
		news.notice                     -/var/log/news/news.notice

		#
		# Some "catch-all" log files.
		#
		#*.=debug;\
		#       auth,authpriv.none;\
		#       news.none;mail.none     -/var/log/debug
		#*.=info;*.=notice;*.=warn;\
		#       auth,authpriv.none;\
		#       cron,daemon.none;\
		#       mail,news.none          -/var/log/messages

		#
		# Emergencies are sent to everybody logged in.
		#
		*.emerg                                :omusrmsg:*

		#
		# I like to have messages displayed on the console, but only on a virtual
		# console I usually leave idle.
		#
		#daemon,mail.*;\
		#       news.=crit;news.=err;news.=notice;\
		#       *.=debug;*.=info;\
		#       *.=notice;*.=warn       /dev/tty8

		# The named pipe /dev/xconsole is for the `xconsole' utility.  To use it,
		# you must invoke `xconsole' with the `-file' option:
		#
		#    $ xconsole -file /dev/xconsole [...]
		#
		# NOTE: adjust the list below, or you'll go crazy if you have a reasonably
		#      busy site..
		#
		daemon.*;mail.*;\
				news.err;\
				*.=debug;*.=info;\
				*.=notice;*.=warn       |/dev/xconsole                                                        
EOF
		touch /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
		chmod og-rwx /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
		chown root:root /var/log/warn /var/log/news.crit /var/log/news.err /var/log/news.notice /var/log/localmessages
		sed -i 's/*.* @@[[:blank:]]*:514/#*.* @@/g' /etc/rsyslog.conf
		systemctl start rsyslog
		pkill -hup rsyslog
		stop_spinner $?
	} | tee -a $LOG
}

####################################################
#### 4.2.1.2 Ensure Journald Service is enabled ####
####################################################
function journald_config() {
	{
		start_spinner 'Configuring Journald Log Retension...'
		echo ""
		### 4.2.2.1 Ensure journald is configured to send logs to rsyslog ###
		sed -i 's/#ForwardToSyslog=yes/ForwardToSyslog=yes/g' /etc/systemd/journald.conf
		### 4.2.2.2 Ensure journald is configured to compress large log files ###
		sed -i 's/#Compress=yes/Compress=yes/g' /etc/systemd/journald.conf
		### 4.2.2.3 Ensure journald is configured to write logfiles to persistent disk ###
		sed -i 's/#Storage=auto/Storage=persistent/g' /etc/systemd/journald.conf
		stop_spinner $?
	} | tee -a $LOG
}

##################################
#### 4.2.2 Configure journald ####
##################################
function logfile_permissions() {
	{
		start_spinner 'Configuring Permissions on all Logfiles...'
		echo ""
		### 4.2.4 Ensure permissions on all logfiles are configured ###
		find /var/log -type f -exec chmod g-wx,o-rwx {} +
		### 4.3 Ensure logrotate is configured ###
		cp /etc/logrotate.conf $BACKUP
		sed -i 's/    create 0664 root utmp/    create 0640 root utmp/g'  /etc/logrotate.conf
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol ]]; then 
			if [ "${OSVER}" = 8 ]; then
				sed -i 's/    create 0664 root utmp/    create 0640 root utmp/g'  /etc/logrotate.d/btmp
				sed -i 's/    create 0664 root utmp/    create 0640 root utmp/g'  /etc/logrotate.d/wtmp
			fi
		fi
		stop_spinner $?
	} | tee -a $LOG
}

#############################################
#### 5.1.1 Ensure cron daemon is enabled ####
#############################################
function crond_enabled() {
	{
		start_spinner 'Configuring Permissions on Cron Daemon...'
		echo ""
		### 5.1.1.1 Ensure cron daemon is enabled ###
		if [ "${OS}" = ubuntu ]; then
			if ! systemctl is-enabled cron; then
				systemctl enable cron
			fi
		else
			if ! systemctl is-enabled crond; then 
				systemctl enable crond
			fi
		fi
		### Ensure permissions on /etc/crontab are configured ###
		chown root.root /etc/crontab
		chmod og-rwx /etc/crontab
		### 5.1.3 Ensure permissions on /etc/cron.hourly are configured ###
		chown root.root /etc/cron.hourly
		chmod og-rwx /etc/cron.hourly
		### 5.1.4 Ensure permissions on /etc/cron.daily are configured ###
		chown root.root /etc/cron.daily
		chmod og-rwx /etc/cron.daily
		### 5.1.5 Ensure permissions on /etc/cron.weekly are configured ###
		chown root.root /etc/cron.weekly
		chmod og-rwx /etc/cron.weekly
		### 5.1.6 Ensure permissions on ?etc/cron.monthly are configured ###
		chown root.root /etc/cron.monthly
		chmod og-rwx /etc/cron.monthly
		### 5.1.7 Ensure permissions on /etc/cron.d are configured ###
		chown root.root /etc/cron.d
		chmod og-rwx /etc/cron.d
		### 5.1.8 Ensure at/cron is restricted to authorized users ###
		stat /etc/cron.deny
		if [ $? != 1 ]; then
			rm -rf /etc/cron.deny
		fi
		stat /etc/at.deny
		if [ $? != 1 ]; then
			rm -rf /etc/at.deny
		fi
		if ! stat /etc/cron.allow; then
			touch /etc/cron.allow
			chown root.root /etc/cron.allow
			chmod og-rwx /etc/cron.allow
		fi
		if ! stat /etc/at.allow; then
			touch /etc/at.allow
			chown root.root /etc/at.allow
			chmod og-rwx /etc/cron.allow
		fi
		stop_spinner $?
	} | tee -a $LOG
}

######################################
#### 5.2 SSH Server Configuration ####
######################################
function config_sshd() {
	{
		start_spinner 'Configuring SSh Server...'
		echo ""
		### 5.2.1 Ensure permissions on /etc/ssh/sshd_config are configured ###
		xargs -n 1 cp -v ${SSHD_FILE} <<< ""${BACKUP} ${SSHD_FILE}.bak""
		chown root.root ${SSHD_FILE}
		chmod og-rwx ${SSHD_FILE}
		### 5.2.2. SSH Protocol 2 is the only supported protocol in modern OpenSSH ###
		sed -i '/^Protocol /d' ${SSHD_FILE}
		sed -i '/^#Protocol /d' ${SSHD_FILE}
		### 5.2.3 Ensure SSH LogLevel is set to info ###
		if ! grep -qi "LogLevel INFO" ${SSHD_FILE}; then
			echo "LogLevel INFO" >> ${SSHD_FILE}
		else
			sed -i 's/#LogLevel INFO/LogLevel INFO/g' ${SSHD_FILE}
		fi	
		### 5.2.4 Ensure SSH X11 forwarding is disabled ###
		if ! grep -qi "X11Forwarding yes" ${SSHD_FILE}; then
			echo "X11Forwarding no" >> ${SSHD_FILE}
		else
			sed -i 's/X11Forwarding yes/X11Forwarding no/g' ${SSHD_FILE}
		fi
		### 5.2.5 Ensure SSH MaxAuthTries is set to 4 or less ###
		if ! grep -qi "MaxAuthTries 6" ${SSHD_FILE}; then
			echo "MaxAuthTries 4" >> ${SSHD_FILE}
		else
			sed -i 's/#MaxAuthTries 6/MaxAuthTries 4/g' ${SSHD_FILE}
		fi
		### 5.2.6 Ensure SSH IgnoreRhosts is enabled ###
		if ! grep -qi "IgnoreRhosts yes" ${SSHD_FILE}; then
			echo "IgnoreRhosts yes" >> ${SSHD_FILE}
		else
			sed -i 's/#IgnoreRhosts yes/IgnoreRhosts yes/g' ${SSHD_FILE}
		fi
		### 5.2.7 Ensure SSH HostbasedAuthentication is disabled ###
		if ! grep -qi "HostbasedAuthentication no" ${SSHD_FILE}; then
			echo "HostbasedAuthentication no" >> ${SSHD_FILE}
		else
			sed -i 's/#HostbasedAuthentication no/HostbasedAuthentication no/g' ${SSHD_FILE}
		fi
		### 5.2.8 Ensure SSH root login is disabled ###
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol ]]; then
			if ! grep -qi "#PermitRootLogin" ${SSHD_FILE}; then
				sed -i 's/PermitRootLogin yes/PermitRootLogin no/g' ${SSHD_FILE}
			else
				sed -i 's/#PermitRootLogin yes/PermitRootLogin no/g' ${SSHD_FILE}
			fi
		elif [ "${OS}" = ubuntu ]; then
			if ! grep -qi "prohibit-password" ${SSHD_FILE}; then
				sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin no/g' ${SSHD_FILE}
			fi
		fi
		### Ensure SSH PermitEmptyPasswords is disabled ###
		sed -i 's/#PermitEmptyPasswords no/PermitEmptyPasswords no/g' ${SSHD_FILE}
		### 5.2.10 Ensure SSH PermitUserEnvironment is disables ###
		if ! grep -qi "#PermitUserEnvironment" ${SSHD_FILE}; then
			echo "PermitUserEnvironment no" >> ${SSHD_FILE}
		else
			sed -i 's/#PermitUserEnvironment no/PermitUserEnvironment no/g' ${SSHD_FILE}
		fi
		### 5.2.11 Ensure ony approved MAC algorithms are used ###
			if ! grep -qi "MACs" ${SSHD_FILE}; then
			echo "MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256" >> ${SSHD_FILE}
		else
			sed -i 's/MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com/MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256/g' ${SSHD_FILE}
		fi
		if ! grep -qi "#ClientAliveInterval" ${SSHD_FILE}; then
			echo "ClientAliveInterval 300" >> ${SSHD_FILE}
		else
			sed -i 's/#ClientAliveInterval 0/ClientAliveInterval 300/g' ${SSHD_FILE}
		fi
		if ! grep -qi "#ClientAliveCountMax" ${SSHD_FILE}; then
			echo "ClientAliveCountMax ${MAXCOUNT}" >> ${SSHD_FILE}
		else
			sed -i "s/#ClientAliveCountMax 3/ClientAliveCountMax \"${MAXCOUNT}\"/g" ${SSHD_FILE}
		fi
		### 5.2.13 Ensure SSH LoginGraceTime is set to one minute or less ###
		if ! grep -qi "LoginGraceTime 120" ${SSHD_FILE}; then
			sed -i 's/#LoginGraceTime 2m/LoginGraceTime 60/g' ${SSHD_FILE}
		else
			sed -i 's/LoginGraceTime 120/LoginGraceTime 60/g' ${SSHD_FILE}
		fi
		### 5.2.14 Ensure SSH access is limited ###
		### 5.2.15 Ensure SSH warning banner is configured ###
		if ! grep -qi "#Banner none" ${SSHD_FILE}; then
			sed -i 's/#Banner \/etc\/issue.net/Banner \/etc\/issue.net/g' ${SSHD_FILE}
		else
			sed -i 's/#Banner none/Banner \/etc\/issue.net/g' ${SSHD_FILE}
		fi
		### 5.2.16 Ensure only strong Key Exchange algorithms are used ###
		if ! grep -qi "kexalgorithms" ${SSHD_FILE}; then
			echo "KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256" >> ${SSHD_FILE}
		fi
		### 5.2.21 Ensure SSH MaxStartups is configured ###
		if ! grep -qi "maxstartups" ${SSHD_FILE}; then
			echo "MaxStartups 10:30:60" >> ${SSHD_FILE}
		else 
			sed -i 's/#MaxStartups 10:30:100/MaxStartups 10:30:60/g' ${SSHD_FILE}
		fi
		### Configuring additional SSH settings ###
		if ! grep -qi "#MaxSessions" ${SSHD_FILE}; then
			echo "MaxSessions 2" >> ${SSHD_FILE}
		else
			sed -i 's/#MaxSessions 10/MaxSessions 2/g' ${SSHD_FILE}
		fi
		if ! grep -qi "#AllowAgentForwarding" ${SSHD_FILE}; then
			echo "AllowAgentForwarding no" >> ${SSHD_FILE}
		else
			sed -i 's/#AllowAgentForwarding yes/AllowAgentForwarding no/g' ${SSHD_FILE}
		fi
		if ! grep -qi "#AllowTcpForwarding" ${SSHD_FILE}; then
			echo "AllowTcpForwarding no" >> ${SSHD_FILE}
		else
			sed -i 's/#AllowTcpForwarding yes/AllowTcpForwarding no/g' ${SSHD_FILE}
		fi
		sed -i 's/#PrintMotd yes/PrintMotd no/g' ${SSHD_FILE}
		if ! grep -qi "PrintLastLog" ${SSHD_FILE}; then
			echo "PrintLastLog no" >> ${SSHD_FILE}
		else
			sed -i 's/#PrintLastLog yes/PrintLastLog no/g' ${SSHD_FILE}
		fi
		if ! grep -qi "TCPKeepAlive" ${SSHD_FILE}; then
			sed -i 's/TCPKeepAlive yes/TCPKeepAlive no/g' ${SSHD_FILE}
		else
			sed -i 's/#TCPKeepAlive yes/TCPKeepAlive no/g' ${SSHD_FILE}
		fi
		if ! grep -qi "Compression" ${SSHD_FILE}; then 
			echo "Compression no" >> ${SSHD_FILE}
		else
			sed -i 's/#Compression delayed/Compression no/g' ${SSHD_FILE}
		fi
		if ! grep -qi "UseDNS" ${SSHD_FILE}; then
			echo "UseDNS no" >> ${SSHD_FILE}
		else
			sed -i 's/#UseDNS yes/UseDNS no/g' ${SSHD_FILE}
			sed -i 's/#UseDNS no/UseDNS no/g' ${SSHD_FILE}
		fi
		if ! grep -qi "#PasswordAuthentication" ${SSHD_FILE}; then
			sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/g' ${SSHD_FILE}
		else
			sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' ${SSHD_FILE}
		fi
		echo 'Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr' >> ${SSHD_FILE}
		if [ "${OS}" = ubuntu ]; then
			systemctl restart ssh
		else
			systemctl restart sshd
		fi
		stop_spinner $?
		} | tee -a $LOG
}

###########################
#### 5.3 Configure PAM ####
###########################
function config_pam() {
	{
		start_spinner 'Configuring PAM Server...'
		echo ""
		### 5.3.1 Ensure password creation requirements are configured ###
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol ]]; then
			xargs -n 1 cp -v /etc/security/pwquality.conf <<< ""${BACKUP} /etc/security/pwquality.conf.bak""
			sed -i 's/minlen = 8/minlen = 14/g' /etc/security/pwquality.conf
			### 5.3.2 Ensure lockout for failed password attempts is configured ###
			xargs -n 1 cp -v /etc/pam.d/password-auth <<< ""${BACKUP} /etc/pam.d/password-auth.bak""
			no_show << EOF > /etc/pam.d/password-auth
			########################################################################################
			#### This password-auth file edited to match CIS level 1 requirements for questions ####
			####    or changes please contact Phil Connor contact@mylinux.work   #### 
			####             Please don't edit it unless you know what your doing               ####
			########################################################################################
			#%PAM-1.0
			# User changes will be destroyed the next time authconfig is run.
			auth        required      pam_env.so
			auth        required      pam_faildelay.so delay=2000000
			auth        required      pam_faillock.so preauth audit silent deny=5 unlock_time=900
			auth   [success=1 default=bad] pam_unix.so
			auth        sufficient    pam_fprintd.so
			auth        sufficient    pam_unix.so nullok try_first_pass
			auth      [default=die]   pam_faillock.so authfail audit deny=5 unlock_time=900
			auth        sufficient    pam_faillock.so authsucc audit deny=5 unlock_time=900
			auth        requisite     pam_succeed_if.so uid >= 1000 quiet_success
			auth        required      pam_deny.so

			account     required      pam_unix.so
			account     sufficient    pam_localuser.so
			account     sufficient    pam_succeed_if.so uid < 1000 quiet
			account     required      pam_permit.so
			account     required      pam_faillock.so

			password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= enforce_for_root
			password    required      pam_pwhistory.so remember=5 use_authlok
			password    sufficient    pam_unix.so remember=5 sha512 shadow try_first_pass use_authtok
			password    required      pam_deny.so

			session     optional      pam_keyinit.so revoke
			session     required      pam_limits.so
			-session     optional      pam_systemd.so
			session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
			session     required      pam_unix.so
			##########################################
			#### Logging key strokes of all USERS ####
			##########################################
			session     required      pam_tty_audit.so disable=*  enable=* log_passwd
EOF
			xargs -n 1 cp -v /etc/pam.d/system-auth <<< ""${BACKUP} /etc/pam.d/system-auth.bak""
			no_show << EOF > /etc/pam.d/system-auth
			######################################################################################
			#### This system-auth file edited to match CIS level 1 requirements for questions ####
			####   or changes please contact Phil Connor contact@mylinux.work  #### 
			####            Please don't edit it unless you know what your doing              ####
			######################################################################################
			#%PAM-1.0
			# User changes will be destroyed the next time authconfig is run.
			auth        required      pam_env.so
			auth        required      pam_faildelay.so delay=2000000
			auth        required      pam_faillock.so preauth audit silent deny=5 unlock_time=900
			auth   [success=1 default=bad] pam_unix.so
			auth        sufficient    pam_fprintd.so
			auth        sufficient    pam_unix.so nullok try_first_pass
			auth      [default=die]   pam_faillock.so authfail audit deny=5 unlock_time=900
			auth        sufficient    pam_faillock.so authsucc audit deny=5 unlock_time=900
			auth        requisite     pam_succeed_if.so uid >= 1000 quiet_success
			auth        required      pam_deny.so

			account     required      pam_unix.so
			account     sufficient    pam_localuser.so
			account     sufficient    pam_succeed_if.so uid < 1000 quiet
			account     required      pam_permit.so
			account     required      pam_faillock.so

			password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= enforce_for_root
			password    required      pam_pwhistory.so remember=5 use_authlok
			password    sufficient    pam_unix.so remember=5 sha512 shadow try_first_pass use_authtok
			password    required      pam_deny.so

			session     optional      pam_keyinit.so revoke
			session     required      pam_limits.so
			-session     optional      pam_systemd.so
			session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
			session     required      pam_unix.so
			##########################################
			#### Logging key strokes of all USERS ####
			##########################################
			session     required      pam_tty_audit.so disable=*  enable=* log_passwd
EOF
		fi
		if [ "${OS}" = ubuntu ]; then 
			debconf-set-selections <<< ""postfix postfix/mailname string "${HOSTNAME}"""
			debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'"
			${PAKMGR} remove libpam-cracklib
			${PAKMGR} install libpam-pwquality --assume-yes
			xargs -n 1 cp -v /etc/pam.d/common-password<<< ""${BACKUP} /etc/pam.d/common-password.bak""  
			#sed -i 's/password[[:blank:]]*requisite[[:blank:]]*pam_pwquality.so retry=3/password	requisite			pam_pwquality.so retry=3 difok=3 reject_username enforce_for_root/g' /etc/pam.d/common-password
			sed -i 's/# minlen = 8/minlen = 14/g' /etc/security/pwquality.conf
			sed -i 's/# dcredit = 0/dcredit=-1/g' /etc/security/pwquality.conf
			sed -i 's/# ucredit = 0/ucredit=-1/g' /etc/security/pwquality.conf
			sed -i 's/# ocredit = 0/ocredit=-1/g' /etc/security/pwquality.conf
			sed -i 's/# lcredit = 0/lcredit=-1/g' /etc/security/pwquality.conf
			no_show << EOF >> /etc/pam.d/common-password
			################################################
			#### 5.3.3 Ensure password reuse is limited ####
			################################################     
			password        required                         pam_unix.so remember=5
			
EOF
			no_show << EOF >> /etc/pam.d/common-auth
			#########################################################################
			#### 5.3.2 Ensure lockout for failed password attempts is configured ####
			#########################################################################       
			auth    required                        pam_faillock.so preauth audit silent deny=5 unlock_time=900
			auth    [default=die]                   pam_faillock.so authfail audit deny=5 unlock_time=900

			##########################################
			#### Logging key strokes of all USERS ####
			##########################################
			session     required      pam_tty_audit.so disable=*  enable=* log_passwd
EOF
		fi
		stop_spinner $?
	} | tee -a $LOG
}

############################################
#### 5.4 User Accounts and Environments ####
############################################
function accounts() {
	{
		start_spinner 'Configuring User Accts and Environments...'
		echo ""
		LODEFS="/etc/login.defs"
		#### 5.4.1.1 Ensure password expiration is 90 days or less ####
		#### 5.4.1.2 Ensure minimum days between password changes is 7 days or more ####
		#### 5.4.1.3 Ensure password expiration warning days is 7 or more ####
		if [ -e ${LODEFS} ]; then
		cp ${LODEFS} ${LODEFS}.tmp
		awk '($1 ~ /^PASS_MAX_DAYS/) { $2="90" }
			($1 ~ /^PASS_MIN_DAYS/) { $2="7" }
			($1 ~ /^PASS_WARN_AGE/) { $2="10" }
			($1 ~ /^PASS_MIN_LEN/)  { $2="14" }
			{ print }' ${LODEFS}.tmp > ${LODEFS}
		rm ${LODEFS}.tmp
		fi
		cut -d: -f1 /etc/passwd | while read -r NAME
		do
			uid=$(id -u "${NAME}")
			if [ "${uid}" -ge 1000 ] && [ "${uid}" != 65534 ]; then
				chage -M 90 -m 7 -W 10 -I 30 "${NAME}"
			fi
		done
		if [ "${OS}" = ubuntu ]; then
			no_show << EOF >> ${LODEFS}
			##################################################################
			#### Make it More Difficult to Bruteforce the Hashed Password ####
			##################################################################
			SHA_CRYPT_MIN_ROUNDS 5000
			SHA_CRYPT_MAX_ROUNDS 10000
EOF
			sed -i 's/pam_faildelay.so  delay=3000000/pam_faildelay.so  delay=300000000/g' /etc/pam.d/login
		else	
			no_show << EOF >> ${LODEFS}
			############################################################################
			#### Establish a forced five-second minimum delay between failed logins ####
			############################################################################
			FAIL_DELAY 5
			
			##################################################################
			#### Make it More Difficult to Bruteforce the Hashed Password ####
			##################################################################
			SHA_CRYPT_MIN_ROUNDS 5000
			SHA_CRYPT_MAX_ROUNDS 10000
EOF
		fi
		chown root:root ${LODEFS}
		chmod 0640 ${LODEFS}
		#### 5.4.1.4 Ensure inactive password lock is 30 days or less ####
		useradd -D -f 30
		stop_spinner $?
	} | tee -a $LOG
}

######################################################
#### 5.4 User Accounts and Environments Continued ####
######################################################
function config_users_permissions() {
	{
		start_spinner 'Configuring User Permissions...'
		echo ""
		#### 5.4.2 Ensure system accounts are non-login ####
		awk -F: '($3 < 1000) {print $1 }' /etc/passwd | while read -r user 
		do
			if [ "$user" != "root" ]; then
				usermod -L "$user"
				if [ "$user" != "sync" ] && [ "$user" != "shutdown" ] && [ "$user" != "halt" ]; then
					usermod -s /usr/sbin/nologin "$user"
				fi
			fi
		done
		#### 5.4.3 Ensure default group for the root account is GID 0 ####
		usermod -g 0 root
		groupadd dev
		groupadd dba
		touch /etc/sudoers.d/cis_conf
		chmod 440 /etc/sudoers.d/cis_conf
		if [ "${OS}" = ubuntu ]; then
			sed -i 's/sudo:x:27:/sudo:x:27:root,ubuntu/g' /etc/group
			sed -i 's/sudo:*::/sudo:*::root,ubuntu/g' /etc/gshadow
			sed -i 's/%sudo[[:blank:]]*ALL=(ALL:ALL)[[:blank:]]*ALL/%sudo    ALL=\(ALL:ALL\) NOPASSWD:ALL/g' /etc/sudoers
		else
			grep -qi "wheel" /etc/group  
			if [ $? != 1 ]; then
				sed -i 's/%wheel[[:blank:]]*ALL=(ALL)[[:blank:]]*ALL/# %wheel        ALL=\(ALL\)       ALL/g' /etc/sudoers
				sed -i 's/^#\s*\(%wheel\s*ALL=(ALL)\s*NOPASSWD:\s*ALL\)/\1/' /etc/sudoers
				sed -i 's/wheel:x:10:opc/wheel:x:10:root,opc/g' /etc/group
				sed -i 's/wheel:::opc/wheel:::root,opc/g' /etc/gshadow
			fi
		fi
		{
		echo "####################"	
		echo "#### Networking ####" 
		echo "####################"
		} >> /etc/sudoers.d/local_conf
		if [ "${OS}" = ubuntu ]; then
			{
			echo "Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /sbin/iptables, /sbin/mii-tool" 
			echo ""
			} >> /etc/sudoers.d/local_conf
		else
			{
			echo "Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /usr/bin/net, /sbin/iptables, /usr/bin/rfcomm, /usr/bin/wvdial, /sbin/iwconfig, /sbin/mii-tool" 
			echo ""
			} >> /etc/sudoers.d/local_conf
		fi
		{
		echo "#################################################" 
		echo "#### Installation and management of software ####" 
		echo "#################################################"
		} >> /etc/sudoers.d/cis_conf 
		if [ "${OS}" = ubuntu ]; then
			{
			echo "Cmnd_Alias SOFTWARE = usr/bin/apt, /usr/bin/dpkg, /usr/bin/apt-get" 
			echo ""
			} >> /etc/sudoers.d/local_conf
		else
			{
			echo "Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum" 
			echo ""
			} >> /etc/sudoers.d/local_conf
		fi
		{
			echo "##################"
			echo "#### Services ####"
			echo "##################"
			echo "Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig, /usr/bin/systemctl start, /usr/bin/systemctl stop, /usr/bin/systemctl reload, /usr/bin/systemctl restart, /usr/bin/systemctl status, /usr/bin/systemctl enable, /usr/bin/systemctl disable"
			echo ""
			echo "######################################"
			echo "#### Updating the locate database ####"
			echo "######################################"
			echo "Cmnd_Alias LOCATE = /usr/bin/updatedb"
			echo ""
			echo "#################"
			echo "#### Storage ####"
			echo "#################"		
			echo "Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, /sbin/partprobe, /bin/mount, /bin/umount"
			echo ""
			echo "################################"
			echo "#### Delegating permissions ####"
			echo "################################"
			echo "Cmnd_Alias DELEGATING = /usr/sbin/visudo, /bin/chown, /bin/chmod, /bin/chgrp"
			echo ""
			echo "###################"
			echo "#### Processes ####"
			echo "###################"
			echo "Cmnd_Alias PROCESSES = /bin/nice, /bin/kill, /usr/bin/kill, /usr/bin/killall"
			echo ""
			echo "#################"
			echo "#### Drivers ####"
			echo "#################"
			echo "Cmnd_Alias DRIVERS = /sbin/modprobe"
			echo ""
			echo "###########################################################################"
			echo "#### Reboot and ShutDown removed from DBA's and Developers 3/4/20 - PC ####"
			echo "###########################################################################"
			echo "Cmnd_Alias SHUTDOWN = /sbin/shutdown, /sbin/reboot, /sbin/halt, /sbin/poweroff"
			echo ""
			echo "###########################"
			echo "#### Our System Groups ####"
			echo "###########################"
			echo "%dba    ALL= NOPASSWD: /usr/bin/su - applmgr, /usr/bin/su - oracle, !NETWORKING, !SOFTWARE, !SERVICES, !STORAGE, !DELEGATING, !PROCESSES, !LOCATE, !DRIVERS, !SHUTDOWN"
			echo "%dev    ALL= NOPASSWD: /usr/bin/su - applmgr, !NETWORKING, !SOFTWARE, !SERVICES, !STORAGE, !DELEGATING, !PROCESSES, !LOCATE, !DRIVERS, !SHUTDOWN"
		} >> /etc/sudoers.d/local_conf
		#### 5.4.4 Ensure default user umask is 027 or more restrictive ####
		if [ "${OS}" = "ubuntu" ]; then 
			grep -Eq "^(\s*)umask\s+\S+(\s*#.*)?\s*$" /etc/bash.bashrc && sed -ri "s/^(\s*)umask\s+\S+(\s*#.*)?\s*$/\1umask 027\2/" /etc/bash.bashrc || echo "umask 027" >> /etc/bash.bashrc
		else	
			grep -Eq "^(\s*)umask\s+\S+(\s*#.*)?\s*$" /etc/bashrc && sed -ri "s/^(\s*)umask\s+\S+(\s*#.*)?\s*$/\1umask 027\2/" /etc/bashrc || echo "umask 027" >> /etc/bashrc
		fi
		grep -Eq "^(\s*)umask\s+\S+(\s*#.*)?\s*$" /etc/profile && sed -ri "s/^(\s*)umask\s+\S+(\s*#.*)?\s*$/\1umask 027\2/" /etc/profile || echo "umask 027" >> /etc/profile
		#### 5.4.5 Ensure default user shell timeout is 900 seconds or less ####
		if grep TMOUT=900 /etc/bashrc; then
			sed -i 's/TMOUT=900/#TMOUT=900/g' /etc/bashrc
		fi

		if grep TMOUT=900 /etc/profile; then
			sed -i 's/TMOUT=900/#TMOUT=900/g' /etc/profile
		fi
		cat >> /etc/profile << 'EOF'
		if [ "$(id -nu)" == "root" ] || [ "$(id -nu)" == "opc" ]; then
			TMOUT=3600
			readonly TMOUT
			export TMOUT
		else
			TMOUT=900
			readonly TMOUT
			export TMOUT
		fi
EOF
		cat >> /etc/bashrc << 'EOF'
		if [ "$(id -nu)" == "root" ] || [ "$(id -nu)" == "opc" ]; then
			if ! echo $TMOUT | grep -q 3600; then
				TMOUT=3600
				readonly TMOUT
				export TMOUT
			fi
		else
			if ! echo $TMOUT | grep -q 900; then
				TMOUT=900
				readonly TMOUT
				export TMOUT
			fi
		fi
EOF
		#### 5.4.5A Ensure default user umask is configured - system wide ####
		sed -ri 's/^([^#]+\s+)?(umask\s+)(\S+\s*)(\s+.*)?$/\1\2 027\4/' /etc/login.defs
		sed -ri 's/^([^#]+\s+)?(umask\s+)(\S+\s*)(\s+.*)?$/\1\2 027\4/' /etc/profile
		sed -ri 's/^([^#]+\s+)?(umask\s+)(\S+\s*)(\s+.*)?$/\1\2 027\4/' /etc/bashrc
		touch /etc/profile.d/cis_profile.sh
		chmod 644 /etc/profile.d/cis_profile.sh
		echo "
		################################
		### Added for CIS Compliance ###
		################################
		umask 077
			" > /etc/profile.d/cis_profile.sh
		#### 5.5 Ensure root login is restricted to system console ####
		xargs -n 1 cp -v /etc/securetty <<< ""${BACKUP} /etc/securetty.bak""
		echo "console" > /etc/securetty
		### 5.6 Ensure access to the su command is restricted ###
		PAMSU="/etc/pam.d/su"
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol ]]; then
			xargs -n 1 cp -v ${PAMSU} <<< ""${BACKUP} ${PAMSU}.bak""
			if [ -e ${PAMSU} ]; then
				cp ${PAMSU} ${PAMSU}.tmp
				awk '( $1=="#auth" && $2=="required" && $3~"pam_wheel.so" ) { print "auth\t\trequired\t",$3,"\tuse_uid"; next };
					{ print }' ${PAMSU}.tmp > ${PAMSU}
				chown root:root ${PAMSU}
				chmod 0644 ${PAMSU}
				rm ${PAMSU}.tmp
			fi
		elif [ "${OS}" = ubuntu ]; then
			sed -i 's/# auth[[:blank:]]*required[[:blank:]]*pam_wheel.so/auth        required    pam_wheel.so use_uid/g' /etc/pam.d/su
			sed -i 's/auth        required    pam_wheel.so use_uid deny group=nosu/#auth        required    pam_wheel.so deny group=nosu/g' /etc/pam.d/su
		fi
		stop_spinner $?
	} | tee -a $LOG
}

################################
#### 6.1 System Permissions ####
################################
function audit_file_permissions() {
	{
		start_spinner 'Auditing File Permissions...'
		echo ""
		### 6.1.1 Audit system file permissions ###
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol ]]; then
			rpm -Va --nomtime --nosize --nomd5 --nolinkto
		elif [ "${OS}" = ubuntu ]; then 
			${PAKMGR} install debsums
			debsums -s
		fi
		### 6.1.2 Ensure permissions on /etc/passwd are configured ###
		chmod 644 /etc/passwd
		chown root.root /etc/passwd
		### 6.1.3 Ensure permissions on /etc/shadow are configured ###
		chmod 000 /etc/shadow
		chown root.root /etc/shadow
		### 6.1.4 Ensure permissions on /etc/group are configured ###
		chmod 644 /etc/group
		chown root.root /etc/group
		### 6.1.5 Ensure permissions on /etc/gshadow are configured ###
		chmod 000 /etc/gshadow
		chown root:root /etc/gshadow
		### 6.1.6 Ensure permissions on /etc/passwd- are configured ###
		chmod 644 /etc/passwd-
		chown root.root /etc/passwd-
		### 6.1.7 Ensure permissions on /etc/shadow- are configured ###
		chmod 000 /etc/shadow-
		chown root.root /etc/shadow-
		### 6.1.4 Ensure permissions on /etc/group- are configured ###
		chmod 644 /etc/group-
		chown root.root /etc/group-
		### 6.1.5 Ensure permissions on /etc/gshadow- are configured ###
		chmod 000 /etc/gshadow-
		chown root:root /etc/gshadow-
		stop_spinner $?
	} | tee -a $LOG
}

####################################
#### 6.1.1 World Writable Files ####
####################################
function world_writable_files() {
	{
		start_spinner 'Resetting Permissions on all World Writable, Unowned and Ungrouped Files...'
		echo ""
		#### 6.1.10 Ensure no world writable files exist ####
		df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -0002 
		#### 6.1.11 Ensure no unowned files or directories exist ####
		df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -nouser -ls 
		#### 6.1.12 Ensure no ungrouped files or directories exist ####
		df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -nogroup -ls 
		#### 6.1.12 Audit SUID executables ####
		df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -4000 -print 
		#### 6.1.14 Audit SGID executables ####
		df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type f -perm -2000 -print
		stop_spinner $?
	} | tee -a $LOG
}

#####################################
#### 6.2 User and Group Settings ####
#####################################
function user_group_settings() {
	{
		start_spinner 'Configuring User and Group Settings...'
		echo ""
		#### 6.2.1 Ensure password fields are not empty ####
		awk -F: '($2 == "" ) { print $1 " does not have a password "}' /etc/shadow
		#### 6.2.2 Ensure no legacy "+" entries exist in /etc/passwd ####
		grep '^+:' /etc/passwd
		#### 6.2.3 Ensure no legacy "+" entries exist in /etc/shadow ####
		grep '^+:' /etc/shadow
		#### 6.2.4 Ensure no legacy "+" entries exist in /etc/group ####
		grep '^+:' /etc/group
		#### 6.2.5 Ensure root is the only UID 0 account ####
		awk -F: '($3 == 0) { print $1 }' /etc/passwd
		#### 6.2.6 Ensure root PATH Intergrity ####
		if [ "$(echo "$PATH" | grep ::)" != "" ]; then
			echo "Empty Directory in PATH (::)"
		fi
		if [ "$(echo "$PATH" | grep :$)"  != "" ]; then
			echo "Trailing : in PATH"
		fi
		p=$(echo "$PATH" | sed -e 's/::/:/' -e 's/:$//' -e 's/:/ /g')
		set -- "$p"
		while [ "$1" != "" ]; 
		do
			if [ "$1" = "." ]; then
				echo "PATH contains ."
				shift
				continue
			fi
			if [ -d "$1" ]; then
				# shellcheck disable=SC2012
				dirperm=$(ls -ldH "$1" | cut -f1 -d" ")
				if [ "$(echo "${dirperm}" | cut -c6)" != "-" ]; then
					echo "Group Write permission set on directory $1"
				fi
				if [ "$(echo "${dirperm}" | cut -c9)" != "-" ]; then
					echo "Other Write permission set on directory $1"
				fi
				# shellcheck disable=SC2012
				dirown=$(ls -ldH "$1" | awk '{print $3}')
				if [ "${dirown}" != "root" ] ; then
					echo "$1 is not owned by root"
				fi
				else
					echo "$1 is not a directory"
			fi
		shift
		done
		stop_spinner $?
	} | tee -a $LOG
}

########################################################
#### 6.2 User and Group Settings Continued - Part 1 ####
########################################################
function home_directories() {
	{
		start_spinner 'Checking and Configuring User Directories...'
		echo ""
		#### 6.2.7 Ensure all users' home directories exist ####
		awk -F: '{ print $1 " " $3 " " $6 }' /etc/passwd | while read -r user uid dir 
		do
			if [ "${uid}" -ge 500 ] && [ -d "${dir}" ] && [ "${user}" != "nfsnobody" ]; then
				owner=$(stat -L -c "%U" "${dir}")
				if [ "${owner}" != "${user}" ]; then
					echo "The home directory (${dir}) of user ${user} is owned by ${owner}."
				fi
			fi
		done
		#### 6.2.8 Ensure users' home directories permissions are 750 or more restrictive ####
		grep -Ev '(root|halt|sync|shutdown)' /etc/passwd | awk -F: '($8 == "PS" && $7 != "/sbin/nologin") { print $6 }' | while read -r dir 
		do
			# shellcheck disable=SC2012
			dirperm=$(ls -ld "${dir}" | cut -f1 -d" ")
			if [ "$( echo "${dirperm}" | cut -c6 )" != "-" ]; then
				echo "Group Write permission set on directory $dir"
			fi
			if [ "$( echo "${dirperm}" | cut -c8 )" != "-" ]; then
				echo "Other Read permission set on directory $dir"
			fi
			if [ "$( echo "${dirperm}" | cut -c9 )" != "-" ]; then
				echo "Other Write permission set on directory $dir"
			fi
			if [ "$( echo "${dirperm}" | cut -c10 )" != "-" ]; then
				echo "Other Execute permission set on directory $dir"
			fi
		done
		#### 6.2.9 Ensure users own their home directories ####
		awk -F: '{ print $1 " " $3 " " $6 }' /etc/passwd | while read -r user uid dir 
		do
			if [ "$uid" -ge 500 ] && [ ! -d "$dir" ] && [ "$user" != "nfsnobody" ]; then
				echo "The home directory ($dir) of user $user does not exist."
			fi
		done
		stop_spinner $?
	} | tee -a $LOG
}

########################################################
#### 6.2 User and Group Settings Continued - Part 2 ####
########################################################
function dot_files() {
	{
		start_spinner 'Checking and Configuring Hidden Files and Directories...'
		echo ""
		#### 6.2.10 Ensure users' dot files are not group or world writable ####
		grep -Ev '(root|sync|halt|shutdown)' /etc/passwd | awk -F: '($7 != "/sbin/nologin") { print $6 }' | while read -r dir
		do
			for file in "$dir"/.[A-Za-z0-9]* 
			do
				if [ ! -h "${file}" ] && [ -f "${file}" ]; then
					# shellcheck disable=SC2012
					fileperm=$(ls -ld "$file" | cut -f1 -d" ")
					if [ "$(echo "$fileperm" | cut -c6 )" != "-" ]; then
						echo "Group Write permission set on file $file"
					fi
					if [ "$(echo "$fileperm" | cut -c9 )" != "-" ]; then
						echo "Other Write permission set on file $file"
					fi
				fi
			done
		done
		awk -F: '($3 >= 500) { print $6 }' /etc/passwd | while read -r DIR
		do
			for FILE in "$DIR"/.[A-Za-z0-9]*
			do
				if [ ! -h "$FILE" ] && [ -f "$FILE" ]; then
					chmod go-w "$FILE"
				fi
			done
		done
		#### 6.2.11 Ensure no users have .forward files ####
		awk -F: '{ print $6 }' /etc/passwd | while read -r dir 
		do
			if [ ! -h "$dir/.forward" ] && [ -f "$dir/.forward" ]; then
				echo ".forward file $dir/.forward exists"
			fi
		done
		#### 6.2.12 Ensure no users have .netrc files ####
		awk -F: '{ print $6 }' /etc/passwd | while read -r dir 
		do
			if [ ! -h "$dir/.netrc" ] && [ -f "$dir/.netrc" ]; then
				echo ".netrc file $dir/.netrc exists"
			fi
		done
		#### Ensure users' .netrc Files are not group or world accessible ####
		grep -Ev '(root|halt|sync|shutdown)' /etc/passwd | awk -F: '($7 != "/sbin/nologin") { print $6 }' | while read -r dir 
		do
			for file in $dir/.netrc 
			do
				if [ ! -h "$file" ] && [ -f "$file" ]; then
					# shellcheck disable=SC2012
					fileperm=$(ls -ld "$file" | cut -f1 -d" ")
					if [ "$(echo "$fileperm" | cut -c5 )" != "-" ]; then
						echo "Group Read set on $file"
					fi
					if [ "$(echo "$fileperm" | cut -c6 )" != "-" ]; then
						echo "Group Write set on $file"
					fi
					if [ "$(echo "$fileperm" | cut -c7 )" != "-" ]; then
						echo "Group Execute set on $file"
					fi
					if [ "$(echo "$fileperm" | cut -c8 )" != "-" ]; then
						echo "Other Read  set on $file" 
					fi
					if [ "$(echo "$fileperm" | cut -c9 )" != "-" ]; then
						echo "Other Write set on $file"
					fi
					if [ "$(echo "$fileperm" | cut -c10 )" != "-" ]; then
						echo "Other Execute set on $file"
					fi
				fi	
			done
		done
		#### Ensure no users have .rhosts files ####
		grep -Ev '(root|halt|sync|shutdown)' /etc/passwd | awk -F: '($7 != "/sbin/nologin") { print $6 }' | while read -r dir 
		do
			for file in $dir/.rhosts; do
				if [ ! -h "$file" ] && [ -f "$file" ]; then
					echo ".rhosts file in $dir" 
				fi
			done
		done
		stop_spinner $?
	} | tee -a $LOG
}

########################################################
#### 6.2 User and Group Settings Continued - Part 3 ####
########################################################
function group_gid_uid() {
	{
		start_spinner 'Checking that all Group and UserIDs are valid...'
		echo ""
		#### Ensure all groups in etc/passwd exist in /etc/group ####
		cut -s -d: -f4 /etc/passwd | sort -u | while read -r i
		do
			if ! grep -q -P "^.*?:x:$i:" /etc/group; then
				echo "Group $i is referenced by /etc/passwd but does not exist in /etc/group" 
			fi
		done
		#### Ensure no duplicate UIDs exist ####
		cut -f3 -d":" /etc/passwd | sort -n | uniq -c | while read -r x  
		do
			[ -z "${x}" ] && break
			# shellcheck disable=SC2086
			set - ${x}
			if [ "$1" -gt 1 ]; then
				users=$(awk -F: '($3 == n) { print $1 }' n="$2" /etc/passwd | xargs)
				echo "Duplicate UID ($2): ${users}" 
			fi
		done
		#### 6.2.17 Ensure no duplicate GIDs exist ####
		cut -f3 -d":" /etc/group | sort -n | uniq -c | while read -r x  
		do
			[ -z "${x}" ] && break
			# shellcheck disable=SC2086
			set - ${x}
			if [ "$1" -gt 1 ]; then
				grps=$(gawk -F: '($3 == n) { print $1 }' n="$2" /etc/group | xargs)
				echo "Duplicate GID ($2): ${grps}" >> ${LOG} 2>&1
			fi
		done
		#### 6.2.18 Ensure no duplicate user names exist ####
		cut -f1 -d":" /etc/passwd | sort -n | /usr/bin/uniq -c | while read -r x  
		do
			[ -z "${x}" ] && break
			# shellcheck disable=SC2086
			set - ${x}
			if [ "$1" -gt 1 ]; then
				uids=$(gawk -F: '($1 == n) { print $3 }' n="$2" /etc/passwd | xargs)
				echo "Duplicate User Name ($2): ${uids}" 
			fi
		done
		#### 6.2.19 Ensure no duplicate group names exist ####
		cut -f1 -d":" /etc/group | sort -n | uniq -c | while read -r x  
		do
			[ -z "${x}" ] && break 
			set - "${x}" 
			if [ "$1" -gt 1 ]; then
				gids=$(gawk -F: '($1 == n) { print $3 }' n="$2" /etc/group | xargs) 
				echo "Duplicate Group Name ($2): ${gids}" 
			fi 
		done
		stop_spinner $?
	} | tee -a $LOG
}

#########################################
#### Auto Unattended Security Upates ####
#########################################
function auto_updates() {
	{
		start_spinner 'Configuring Auto Security Updates...'
		echo ""
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			if [ "${OSVER}" = 7 ]; then
				${PAKMGR} install yum-cron 
				sed -i 's/update_cmd = default/update_cmd = security/g' /etc/yum/yum-cron.conf
				sed -i 's/apply_updates = no/apply_updates = yes/g' /etc/yum/yum-cron.conf
				sed -i 's/download_updates = no/download_updates = yes/g' /etc/yum/yum-cron-hourly.conf
				systemctl enable yum-cron 
				systemctl start yum-cron
			fi
			if [ "${OSVER}" = 8 ]; then
				${PAKMGR} install dnf-automatic 
				sed -i 's/upgrade_type = default/upgrade_type = security/g' /etc/dnf/automatic.conf
				sed -i 's/apply_updates = no/apply_updates = yes/g' /etc/dnf/automatic.conf
				systemctl enable --now dnf-automatic.timer
			fi
		elif [ "${OS}" = ubuntu ]; then
			${PAKMGR} install unattended-upgrades apticron
			touch /etc/apt/apt.conf.d/20auto-upgrades
			no_show << EOF > /etc/apt/apt.conf.d/20auto-upgrades
			APT::Periodic::Update-Package-Lists "1";
			APT::Periodic::Download-Upgradeable-Packages "1";
			APT::Periodic::AutocleanInterval "7";
			APT::Periodic::Unattended-Upgrade "1";
EOF
			sed -i 's/\/\/Unattended-Upgrade\:\:Mail "root";/Unattended-Upgrade\:\:Mail "root";/g' /etc/apt/apt.conf.d/50unattended-upgrades
		fi
		stop_spinner $?
	} | tee -a $LOG
}

#######################################################
#### Install SysStat Redhat/CentOS 7 and 8, Ubuntu ####
#######################################################
function install_sysstat() {
	{
		start_spinner 'Installing and Configuring SysStat...'
		echo ""
		${PAKMGR} install sysstat
		if [ "${OS}" = ubuntu ]; then
			sed -i 's/ENABLED="false"/ENABLED="true"/g' /etc/default/sysstat
			no_show << EOF > /etc/cron.d/sysstat
			# The first element of the path is a directory where the debian-sa1
			# script is located
			PATH=/usr/lib/sysstat:/usr/sbin:/usr/sbin:/usr/bin:/sbin:/bin
		
			# Activity reports every 10 minutes everyday
			5-55/10 * * * * root command -v debian-sa1 > /dev/null && debian-sa1 1 1
			
			# Additional run at 23:59 to rotate the statistics file
			59 23 * * * root command -v debian-sa1 > /dev/null && debian-sa1 60 2
EOF
		else
			if [ ! -d /var/log/sa ]; then
				mkdir /var/log/sa
			fi
		fi
		systemctl enable sysstat 
		systemctl start sysstat 
		stop_spinner $?
	} | tee -a $LOG
}

##############################################################
#### Install RootKit Hunter Redhat/CentOS 7 and 8, Ubuntu ####
##############################################################
function install_rkhunter() {
	{
		start_spinner 'Installing and Configuring RKHunter...'
		echo ""
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			${PAKMGR} install epel-release 
			${PAKMGR} install rkhunter 
		elif [ "${OS}" = ol ]; then
			if [ "${OSVER}" = 7 ]; then
				${PAKMGR} install oracle-epel-release-el7
				sed -i 's/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-epel-ol7.repo
			fi
			if [ "${OSVER}" = 8 ]; then
				${PAKMGR} install oracle-epel-release-el8
				sed -i 's/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-epel-ol8.repo
			fi		
			${PAKMGR} install rkhunter 
		elif [ "${OS}" = ubuntu ]; then
			debconf-set-selections <<< ""postfix postfix/mailname string "${HOSTNAME}"""
			debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Local Only'"
			DEBIAN_FRONTEND=noninteractive ${PAKMGR} install rkhunter >> ${LOG} 2>&1
		fi
		rkhunter --update
		rkhunter --propupd
		sed -i 's/ALLOW_SSH_ROOT_USER=unset/ALLOW_SSH_ROOT_USER=no/g' /etc/rkhunter.conf
		stop_spinner $?
	} | tee -a $LOG
}

###################################################
#### Install LMD Redhat/CentOS 7 and 8, Ubuntu ####
###################################################
function install_lmd() {
	{
		start_spinner 'Installing and Configuring MalDetect...'
		echo ""
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then
			${PAKMGR} install epel-release 
			${PAKMGR} install mailx inotify-tools tar wget
		elif [ "${OS}" = ol ]; then
			if [ "${OSVER}" = 7 ]; then
				${PAKMGR} install oracle-epel-release-el7
				sed -i 's/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-epel-ol7.repo
			fi
			if [ "${OSVER}" = 8 ]; then
				${PAKMGR} install oracle-epel-release-el8
				sed -i 's/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-epel-ol8.repo
			fi
			${PAKMGR} install mailx inotify-tools tar wget
		elif [ "${OS}" = ubuntu ]; then
			export DEBIAN_FRONTEND=noninteractive
			${PAKMGR} install inotify-tools wget
		fi
			wget http://www.rfxn.com/downloads/maldetect-current.tar.gz 
			tar -xvzf maldetect-current.tar.gz 
			cd maldetect-1* || return $?
			./install.sh 
			cd .. || return $?
			rm -rf maldetect-*
		if [ "${OS}" = ubuntu ]; then
			ln -s /usr/local/maldetect/maldet /bin/maldet
			hash -r
		fi
		sed -i 's/email_alert="0"/email_alert="1"/g' /usr/local/maldetect/conf.maldet
		sed -i 's/email_addr="you@domain.com"/email_addr="root@localhost"/g' /usr/local/maldetect/conf.maldet
		sed -i 's/quarantine_hits="0"/quarantine_hits="1"/g' /usr/local/maldetect/conf.maldet
		sed -i 's/quarantine_clean="0"/quarantine_clean="1"/g' /usr/local/maldetect/conf.maldet
		if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol ]]; then
			${PAKMGR} install clamav clamav-devel
		elif [ "${OS}" = ubuntu ]; then
			export DEBIAN_FRONTEND=noninteractive
			${PAKMGR} install clamav clamav-daemon clamdscan clamav-freshclam
		fi
		freshclam
		stop_spinner $?
		} | tee -a $LOG
}

##########################
#### Install Logwatch ####
##########################
function install_logwatch() {
	{
		start_spinner 'Installing and Configuring LogWatch...'
		${PAKMGR} install logwatch
		LOG_ZZ=/usr/share/logwatch/default.conf/services/zz-disk_space.conf
		# shellcheck disable=SC2016
		sed -i 's/#$show_home_dir_sizes = 1/$show_home_dir_sizes = 1/g' $LOG_ZZ
		# shellcheck disable=SC2016
		sed -i 's/#$home_dir = "\/home"/$home_dir = "\/home"/g' $LOG_ZZ
		# shellcheck disable=SC2016
		sed -i 's/#$show_mail_dir_sizes = 1/#$show_mail_dir_sizes = 1/g' $LOG_ZZ
		# shellcheck disable=SC2016
		sed -i 's/#$mail_dir = "\/var\/spool\/mail/$mail_dir = "\/var\/spool\/mail/g' $LOG_ZZ
		# shellcheck disable=SC2016
		sed -i 's/#$show_disk_usage = 1/$show_disk_usage = 1/g' $LOG_ZZ
		# shellcheck disable=SC2016
		sed -i 's/$HTTP_IGNORE_ERROR_HACKS = 0/$HTTP_IGNORE_ERROR_HACKS = 1/g' /usr/share/logwatch/default.conf/services/http.conf
		sed -i 's/Detail = Low/Detail = Med/g' /usr/share/logwatch/default.conf/logwatch.conf
		stop_spinner $?
	} | tee -a $LOG
}

###############################
#### Oracle EBS PreInstall ####
###############################
function oci_oracle_ebs_setup() {
	{
		start_spinner 'Configuring Server for Oracle EBS/WebLogic...'
		if [ "${SRVTYPE}" != 3 ]; then
			if [[ ${OS} = centos || ${OS} = rhel || ${OS} = ol || ${OS} = rocky || ${OS} = almalinux ]]; then 
				${PAKMGR} install oracle-ebs-server-R12-preinstall openmotif21
				oci-network-config -X ens3
				sed -i 's/PRESERVE_HOSTINFO=0/PRESERVE_HOSTINFO=2/g' /etc/oci-hostname.conf
				groupadd dba
				groupadd dev
				touch /etc/oraInst.loc
				chmod 600 /etc/oraInst.loc
				chown applmgr. /etc/oraInst.loc
			elif [ "${OS}" = ubuntu ]; then
				echo ""
				echo -e "\e[7m**** !EBS PreInstall for Ubuntu is not supported! ****\e[0m"
				echo ""
			fi
		fi
		if [ "${SRVTYPE}" == 3 ]; then
			oci-network-config -X ens3
			sed -i 's/PRESERVE_HOSTINFO=0/PRESERVE_HOSTINFO=2/g' /etc/oci-hostname.conf
		fi	
	} | tee -a $LOG
}

########################
#### Function Calls ####
########################
function oci_rh_ub_common() {
	{
		check_root
		backup
		make_swap
		time_set
		disable_filesystems
		tmp_directory
		stickybit
		gpgkeys
		aide_install
		sudo_changes
		boot_load
		core_dumps
		sysctl_conf
		pre_link
		se_troubleshoot_mcs
		unconf_daemons
		se_linux
		banners
		inet_service
		ntp_config
		chrony_cfg
		update_security
		unsecure_services
		mail_config
		addon_inet_services
		service_clients
		tcp_wrappers
		auto_updates
		uncommon_protocols
		iptables_config
		auditd_accounting
		rsyslog_service
		journald_config
		logfile_permissions
		crond_enabled
		compress_auditd
		config_sshd
		config_pam
		accounts
		config_users_permissions
		audit_file_permissions
		world_writable_files
		user_group_settings
		home_directories
		dot_files
		group_gid_uid
		install_sysstat
		install_rkhunter
		install_lmd
		install_logwatch
	}
}

##################
#### OCI Only ####
##################
function oci_only() {
	{
		oci_iptables
	} 
}

##################
#### AWS Only ####
##################
function aws_only() {
	{
		aws_iptables
	}
}

warn_message