Under Construction
Aixpert Script for SSHD Settings
In the example shown so far, only the PermitRootLogin attribute can be set to “yes,” and back to “no” for an undo. Besides PermitRootLogin, there are a number of other security-relevant attributes, such as Ciphers, DisableForwarding, or PermitEmptyPasswords. Instead of writing a separate script for each of these attributes, based on the script developed above, it is advisable to adapt the existing script and support arbitrary attributes and values. To do this, the attribute and desired value must be passed as arguments, as in the standard script chusrattr. The only argument so far, the rule name, should be optional, as with chusrattr. If the argument is present, an undo entry should be created; if the argument is not present, no undo entry is created.
First, we change the description of the local_chsshdconf script as follows:
# Command Line Arguments : This script expects one or two command line arguments.
# The first argument should be of the form
# 'Attr=value', where 'Attr' is a valid keyword for sshd_config
# and 'value' is the value to set or to check for.
# The second argument is optional and if provided,
# indicates that the undo xml rule has to be
# generated.
# Syntac - local_chsshdconf Attr=value [rulename]
#
# OUTPUT : None
#
# Description : This script changes the attribute 'Attr' to
# the value 'value' in /etc/ssh/sshd_config.
# It dynamically generates an undo XML rule with
# shortname as "Undo$2_<timestamp>" if the second
# argument is provided.
# This script should be run with superuser privileges.
As a path prefix for temporary files we now use /etc/security/aixpert/tmp/local_chsshdconf (variable TMP):
# Initialize variables AIXPERT_FIFO, LOG, REPORT, SCPTDIR and UNDOXML
. /etc/security/aixpert/bin/initialize_variables
TMP=/etc/security/aixpert/tmp/local_chsshdconf
PID=$$
The check for the correct number of arguments must also be modified. The script must be called with one or two arguments:
if [ $# -lt 1 ] || [ $# -gt 2 ]
then
echo "Usage : local_chsshdconf Attr=value [rulename]\n"
exit 1
fi
The attribute to be set or checked is passed along with its value as an argument of the form “Attr=value“. The argument must be split into the attribute name and the value:
# Determine the user attribute that has to be changed.
sshdattr=`echo $1 | awk -F "=" '{print $1; if(NF != 2) exit 1}'`
if [ $? -ne 0 ] || [ "$sshdattr" = "" ]
then
dspmsg -s 4 aixpert.cat 1 "Usage : local_chsshdconf Attr=value [Rulename]\n"
exit 1
fi
# Determine the value that is being assigned to the $sshdattr
value=`echo $1 | awk -F "=" '{print $2}'`
The attribute name is stored in the variable sshdattr and the value in the variable value.
To check attributes, we write a small function that we place at the beginning of the script. This function prints the effective configuration using “sshd -T“, searches for the line containing the desired attribute, and returns the corresponding value.
function getEffectiveSshdValue
{
typeset -l keyword="$1" # translate to lower case
typeset key
typeset value="invalid"
sshd -T | grep -w "$keyword" | read key value
print "$value"
}
Using this function, you can then rewrite the check for an attribute. The previous check:
defvalue=`awk '$1 ~ /^PermitRootLogin$/ { print $2; }' /etc/ssh/sshd_config 2>/dev/null | tail -n 1`
case "$defvalue" in
[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]) ret=0 ;;
esac
we then rewrite as follows:
defvalue=`getEffectiveSshdValue "$sshdattr"`
[ "$defvalue" = "$value" ] && ret=0
The messages if the check is not successful (set value deviates from the target value) must also be adjusted slightly:
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" $sshdattr
$value $defvalue >>$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" $sshdattr
$value $defvalue >>$TMPREPT
else
printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" $sshdattr
$value $defvalue >>$REPORT
printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" $sshdattr
$value $defvalue >>$AIXPERT_FIFO
fi
fi
To start a test run for the modified verification, the XML file custom/sshd.xml must be adjusted:
/etc/security/aixpert # cat custom/sshd.xml
<?xml version="1.0" encoding="UTF-8"?>
<AIXPertSecurityHardening>
<AIXPertEntry name="test_permitrootlogin" function="permitrootlogin">
<AIXPertRuleType type="TEST"/>
<AIXPertDescription>Ensure that PermitRootLogin is False.</AIXPertDescription>
<AIXPertPrereqList>openssh.base.server</AIXPertPrereqList>
<AIXPertCommand>/etc/security/aixpert/bin/local_chsshdconf</AIXPertCommand>
<AIXPertArgs>PermitRootLogin=no test_permitrootlogin</AIXPertArgs>
<AIXPertGroup>SSHD policy rules</AIXPertGroup>
</AIXPertEntry>
</AIXPertSecurityHardening>
/etc/security/aixpert #
The current value of PermitRootLogin is:
# grep ^PermitRootLogin /etc/ssh/sshd_config
PermitRootLogin yes
#
A review should therefore not be successful:
# aixpert -c -P custom/sshd.xml
Processedrules=1 Passedrules=0 Failedrules=1 Level=TEST
Input file=custom/sshd.xml
#
As expected, the verification fails (Failedrules=1). We change the value of PermitRootLogin to “no” and run another verification:
# aixpert -c -P custom/sshd.xml
Processedrules=1 Passedrules=1 Failedrules=0 Level=TEST
Input file=custom/sshd.xml
#
The verification is now successful. This allows the modified script to check any attributes of the sshd.
Next, we implement the setting of arbitrary attributes in /etc/ssh/sshd_config. Here, too, we use a function that should be placed at the beginning of the script:
function setSshdValue
{
typeset -l keyToChange="$1"
typeset newValue="$2"
typeset -l lowerCaseKey
changed=false
while read -r line
do
print "$line" | read -r key value rest
lowerCaseKey="$key"
case "$lowerCaseKey" in
$keyToChange)
print "$key $newValue"
changed=true
;;
*) print "$line" ;;
esac
done </etc/ssh/sshd_config >/etc/ssh/sshd_config.new
${change} || print "$key $newValue" >>/etc/ssh/sshd_config.new
cp /etc/ssh/sshd_config.new /etc/ssh/sshd_config
rm -f /etc/ssh/sshd_config.new
}
A while loop searches line by line for the attribute name to be changed. If it is found, the name and new value are output. Otherwise, the lines are output unchanged. If the attribute is not found, the name and new value are output at the end. All output is redirected to an intermediate file (/etc/ssh/sshd_config.new).
The previous lines for setting PermitRootLogin (in the script after the verification) can then be removed and replaced by the following call to the above function:
setSshdValue "$sshdattr" "$value"
Before we test the new script version, we set PermitRootLogin to “yes” and remove all active rules:
/etc/security/aixpert # aixpert -u
/etc/security/aixpert # aixpert -u
There are no security rules to undo in file /etc/security/aixpert/core/appliedaixpert.xml
/etc/security/aixpert # rm check_report.txt core/appliedaixpert.* core/undo.xml log/* tmp/* undo/*
rm: check_report.txt: No such file or directory
rm: cannot remove directory undo/data
/etc/security/aixpert # grep ^PermitRootLogin /etc/ssh/sshd_config
PermitRootLogin yes
/etc/security/aixpert #
We now apply the rule for setting PermitRootLogin again:
/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 processed (Passedrules=1). A quick check with “aixpert -c” and grep shows that PermitRootLogin was set to “no“:
# aixpert -c
Processedrules=1 Passedrules=1 Failedrules=0 Level=TEST
Input file=/etc/security/aixpert/core/appliedaixpert.xml
# grep ^PermitRo /etc/ssh/sshd_config
PermitRootLogin no
#
Finally, the undo functionality needs to be adjusted. To perform an undo, the script simply needs to be called with the attribute name and the original value of the attribute. A rule name cannot be specified in this case, since no new undo entry should be created in /etc/security/aixpert/core/undo.xml during the undo.
We check whether the script was called with two arguments, i.e., with the rule name. If this is the case, the current value of the attribute is determined and stored in the variable defvalue. The variable undo is also set.
# This script generates Undo rule if the number of arguments is 2,
# otherwise it works as undo script.
if [ $# -eq 2 ]
then
# Determine the current value of $sshdattr from the effective configuration
defvalue=`getEffectiveSshdValue "$sshdattr"`
…
# Generate a dynamic undo rule
undo=1
fi
The script no longer needs to create an undo script, since the script itself can be called for undo. The corresponding lines in the script for creating the undo script are thus eliminated.
However, the undo entry in the XML file /etc/security/aixpert/core/undo.xml still needs to be created. However, the script itself is now stored as the AIXPertCommand, and the attribute name is specified as the argument (AIXPertArgs) along with the original value ($defvalue):
# Add an undo XML rule to the file $UNDOXML
awk -v rulepart1="\t<AIXPertEntry name=\"$name\">\n\
\t\t<AIXPertRuleType type=\"Undo\"/>\n"\
-v rulepart2="\t\t<AIXPertDescription ${desc_catmsginfo}>$undomsg \"$desc\"</AIXPertDes
cription>\n\
\t\t<AIXPertPrereqList/>\n"\
-v rulepart3="\t\t<AIXPertCommand>/etc/security/aixpert/bin/local_chsshdconf</AIXPertCo
mmand>\n\
\t\t<AIXPertArgs>$sshdattr=$defvalue</AIXPertArgs>\n\
\t\t<AIXPertGroup>SSHD policy rules</AIXPertGroup>\n\
\t</AIXPertEntry>" '{if(match($0,"^[\t ]*</AIXPertUndo>")==0) print $0;
else print rulepart1 rulepart2 rulepart3 "\n" $0}' $UNDOXML >$TMP$PID
Overall, this results in the following version of the script:
/etc/security/aixpert # cat bin/local_chsshdconf
#! /bin/ksh
#
# Copyright (c) 2022 by PowerCampus 01 GmbH
#
# Anyone is free to copy, publish, use, or distribute this software,
# for any purpose, commercial or non-commercial, and by any means,
# as long as this copyright notice is kept.
# Modification of this software is allowed, as long as this copyright
# notice is kept, and a notice is placed in the software that indicates
# that the software has been modified. It is not allowed to sell this
# software without the written permission of PowerCampus 01.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
#
# Command Line Arguments : This script expects one or two command line arguments.
# The first argument should be of the form
# 'Attr=value', where 'Attr' is a valid keyword for sshd_config
# and 'value' is the value to set or to check for.
# The second argument is optional and if provided,
# indicates that the undo xml rule has to be
# generated.
# Syntax - local_chsshdconf Attr=value [rulename]
#
# OUTPUT : None
#
# Description : This script changes the attribute 'Attr' to
# the value 'value' in /etc/ssh/sshd_config.
# It dynamically generates an undo XML rule with
# shortname as "Undo$2_<timestamp>" if the second
# argument is provided.
# This script should be run with superuser privileges.
#
function getEffectiveSshdValue
{
typeset -l keyword="$1"
typeset key
typeset value="invalid"
sshd -T | grep -w "$keyword" | read key value
print "$value"
}
function setSshdValue
{
typeset -l keyToChange="$1"
typeset newValue="$2"
typeset -l lowerCaseKey
changed=false
while read -r line
do
print "$line" | read -r key value rest
lowerCaseKey="$key"
case "$lowerCaseKey" in
$keyToChange)
print "$key $newValue"
changed=true
;;
*) print "$line" ;;
esac
done </etc/ssh/sshd_config >/etc/ssh/sshd_config.new
${change} || print "$key $newValue" >>/etc/ssh/sshd_config.new
cp /etc/ssh/sshd_config.new /etc/ssh/sshd_config
rm -f /etc/ssh/sshd_config.new
}
export PATH=/usr/bin:/usr/sbin:$PATH
# Initialize variables AIXPERT_FIFO, LOG, REPORT, SCPTDIR and UNDOXML
. /etc/security/aixpert/bin/initialize_variables
TMP=/etc/security/aixpert/tmp/local_chsshdconf
PID=$$
# 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 [ $# -lt 1 ] || [ $# -gt 2 ]
then
echo "Usage : local_chsshdconf Attr=value [rulename]\n"
exit 1
fi
# A value of 0 indicates that Undo rule need not be created.
# This variable will be set later in the script if there is anything to be undone
undo=0
# Check whether AIXPERT_CHECK_REPORT environment variable is set or not.
report=`echo $AIXPERT_CHECK_REPORT`
BrType=`echo $BASE_REPT`
DrType=`echo $DETAILED_REPT`
# Determine the user attribute that has to be changed.
sshdattr=`echo $1 | awk -F "=" '{print $1; if(NF != 2) exit 1}'`
if [ $? -ne 0 ] || [ "$sshdattr" = "" ]
then
dspmsg -s 4 aixpert.cat 1 "Usage : local_chsshdconf Attr=value [Rulename]\n"
exit 1
fi
# Determine the value that is being assigned to the $sshdattr
value=`echo $1 | awk -F "=" '{print $2}'`
# This script generates Undo rule if the number of arguments is 2,
# otherwise it works as undo script.
if [ $# -eq 2 ]
then
# Determine the current value of $sshdattr from the effective configuration
defvalue=`getEffectiveSshdValue "$sshdattr"`
if [ "$report" = "1" ]
then
ret=1
[ "$defvalue" = "$value" ] && ret=0
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" $sshdattr $value $defvalue >>$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" $sshdattr $value $defvalue >>$TMPREPT
else
printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" $sshdattr $value $defvalue >>$REPORT
printf "local_chsshdconf: sshd attribute %s should have value %s, but it is %s now\n" $sshdattr $value $defvalue >>$AIXPERT_FIFO
fi
fi
exit $ret
fi
# Generate a dynamic undo rule
undo=1
fi
setSshdValue "$sshdattr" "$value"
if [ $undo -eq 1 ]
then
# Check if UNDOXML file has <AIXPertUndo> tag or not
empty=`grep "^<AIXPertUndo>" $UNDOXML`
if [ "$empty" = "" ]
then
echo "\n<AIXPertUndo>\n</AIXPertUndo>" >> $UNDOXML
fi
# Get the rulename and put it in undo rule
name=`echo $AIXPERT_NAME`
# Get the rule description & pass it to undo rule
desc=`echo $AIXPERT_DESC`
desc_catmsginfo=`echo $AIXPERT_DESC_CATMSGINFO`
undomsg=`/usr/bin/dspmsg -s 49 aixpert.cat 1 "Undo action for: "`
# Add an undo XML rule to the file $UNDOXML
awk -v rulepart1="\t<AIXPertEntry name=\"$name\">\n\
\t\t<AIXPertRuleType type=\"Undo\"/>\n"\
-v rulepart2="\t\t<AIXPertDescription ${desc_catmsginfo}>$undomsg \"$desc\"</AIXPertDescription>\n\
\t\t<AIXPertPrereqList/>\n"\
-v rulepart3="\t\t<AIXPertCommand>/etc/security/aixpert/bin/local_chsshdconf</AIXPertCommand>\n\
\t\t<AIXPertArgs>$sshdattr=$defvalue</AIXPertArgs>\n\
\t\t<AIXPertGroup>SSHD policy rules</AIXPertGroup>\n\
\t</AIXPertEntry>" '{if(match($0,"^[\t ]*</AIXPertUndo>")==0) print $0;
else print rulepart1 rulepart2 rulepart3 "\n" $0}' $UNDOXML >$TMP$PID
if [ $? -eq 0 ] ; then
mv $TMP$PID $UNDOXML
fi
fi
exit 0
/etc/security/aixpert #
Before we run the final script version again, we set PermitRootLogin back to “yes” and remove all active rules:
/etc/security/aixpert # aixpert -u
/etc/security/aixpert # aixpert -u
There are no security rules to undo in file /etc/security/aixpert/core/appliedaixpert.xml
/etc/security/aixpert # rm check_report.txt core/appliedaixpert.* core/undo.xml log/* tmp/* undo/*
rm: check_report.txt: No such file or directory
rm: cannot remove directory undo/data
/etc/security/aixpert # grep ^PermitRootLogin /etc/ssh/sshd_config
PermitRootLogin yes
/etc/security/aixpert #
We apply the rule to our system again:
/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 #
Let’s look at the entry in the undo.xml:
/etc/security/aixpert # cat /etc/security/aixpert/core/undo.xml
<AIXPertUndo>
<AIXPertEntry name="test_permitrootlogin_DD8096ED">
<AIXPertRuleType type="Undo"/>
<AIXPertDescription catalog="" setNum="" msgNum="">Undo action for: "Ensure that PermitRootLogin is False."</AIXPertDescription>
<AIXPertPrereqList/>
<AIXPertCommand>/etc/security/aixpert/bin/local_chsshdconf</AIXPertCommand>
<AIXPertArgs>PermitRootLogin=yes</AIXPertArgs>
<AIXPertGroup>SSHD policy rules</AIXPertGroup>
</AIXPertEntry>
</AIXPertUndo>
/etc/security/aixpert #
The undo entry calls the above script and uses the argument “PermitRootLogin=yes”, which is the original value of PermitRootLogin.
Finally, we check if the undo works correctly:
# aixpert -u
#
A quick check shows that the entries from appliedaixpert.xml and undo.xml have been removed and the value of PermitRootLogin is again “yes”:
/etc/security/aixpert # cat core/appliedaixpert.xml
<?xml version="1.0"?>
<AIXPertSecurityHardening>
</AIXPertSecurityHardening>
/etc/security/aixpert # cat core/undo.xml
<AIXPertUndo>
</AIXPertUndo>
/etc/security/aixpert # grep ^PermitRootLogin /etc/ssh/sshd_config
PermitRootLogin yes
/etc/security/aixpert #