#!/bin/sh
#
#	 Copyright (c) 2016-2020 Brocade Communications Systems, Inc.
#	 All rights reserved.
#
#	 File name:   countsession
#	 Module name: fabos/src/security/countsession.sh
#
#	 This script counts number of user sessions to determine 
#	 if we have reached max sessions
#

#
# Get the number of session the current user is logged in
#

max_telnet_sessions=4
max_maintenance_sessions=4
max_total_sessions=32

# Total number of locally authenticated admin / maintenance sessions allowed
max_total_local_admin_maint=12

#
# Get the number of sessions used by admin + maintenance users with 
# particular auth_type passed as parameter. Currently tested for 
# auth_type 0 only.
#
get_count_of_admin_maint_users_by_auth_type()
{
	# auth_type can be local (0) or AAA (1)
	auth_type=$1

	rlogin_aaa_admin_maint=0

	# Get only the admin and maintenance sessions
	login_list=`/usr/bin/who -u | /bin/grep -E "admin|maintenance" | /bin/awk {'print $7'}` 2>/dev/null
	for l in `echo $login_list`
	do
                # The auth type in this proc file reflects local(0) or aaa(1) session
                env=`/bin/cat /proc/$l/environ  2>/dev/null | /bin/grep 'AUTH_TYPE='$auth_type` 2>/dev/null
                if [[ ! -z $env ]]; then
                        rlogin_aaa_admin_maint=`/usr/bin/expr $rlogin_aaa_admin_maint + 1`
                else
			# telnet and console process from "who" command will have
			# "login" as the process. Go to the child process of this
			# pid and grep for the rbash process. If its tty its console
			# and if its pts its telnet. We can combine this logic also
			# but keeing it like this just in case we need to differentiate
			# between the two for any case in future.

			console_rbash_pid=`/bin/ps --ppid $l|/bin/grep rbash|/bin/grep tty|/bin/awk '{print  $1 }'`
			telnet_rbash_pid=`/bin/ps --ppid $l|/bin/grep rbash|/bin/grep pts|/bin/awk '{print  $1 }'`

			if [[ ! -z $console_rbash_pid ]]; then
				env=`/bin/cat /proc/$console_rbash_pid/environ  2>/dev/null | /bin/grep 'AUTH_TYPE='$auth_type` 2>/dev/null
				if [[ ! -z $env ]]; then
					rlogin_aaa_admin_maint=`/usr/bin/expr $rlogin_aaa_admin_maint + 1`
				fi
			fi

			if [[ ! -z $telnet_rbash_pid ]]; then
				env=`/bin/cat /proc/$telnet_rbash_pid/environ  2>/dev/null | /bin/grep 'AUTH_TYPE='$auth_type` 2>/dev/null
				if [[ ! -z $env ]]; then
					rlogin_aaa_admin_maint=`/usr/bin/expr $rlogin_aaa_admin_maint + 1`
				fi
			fi
		fi
	done
	echo $rlogin_aaa_admin_maint
}

#
# Get the number of session by remote user with given role
#
get_remote_count()
{
	rlogin=0
	uid=`/usr/bin/id -u`
	login_list=`/bin/ps -u $uid | /bin/grep "rbash" | /bin/awk {'print $1'}` 2>/dev/null
	for l in `echo $login_list`
	do
		env=`/bin/cat /proc/$l/environ  2>/dev/null | /bin/grep 'AUTH_TYPE=1'` 2>/dev/null
		if [[ ! -z $env ]]; then
			rlogin=`/usr/bin/expr $rlogin + 1`
		fi	
	done
	echo $rlogin
}

get_user_session_count()
{
	USER=$1
	count=0
	userlength=`/usr/bin/expr length $USER`
	#Here console port login is also included from no_sessions
	if [ $userlength -gt 32 ]; then
		username=`echo $USER | /usr/bin/cut -c 1-32`
	else
		username=$USER
	fi
	user_list=`/usr/bin/who -u | /bin/grep $username | /usr/bin/cut -d ' ' -f1` 2>/dev/null
	for u in `echo $user_list`
	do
		if [ $u = $username ]; then
			count=`/usr/bin/expr $count + 1`
		fi
	done
	if [ "$username" == "admin" ] || [ "$username" == "user" ]; then
		rlogin=`get_remote_count $username`
		if [ $rlogin  -le $count ]; then
			count=`/usr/bin/expr $count - $rlogin`
		fi
	fi
	echo $count

}

#Here accounts logged in using switch authentication type are considered

# validate input parameters
case $# in
    0) echo "No username provided" >&2 ; exit 255;;
    1) echo "Not enough parameters provided" >&2 ; exit 255;;
    2) echo "Not enough parameters provided" >&2 ; exit 255;;
    3) echo "Not enough parameters provided" >&2 ; exit 255;;
    4) user=$1; auth_type=$2; rolename=$3 is_ssh_inline=$4;;
    *) echo "Too many parameters provided" >&2 ; exit 255;;
esac

# local
if [ "$auth_type" == "0" ]; then
	no_sessions=`get_user_session_count $user`
	if [[ "$user" == "maintenance" || "$user" == "admin" ]]; then

		# Passing 0 to get_count_of_admin_maint_users_by_auth_type
		# to get local account counts only
		ret_val=`get_count_of_admin_maint_users_by_auth_type 0`

		# There seems to be difference in session count while countsession script 
		# is being called from /etc/profile vs when it is being called from 
		# ssh inline code path. In case of profile path, the current session also 
		# gets counted in /proc logic while in case of ssh inline path the 
		# current session doesn't get counted in our /proc logic. Handled 
		# this by passing is_ssh_inline parameter to the count script.

		threshold=$max_total_local_admin_maint

		if [ "$is_ssh_inline" == "1" ]; then
			threshold=`/usr/bin/expr $threshold - 1`
		fi

		if [ $ret_val -gt $threshold ];then
			# failure case
			/bin/echo "Max remote sessions for login:admin and login:maintenance is $max_total_local_admin_maint"
			exit 1 2>/dev/null
		fi
	else
		if [ "$is_ssh_inline" == "1" ]; then
			max_telnet_thresh=`/usr/bin/expr $max_telnet_sessions - 1`
		else
			max_telnet_thresh=$max_telnet_sessions
		fi
		if [ $no_sessions -gt $max_telnet_thresh ]; then
			/bin/echo "Max remote sessions for login:$user is $max_telnet_sessions"
			exit 1 2>/dev/null
		fi
	fi
# remote
else
	if [ "$rolename" = "maintenance" ]; then
		#Here console port login is also included from no_sessions
		no_sessions=`/usr/bin/who -u | /bin/grep "$rolename" | /usr/bin/wc -l` 2>/dev/null
		if [ "$is_ssh_inline" == "1" ]; then
			max_maint_thresh=`/usr/bin/expr $max_maintenance_sessions - 1`
		else
			max_maint_thresh=$max_maintenance_sessions
		fi
		if [ "$no_sessions" -gt $max_maint_thresh ]; then
			/bin/echo "Max remote sessions for login:$user is $max_maintenance_sessions"
			exit 1 2>/dev/null
		fi
	fi
fi	

total_sessions=`/usr/bin/who | /usr/bin/wc -l` 2>/dev/null
if [ "$is_ssh_inline" == "1" ]; then
	max_total_thresh=`/usr/bin/expr $max_total_sessions - 1`
else
	max_total_thresh=$max_total_sessions
fi
if [ $total_sessions -gt $max_total_thresh ]; then
	/bin/echo "Max remote sessions for all accounts is $max_total_sessions"
   exit 1 2>/dev/null
fi

exit 0 2>/dev/null
