Problèmes de gestion de variables

Bonjour,

J’ai une fonction assez simple qui est appelée avec deux paramètres:

  • check: résultat d’une commande (plusieurs lignes)
  • output: une variables contenant les lignes à vérifier avec la variable précédente
    Le script est le suivant (c’est une fonction):
# Function to check auditd test results
auditd_rule_check()
{
        res=true
        local -n check=$1
        local -n output=$2
        count=0
        while [ $count -lt ${#check[@]} ]
        do
                [ "${check[$count]}" != "${output[$count]}" ] && { res=false; break; }
                count=$((count+1))
        done
        echo $res
}

comme le script l’indique, le passage des variables se fait par nom.

auditd_rule_check tcheck_disk toutput_disk

la variable tcheck_disk est:

tcheck_disk=($({ awk "/^ *-a *always,exit/ \
                        &&/ -F *arch=b(32|64)/ \
                        &&(/ -F *auid!=unset/||/ -F *auid!=-1/||/ -F *auid!=4294967295/) \
                        &&/ -S/ \
                        &&/ -F *auid>=${UID_MIN}/ \
                        &&(/chmod/||/fchmod/||/fchmodat/ \
                        ||/chown/||/fchown/||/fchownat/||/lchown/ \
                        ||/setxattr/||/lsetxattr/||/fsetxattr/ \
                        ||/removexattr/||/lremovexattr/||/fremovexattr/) \
                        &&(/ key= *[!-~]* *$/||/ -k *[!-~]* *$/)" /etc/audit/rules.d/*.rules
                }))

la variable toutput_disk est:

UID_MIN=$(awk '/^\s*UID_MIN/{print $2}' /etc/login.defs)
toutput_disk=("-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod" \
               "-a always,exit -F arch=b64 -S chown,fchown,lchown,fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod" \
               "-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod" \
               "-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod" \
               "-a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod" \
               "-a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod")

en fait toutput est le résultat de ce que doit donner tcheck.
La fonction sert à comparer les deux.
Si au moins un résultat n’est pas bon alors le test est négatif (false).
Le test permet de déterminer si les règles voulues sont bien définies dans les fichiers de configuration de audit.

Quand j’essaye d’afficher le contenu des variables, toutput s’affiche correctement, c’est à dire par lignes. Par exemple:

printf '%s\n' "toutput_disk=" "${toutput_disk[@]}"
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod

Mais tcheck dont la sortie est pourtant en ligne n’affiche que les blocks de chaque ligne:

printf '%s\n' "tcheck_disk=" "${tcheck_disk[@]}"
-a always,exit 
-F arch=b64 
-S chmod,fchmod,fchmodat 
-F auid>=1000 
-F auid!=unset 
-F key=perm_mod

je ne trouve pas le moyen que chaque entrée des arrays correspondent.

EDIT: apparemment c’est lié à awk et sa façon de gérer la vérification.
La seule solution fonctionnelle trouvée c’est de passer par un fichier de sortie en RAMDISK pour la fonction awk puis de lire ce fichier qui là est dans le bon format.

Finalement j’ai contourné le problème, en utilisant des fichiers temporaires dans un RAMDISK temporaire.

La fonction de vérification:

CIS-6_2_3_5_check()
{
        printf '%s\n' "--------------------------------------------------"

        printf '%s\n' "CIS-6.2.3.5 Check events that modify the system's network environment are collected"
        local FNAME=`basename -- "$0"`
        file=(/etc/audit/rules.d/*.rules)
        if [ -f "$file" ]; then
                f_tmp_ramdisk_up
                awk '/^ *-a *always,exit/ \
                        &&/ -F *arch=b(32|64)/ \
                        &&/ -S/ \
                        &&(/sethostname/ \
                        ||/setdomainname/) \
                        &&(/ key= *[!-~]* *$/||/ -k *[!-~]* *$/)' /etc/audit/rules.d/*.rules > $TMPCISDISK/CIS-6_2_3_5_check.disk
                awk '/^ *-w/ \
                        &&(/\/etc\/issue/ \
                        ||/\/etc\/issue.net/ \
                        ||/\/etc\/hosts/ \
                        ||/\/etc\/network/ \
                        ||/\/etc\/netplan/) \
                        &&/ +-p *wa/ \
                        &&(/ key= *[!-~]* *$/||/ -k *[!-~]* *$/)' /etc/audit/rules.d/*.rules >> $TMPCISDISK/CIS-6_2_3_5_check.disk
                auditctl -l | awk '/^ *-a *always,exit/ \
                        &&/ -F *arch=b(32|64)/ \
                        &&/ -S/ \
                        &&(/sethostname/ \
                        ||/setdomainname/) \
                        &&(/ key= *[!-~]* *$/||/ -k *[!-~]* *$/)' > $TMPCISDISK/CIS-6_2_3_5_check.loaded
                auditctl -l | awk '/^ *-w/ \
                        &&(/\/etc\/issue/ \
                        ||/\/etc\/issue.net/ \
                        ||/\/etc\/hosts/ \
                        ||/\/etc\/network/ \
                        ||/\/etc\/netplan/) \
                        &&/ +-p *wa/ \
                        &&(/ key= *[!-~]* *$/||/ -k *[!-~]* *$/)' >> $TMPCISDISK/CIS-6_2_3_5_check.loaded
        toutput_disk=("-a always,exit -F arch=b64 -S sethostname,setdomainname -k system-locale" \
                "-a always,exit -F arch=b32 -S sethostname,setdomainname -k system-locale" \
                "-w /etc/issue -p wa -k system-locale" \
                "-w /etc/issue.net -p wa -k system-locale" \
                "-w /etc/hosts -p wa -k system-locale" \
                "-w /etc/networks -p wa -k system-locale" \
                "-w /etc/network -p wa -k system-locale" \
                "-w /etc/netplan -p wa -k system-locale")
        toutput_loaded=("-a always,exit -F arch=b64 -S sethostname,setdomainname -F key=system-locale" \
                "-a always,exit -F arch=b32 -S sethostname,setdomainname -F key=system-locale" \
                "-w /etc/issue -p wa -k system-locale" \
                "-w /etc/issue.net -p wa -k system-locale" \
                "-w /etc/hosts -p wa -k system-locale" \
                "-w /etc/networks -p wa -k system-locale" \
                "-w /etc/network -p wa -k system-locale" \
                "-w /etc/netplan -p wa -k system-locale")
        [ $(auditd_rule_check "$TMPCISDISK/CIS-6_2_3_5_check.disk" toutput_disk) = true ] && \
                printf '%s\n' "Success (disk): events that modify the system's network environment are collected" || \
                printf '%s\n' "Failure (disk): events that modify the system's network environment are collected"
        [ $(auditd_rule_check "$TMPCISDISK/CIS-6_2_3_5_check.loaded" toutput_loaded) = true ] && \
                printf '%s\n' "Success (loaded): events that modify the system's network environment are collected" || \
                printf '%s\n' "Failure (loaded): events that modify the system's network environment are not collected"
                f_tmp_ramdisk_down
        else
                printf '%s\n' "Failure: events that modify the system's network environment are not collected"
        fi
}

Et la fonction de comparaison:

auditd_rule_check()
{
        res=true
        local check=$1
        local -n output=$2
        count=0
        if [ -s $check ]; then
                while IFS= read -r line
                do
                        [ "$line" != "${output[$count]}" ] && { res=false; break; }
                        count=$((count+1))
                done < $check
        else
                res=false
        fi
        echo $res
}

Ça ne me convient pas complètement mais ce n’est pas trop sale.