#!/bin/sh
#
#    Copyright (c) 2007-2008 Brocade Communications Systems, Inc.
#    All rights reserved.
#   
#    File name:   cipherutil
#    Module name: fabos/src/security/cipherutil.sh
#   
#    This script modifies the ssh cipher list and restarts the SSH deamon.
#   
    
export PATH=/fabos/sbin:/fabos/bin:/bin:/usr/bin:/sbin:/usr/sbin:/fabos/cliexec:/fabos/libexec:


#Absolute path for generic utilities 
ECHO=/bin/echo
GREP=/bin/grep
CUT=/usr/bin/cut
SED=/bin/sed
CAT=/bin/cat
RM=/bin/rm
PS=/bin/ps
CP=/bin/cp
TR=/usr/bin/tr
AWK=/bin/awk
SYS_CONFIG=/fabos/cliexec/config
KILL=/bin/kill
KILLALL=/usr/bin/killall
RSH=/usr/bin/rsh
PING=/bin/ping

# SSH Configuration Files 

SSHD_CONFIG=/etc/sshd_config
SSH_CONFIG=/etc/ssh_config

# Temporary config file used for validation 

TMP_SSHD_CONFIG=/etc/tmp_sshd_config

# SSH Daemon
SSHD=/usr/sbin/sshd

# Replacing SSH config 
SSH_KEX_REPLACE=replacekex
SSH_ENC_REPLACE=replaceenc
SSH_MAC_REPLACE=replacemac

# Verify - Used to verify if one set is subset of another
SSH_KEX_VERIFY=verifykex
SSH_ENC_VERIFY=verifyenc
SSH_MAC_VERIFY=verifymac

#Validate 
SSH_KEX_VALIDATE=validatekex
SSH_ENC_VALIDATE=validateenc
SSH_MAC_VALIDATE=validatemac

#restartSSH

SSH_RESTART=restartssh
SSH_RELOAD=reloadssh
TEST_SSH_RESTART=testrestartssh
SYSLOG_RESTART=restartsyslog
#Get Other host ip
GET_OTHERHOST=get_otherhost

#TLS 
WEB_RPC_KILL=webrpckill
CIPHER_VERIFICATION=validatetlscipher
CIPHER_VERIFICATION_TLSv3=validatetls1.3cipher
CIPHER_VERIFY_SUBSET=verifytlscipher
CIPHER_VERIFY_SUBSET_TLSv3=verifytls1.3cipher
HTTPD_PID_FILE=/tmp/webtools/httpd.pid.0
WEBDRESTART="/fabos/libexec/webdcfghandler http.restart:1"
OPENSSL_CIPHER_CMD="/usr/bin/openssl ciphers"
TMPFILE="/tmp/tmpfile"

#restartHTTPS

HTTPS_RESTART=restarthttps

# convert option to all lower case
cmd_option=`$ECHO $1 | $TR "[:upper:]" "[:lower:]"`


strstr() {
  [ "${1#*$2*}" = "$1" ] && return 1
  return 0
}
swbd() {
    /bin/sed -n -e 's/^.*\(SWBD[[:digit:]]\{1,\}\).\+$/\1/gp'
}
cpid() {
    sed -n -e 's/^Control.\+No: \([[:digit:]]\{1,\}\)$/\1/gp'
}
SWBD=$(/sbin/sin | swbd 2> /dev/null)
CPID=$(/sbin/sin | cpid 2> /dev/null)

otherhost(){
    case ${SWBD##SWBD} in
    '62')
        printf 127.1.1.$((8 - CPID % 2))
        ;;
    '77')
        printf 127.1.1.$((6 - CPID % 2))
        ;;
    '141')
        printf 127.1.$((17 - CPID % 2)).$((17 - CPID % 2))
        ;;
    '142')
        printf 127.1.$((15 - CPID % 2)).$((15 - CPID % 2))
        ;;
    '165' | '166' | '179' | '180')
        printf 127.3.1.$((2 - CPID % 2))
        ;;
    *)
        printf 10.0.0.$((6 - CPID % 2))
        ;;
    esac
}

restart_SSH (){
        # Restart sshd.
        pizzabox=$(/fabos/cliexec/hashow | $GREP -c "Not supported on this platform")
        pid=`$PS -ef | $GREP "sshd" | $GREP -v "sshd:" | \
            $GREP -v "sshd_config" | $GREP -v grep|$AWK '{print $2}'`
        if [ -n "$pid" ]; then
            $KILL $pid
        fi
        $SSHD >/dev/null 2>/dev/null

        pid=`$PS -ef | $GREP "sshd" | $GREP -v "sshd:" | \
            $GREP -v "sshd_config" | $GREP -v grep|$AWK '{print $2}'`
        if [ $pizzabox -eq 1 ]; then
            if [ -z "$pid" ]; then
                exit 1
            fi
        fi
        if [ $pizzabox -eq 0 ]; then
            # Restart ssh on standby cp only if standby cp is up
            if  $PING -c 2 $(otherhost) >/dev/null 2>&1 ; then
                pid=`$RSH -n $(otherhost)  $PS -ef 2> /dev/null | $GREP "sshd" | \
                    $GREP -v "sshd:" | $GREP -v "sshd_config" | $GREP -v grep \
                    | $AWK '{print $2}'`
                if [ -n "$pid" ]; then
                    $RSH -n $(otherhost) $KILL $pid 2> /dev/null
                fi
                $RSH -n $(otherhost) $SSHD >/dev/null 2>&1
                pid=`$RSH -n $(otherhost) $PS -ef 2> /dev/null | $GREP "sshd" | $GREP -v "sshd:" | \
                    $GREP -v "sshd_config" | $GREP -v grep|$AWK '{print $2}'`
                if [ -z "$pid" ]; then
                    exit 1
                fi
            fi
        fi
}

reload_SSH (){
        # Reload SSHD configuration on current CP and otherhost

        pizzabox=$(/fabos/cliexec/hashow | $GREP -c "Not supported on this platform")
        #Handle Standby CP
        if [ $pizzabox -eq 0 ]; then
            # Reload SSHD on standby CP only if standby CP is up
            if  $PING -c 2 $(otherhost) >/dev/null 2>&1 ; then
                pid=`$RSH -n $(otherhost)  $PS -ef 2> /dev/null | $GREP "sshd" | \
                    $GREP -v "sshd:" | $GREP -v "sshd_config" | $GREP -v grep \
                    | $AWK '{print $2}'`
                if [ -n "$pid" ]; then
                    $RSH -n $(otherhost) $KILL -s HUP $pid 2> /dev/null
                    if [ $? != 0 ]; then
                        exit 1
                    fi
                fi
            fi
        fi

        # Handle current CP
        pid=`$PS -ef | $GREP "sshd" | $GREP -v "sshd:" | \
            $GREP -v "sshd_config" | $GREP -v grep|$AWK '{print $2}'`
        if [ -n "$pid" ]; then
            $KILL -s HUP $pid
            if [ $? != 0 ]; then
                exit 1
            fi
        fi
}
#Main processiong starts here. 

case "$cmd_option" in

################################################
#  SSH based options
################################################

#SSH replace options 

"$SSH_ENC_REPLACE" )
    # Verify  the no of input arguments before processing
    if [ $# -ne 3 ]
    then
        exit 1
    fi

    # Modify ssh server configuration
    # Finds out whether Cipher filed exists or not.
    cipher=`$CAT $SSHD_CONFIG|$GREP -ce "^#*Ciphers"`
    if [ "$cipher" -eq 0 ]; then
        $ECHO Ciphers $2 >> $SSHD_CONFIG
        $SYS_CONFIG save $SSHD_CONFIG
    else
        cipherlist=`$CAT $SSHD_CONFIG|$GREP -ie "^#*Ciphers" | \
                    cut -d" " -f2-`

        $SED "s/^#*Ciphers $cipherlist/Ciphers $2/" $SSHD_CONFIG > $TMPFILE
        $CAT $TMPFILE > $SSHD_CONFIG
        $RM $TMPFILE
        $SYS_CONFIG save $SSHD_CONFIG
    fi

    #Modify the ssh client configuration
    cipher=`$CAT $SSH_CONFIG|$GREP -ce "^#*Ciphers"`
    if [ "$cipher" -eq 0 ]; then
        $ECHO Ciphers $2 >> $SSH_CONFIG
        $SYS_CONFIG save $SSH_CONFIG
    else
        cipherlist=`$CAT $SSH_CONFIG|$GREP -ie "^#*Ciphers" | \
                    $CUT -d" " -f2-`

        $SED "s/^#*Ciphers $cipherlist/Ciphers $2/" $SSH_CONFIG > $TMPFILE
        $CAT $TMPFILE > $SSH_CONFIG
        $RM $TMPFILE
        $SYS_CONFIG save $SSH_CONFIG
    fi

    if [ $3 -eq 0 ]; then
        # Restart sshd.
    	restart_SSH
    fi
;;


"$SSH_RESTART" )
        # Restart sshd.
	restart_SSH
;;

"$SSH_RELOAD" )
        # Reload SSHD.
        reload_SSH
;;

"$TEST_SSH_RESTART" )

        $SSHD -T -f $SSHD_CONFIG >/dev/null 2>&1

        if [ $? != 0 ]; then
                exit 1
        fi
;;

"$SYSLOG_RESTART" )
		$KILLALL syslog-ng > /dev/null 2>&1
		/etc/rc.d/init.d/syslog start 2>/dev/null

;;

"$GET_OTHERHOST" )
        # Get otherhost ip.
	otherhost
;;

"$SSH_KEX_REPLACE" )
    # Verify  the no of input arguments before processing
    if [ $# -ne 3 ]
    then
        exit 1
    fi

    # Finds out whether Cipher filed exists or not.
    kex=`$CAT $SSHD_CONFIG|$GREP -ce "^#*KexAlgorithms"`
        if [ "$kex" -eq 0 ]; then
        $ECHO KexAlgorithms $2 >> $SSHD_CONFIG
        $SYS_CONFIG save $SSHD_CONFIG
    else
        kexlist=`$CAT $SSHD_CONFIG|$GREP -ie "^#*KexAlgorithms" | \
                    $CUT -d" " -f2-`
        $SED "s/^#*KexAlgorithms $kexlist/KexAlgorithms $2/" $SSHD_CONFIG > $TMPFILE
        $CAT $TMPFILE > $SSHD_CONFIG
        $RM $TMPFILE
        $SYS_CONFIG save $SSHD_CONFIG
    fi
    #Modify the SSH client configuration
    kex=`$CAT $SSH_CONFIG|$GREP -ce "^#*KexAlgorithms"`
    if [ "$kex" -eq 0 ]; then
        $ECHO KexAlgorithms $2 >> $SSH_CONFIG
        $SYS_CONFIG save $SSH_CONFIG
    else
        kexlist=`$CAT $SSH_CONFIG|$GREP -ie "^#*KexAlgorithms" | \
                    $CUT -d" " -f2-`
        $SED "s/^#*KexAlgorithms $kexlist/KexAlgorithms $2/" $SSH_CONFIG > $TMPFILE
        $CAT $TMPFILE > $SSH_CONFIG
        $RM $TMPFILE
        $SYS_CONFIG save $SSH_CONFIG
    fi

    if [ $3 -eq 0 ]; then
        # Restart sshd.
	restart_SSH
    fi

;;

"$SSH_MAC_REPLACE" )
    # Verify  the no of input arguments before processing
    if [ $# -ne 3 ]
    then
        exit 1
    fi

    # Finds out whether Cipher filed exists or not.
    mac1=`$CAT $SSHD_CONFIG|$GREP -ce "^#*MACs"`
    mac2=`$CAT $SSHD_CONFIG|$GREP -ce "^#*Macs"`
    if [ "$mac1" -eq 0 ]; then
        if [ "$mac2" -eq 0 ]; then
            $ECHO MACs $2 >> $SSHD_CONFIG
            $SYS_CONFIG save $SSHD_CONFIG
        fi
    else
        if [ "$mac1" -eq 1 ] && [ "$mac2" -eq 1 ]; then

            maclist=`$CAT $SSHD_CONFIG|$GREP -e "^#*MACs" | \
                         $CUT -d" " -f2-`
            $SED "s/^#*MACs $maclist/MACs $2/" $SSHD_CONFIG > $TMPFILE

            $CAT $TMPFILE > $SSHD_CONFIG
            $RM $TMPFILE
            $SYS_CONFIG save $SSHD_CONFIG

            maclist=`$CAT $SSHD_CONFIG|$GREP -e "^#*Macs" | \
                         $CUT -d" " -f2-`
            $SED "s/^#*Macs $maclist/Macs $2/" $SSHD_CONFIG > $TMPFILE
        elif [ "$mac1" -eq 1 ]; then
            maclist=`$CAT $SSHD_CONFIG|$GREP -e "^#*MACs" | \
                         $CUT -d" " -f2-`
            $SED "s/^#*MACs $maclist/MACs $2/" $SSHD_CONFIG > $TMPFILE

        else
            maclist=`$CAT $SSHD_CONFIG|$GREP -e "^#*Macs" | \
                         $CUT -d" " -f2-`
            $SED "s/^#*Macs $maclist/Macs $2/" $SSHD_CONFIG > $TMPFILE

        fi

        $CAT $TMPFILE > $SSHD_CONFIG
        $RM $TMPFILE
        $SYS_CONFIG save $SSHD_CONFIG
    fi

    #Modify the SSH client configuration
    mac1=`$CAT $SSH_CONFIG|$GREP -ce "^#*MACs"`
    mac2=`$CAT $SSH_CONFIG|$GREP -ce "^#*Macs"`
    if [ "$mac1" -eq 0 ]; then
        if [ "$mac2" -eq 0 ]; then
            $ECHO MACs $2 >> $SSH_CONFIG
            $SYS_CONFIG save $SSH_CONFIG
        fi
    else
        if [ "$mac1" -eq 1 ] && [ "$mac2" -eq 1 ]; then
            maclist=`$CAT $SSH_CONFIG|$GREP -e "^#*MACs" | \
                         $CUT -d" " -f2-`
            $SED "s/^#*MACs $maclist/MACs $2/" $SSH_CONFIG > $TMPFILE

            $CAT $TMPFILE > $SSH_CONFIG
            $RM $TMPFILE
            $SYS_CONFIG save $SSH_CONFIG

            maclist=`$CAT $SSH_CONFIG|$GREP -e "^#*Macs" | \
                         $CUT -d" " -f2-`
            $SED "s/^#*Macs $maclist/Macs $2/" $SSH_CONFIG > $TMPFILE
        elif [ "$mac1" -eq 1 ]; then
            maclist=`$CAT $SSH_CONFIG|$GREP -e "^#*MACs" | \
                         $CUT -d" " -f2-`
            $SED "s/^#*MACs $maclist/MACs $2/" $SSH_CONFIG > $TMPFILE

        else
            maclist=`$CAT $SSH_CONFIG|$GREP -e "^#*Macs" | \
                         $CUT -d" " -f2-`
            $SED "s/^#*Macs $maclist/Macs $2/" $SSH_CONFIG > $TMPFILE

        fi

        $CAT $TMPFILE > $SSH_CONFIG
        $RM $TMPFILE
        $SYS_CONFIG save $SSH_CONFIG
    fi

    if [ $3 -eq 0 ]; then
        # Restart sshd.
	restart_SSH
    fi

;;

# SSH validate options 

"$SSH_KEX_VALIDATE" )
	if [ -z "$2" ]; then
		exit 1
	fi
	$CP $SSHD_CONFIG $TMP_SSHD_CONFIG
	$ECHO KexAlgorithms $2 >> $TMP_SSHD_CONFIG
	$SSHD -T -f $TMP_SSHD_CONFIG  >/dev/null 2>&1

	if [ $? != 0 ]; then
		$RM $TMP_SSHD_CONFIG
		exit 1
	fi
	$RM $TMP_SSHD_CONFIG
;;

"$SSH_MAC_VALIDATE" )
	if [ -z "$2" ]; then
		exit 1
	fi
	$CP $SSHD_CONFIG $TMP_SSHD_CONFIG
	$ECHO Macs $2 >> $TMP_SSHD_CONFIG
	$SSHD -T -f $TMP_SSHD_CONFIG  >/dev/null 2>&1

	if [ $? != 0 ]; then
		$RM $TMP_SSHD_CONFIG
		exit 1
	fi
	$RM $TMP_SSHD_CONFIG
;;

"$SSH_ENC_VALIDATE" )
	if [ -z "$2" ]; then
		exit 1
	fi

	$CP $SSHD_CONFIG $TMP_SSHD_CONFIG
	$ECHO Ciphers $2 >> $TMP_SSHD_CONFIG
	$SSHD -T -f $TMP_SSHD_CONFIG  >/dev/null 2>&1

	if [ $? != 0 ]; then
		$RM $TMP_SSHD_CONFIG
		exit 1
	fi
	$RM $TMP_SSHD_CONFIG
;;


################################################
#  TLS based options
################################################

"$CIPHER_VERIFICATION" )
	if [ -z "$2" ]; then
		exit 1
	fi
	$OPENSSL_CIPHER_CMD $2 >/dev/null 2>&1
	if [ $? != 0 ]; then
		exit 1
	fi
;;

"$CIPHER_VERIFICATION_TLSv3" )
	if [ -z "$2" ]; then
		exit 1
	fi
	$OPENSSL_CIPHER_CMD -ciphersuites $2 >/dev/null 2>&1
	if [ $? != 0 ]; then
		exit 1
	fi
;;

"$CIPHER_VERIFY_SUBSET" )
	if [ -z "$3" ]; then
		exit 1
	fi


	# -v required to get one cipher at a time. 
	conf_ciph=`$OPENSSL_CIPHER_CMD -v $2 | $CUT -f 1 -d ' '`
	rcvd_ciph=`$OPENSSL_CIPHER_CMD -v $3 | $CUT -f 1 -d ' '`

    for cip in $rcvd_ciph
    do
		issubbset=0
        for sys_cip in $conf_ciph
        do
            if [ $cip == $sys_cip ]; then
				issubbset=1
				break
			fi
        done
		
		if [ $issubbset -eq 0 ]; then
			exit 1
		fi
    done
;;
"$CIPHER_VERIFY_SUBSET_TLSv3" )
	if [ -z "$3" ]; then
		exit 1
	fi


	# -v required to get one cipher at a time. 
	conf_ciph=`$OPENSSL_CIPHER_CMD -s -v -tls1_3 -ciphersuites $2 | $CUT -f 1 -d ' '`
	rcvd_ciph=`$OPENSSL_CIPHER_CMD -s -v -tls1_3 -ciphersuites $3 | $CUT -f 1 -d ' '`

    for cip in $rcvd_ciph
    do
		issubbset=0
        for sys_cip in $conf_ciph
        do
            if [ $cip == $sys_cip ]; then
				issubbset=1
				break
			fi
        done
		
		if [ $issubbset -eq 0 ]; then
			exit 1
		fi
    done
;;

"$WEB_RPC_KILL" )
    # Restart webd.
         $WEBDRESTART
         if [ ! -f $HTTPD_PID_FILE ]; then
             # In case of webrestart failure, retry max 7 times
             for i in `seq 7`
             do
                 sleep 1
                 if [ ! -f $HTTPD_PID_FILE ]; then 
                     if [ $i -ge 7 ]; then
                         echo "Invalid cipher. Web server failed to restart."
                         exit 1
                     fi
                 else
                     # Webservice is restarted. Exit from for loop
                     break
                 fi
             done
        fi

        pizzabox=$(/fabos/cliexec/hashow | $GREP -c "Not supported on this platform")

        if [ $pizzabox -eq 0 ]; then
            `$RSH -n $(otherhost)  $WEBDRESTART 2> /dev/null`
             file=`$RSH -n $(otherhost) "ls -l  $HTTPD_PID_FILE 2> /dev/null | wc -l " 2> /dev/null`
             if [[ $file -eq 0 ]]; then
                  # In case of webrestart failure, retry max 7 times
                  for i in `seq 7`
                  do
                      sleep 1
                      file=`$RSH -n $(otherhost) "ls -l  $HTTPD_PID_FILE  2> /dev/null | wc -l " 2> /dev/null`
                      if [[ $file -eq 0 ]]; then
                          if [ $i -ge 7 ]; then
                              echo "Invalid cipher. Web server failed to restart on Standby."
                              exit 1
                          fi
                      else
                          # Webservice is restarted. Exit from for loop
                          break
                      fi
                  done
             fi
        fi
;;  

"$HTTPS_RESTART" )
        # Restart https after 7 seconds, a time given for REST response to reach the initiator
	sleep 7
	$WEBDRESTART
	echo "HTTPS restarted from REST "$?
;;


#Default option
* )
exit 1 
;;      
    
esac

#Script Exit 
exit 0
