Under Construction

Step 5: Set PermitRootLogin to no

Next, we’ll implement setting PermitRootLogin to “no“. Before we implement this, let’s apply the rule from custom/sshd.xml to the system:

/etc/security/aixpert # aixpert -f custom/sshd.xml
Processedrules=1        Passedrules=1   PrereqFailedrules=0     Failedrules=0   Level=TEST
        Input file=custom/sshd.xml
/etc/security/aixpert #

According to the output, the rule was successfully implemented (Passedrules=1)! However, a check shows that this is obviously not the case (Failedrules=1), after all, we haven’t implemented the implementation yet:

/etc/security/aixpert # aixpert -c
Processedrules=1        Passedrules=0   Failedrules=1   Level=TEST
        Input file=/etc/security/aixpert/core/appliedaixpert.xml
/etc/security/aixpert #

We extend our script and add the following loop to the end of the script:

firstOccurrence=true
while read -r line
do
        case "$line" in
        PermitRootLogin*)
                if $firstOccurrence
                then
                        print "PermitRootLogin no"
                        firstOccurrence=false
                fi
                ;;
        *)
                print $line ;;
        esac
done </etc/ssh/sshd_config >/etc/ssh/sshd_config.new
$firstOccurrence && print "PermitRootLogin no" >>/etc/ssh/sshd_config.new
cp /etc/ssh/sshd_config.new /etc/ssh/sshd_config
rm /etc/ssh/sshd_config.new

The loop reads /etc/ssh/sshd_config line by line. If a line begins with PermitRootLogin, it is replaced with “PermitRootLogin no” (but only the first time it occurs). All other lines are simply copied. The lines are written to the file /etc/ssh/sshd_config.new. If there was no line with PermitRootLogin, the line “PermitRootLogin no” is simply appended to the end of /etc/ssh/sshd_config.new. Finally, /etc/ssh/sshd_config.new is copied to /etc/ssh/sshd_config, and the intermediate file is deleted.

Note: This loop is a first draft and does not account for all practical scenarios. For example, there may be one or more spaces or tabs before PermitRootLogin, or match statements may have been used in sshd_config. In that case, it would be necessary to ensure that “PermitRootLogin no” precedes the match statements. And there are certainly other special cases that need to be considered.

Overall, this results in the following version of the script:

# cat /etc/security/aixpert/bin/local_chsshdconf
#! /bin/ksh

export PATH=/usr/bin:/usr/sbin:$PATH

# Initialize variables AIXPERT_FIFO, LOG, REPORT, SCPTDIR and UNDOXML
. /etc/security/aixpert/bin/initialize_variables

# Log output and errors to /etc/security/aixpert/log/aixpert.log
exec 1>>$LOG
exec 2>&1

# echo all the commands and the current time and date to the AIXpert log
set -x
date
echo $0 $@ AIXPERT_CHECK_REPORT=$AIXPERT_CHECK_REPORT BASE_REPT=$BASE_REPT DETAILED_REPT=$DETAILED_REPT

if [ $# -ne 0 ]
then
    echo "Usage : local_chsshdconf\n"
    exit 1
fi

# Check whether AIXPERT_CHECK_REPORT environment variable is set or not.
report=`echo $AIXPERT_CHECK_REPORT`
BrType=`echo $BASE_REPT`
DrType=`echo $DETAILED_REPT`

if [ "$report" = "1" ]
then
        ret=1

        permit=$( awk '$1 ~ /^PermitRootLogin$/ { print $2; }' /etc/ssh/sshd_config 2>/dev/null | tail -n 1 )
        case "${permit}" in
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]) ret=0 ;;
        esac

        if [ $ret = 1 ]
        then
                if [ "$BrType" = "1" ]
                then
                        echo "Base Compliance Report\n";
                        printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" PermitRootLogin no $permit >>$TMPREPT
                elif [ "$DrType" = "1" ]
                then
                        echo "Description Report\n";
                        printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" PermitRootLogin no $permit >>$TMPREPT
                else
                        printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" PermitRootLogin no $permit >>$REPORT
                        printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" PermitRootLogin no $permit >>$AIXPERT_FIFO
                fi
        fi

        exit $ret
fi

firstOccurrence=true
while read -r line
do
       case "$line" in
        PermitRootLogin*)
                if $firstOccurrence
                then
                        print "PermitRootLogin no"
                        firstOccurrence=false
                fi
                ;;
        *)
                print $line ;;
        esac
done </etc/ssh/sshd_config >/etc/ssh/sshd_config.new
$firstOccurrence && print "PermitRootLogin no" >>/etc/ssh/sshd_config.new
cp /etc/ssh/sshd_config.new /etc/ssh/sshd_config
rm /etc/ssh/sshd_config.new

exit 0

#

A test run is again successful according to the output:

/etc/security/aixpert # aixpert -f custom/sshd.xml
Processedrules=1        Passedrules=1   PrereqFailedrules=0     Failedrules=0   Level=TEST
        Input file=custom/sshd.xml
/etc/security/aixpert #

We start a check and see whether it was really successful (Passedrules=1):

/etc/security/aixpert # aixpert -c
Processedrules=1        Passedrules=1   Failedrules=0   Level=TEST
        Input file=/etc/security/aixpert/core/appliedaixpert.xml
/etc/security/aixpert #

A quick check of /etc/ssh/sshd_config shows that the value of PermitRootLogin has now indeed been changed:

# grep -w PermitRootLogin /etc/ssh/sshd_config
PermitRootLogin no
#

What’s also missing from the above loop is an error check! If an error occurs during one of the commands, a message should be written to /etc/security/aixpert/log/aixpert.log and the script should abort with an exit status other than 0. We won’t implement this for now.

What’s still missing is support for the undo functionality. We’ll address that in the next step.