#!/bin/sh
#
#    Copyright (c) 2002-2007 Brocade Communications Systems, Inc.
#    All rights reserved.
#
#    File name:   logout
#    Module name: fabos/src/security/utils.c
#
#    This script will logout all sessions of specified particular users.
#    It's called by the in a number of situtaions in secure mode
#    by the FABOS code such as when passwords change or FCS role
#    change.
#
PATH=/fabos/sbin:/fabos/bin:/bin:/usr/bin:/sbin
FILENAME=$(/bin/basename "${BASH_SOURCE}")
DATE=/bin/date
ECHO=/bin/echo
AWK=/bin/awk
GREP=/bin/grep
# A common function to logout all the sessions in case of AAA config change
# or ssh session termination on zeroization

logout_all_sessions()
{

	mytty=`tty | /bin/sed  -e 's/\/dev\///g'`
	killown=0
	if [ "$1" == "user" ]; then
		session_list=`/usr/bin/who | /bin/grep -w "$2"|  /bin/sed -e 's/   / /g' | /bin/sed -e 's/  / /g' | /bin/sed -e 's/  / /g' \
					 | /usr/bin/cut -d' ' -f2`
	else
		session_list=`/usr/bin/who | /bin/sed -e 's/   / /g' | /bin/sed -e 's/  / /g' | /bin/sed -e 's/  / /g' | /usr/bin/cut -d' ' -f2`
	fi

	for tty in $session_list
	do
		/bin/echo "*tty - $tty*" >> /var/log/user.log
		#kill all other shells first
		if [ "$tty" != "$mytty" ]; then
			pid=`/bin/ps -t /dev/$tty |  $GREP -w -v "ps\|grep" | $AWK '{print $1}' | $GREP -v PID` > /dev/null 2>&1
			#   echo Killing PID $pid
			if [ "$pid" != "" ]; then
				pidarray=$(/bin/echo $pid | /usr/bin/tr " " "\n")
				for eachpid in $pidarray
				do
					if [ "$1" == "AAA" ] || [ "$1" == "saveown" ]; then
						ppid=`ps -o ppid= $eachpid`
					elif [ "$1" == "user" ]; then

						# Kill only local user sessions
						if [ -f /proc/$eachpid/environ ]; then
							ret=$(/bin/grep -cw "AUTH_TYPE=1" /proc/$eachpid/environ)
							/bin/echo "*ret - $ret" >> /var/log/user.log
							if [ $ret -ne 1 ]; then
								ppid=`ps -o ppid= $eachpid`
							fi
						fi
					elif [ "$1" == "ssh" ] || [ "$1" == "sftp" ]; then
						ppid=`/bin/ps -o ppid= $eachpid`
						process_name=`/bin/ps -p $ppid -o comm= 2> /dev/null`
						if [ "$process_name" != "sshd" ] && [ "$process_name" != "sftp" ]; then
							ppid=""
							eachpid=""
						fi
					fi
					if [[ ! -z $eachpid ]] && [ "$tty" == "ttyS0" ]; then
						$ECHO "`$DATE`::$FILENAME:$LINENO - Killing process - $eachpid\n" >> /var/log/user.log
						/bin/kill -9 $eachpid 2> /dev/null
					elif [[ ! -z $ppid ]] && [ $ppid != 1 ] && [ $ppid != $PPID ]; then
						$ECHO "`$DATE`::$FILENAME:$LINENO - Killing process - $ppid\n" >> /var/log/user.log
						/bin/kill -9 $ppid 2> /dev/null
					fi
				done
			fi
		else
			/bin/sleep 1
			killown=1
		fi
	done

	#Check for chassis/pizzabox
	# Terminate standby sessions in case of ssh/sftp
	pizzabox=$(/fabos/cliexec/hashow | /bin/grep -c "Not supported on this platform")
	if [[ $pizzabox -eq 0 ]]; then
		# Chassis
		if [ "$1" == "ssh" ]; then
			terminate_process_standby "sshd:"
		elif [ "$1" == "sftp" ]; then
			terminate_process_standby "sftp"
		fi
	fi

	#Kill ssh session without pts/tty associated with them
	if [ "$1" == "ssh" ];then
		ssh_pid_without_terminal=`/bin/ps -eaf | /bin/grep sshd: | /bin/grep -v "grep\|pts\|tty" |  /bin/sed -e 's/  */ /g' |  /usr/bin/cut -d' ' -f2`
		for eachpid in $ssh_pid_without_terminal
		do
			$ECHO "`$DATE`::$FILENAME:$LINENO - Killing process - $eachpid\n" >> /var/log/user.log
			/bin/kill -9 $eachpid 2>/dev/null
		done
	fi 

	#kill own shell
	if [ $killown == 1 ]; then
		if [ "$1" != "saveown" ] && [ "$1" != "sftp" ]; then
			# FOS-818951: Fix to address passwddefault not kicking root user out
			if [ "$2" == "root" ] && [ "$mytty" == "ttyS0" ]; then
				pid=`/bin/ps | /bin/grep ttyS0 | /bin/grep sh | /bin/awk '{ print $1 }'`
			else
				pid=`/bin/ps -t /dev/$mytty | $GREP -w -v "ps\|grep" | $AWK '{print $1}' | $GREP -v PID` > /dev/null 2>&1
			fi
			# End of Fix for FOS-818951
			/bin/echo "All PID's associated with Shell = ${pid}" >> /var/log/user.log
			if [ "$1" == "AAA" ]; then
				ret=0
			else
				ret=1
			fi
			if [ "$pid" != "" ]; then
				pidarray=$(/bin/echo $pid | /usr/bin/tr " " "\n")
				for eachpid in $pidarray
				do	
					if [ "$eachpid" != "" ]; then
						ppid=`/bin/ps -o ppid= $eachpid`
						if [ "$1" == "user" ]; then
							# Kill only local user sessions
							if [ -f /proc/$eachpid/environ ]; then
								ret=$(/bin/grep -cw "AUTH_TYPE=1" /proc/$eachpid/environ)
								/bin/echo "*ret - $ret" >> /var/log/user.log
							fi
						elif [ "$1" == "ssh" ]; then
							process_name=`/bin/ps -p $ppid -o comm= 2> /dev/null`
							if [ "$process_name" == "sshd" ]; then
								ret=0
							fi
						fi
						if [ $ret -ne 1 ]; then
							shell=`/bin/ps -p $eachpid -o comm= 2> /dev/null`
							if [ "$shell" == "sh" ] || [ "$shell" == "rbash" ]; then
								/bin/echo "shell PID = $eachpid" >> /var/log/user.log
								/bin/sleep 1
								if [ "$mytty" == "ttyS0" ]; then
									$ECHO "`$DATE`::$FILENAME:$LINENO - Killing process - $eachpid\n" >> /var/log/user.log
									/bin/kill -9 $eachpid 2> /dev/null
								elif [[ ! -z $ppid ]] && [ $ppid != 1 ]; then
									$ECHO "`$DATE`::$FILENAME:$LINENO - Killing process - $ppid\n" >> /var/log/user.log
									/bin/kill -9 $ppid 2> /dev/null
								fi
							fi
						fi
					fi
				done
			fi
		fi
	fi
}

terminate_process_standby() {
	otherhost=`/fabos/rbin/cipherutil get_otherhost 2>/dev/null`
	if  /bin/ping -c 2 $otherhost >& /dev/null ; then
		/usr/bin/rsh -n $otherhost "for ssh_sess_pid in \`/bin/ps -aef| /bin/grep "$1" |/bin/grep -v grep|/bin/sed -e 's/  */ /g'|/usr/bin/cut -d' ' -f2\`;
		do
		/bin/kill -9 \$ssh_sess_pid 2> /dev/null;
		done" >& /dev/null
	fi
}

terminate_service_sessions()
{
	msg="Service session will be logged out"
	killown=0

	pidlist=`/bin/ps -aef | /bin/grep maintenance | /bin/grep "\-\-init-file /fabos/users/maintenance/.service"| /bin/sed -e 's/  */ /g' | /usr/bin/cut -d' ' -f2`
	#Self sesion kill will only be invoked in --reset from service shell
	#PPID will denote --reset, parent of ppid will denote bash
	mysesspid=`ps -o ppid= $PPID | /bin/sed 's/^[ \t]*//'`
	for pid in $pidlist
	do
		if [ "$pid" != "$mysesspid" ]; then
			tty=`/bin/ps -o tty= -p $pid`
			if [ "$tty" != "" ]; then
				/bin/echo -e "\n$msg" > /dev/$tty
				sleep 1
			fi
			$ECHO "`$DATE`::$FILENAME:$LINENO - Killing process - $pid\n" >> /var/log/user.log
			/bin/kill -9 $pid 2> /dev/null
			/bin/stty echo icanon lnext ^V -F /dev/$tty > /dev/null 2>&1
		else
			killown=1
		fi
	done

	sleep 1
	/fabos/rbin/cipherutil sskillchild	
	if [ "$killown" != "0" ]; then
		tty=`/bin/ps -o tty= -p $mysesspid`
		if [ "$tty" != "" ]; then
			/bin/echo -e "\n$msg" > /dev/$tty
			sleep 1
		fi
		$ECHO "`$DATE`::$FILENAME:$LINENO - Killing process - $mysesspid\n" >> /var/log/user.log
		/bin/kill -9 $mysesspid 2> /dev/null
	fi
}

terminate_factory_sessions()
{
	msg="Factory session will be logged out"
	killown=0

	pidlist=`/bin/ps -aef | /bin/grep maintenance | /bin/grep "\-\-init-file /fabos/users/maintenance/.factory"| /bin/sed -e 's/  */ /g' | /usr/bin/cut -d' ' -f2`
	#Self sesion kill will only be invoked in --reset from factory shell
	#PPID will denote --reset, parent of ppid will denote bash
	mysesspid=`ps -o ppid= $PPID | /bin/sed 's/^[ \t]*//'`
	for pid in $pidlist
	do
		if [ "$pid" != "$mysesspid" ]; then
			tty=`/bin/ps -o tty= -p $pid`
			if [ "$tty" != "" ]; then
				/bin/echo -e "\n$msg" > /dev/$tty
				sleep 1
			fi
			$ECHO "`$DATE`::$FILENAME:$LINENO - Killing process - $pid\n" >> /var/log/user.log
			/bin/kill -15 $pid 2> /dev/null
		else
			killown=1
		fi
	done
	if [ "$killown" != "0" ]; then
		tty=`/bin/ps -o tty= -p $mysesspid`
		if [ "$tty" != "" ]; then
			/bin/echo -e "\n$msg" > /dev/$tty
			sleep 1
		fi
		$ECHO "`$DATE`::$FILENAME:$LINENO - Killing process - $mysesspid\n" >> /var/log/user.log
		/bin/kill -9 $mysesspid 2> /dev/null
	fi
}

if [ $# -ge 1 ]; then
	# Logout Multiple Users
	if [ $# -ge 2 ]; then
		# Information for User
		#echo Will logout user: $1
		line="$*"
		sw=`/bin/echo $line | /usr/bin/cut -d' ' -f 1`
		accts=`/bin/echo $line | /usr/bin/cut -d' ' -f 2-`

		if [ $1 == "-user" ]; then
			if [ "$3" == "genericmsg" ]; then
				msg="Security Policy, Password or Account Attribute Change: "
				accts=$2
				/bin/sleep 1
			elif [ "$3" == "timeout" ]; then
				msg="Time of Day Expired: "
				accts="$2"
			else
				msg="Security Policy, Password or Account Attribute Change: "
			fi
		else
			msg="Security Policy, Password or Account Attribute Change: "
		fi
		msg=$msg$accts" will be logged out"
		chassis_info=`getchassisconfig`
		num_switches=`/bin/echo $chassis_info | \
		/bin/sed -n -e 's/Number of switches: //gp' | \
		/bin/sed -n -e 's/ .*//gp'`
	fi

	if [ $# -eq 1 ]; then
		# Logout Invalid Users
		if [ $1 == "-invalid" ]; then
			/bin/echo "Finding invalid users" >> /var/log/user.log
			for logged_user in `/usr/bin/who | /usr/bin/cut -d' ' -f1`
			do
				/bin/echo "*logged_user - $logged_user* " >> /var/log/user.log
				kill_user=1
				# Check if the user is valid by searching the /etc/passwd file
				for valid_user in `/bin/grep "$logged_user" < /etc/passwd | /usr/bin/cut -d':' -f1`
				do
					if [ "$logged_user" == "$valid_user" ]
					then
						kill_user=0
						break
					fi
				done
				# If user is invalid, add it to the list of accounts
				if [ $kill_user -eq 1 ]
				then
					accts="$logged_user $accts"
				fi
			done
			if [ "$accts" != "" ]; then
				/usr/bin/wall "Active CP : Invalid users \"$accts\" will be logged out." 2>/dev/null
			fi
			accts=`/bin/echo $accts | /usr/bin/cut -d' ' -f1-`

			# matador fips rel v7.0, need to terminate all SSH sessions
			# after zeroizing ssh public/private keys. 
		elif [ $1 == "-ssh" ]; then
			msg="All SSH accounts will be logged out"
			/usr/bin/wall "$msg" 2>/dev/null
			/bin/sleep 1
			logout_all_sessions "ssh"
		elif [ $1 == "-sftp" ]; then
			msg="SSH public/private Keys are Zeroized. SFTP sessions will be terminated"
			/usr/bin/wall "$msg" 2>/dev/null
			logout_all_sessions "sftp"
		elif [ $1 == "-saveown" ]; then
			msg="Security Policy, Password or Account Attribute Change: all accounts will be logged out"
			/usr/bin/wall "$msg" 2>/dev/null
			logout_all_sessions "saveown"
			/bin/sleep 1
		elif [ "$1" == "-service" ]; then
			terminate_service_sessions
			exit 0
		elif [ "$1" == "-factory" ]; then
			terminate_factory_sessions
			exit 0
		elif [ "$1" == "-factreset" ]; then
			msg="Factory reset: all accounts will be logged out"
			/usr/bin/wall "$msg" 2>/dev/null
			logout_all_sessions "AAA"
			/bin/sleep 1
		else
			/bin/echo "Invalid Arguments/Options for usrlogout"
		fi

	elif [ $1 == "-user" ]; then
		msg="Logging out all the sessions of user $2"
		# Only display message to user being logged out
		for user_sess in `/usr/bin/who | /bin/grep -w $2 | /bin/awk '{print $2}'`
		do
			/bin/echo "$msg" > /dev/$user_sess
			/bin/sleep 1
		done
		logout_all_sessions "user" "$2"
		/bin/sleep 1 
		exit 0
	fi

	/bin/echo "logged_users : $accts" >> /var/log/user.log
	/bin/echo "" >> /var/log/user.log
	/bin/echo "looping through all accounts" >> /var/log/user.log
	# Loop through all accounts
	for name in $accts; do
		/bin/echo "$name" >> /var/log/user.log
		msg="Logging out all the sessions of user $name"
		# Only display message to user being logged out
		for user_sess in `/usr/bin/who | /bin/grep -w $name | /bin/awk '{print $2}'`
		do
			/bin/echo "$msg" > /dev/$user_sess
			/bin/sleep 1
		done
		logout_all_sessions "user" "$name"
	done

	# no argument, logout all
elif [ $# -eq 0 ]; then
	msg="All accounts will be logged out"
	/usr/bin/wall "$msg" 2>/dev/null
	pizzabox=$(/fabos/cliexec/hashow | /bin/grep -c "Not supported on this platform")
	act_standby=$(/fabos/cliexec/hashow | /bin/grep "Local CP" | /bin/awk '{print $6}')
	if [ "${act_standby:0:6}" == "Active" ] || [ $pizzabox -eq 1 ]; then
		/bin/echo " Logging out all the sessions"
	else
		/bin/echo " Logging out all the sessions on Standby"
	fi
	logout_all_sessions "AAA"
	/bin/sleep 1
fi
