Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debian11 #29

Merged
merged 10 commits into from
Feb 8, 2021
Merged

Debian11 #29

merged 10 commits into from
Feb 8, 2021

Conversation

thibaultserti
Copy link
Contributor

bin/hardening/5.2.15_ssh_cry_kex.sh Outdated Show resolved Hide resolved
lib/utils.sh Show resolved Hide resolved
@speed47
Copy link
Collaborator

speed47 commented Jan 22, 2021

This may be a good idea to tell the user that they're running the script in a non-officially supported Debian version, as in "there's no official PDF for this version so we'll do our best to show you results that are not entirely stupid, but please take those with a grain of salt". Same stuff if somebody has the idea to run it under Ubuntu or any other Debian derivative. Most tests will still work, but might give a false sense of security because e.g. we're looking for a package that has a different name under Ubuntu, or because defaults under Ubuntu are different so more stuff should be looked after to be disabled etc. In other words, 100% compliance under Ubuntu (or any other non-Debian-9-10 distro) does NOT mean that the system is properly hardened.
The user should be warned in some way. There are several ways to do it:

  • Boldly refusing to run unless --allow-unsupported-distribution is specified on the cmdline
  • Showing a big fat warn somewhere but run nevertheless, the warning could be silenced by a cmdline option
  • Adding a test that always fail if not Debian-9-10, hence sysadmins would have to disable this test, and doing so, acknowledging that they know what they're doing

... and maybe other ways :)

@github-actions
Copy link

sh-checker report

shellcheck output

�[1mIn bin/hardening.sh line 346:�[0m
�[0m        CONFORMITY_PERCENTAGE=$(div $(($PASSED_CHECKS * 100)) $TOTAL_TREATED_CHECKS)�[0m
�[32m                                       ^------------^ SC2004: $/${} is unnecessary on arithmetic variables.�[0m


�[1mIn bin/hardening.sh line 359:�[0m
�[0m    ENABLED_CHECKS_PERCENTAGE=$(div $(($TOTAL_TREATED_CHECKS * 100)) $TOTAL_CHECKS)�[0m
�[32m                                       ^-------------------^ SC2004: $/${} is unnecessary on arithmetic variables.�[0m


�[1mIn bin/hardening.sh line 360:�[0m
�[0m    CONFORMITY_PERCENTAGE=$(div $(($PASSED_CHECKS * 100)) $TOTAL_TREATED_CHECKS)�[0m
�[32m                                   ^------------^ SC2004: $/${} is unnecessary on arithmetic variables.�[0m

For more information:
https://www.shellcheck.net/wiki/SC2004 -- $/${} is unnecessary on arithmeti...

The files above have some shellcheck issues

shfmt output
bin/hardening.sh
--- bin/hardening.sh.orig
+++ bin/hardening.sh
@@ -1,368 +1,367 @@
 #!/bin/bash
 
 # run-shellcheck
 #
 # CIS Debian Hardening
 # Authors : Thibault Dewailly, OVH <thibault.dewailly@corp.ovh.com>
 #
 
 #
 # Main script : Execute hardening considering configuration
 #
 
 LONG_SCRIPT_NAME=$(basename "$0")
 SCRIPT_NAME=${LONG_SCRIPT_NAME%.sh}
 DISABLED_CHECKS=0
 PASSED_CHECKS=0
 FAILED_CHECKS=0
 TOTAL_CHECKS=0
 TOTAL_TREATED_CHECKS=0
 AUDIT=0
 APPLY=0
 AUDIT_ALL=0
 AUDIT_ALL_ENABLE_PASSED=0
 CREATE_CONFIG=0
 ALLOW_SERVICE_LIST=0
 SET_HARDENING_LEVEL=0
 SUDO_MODE=''
 BATCH_MODE=''
 ALLOW_UNSUPPORTED_DISTRIBUTION=0
 
 usage() {
     cat <<EOF
 $LONG_SCRIPT_NAME <RUN_MODE> [OPTIONS], where RUN_MODE is one of:
 
     --help -h
         Show this help
 
     --apply
         Apply hardening for enabled scripts.
         Beware that NO confirmation is asked whatsoever, which is why you're warmly
         advised to use --audit before, which can be regarded as a dry-run mode.
 
     --audit
         Audit configuration for enabled scripts.
         No modification will be made on the system, we'll only report on your system
         compliance for each script.
 
     --audit-all
         Same as --audit, but for *all* scripts, even disabled ones.
         This is a good way to peek at your compliance level if all scripts were enabled,
         and might be a good starting point.
 
     --audit-all-enable-passed
         Same as --audit-all, but in addition, will *modify* the individual scripts
         configurations to enable those which passed for your system.
         This is an easy way to enable scripts for which you're already compliant.
         However, please always review each activated script afterwards, this option
         should only be regarded as a way to kickstart a configuration from scratch.
         Don't run this if you have already customized the scripts enable/disable
         configurations, obviously.
 
     --set-hardening-level <level>
         Modifies the configuration to enable/disable tests given an hardening level,
         between 1 to 5. Don't run this if you have already customized the scripts
         enable/disable configurations.
         1: very basic policy, failure to pass tests at this level indicates severe
             misconfiguration of the machine that can have a huge security impact
         2: basic policy, some good practice rules that, once applied, shouldn't
             break anything on most systems
         3: best practices policy, passing all tests might need some configuration
             modifications (such as specific partitioning, etc.)
         4: high security policy, passing all tests might be time-consuming and
             require high adaptation of your workflow
         5: placebo, policy rules that might be very difficult to apply and maintain,
             with questionable security benefits
 
     --allow-service <service>
         Use with --set-hardening-level.
         Modifies the policy to allow a certain kind of services on the machine, such
         as http, mail, etc. Can be specified multiple times to allow multiple services.
         Use --allow-service-list to get a list of supported services.
     
     --create-config-files-only
         Create the config files in etc/conf.d
         Must be run as root, before running the audit with user secaudit
 
 OPTIONS:
 
     --only <test_number>
         Modifies the RUN_MODE to only work on the test_number script.
         Can be specified multiple times to work only on several scripts.
         The test number is the numbered prefix of the script,
         i.e. the test number of 1.2_script_name.sh is 1.2.
 
     --sudo
         This option lets you audit your system as a normal user, but allows sudo
         escalation to gain read-only access to root files. Note that you need to
         provide a sudoers file with NOPASSWD option in /etc/sudoers.d/ because
         the '-n' option instructs sudo not to prompt for a password.
         Finally note that '--sudo' mode only works for audit mode.
 
     --batch
         While performing system audit, this option sets LOGLEVEL to 'ok' and
         captures all output to print only one line once the check is done, formatted like :
         OK|KO OK|KO|WARN{subcheck results} [OK|KO|WARN{...}]
     
     --allow-unsupported-distribution
         Must be specified manually in the command line to allow the run on non compatible
         version or distribution. If you want to mute the warning change the LOGLEVEL
         in /etc/hardening.cfg
 
 EOF
     exit 0
 }
 
 if [ $# = 0 ]; then
     usage
 fi
 
 declare -a TEST_LIST ALLOWED_SERVICES_LIST
 
 # Arguments parsing
 while [[ $# -gt 0 ]]; do
     ARG="$1"
     case $ARG in
     --audit)
         AUDIT=1
         ;;
     --audit-all)
         AUDIT_ALL=1
         ;;
     --audit-all-enable-passed)
         AUDIT_ALL_ENABLE_PASSED=1
         ;;
     --apply)
         APPLY=1
         ;;
     --allow-service-list)
         ALLOW_SERVICE_LIST=1
         ;;
     --create-config-files-only)
         CREATE_CONFIG=1
         ;;
     --allow-service)
         ALLOWED_SERVICES_LIST[${#ALLOWED_SERVICES_LIST[@]}]="$2"
         shift
         ;;
     --set-hardening-level)
         SET_HARDENING_LEVEL="$2"
         shift
         ;;
     --only)
         TEST_LIST[${#TEST_LIST[@]}]="$2"
         shift
         ;;
     --sudo)
         SUDO_MODE='--sudo'
         ;;
     --batch)
         BATCH_MODE='--batch'
         LOGLEVEL=ok
         ;;
     --allow-unsupported-distribution)
         ALLOW_UNSUPPORTED_DISTRIBUTION=1
         ;;
     -h | --help)
         usage
         ;;
     *)
         usage
         ;;
     esac
     shift
 done
 
 # if no RUN_MODE was passed, usage and quit
 if [ "$AUDIT" -eq 0 ] && [ "$AUDIT_ALL" -eq 0 ] && [ "$AUDIT_ALL_ENABLE_PASSED" -eq 0 ] && [ "$APPLY" -eq 0 ] && [ "$CREATE_CONFIG" -eq 0 ]; then
     usage
 fi
 
 # Source Root Dir Parameter
 if [ -r /etc/default/cis-hardening ]; then
     # shellcheck source=../debian/default
     . /etc/default/cis-hardening
 fi
 if [ -z "$CIS_ROOT_DIR" ]; then
     echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment."
     echo "Cannot source CIS_ROOT_DIR variable, aborting."
     exit 128
 fi
 # shellcheck source=../lib/constants.sh
 [ -r "$CIS_ROOT_DIR"/lib/constants.sh ] && . "$CIS_ROOT_DIR"/lib/constants.sh
 # shellcheck source=../etc/hardening.cfg
 [ -r "$CIS_ROOT_DIR"/etc/hardening.cfg ] && . "$CIS_ROOT_DIR"/etc/hardening.cfg
 # shellcheck source=../lib/common.sh
 [ -r "$CIS_ROOT_DIR"/lib/common.sh ] && . "$CIS_ROOT_DIR"/lib/common.sh
 # shellcheck source=../lib/utils.sh
 [ -r "$CIS_ROOT_DIR"/lib/utils.sh ] && . "$CIS_ROOT_DIR"/lib/utils.sh
 
 if [ "$BATCH_MODE" ]; then MACHINE_LOG_LEVEL=3; fi
 
 # If we're on a unsupported platform and there is no flag --allow-unsupported-distribution
 # print warning, otherwise quit
 
 get_distribution
 if [ "debian" != "$DISTRIBUTION" ]; then
     echo "Your distribution has been identified as $DISTRIBUTION which is not debian"
     if [ "$ALLOW_UNSUPPORTED_DISTRIBUTION" -eq 0 ]; then
         echo "If you want to run it anyway, you can use the flag --allow-unsupported-distribution"
         echo "Exiting now"
         exit 100
     elif [ "$ALLOW_UNSUPPORTED_DISTRIBUTION" -eq 0 ] && [ "$MACHINE_LOG_LEVEL" -ge 2 ]; then
         echo "Be aware that the result given by this set of scripts can give you a false feedback of security on unsupported distributions !"
         echo "You can deactivate this message by setting the LOGLEVEL variable in /etc/hardening.cfg"
     fi
-else 
+else
     get_debian_major_version
     if [ "$DEB_MAJ_VER" = "sid" ] || [ "$DEB_MAJ_VER" -ge 11 ]; then
         echo "Your debian version is too recent and is not supported yet because there is no official CIS PDF for this version yet."
         if [ "$ALLOW_UNSUPPORTED_DISTRIBUTION" -eq 0 ]; then
             echo "If you want to run it anyway, you can use the flag --allow-unsupported-distribution"
             echo "Exiting now"
             exit 100
         elif [ "$ALLOW_UNSUPPORTED_DISTRIBUTION" -eq 0 ] && [ "$MACHINE_LOG_LEVEL" -ge 2 ]; then
             echo "Be aware that the result given by this set of scripts can give you a false feedback of security on unsupported distributions !"
             echo "You can deactivate this message by setting the LOGLEVEL variable in /etc/hardening.cfg"
         fi
     elif [ "$DEB_MAJ_VER" -le 8 ]; then
         echo "Your debian version is deprecated and is no more maintained. Please upgrade to a supported version."
         if [ "$ALLOW_UNSUPPORTED_DISTRIBUTION" -eq 0 ]; then
             echo "If you want to run it anyway, you can use the flag --allow-unsupported-distribution"
             echo "Exiting now"
             exit 100
         elif [ "$ALLOW_UNSUPPORTED_DISTRIBUTION" -eq 0 ] && [ "$MACHINE_LOG_LEVEL" -ge 2 ]; then
             echo "Be aware that the result given by this set of scripts can give you a false feedback of security on unsupported distributions, especially on deprecated ones !"
             echo "You can deactivate this message by setting the LOGLEVEL variable in /etc/hardening.cfg"
         fi
     fi
 fi
 
-
 # If --allow-service-list is specified, don't run anything, just list the supported services
 if [ "$ALLOW_SERVICE_LIST" = 1 ]; then
     declare -a HARDENING_EXCEPTIONS_LIST
     for SCRIPT in $(find "$CIS_ROOT_DIR"/bin/hardening/ -name "*.sh" | sort -V); do
         template=$(grep "^HARDENING_EXCEPTION=" "$SCRIPT" | cut -d= -f2)
         [ -n "$template" ] && HARDENING_EXCEPTIONS_LIST[${#HARDENING_EXCEPTIONS_LIST[@]}]="$template"
     done
     echo "Supported services are:" "$(echo "${HARDENING_EXCEPTIONS_LIST[@]}" | tr " " "\n" | sort -u | tr "\n" " ")"
     exit 0
 fi
 
 # If --set-hardening-level is specified, don't run anything, just apply config for each script
 if [ -n "$SET_HARDENING_LEVEL" ] && [ "$SET_HARDENING_LEVEL" != 0 ]; then
     if ! grep -q "^[12345]$" <<<"$SET_HARDENING_LEVEL"; then
         echo "Bad --set-hardening-level specified ('$SET_HARDENING_LEVEL'), expected 1 to 5"
         exit 1
     fi
 
     for SCRIPT in $(find "$CIS_ROOT_DIR"/bin/hardening/ -name "*.sh" | sort -V); do
         SCRIPT_BASENAME=$(basename "$SCRIPT" .sh)
         script_level=$(grep "^HARDENING_LEVEL=" "$SCRIPT" | cut -d= -f2)
         if [ -z "$script_level" ]; then
             echo "The script $SCRIPT_BASENAME doesn't have a hardening level, configuration untouched for it"
             continue
         fi
         wantedstatus=disabled
         [ "$script_level" -le "$SET_HARDENING_LEVEL" ] && wantedstatus=enabled
         sed -i -re "s/^status=.+/status=$wantedstatus/" "$CIS_ROOT_DIR/etc/conf.d/$SCRIPT_BASENAME.cfg"
     done
     echo "Configuration modified to enable scripts for hardening level at or below $SET_HARDENING_LEVEL"
     exit 0
 fi
 
 if [ "$CREATE_CONFIG" = 1 ] && [ "$EUID" -ne 0 ]; then
     echo "For --create-config-files-only, please run as root"
     exit 1
 fi
 
 # Parse every scripts and execute them in the required mode
 for SCRIPT in $(find "$CIS_ROOT_DIR"/bin/hardening/ -name "*.sh" | sort -V); do
     if [ "${#TEST_LIST[@]}" -gt 0 ]; then
         # --only X has been specified at least once, is this script in my list ?
         SCRIPT_PREFIX=$(grep -Eo '^[0-9.]+' <<<"$(basename "$SCRIPT")")
         # shellcheck disable=SC2001
         SCRIPT_PREFIX_RE=$(sed -e 's/\./\\./g' <<<"$SCRIPT_PREFIX")
         if ! grep -qwE "(^| )$SCRIPT_PREFIX_RE" <<<"${TEST_LIST[@]}"; then
             # not in the list
             continue
         fi
     fi
 
     info "Treating $SCRIPT"
     if [ "$CREATE_CONFIG" = 1 ]; then
         debug "$CIS_ROOT_DIR/bin/hardening/$SCRIPT --create-config-files-only"
         "$SCRIPT" --create-config-files-only "$BATCH_MODE"
     elif [ "$AUDIT" = 1 ]; then
         debug "$CIS_ROOT_DIR/bin/hardening/$SCRIPT --audit $SUDO_MODE $BATCH_MODE"
         "$SCRIPT" --audit "$SUDO_MODE" "$BATCH_MODE"
     elif [ "$AUDIT_ALL" = 1 ]; then
         debug "$CIS_ROOT_DIR/bin/hardening/$SCRIPT --audit-all $SUDO_MODE $BATCH_MODE"
         "$SCRIPT" --audit-all "$SUDO_MODE" "$BATCH_MODE"
     elif [ "$AUDIT_ALL_ENABLE_PASSED" = 1 ]; then
         debug "$CIS_ROOT_DIR/bin/hardening/$SCRIPT --audit-all $SUDO_MODE $BATCH_MODE"
         "$SCRIPT" --audit-all "$SUDO_MODE" "$BATCH_MODE"
     elif [ "$APPLY" = 1 ]; then
         debug "$CIS_ROOT_DIR/bin/hardening/$SCRIPT"
         "$SCRIPT"
     fi
 
     SCRIPT_EXITCODE=$?
 
     debug "Script $SCRIPT finished with exit code $SCRIPT_EXITCODE"
     case $SCRIPT_EXITCODE in
     0)
         debug "$SCRIPT passed"
         PASSED_CHECKS=$((PASSED_CHECKS + 1))
         if [ "$AUDIT_ALL_ENABLE_PASSED" = 1 ]; then
             SCRIPT_BASENAME=$(basename "$SCRIPT" .sh)
             sed -i -re 's/^status=.+/status=enabled/' "$CIS_ROOT_DIR/etc/conf.d/$SCRIPT_BASENAME.cfg"
             info "Status set to enabled in $CIS_ROOT_DIR/etc/conf.d/$SCRIPT_BASENAME.cfg"
         fi
         ;;
     1)
         debug "$SCRIPT failed"
         FAILED_CHECKS=$((FAILED_CHECKS + 1))
         ;;
     2)
         debug "$SCRIPT is disabled"
         DISABLED_CHECKS=$((DISABLED_CHECKS + 1))
         ;;
     esac
 
     TOTAL_CHECKS=$((TOTAL_CHECKS + 1))
 
 done
 
 TOTAL_TREATED_CHECKS=$((TOTAL_CHECKS - DISABLED_CHECKS))
 
 if [ "$BATCH_MODE" ]; then
     BATCH_SUMMARY="AUDIT_SUMMARY "
     BATCH_SUMMARY+="PASSED_CHECKS:${PASSED_CHECKS:-0} "
     BATCH_SUMMARY+="RUN_CHECKS:${TOTAL_TREATED_CHECKS:-0} "
     BATCH_SUMMARY+="TOTAL_CHECKS_AVAIL:${TOTAL_CHECKS:-0}"
     if [ "$TOTAL_TREATED_CHECKS" != 0 ]; then
         CONFORMITY_PERCENTAGE=$(div $(($PASSED_CHECKS * 100)) $TOTAL_TREATED_CHECKS)
         BATCH_SUMMARY+=" CONFORMITY_PERCENTAGE:$(printf "%s" "$CONFORMITY_PERCENTAGE")"
     else
         BATCH_SUMMARY+=" CONFORMITY_PERCENTAGE:N.A" # No check runned, avoid division by 0
     fi
     becho "$BATCH_SUMMARY"
 else
     printf "%40s\n" "################### SUMMARY ###################"
     printf "%30s %s\n" "Total Available Checks :" "$TOTAL_CHECKS"
     printf "%30s %s\n" "Total Runned Checks :" "$TOTAL_TREATED_CHECKS"
     printf "%30s [ %7s ]\n" "Total Passed Checks :" "$PASSED_CHECKS/$TOTAL_TREATED_CHECKS"
     printf "%30s [ %7s ]\n" "Total Failed Checks :" "$FAILED_CHECKS/$TOTAL_TREATED_CHECKS"
 
     ENABLED_CHECKS_PERCENTAGE=$(div $(($TOTAL_TREATED_CHECKS * 100)) $TOTAL_CHECKS)
     CONFORMITY_PERCENTAGE=$(div $(($PASSED_CHECKS * 100)) $TOTAL_TREATED_CHECKS)
     printf "%30s %s %%\n" "Enabled Checks Percentage :" "$ENABLED_CHECKS_PERCENTAGE"
     if [ "$TOTAL_TREATED_CHECKS" != 0 ]; then
         printf "%30s %s %%\n" "Conformity Percentage :" "$CONFORMITY_PERCENTAGE"
     else
         printf "%30s %s %%\n" "Conformity Percentage :" "N.A" # No check runned, avoid division by 0
     fi
 fi
 
lib/utils.sh
--- lib/utils.sh.orig
+++ lib/utils.sh
@@ -1,513 +1,514 @@
 # shellcheck shell=bash
 # CIS Debian Hardening Utility functions
 
 # run-shellcheck
 
 #
 # Sysctl
 #
 
 has_sysctl_param_expected_result() {
     local SYSCTL_PARAM=$1
     local EXP_RESULT=$2
 
     if [ "$($SUDO_CMD sysctl "$SYSCTL_PARAM" 2>/dev/null)" = "$SYSCTL_PARAM = $EXP_RESULT" ]; then
         FNRET=0
     elif [ "$?" = 255 ]; then
         debug "$SYSCTL_PARAM does not exist"
         FNRET=255
     else
         debug "$SYSCTL_PARAM should be set to $EXP_RESULT"
         FNRET=1
     fi
 }
 
 does_sysctl_param_exists() {
     local SYSCTL_PARAM=$1
     if [ "$($SUDO_CMD sysctl -a 2>/dev/null | grep "$SYSCTL_PARAM" -c)" = 0 ]; then
         FNRET=1
     else
         FNRET=0
     fi
 }
 
 set_sysctl_param() {
     local SYSCTL_PARAM=$1
     local VALUE=$2
     debug "Setting $SYSCTL_PARAM to $VALUE"
     if [ "$(sysctl -w "$SYSCTL_PARAM"="$VALUE" 2>/dev/null)" = "$SYSCTL_PARAM = $VALUE" ]; then
         FNRET=0
     elif [ $? = 255 ]; then
         debug "$SYSCTL_PARAM does not exist"
         FNRET=255
     else
         warn "$SYSCTL_PARAM failed!"
         FNRET=1
     fi
 }
 
 #
 # Dmesg
 #
 
 does_pattern_exist_in_dmesg() {
     local PATTERN=$1
     if $SUDO_CMD dmesg | grep -qE "$PATTERN"; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 #
 # File
 #
 
 does_file_exist() {
     local FILE=$1
     if $SUDO_CMD [ -e "$FILE" ]; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 has_file_correct_ownership() {
     local FILE=$1
     local USER=$2
     local GROUP=$3
     local USERID
     local GROUPID
     USERID=$(id -u "$USER")
     GROUPID=$(getent group "$GROUP" | cut -d: -f3)
     debug "$SUDO_CMD stat -c '%u %g' $FILE"
     if [ "$($SUDO_CMD stat -c "%u %g" "$FILE")" = "$USERID $GROUPID" ]; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 has_file_one_of_ownership() {
     local FILE=$1
     local USER=$2
     local GROUPS_OK=$3
 
     local USEROK=1
     local GROUPOK=1
 
     local USERID
     USERID=$(id -u "$USER")
     if [ "$($SUDO_CMD stat -c "%u" "$FILE")" = "$USERID" ]; then
         USEROK=0
     fi
 
     for GROUP in $GROUPS_OK; do
         local GROUPID
         GROUPID=$(getent group "$GROUP" | cut -d: -f3)
         if [ "$($SUDO_CMD stat -c "%g" "$FILE")" = "$GROUPID" ]; then
             GROUPOK=0
         fi
     done
 
     if [[ "$GROUPOK" = 0 ]] && [[ "$USEROK" = 0 ]]; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 has_file_correct_permissions() {
     local FILE=$1
     local PERMISSIONS=$2
 
     if [ "$($SUDO_CMD stat -L -c "%a" "$FILE")" = "$PERMISSIONS" ]; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 has_file_one_of_permissions() {
     local FILE=$1
     local PERMISSIONS=$2
     FNRET=1
     for PERMISSION in $PERMISSIONS; do
         if [ "$($SUDO_CMD stat -L -c "%a" "$FILE")" = "$PERMISSION" ]; then
             FNRET=0
         fi
     done
 }
 
 does_pattern_exist_in_file_nocase() {
     _does_pattern_exist_in_file "-Ei" "$@"
 }
 
 does_pattern_exist_in_file() {
     _does_pattern_exist_in_file "-E" "$@"
 }
 
 _does_pattern_exist_in_file() {
     local OPTIONS="$1"
     shift
     local FILE="$1"
     shift
     local PATTERN="$*"
 
     debug "Checking if $PATTERN is present in $FILE"
     if $SUDO_CMD [ -r "$FILE" ]; then
         debug "$SUDO_CMD grep -q $OPTIONS -- '$PATTERN' $FILE"
         if $SUDO_CMD grep -q "$OPTIONS" -- "$PATTERN" "$FILE"; then
             debug "Pattern found in $FILE"
             FNRET=0
         else
             debug "Pattern NOT found in $FILE"
             FNRET=1
         fi
     else
         debug "File $FILE is not readable!"
         FNRET=2
     fi
 }
 
 get_db() {
     local DB="$1"
     $SUDO_CMD getent --service files "$DB"
 }
 
 # Look for pattern in file that can spread over multiple lines
 # The func will remove commented lines (that begin with '#')
 # and consider the file as one long line.
 # Thus, this is not possible to look for pattern at beginning of line
 # with this func ('^' and '$')
 does_pattern_exist_in_file_multiline() {
     local FILE="$1"
     shift
     local PATTERN="$*"
 
     debug "Checking if multiline pattern: $PATTERN is present in $FILE"
     if $SUDO_CMD [ -r "$FILE" ]; then
         debug "$SUDO_CMD grep -v '^[[:space:]]*#' $FILE | tr '\n' ' ' | grep -Pq -- $PATTERN"
         if $SUDO_CMD grep -v '^[[:space:]]*#' "$FILE" | tr '\n' ' ' | grep -Pq -- "$PATTERN"; then
             debug "Pattern found in $FILE"
             FNRET=0
         else
             debug "Pattern NOT found in $FILE"
             FNRET=1
         fi
     else
         debug "File $FILE is not readable!"
         FNRET=2
     fi
 }
 
 add_end_of_file() {
     local FILE=$1
     local LINE=$2
 
     debug "Adding $LINE at the end of $FILE"
     backup_file "$FILE"
     echo "$LINE" >>"$FILE"
 }
 
 add_line_file_before_pattern() {
     local FILE=$1
     local LINE=$2
     local PATTERN=$3
 
     backup_file "$FILE"
     debug "Inserting $LINE before $PATTERN in $FILE"
     # shellcheck disable=SC2001
     PATTERN=$(sed 's@/@\\\/@g' <<<"$PATTERN")
     debug "sed -i '/$PATTERN/i $LINE' $FILE"
     sed -i "/$PATTERN/i $LINE" "$FILE"
     FNRET=0
 }
 
 replace_in_file() {
     local FILE=$1
     local SOURCE=$2
     local DESTINATION=$3
 
     backup_file "$FILE"
     debug "Replacing $SOURCE to $DESTINATION in $FILE"
     # shellcheck disable=SC2001
     SOURCE=$(sed 's@/@\\\/@g' <<<"$SOURCE")
     debug "sed -i 's/$SOURCE/$DESTINATION/g' $FILE"
     sed -i "s/$SOURCE/$DESTINATION/g" "$FILE"
     FNRET=0
 }
 
 delete_line_in_file() {
     local FILE=$1
     local PATTERN=$2
 
     backup_file "$FILE"
     debug "Deleting lines from $FILE containing $PATTERN"
     # shellcheck disable=SC2001
     PATTERN=$(sed 's@/@\\\/@g' <<<"$PATTERN")
     debug "sed -i '/$PATTERN/d' $FILE"
     sed -i "/$PATTERN/d" "$FILE"
     FNRET=0
 }
 
 #
 # Users and groups
 #
 
 does_user_exist() {
     local USER=$1
     if getent passwd "$USER" >/dev/null 2>&1; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 does_group_exist() {
     local GROUP=$1
     if getent group "$GROUP" >/dev/null 2>&1; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 #
 # Service Boot Checks
 #
 
 is_service_enabled() {
     local SERVICE=$1
     if [ "$($SUDO_CMD find /etc/rc?.d/ -name "S*$SERVICE" -print | wc -l)" -gt 0 ]; then
         debug "Service $SERVICE is enabled"
         FNRET=0
     else
         debug "Service $SERVICE is disabled"
         FNRET=1
     fi
 }
 
 #
 # Kernel Options checks
 #
 
 is_kernel_option_enabled() {
     local KERNEL_OPTION="$1"
     local MODULE_NAME=""
     local RESULT=""
 
     if [ $# -ge 2 ]; then
         MODULE_NAME="$2"
     fi
 
     if $SUDO_CMD [ -r "/proc/config.gz" ]; then
         RESULT=$($SUDO_CMD zgrep "^$KERNEL_OPTION=" /proc/config.gz) || :
     elif $SUDO_CMD [ -r "/boot/config-$(uname -r)" ]; then
         RESULT=$($SUDO_CMD grep "^$KERNEL_OPTION=" "/boot/config-$(uname -r)") || :
     else
         debug "No information about kernel found, you're probably in a container"
         FNRET=127
         return
     fi
 
     ANSWER=$(cut -d = -f 2 <<<"$RESULT")
     if [ "x$ANSWER" = "xy" ]; then
         debug "Kernel option $KERNEL_OPTION enabled"
         FNRET=0
     elif [ "x$ANSWER" = "xn" ]; then
         debug "Kernel option $KERNEL_OPTION disabled"
         FNRET=1
     else
         debug "Kernel option $KERNEL_OPTION not found"
         FNRET=2 # Not found
     fi
 
     if $SUDO_CMD [ "$FNRET" -ne 0 ] && [ -n "$MODULE_NAME" ] && [ -d "/lib/modules/$(uname -r)" ]; then
         # also check in modules, because even if not =y, maybe
         # the admin compiled it separately later (or out-of-tree)
         # as a module (regardless of the fact that we have =m or not)
         debug "Checking if we have $MODULE_NAME.ko"
         local modulefile
         modulefile=$($SUDO_CMD find "/lib/modules/$(uname -r)/" -type f -name "$MODULE_NAME.ko")
         if $SUDO_CMD [ -n "$modulefile" ]; then
             debug "We do have $modulefile!"
             # ... but wait, maybe it's blacklisted? check files in /etc/modprobe.d/ for "blacklist xyz"
             if grep -qRE "^\s*blacklist\s+$MODULE_NAME\s*$" /etc/modprobe.d/; then
                 debug "... but it's blacklisted!"
                 FNRET=1 # Not found (found but blacklisted)
                 # FIXME: even if blacklisted, it might be present in the initrd and
                 # be insmod from there... but painful to check :/ maybe lsmod would be enough ?
             fi
             FNRET=0 # Found!
         fi
     fi
 }
 
 #
 # Mounting point
 #
 
 # Verify $1 is a partition declared in fstab
 is_a_partition() {
     local PARTITION=$1
     FNRET=128
     if grep "[[:space:]]$1[[:space:]]" /etc/fstab | grep -vqE "^#"; then
         debug "$PARTITION found in fstab"
         FNRET=0
     else
         debug "Unable to find $PARTITION in fstab"
         FNRET=1
     fi
 }
 
 # Verify that $1 is mounted at runtime
 is_mounted() {
     local PARTITION=$1
     if grep -q "[[:space:]]$1[[:space:]]" /proc/mounts; then
         debug "$PARTITION found in /proc/mounts, it's mounted"
         FNRET=0
     else
         debug "Unable to find $PARTITION in /proc/mounts"
         FNRET=1
     fi
 }
 
 # Verify $1 has the proper option $2 in fstab
 has_mount_option() {
     local PARTITION=$1
     local OPTION=$2
     if grep "[[:space:]]${PARTITION}[[:space:]]" /etc/fstab | grep -vE "^#" | awk '{print $4}' | grep -q "bind"; then
         local actual_partition
         actual_partition="$(grep "[[:space:]]${PARTITION}[[:space:]]" /etc/fstab | grep -vE "^#" | awk '{print $1}')"
         debug "$PARTITION is a bind mount of $actual_partition"
         PARTITION="$actual_partition"
     fi
     if grep "[[:space:]]${PARTITION}[[:space:]]" /etc/fstab | grep -vE "^#" | awk '{print $4}' | grep -q "$OPTION"; then
         debug "$OPTION has been detected in fstab for partition $PARTITION"
         FNRET=0
     else
         debug "Unable to find $OPTION in fstab for partition $PARTITION"
         FNRET=1
     fi
 }
 
 # Verify $1 has the proper option $2 at runtime
 has_mounted_option() {
     local PARTITION=$1
     local OPTION=$2
     if grep "[[:space:]]$1[[:space:]]" /proc/mounts | awk '{print $4}' | grep -q "$2"; then
         debug "$OPTION has been detected in /proc/mounts for partition $PARTITION"
         FNRET=0
     else
         debug "Unable to find $OPTION in /proc/mounts for partition $PARTITION"
         FNRET=1
     fi
 }
 
 # Setup mount option in fstab
 add_option_to_fstab() {
     local PARTITION=$1
     local OPTION=$2
     debug "Setting $OPTION for $PARTITION in fstab"
     backup_file "/etc/fstab"
     # For example :
     # /dev/sda9       /home           ext4  auto,acl,errors=remount-ro  0       2
     # /dev/sda9       /home           ext4  auto,acl,errors=remount-ro,nodev  0       2
     debug "Sed command :  sed -ie \"s;\(.*\)\(\s*\)\s\($PARTITION\)\s\(\s*\)\(\w*\)\(\s*\)\(\w*\)*;\1\2 \3 \4\5\6\7,$OPTION;\" /etc/fstab"
     sed -ie "s;\(.*\)\(\s*\)\s\($PARTITION\)\s\(\s*\)\(\w*\)\(\s*\)\(\w*\)*;\1\2 \3 \4\5\6\7,$OPTION;" /etc/fstab
 }
 
 remount_partition() {
     local PARTITION=$1
     debug "Remounting $PARTITION"
     mount -o remount "$PARTITION"
 }
 
 #
 # APT
 #
 
 apt_update_if_needed() {
     if [ -e /var/cache/apt/pkgcache.bin ]; then
         UPDATE_AGE=$(($(date +%s) - $(stat -c '%Y' /var/cache/apt/pkgcache.bin)))
 
         if [ "$UPDATE_AGE" -gt 21600 ]; then
             # update too old, refresh database
             $SUDO_CMD apt-get update -y >/dev/null 2>/dev/null
         fi
     else
         $SUDO_CMD apt-get update -y >/dev/null 2>/dev/null
     fi
 }
 
 apt_check_updates() {
     local NAME="$1"
     local DETAILS="/dev/shm/${NAME}"
     $SUDO_CMD apt-get upgrade -s 2>/dev/null | grep -E "^Inst" >"$DETAILS" || :
     local COUNT
     COUNT=$(wc -l <"$DETAILS")
     FNRET=128 # Unknown function return result
     RESULT="" # Result output for upgrade
     if [ "$COUNT" -gt 0 ]; then
         RESULT="There is $COUNT updates available :\n$(cat "$DETAILS")"
         FNRET=1
     else
         RESULT="OK, no updates available"
         FNRET=0
     fi
     rm "$DETAILS"
 }
 
 apt_install() {
     local PACKAGE=$1
     DEBIAN_FRONTEND='noninteractive' apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install "$PACKAGE" -y
     FNRET=0
 }
 
 #
 #   Returns if a package is installed
 #
 
 is_pkg_installed() {
     PKG_NAME=$1
     if dpkg -s "$PKG_NAME" 2>/dev/null | grep -q '^Status: install '; then
         debug "$PKG_NAME is installed"
         FNRET=0
     else
         debug "$PKG_NAME is not installed"
         FNRET=1
     fi
 }
 
 # Returns Debian major version
 
 get_debian_major_version() {
     DEB_MAJ_VER=""
     does_file_exist /etc/debian_version
     if [ "$FNRET" = 0 ]; then
         if grep -q "sid" /etc/debian_version; then
             DEB_MAJ_VER="sid"
         else
             DEB_MAJ_VER=$(cut -d '.' -f1 /etc/debian_version)
         fi
     else
         # shellcheck disable=2034
         DEB_MAJ_VER=$(lsb_release -r | cut -f2 | cut -d '.' -f 1)
     fi
 }
 
 # Returns the distribution
 
 get_distribution() {
     DISTRIBUTION=""
     DISTRIBUTION=$(awk '/DISTRIB_ID=/' /etc/*-release | sed 's/DISTRIB_ID=//' | tr '[:upper:]' '[:lower:]')
     if [ -z "$OS" ]; then
         # shellcheck disable=2034
         DISTRIBUTION=$(awk '{print $1}' /etc/*-release | tr '[:upper:]' '[:lower:]')
         FNRET=0
     else
         debug "Distribution not found !"
         FNRET=127
     fi
 }
+

The files above have some formatting problems, you can use shfmt -w to fix them

To get the full details about this job

@github-actions
Copy link

sh-checker report

shellcheck output
No errors or shellcheck is disabled

The files above have some shellcheck issues

shfmt output
lib/utils.sh
--- lib/utils.sh.orig
+++ lib/utils.sh
@@ -1,513 +1,513 @@
 # shellcheck shell=bash
 # CIS Debian Hardening Utility functions
 
 # run-shellcheck
 
 #
 # Sysctl
 #
 
 has_sysctl_param_expected_result() {
     local SYSCTL_PARAM=$1
     local EXP_RESULT=$2
 
     if [ "$($SUDO_CMD sysctl "$SYSCTL_PARAM" 2>/dev/null)" = "$SYSCTL_PARAM = $EXP_RESULT" ]; then
         FNRET=0
     elif [ "$?" = 255 ]; then
         debug "$SYSCTL_PARAM does not exist"
         FNRET=255
     else
         debug "$SYSCTL_PARAM should be set to $EXP_RESULT"
         FNRET=1
     fi
 }
 
 does_sysctl_param_exists() {
     local SYSCTL_PARAM=$1
     if [ "$($SUDO_CMD sysctl -a 2>/dev/null | grep "$SYSCTL_PARAM" -c)" = 0 ]; then
         FNRET=1
     else
         FNRET=0
     fi
 }
 
 set_sysctl_param() {
     local SYSCTL_PARAM=$1
     local VALUE=$2
     debug "Setting $SYSCTL_PARAM to $VALUE"
     if [ "$(sysctl -w "$SYSCTL_PARAM"="$VALUE" 2>/dev/null)" = "$SYSCTL_PARAM = $VALUE" ]; then
         FNRET=0
     elif [ $? = 255 ]; then
         debug "$SYSCTL_PARAM does not exist"
         FNRET=255
     else
         warn "$SYSCTL_PARAM failed!"
         FNRET=1
     fi
 }
 
 #
 # Dmesg
 #
 
 does_pattern_exist_in_dmesg() {
     local PATTERN=$1
     if $SUDO_CMD dmesg | grep -qE "$PATTERN"; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 #
 # File
 #
 
 does_file_exist() {
     local FILE=$1
     if $SUDO_CMD [ -e "$FILE" ]; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 has_file_correct_ownership() {
     local FILE=$1
     local USER=$2
     local GROUP=$3
     local USERID
     local GROUPID
     USERID=$(id -u "$USER")
     GROUPID=$(getent group "$GROUP" | cut -d: -f3)
     debug "$SUDO_CMD stat -c '%u %g' $FILE"
     if [ "$($SUDO_CMD stat -c "%u %g" "$FILE")" = "$USERID $GROUPID" ]; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 has_file_one_of_ownership() {
     local FILE=$1
     local USER=$2
     local GROUPS_OK=$3
 
     local USEROK=1
     local GROUPOK=1
 
     local USERID
     USERID=$(id -u "$USER")
     if [ "$($SUDO_CMD stat -c "%u" "$FILE")" = "$USERID" ]; then
         USEROK=0
     fi
 
     for GROUP in $GROUPS_OK; do
         local GROUPID
         GROUPID=$(getent group "$GROUP" | cut -d: -f3)
         if [ "$($SUDO_CMD stat -c "%g" "$FILE")" = "$GROUPID" ]; then
             GROUPOK=0
         fi
     done
 
     if [[ "$GROUPOK" = 0 ]] && [[ "$USEROK" = 0 ]]; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 has_file_correct_permissions() {
     local FILE=$1
     local PERMISSIONS=$2
 
     if [ "$($SUDO_CMD stat -L -c "%a" "$FILE")" = "$PERMISSIONS" ]; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 has_file_one_of_permissions() {
     local FILE=$1
     local PERMISSIONS=$2
     FNRET=1
     for PERMISSION in $PERMISSIONS; do
         if [ "$($SUDO_CMD stat -L -c "%a" "$FILE")" = "$PERMISSION" ]; then
             FNRET=0
         fi
     done
 }
 
 does_pattern_exist_in_file_nocase() {
     _does_pattern_exist_in_file "-Ei" "$@"
 }
 
 does_pattern_exist_in_file() {
     _does_pattern_exist_in_file "-E" "$@"
 }
 
 _does_pattern_exist_in_file() {
     local OPTIONS="$1"
     shift
     local FILE="$1"
     shift
     local PATTERN="$*"
 
     debug "Checking if $PATTERN is present in $FILE"
     if $SUDO_CMD [ -r "$FILE" ]; then
         debug "$SUDO_CMD grep -q $OPTIONS -- '$PATTERN' $FILE"
         if $SUDO_CMD grep -q "$OPTIONS" -- "$PATTERN" "$FILE"; then
             debug "Pattern found in $FILE"
             FNRET=0
         else
             debug "Pattern NOT found in $FILE"
             FNRET=1
         fi
     else
         debug "File $FILE is not readable!"
         FNRET=2
     fi
 }
 
 get_db() {
     local DB="$1"
     $SUDO_CMD getent --service files "$DB"
 }
 
 # Look for pattern in file that can spread over multiple lines
 # The func will remove commented lines (that begin with '#')
 # and consider the file as one long line.
 # Thus, this is not possible to look for pattern at beginning of line
 # with this func ('^' and '$')
 does_pattern_exist_in_file_multiline() {
     local FILE="$1"
     shift
     local PATTERN="$*"
 
     debug "Checking if multiline pattern: $PATTERN is present in $FILE"
     if $SUDO_CMD [ -r "$FILE" ]; then
         debug "$SUDO_CMD grep -v '^[[:space:]]*#' $FILE | tr '\n' ' ' | grep -Pq -- $PATTERN"
         if $SUDO_CMD grep -v '^[[:space:]]*#' "$FILE" | tr '\n' ' ' | grep -Pq -- "$PATTERN"; then
             debug "Pattern found in $FILE"
             FNRET=0
         else
             debug "Pattern NOT found in $FILE"
             FNRET=1
         fi
     else
         debug "File $FILE is not readable!"
         FNRET=2
     fi
 }
 
 add_end_of_file() {
     local FILE=$1
     local LINE=$2
 
     debug "Adding $LINE at the end of $FILE"
     backup_file "$FILE"
     echo "$LINE" >>"$FILE"
 }
 
 add_line_file_before_pattern() {
     local FILE=$1
     local LINE=$2
     local PATTERN=$3
 
     backup_file "$FILE"
     debug "Inserting $LINE before $PATTERN in $FILE"
     # shellcheck disable=SC2001
     PATTERN=$(sed 's@/@\\\/@g' <<<"$PATTERN")
     debug "sed -i '/$PATTERN/i $LINE' $FILE"
     sed -i "/$PATTERN/i $LINE" "$FILE"
     FNRET=0
 }
 
 replace_in_file() {
     local FILE=$1
     local SOURCE=$2
     local DESTINATION=$3
 
     backup_file "$FILE"
     debug "Replacing $SOURCE to $DESTINATION in $FILE"
     # shellcheck disable=SC2001
     SOURCE=$(sed 's@/@\\\/@g' <<<"$SOURCE")
     debug "sed -i 's/$SOURCE/$DESTINATION/g' $FILE"
     sed -i "s/$SOURCE/$DESTINATION/g" "$FILE"
     FNRET=0
 }
 
 delete_line_in_file() {
     local FILE=$1
     local PATTERN=$2
 
     backup_file "$FILE"
     debug "Deleting lines from $FILE containing $PATTERN"
     # shellcheck disable=SC2001
     PATTERN=$(sed 's@/@\\\/@g' <<<"$PATTERN")
     debug "sed -i '/$PATTERN/d' $FILE"
     sed -i "/$PATTERN/d" "$FILE"
     FNRET=0
 }
 
 #
 # Users and groups
 #
 
 does_user_exist() {
     local USER=$1
     if getent passwd "$USER" >/dev/null 2>&1; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 does_group_exist() {
     local GROUP=$1
     if getent group "$GROUP" >/dev/null 2>&1; then
         FNRET=0
     else
         FNRET=1
     fi
 }
 
 #
 # Service Boot Checks
 #
 
 is_service_enabled() {
     local SERVICE=$1
     if [ "$($SUDO_CMD find /etc/rc?.d/ -name "S*$SERVICE" -print | wc -l)" -gt 0 ]; then
         debug "Service $SERVICE is enabled"
         FNRET=0
     else
         debug "Service $SERVICE is disabled"
         FNRET=1
     fi
 }
 
 #
 # Kernel Options checks
 #
 
 is_kernel_option_enabled() {
     local KERNEL_OPTION="$1"
     local MODULE_NAME=""
     local RESULT=""
 
     if [ $# -ge 2 ]; then
         MODULE_NAME="$2"
     fi
 
     if $SUDO_CMD [ -r "/proc/config.gz" ]; then
         RESULT=$($SUDO_CMD zgrep "^$KERNEL_OPTION=" /proc/config.gz) || :
     elif $SUDO_CMD [ -r "/boot/config-$(uname -r)" ]; then
         RESULT=$($SUDO_CMD grep "^$KERNEL_OPTION=" "/boot/config-$(uname -r)") || :
     else
         debug "No information about kernel found, you're probably in a container"
         FNRET=127
         return
     fi
 
     ANSWER=$(cut -d = -f 2 <<<"$RESULT")
     if [ "x$ANSWER" = "xy" ]; then
         debug "Kernel option $KERNEL_OPTION enabled"
         FNRET=0
     elif [ "x$ANSWER" = "xn" ]; then
         debug "Kernel option $KERNEL_OPTION disabled"
         FNRET=1
     else
         debug "Kernel option $KERNEL_OPTION not found"
         FNRET=2 # Not found
     fi
 
     if $SUDO_CMD [ "$FNRET" -ne 0 ] && [ -n "$MODULE_NAME" ] && [ -d "/lib/modules/$(uname -r)" ]; then
         # also check in modules, because even if not =y, maybe
         # the admin compiled it separately later (or out-of-tree)
         # as a module (regardless of the fact that we have =m or not)
         debug "Checking if we have $MODULE_NAME.ko"
         local modulefile
         modulefile=$($SUDO_CMD find "/lib/modules/$(uname -r)/" -type f -name "$MODULE_NAME.ko")
         if $SUDO_CMD [ -n "$modulefile" ]; then
             debug "We do have $modulefile!"
             # ... but wait, maybe it's blacklisted? check files in /etc/modprobe.d/ for "blacklist xyz"
             if grep -qRE "^\s*blacklist\s+$MODULE_NAME\s*$" /etc/modprobe.d/; then
                 debug "... but it's blacklisted!"
                 FNRET=1 # Not found (found but blacklisted)
                 # FIXME: even if blacklisted, it might be present in the initrd and
                 # be insmod from there... but painful to check :/ maybe lsmod would be enough ?
             fi
             FNRET=0 # Found!
         fi
     fi
 }
 
 #
 # Mounting point
 #
 
 # Verify $1 is a partition declared in fstab
 is_a_partition() {
     local PARTITION=$1
     FNRET=128
     if grep "[[:space:]]$1[[:space:]]" /etc/fstab | grep -vqE "^#"; then
         debug "$PARTITION found in fstab"
         FNRET=0
     else
         debug "Unable to find $PARTITION in fstab"
         FNRET=1
     fi
 }
 
 # Verify that $1 is mounted at runtime
 is_mounted() {
     local PARTITION=$1
     if grep -q "[[:space:]]$1[[:space:]]" /proc/mounts; then
         debug "$PARTITION found in /proc/mounts, it's mounted"
         FNRET=0
     else
         debug "Unable to find $PARTITION in /proc/mounts"
         FNRET=1
     fi
 }
 
 # Verify $1 has the proper option $2 in fstab
 has_mount_option() {
     local PARTITION=$1
     local OPTION=$2
     if grep "[[:space:]]${PARTITION}[[:space:]]" /etc/fstab | grep -vE "^#" | awk '{print $4}' | grep -q "bind"; then
         local actual_partition
         actual_partition="$(grep "[[:space:]]${PARTITION}[[:space:]]" /etc/fstab | grep -vE "^#" | awk '{print $1}')"
         debug "$PARTITION is a bind mount of $actual_partition"
         PARTITION="$actual_partition"
     fi
     if grep "[[:space:]]${PARTITION}[[:space:]]" /etc/fstab | grep -vE "^#" | awk '{print $4}' | grep -q "$OPTION"; then
         debug "$OPTION has been detected in fstab for partition $PARTITION"
         FNRET=0
     else
         debug "Unable to find $OPTION in fstab for partition $PARTITION"
         FNRET=1
     fi
 }
 
 # Verify $1 has the proper option $2 at runtime
 has_mounted_option() {
     local PARTITION=$1
     local OPTION=$2
     if grep "[[:space:]]$1[[:space:]]" /proc/mounts | awk '{print $4}' | grep -q "$2"; then
         debug "$OPTION has been detected in /proc/mounts for partition $PARTITION"
         FNRET=0
     else
         debug "Unable to find $OPTION in /proc/mounts for partition $PARTITION"
         FNRET=1
     fi
 }
 
 # Setup mount option in fstab
 add_option_to_fstab() {
     local PARTITION=$1
     local OPTION=$2
     debug "Setting $OPTION for $PARTITION in fstab"
     backup_file "/etc/fstab"
     # For example :
     # /dev/sda9       /home           ext4  auto,acl,errors=remount-ro  0       2
     # /dev/sda9       /home           ext4  auto,acl,errors=remount-ro,nodev  0       2
     debug "Sed command :  sed -ie \"s;\(.*\)\(\s*\)\s\($PARTITION\)\s\(\s*\)\(\w*\)\(\s*\)\(\w*\)*;\1\2 \3 \4\5\6\7,$OPTION;\" /etc/fstab"
     sed -ie "s;\(.*\)\(\s*\)\s\($PARTITION\)\s\(\s*\)\(\w*\)\(\s*\)\(\w*\)*;\1\2 \3 \4\5\6\7,$OPTION;" /etc/fstab
 }
 
 remount_partition() {
     local PARTITION=$1
     debug "Remounting $PARTITION"
     mount -o remount "$PARTITION"
 }
 
 #
 # APT
 #
 
 apt_update_if_needed() {
     if [ -e /var/cache/apt/pkgcache.bin ]; then
         UPDATE_AGE=$(($(date +%s) - $(stat -c '%Y' /var/cache/apt/pkgcache.bin)))
 
         if [ "$UPDATE_AGE" -gt 21600 ]; then
             # update too old, refresh database
             $SUDO_CMD apt-get update -y >/dev/null 2>/dev/null
         fi
     else
         $SUDO_CMD apt-get update -y >/dev/null 2>/dev/null
     fi
 }
 
 apt_check_updates() {
     local NAME="$1"
     local DETAILS="/dev/shm/${NAME}"
     $SUDO_CMD apt-get upgrade -s 2>/dev/null | grep -E "^Inst" >"$DETAILS" || :
     local COUNT
     COUNT=$(wc -l <"$DETAILS")
     FNRET=128 # Unknown function return result
     RESULT="" # Result output for upgrade
     if [ "$COUNT" -gt 0 ]; then
         RESULT="There is $COUNT updates available :\n$(cat "$DETAILS")"
         FNRET=1
     else
         RESULT="OK, no updates available"
         FNRET=0
     fi
     rm "$DETAILS"
 }
 
 apt_install() {
     local PACKAGE=$1
     DEBIAN_FRONTEND='noninteractive' apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install "$PACKAGE" -y
     FNRET=0
 }
 
 #
 #   Returns if a package is installed
 #
 
 is_pkg_installed() {
     PKG_NAME=$1
     if dpkg -s "$PKG_NAME" 2>/dev/null | grep -q '^Status: install '; then
         debug "$PKG_NAME is installed"
         FNRET=0
     else
         debug "$PKG_NAME is not installed"
         FNRET=1
     fi
 }
 
 # Returns Debian major version
 
 get_debian_major_version() {
     DEB_MAJ_VER=""
     does_file_exist /etc/debian_version
     if [ "$FNRET" = 0 ]; then
         if grep -q "sid" /etc/debian_version; then
             DEB_MAJ_VER="sid"
         else
             DEB_MAJ_VER=$(cut -d '.' -f1 /etc/debian_version)
         fi
     else
         # shellcheck disable=2034
         DEB_MAJ_VER=$(lsb_release -r | cut -f2 | cut -d '.' -f 1)
     fi
 }
 
 # Returns the distribution
 
 get_distribution() {
     DISTRIBUTION=""
     if [ -f /etc/os-release ]; then
         # shellcheck disable=2034
-        DISTRIBUTION=$(grep "^ID=" /etc/os-release | sed 's/ID=//' |tr '[:upper:]' '[:lower:]')
+        DISTRIBUTION=$(grep "^ID=" /etc/os-release | sed 's/ID=//' | tr '[:upper:]' '[:lower:]')
         FNRET=0
     else
         debug "Distribution not found !"
         FNRET=127
     fi
 }
 

The files above have some formatting problems, you can use shfmt -w to fix them

To get the full details about this job

README.md Outdated Show resolved Hide resolved
bin/hardening.sh Outdated Show resolved Hide resolved
bin/hardening.sh Outdated Show resolved Hide resolved
bin/hardening/5.2.15_ssh_cry_kex.sh Outdated Show resolved Hide resolved
bin/hardening/99.99_check_distribution.sh Outdated Show resolved Hide resolved
bin/hardening/99.99_check_distribution.sh Outdated Show resolved Hide resolved
bin/hardening/99.99_check_distribution.sh Outdated Show resolved Hide resolved
lib/constants.sh Outdated
get_debian_major_version

# shellcheck disable=SC2034
SMALLEST_SUPPORTED_DEBIAN_VERSION="$(cat "$CIS_ROOT_DIR"/debian/compat)"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure about this ? can we find this information once the packet is deployed in production ? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed I thought it was a great idea but it's stupid because it's not present in the deb package ...

@thibaultserti thibaultserti merged commit 6ae05f3 into master Feb 8, 2021
@thibaultserti thibaultserti deleted the debian11 branch February 22, 2021 07:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Run on unsupported version/distribution [[: bullseye/sid: division by 0 (error token is "sid")
3 participants