#!/bin/bash ################################################################################ # This is property of eXtremeSHOK.com # You are free to use, modify and distribute, however you may not remove this notice. # Copyright (c) Adrian Jon Kriel :: admin@extremeshok.com ################################################################################ # # Script updates can be found at: https://github.com/extremeshok/clamav-unofficial-sigs # # Originially based on: # Script provide by Bill Landry (unofficialsigs@gmail.com). # # License: BSD (Berkeley Software Distribution) # ################################################################################ # # THERE ARE NO USER CONFIGURABLE OPTIONS IN THIS SCRIPT # ALL CONFIGURATION OPTIONS ARE LOCATED IN THE INCLUDED CONFIGURATION FILE # ################################################################################ ################################################################################ ###### ####### # # ####### ####### ####### ###### ### ####### # # # # ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##### # # # # # # # # # # # # # # # # # # # # # # # # ## # # # # # # # # ###### ####### # # ####### # ####### ###### ### # ################################################################################ # Detect to make sure the entire script is avilable, fail if the script is missing contents if [ ! "$( tail -1 "$0" | head -1 | cut -c1-7 )" == "exit \$?" ] ; then echo "FATAL ERROR: Script is incomplete, please redownload" exit 1 fi # trap the keyboard interrupt (ctrl+c) trap xshok_control_c SIGINT ################################################################################ # HELPER FUNCTIONS ################################################################################ # Function to support user config settings for applying file and directory access permissions. function perms () { if [ -n "$clam_user" ] && [ -n "$clam_group" ] ; then "${@:-}" fi } # Function to prompt a user if they should complete an action with Y or N # usage: xshok_prompt_confirm # if xshok_prompt_confirm; then # xshok_prompt_confirm && echo "accepted" # xshok_prompt_confirm && echo "yes" || echo "no" function xshok_prompt_confirm () { #optional_message message="${1:-Are you sure?}" while true; do read -r -p "$message [y/N]" response "$pidfile" if [ $? -ne 0 ] ; then xshok_pretty_echo_and_log "ERROR: Could not create PID file: $pidfile" exit 1 fi else xshok_pretty_echo_and_log "ERROR: Missing value for option" "=" exit 1 fi } # Function to intercept ctrl+c and calls the cleanup function function xshok_control_c () { echo -en "\n" xshok_pretty_echo_and_log "--------------| Exiting ... Please wait |--------------" "-" xshok_cleanup exit $? } # cleanup function function xshok_cleanup () { #wait for all processes to end wait xshok_pretty_echo_and_log " Powered By https://eXtremeSHOK.com " "#" return $? } # Function to check if the current running user is the root user, otherwise return false function xshok_is_root () { if [ "$(uname -s)" = "SunOS" ] ; then id_bin="/usr/xpg4/bin/id" else id_bin="$(which id)" fi if [ "$($id_bin -u)" = 0 ] ; then return 0 ; else return 1 ; #not root fi } # Function to check if its a file, otherwise return false function xshok_is_file () { #"filepath" filepath="$1" if [ -f "${filepath}" ] ; then return 0 ; else return 1 ; #not a file fi } # Function to check if filepath is a subdir, otherwise return false # Usage: xshok_is_subdir "filepath" # xshok_is_subdir "/root/" - false # xshok_is_subdir "/usr/local/etc" && echo "yes" - yes function xshok_is_subdir () { #filepath filepath=$(echo "$1" | sed 's:/*$::') if [ -d "$filepath" ] ; then res="${filepath//[^\/]}" if [ "${#res}" -gt 1 ] ; then return 0 ; else return 1 ; #not a subdir fi else return 1 ; #not a dir fi } # Function to create a dir and set the ownership function xshok_mkdir_ownership () { #"path" if [ "$1" ] ; then mkdir -p "$1" 2>/dev/null if [ $? -ne 0 ] ; then xshok_pretty_echo_and_log "ERROR: Could not create directory: $1" exit 1 fi perms chown -f "$clam_user:$clam_group" "$1" > /dev/null 2>&1 else xshok_pretty_echo_and_log "ERROR: Missing value for option" "=" exit 1 fi } # Function to check if a user and group exists on the system otherwise return false # Usage: # xshok_is_subdir "username" && echo "user found" || echo "no" # xshok_is_subdir "username" "groupname" && echo "user and group found" || echo "no" function xshok_user_group_exists () { #"username" "groupname" if [ "$(uname -s)" = "SunOS" ] ; then id_bin="/usr/xpg4/bin/id" else id_bin="$(which id)" fi if [ "$1" ] ; then $id_bin -u "$1" > /dev/null 2>&1 if [ $? -eq 0 ]; then if [ "$2" ] ; then $id_bin -g "$2" > /dev/null 2>&1 if [ $? -eq 0 ]; then return 0 ; #user and group exists else return 1 ; #group does NOT exist fi else return 0 ; #user exists fi else return 1 ; #user does NOT exist fi else xshok_pretty_echo_and_log "ERROR: Missing value for option" "=" exit 1 fi } # Function to handle comments with/out borders and logging. # Usage: # pretty_echo_and_log "one" # one # pretty_echo_and_log "two" "-" # --- # two # --- # pretty_echo_and_log "three" "=" "8" # ======== # three # ======== # pretty_echo_and_log "" "/\" "7" # /\/\/\/\/\/\ #type: e = error, w= warning "" function xshok_pretty_echo_and_log () { #"string" "repeating" "count" "type" # handle comments if [ "$comment_silence" = "no" ] ; then if [ "${#@}" = "1" ] ; then echo "$1" else myvar="" if [ -n "$3" ] ; then mycount="$3" else mycount="${#1}" fi for (( n = 0; n < mycount; n++ )) ; do myvar="$myvar$2" done if [ "$1" != "" ] ; then echo -e "$myvar\n$1\n$myvar" else echo -e "$myvar" fi fi fi # handle logging if [ "$enable_log" == "yes" ] ; then if [ ! -e "$log_file_path/$log_file_name" ] ; then #xshok_mkdir_ownership "$log_file_path" mkdir -p "$log_file_path" touch "$log_file_path/$log_file_name" 2>/dev/null perms chown -f "$clam_user:$clam_group" "$log_file_path/$log_file_name" fi if [ ! -w "$log_file_path/$log_file_name" ] ; then echo "Warning: Logging Disabled, as file not writable: $log_file_path/$log_file_name" enable_log="no" else echo "$(date "+%b %d %T")" "$1" >> "$log_file_path/$log_file_name" fi fi } # function to check if the $2 value is not null and does not start with - function xshok_check_s2 () { #value1 #value2 if [ "$1" ] ; then if [[ "$1" =~ ^-.* ]] ; then xshok_pretty_echo_and_log "ERROR: Missing value for option or value begins with -" "=" exit 1 fi else xshok_pretty_echo_and_log "ERROR: Missing value for option" "=" exit 1 fi } # function to count array elements and output the total element count # required due to compound array assignment # Usage: # array=("one" "two" "three") # xshok_array_count $array # 3 function xshok_array_count () { #array k_array=( "$@" ) if [ -n "${k_array[*]}" ] ; then i="0" for k in "${k_array[@]}" ; do let i=$i+1; done echo "$i" else echo "0" fi } # function to auto update function xshok_auto_update() { #version xshok_pretty_echo_and_log "Performing automatic update..." # Download new version echo -n "Downloading latest version..." if ! wget --quiet --output-document="$0.tmp" $UPDATE_BASE/$SELF ; then echo "Failed: Error while trying to wget new version!" echo "File requested: $UPDATE_BASE/$SELF" exit 1 fi echo "Done." # Copy over modes from old version OCTAL_MODE=$(stat -c '%a' $SELF) if ! chmod $OCTAL_MODE "$0.tmp" ; then echo "Failed: Error while trying to set mode on $0.tmp." exit 1 fi # Generate the update script cat > xshok_update_script.sh << EOF #!/bin/bash # Overwrite old file with new if mv "$0.tmp" "$0"; then echo "Done. Update complete." rm \$0 else echo "Failed! The update was not completed." fi EOF echo -n "Inserting update process..." #replaced with $0, so code will update and then call itself with the same parameters it had #exec /bin/bash xshok_update_script.sh exec "$0" "$@" } #function to handle list of database files function clamav_files () { echo "$clam_dbs/$db" >> "$current_tmp" if [ "$keep_db_backup" = "yes" ] ; then echo "$clam_dbs/$db-bak" >> "$current_tmp" fi } # Function to manage the databases and allow multi-dimensions as well as global overrides # since the datbases are basically a multi-dimentional associative arrays in bash # ratings: LOW| MEDIUM| HIGH| REQUIRED| LOWONLY| MEDIUMONLY| LOWMEDIUMONLY | MEDIUMHIGHONLY | HIGHONLY| DISABLED function xshok_database () { #database #rating # assign current_dbs="$1" current_rating="$2" # zero new_dbs="" if [ -n "$current_dbs" ] ; then if [ "$(xshok_array_count "$current_dbs")" -ge "1" ] ; then for db_name in $current_dbs ; do #checks if [ "$enable_yararules" == "no" ] ; then #yararules are disabled if [[ "$db_name" = *".yar"* ]] ; then # if it's the value you want to delete continue # skip to the next value fi fi if [ "$current_rating" == "" ] ; then #yararules are disabled new_dbs="$new_dbs $db_name" else if [[ ! "$db_name" = *"|"* ]] ; then # this old format new_dbs="$new_dbs $db_name" else db_name_rating=$(echo "$db_name" | cut -d "|" -f2) db_name=$(echo "$db_name" | cut -d "|" -f1) if [ "$db_name_rating" != "DISABLED" ] ; then if [ "$db_name_rating" == "$current_rating" ] ; then new_dbs="$new_dbs $db_name" elif [ "$db_name_rating" == "REQUIRED" ] ; then new_dbs="$new_dbs $db_name" elif [ "$current_rating" == "LOW" ] ; then if [ "$db_name_rating" == "LOWONLY" ] || [ "$db_name_rating" == "LOW" ] || [ "$db_name_rating" == "LOWMEDIUM" ] ; then new_dbs="$new_dbs $db_name" fi elif [ "$current_rating" == "MEDIUM" ] ; then if [ "$db_name_rating" == "MEDIUMONLY" ] || [ "$db_name_rating" == "MEDIUM" ] || [ "$db_name_rating" == "LOW" ] || [ "$db_name_rating" == "LOWMEDIUM" ] ; then new_dbs="$new_dbs $db_name" fi elif [ "$current_rating" == "HIGH" ] ; then if [ "$db_name_rating" == "HIGH" ] || [ "$db_name_rating" == "MEDIUM" ] || [ "$db_name_rating" == "LOW" ] ; then new_dbs="$new_dbs $db_name" fi fi fi fi fi done fi fi echo "$new_dbs" | xargs #remove extra whitespace } ################################################################################ # ADDITIONAL PROGRAM FUNCTIONS ################################################################################ #generates a man config and installs it function install_man () { if [ -n "$pkg_mgr" ] || [ -n "$pkg_rm" ] ; then echo "This script (clamav-unofficial-sigs) was installed on the system via '$pkg_mgr'" exit 1 fi echo "" echo "Generating man file for install...." #Use defined varibles or attempt to use default varibles if [ ! -e "$man_dir/$man_filename" ] ; then mkdir -p "$man_dir" touch "$man_dir/$man_filename" 2>/dev/null fi if [ ! -w "$man_dir/$man_filename" ] ; then echo "ERROR: man install aborted, as file not writable: $man_dir/$man_filename" else BOLD="\fB" #REV="" NORM="\fR" manresult=$(help_and_usage "man") #Our template.. cat << EOF > "$man_dir/$man_filename" .\" Manual page for eXtremeSHOK.com ClamAV Unofficial Signature Updater .TH clamav-unofficial-sigs 8 "$script_version_date" "Version: $script_version" "SCRIPT COMMANDS" .SH NAME clamav-unofficial-sigs \- Download, test, and install third-party ClamAV signature databases. .SH SYNOPSIS .B clamav-unofficial-sigs .RI [ options ] .SH DESCRIPTION \fBclamav-unofficial-sigs\fP provides a simple way to download, test, and update third-party signature databases provided by Sanesecurity, FOXHOLE, OITC, Scamnailer, BOFHLAND, CRDF, Porcupine, Securiteinfo, MalwarePatrol, Yara-Rules Project, etc. It will also generate and install cron, logrotate, and man files. .SH UPDATES Script updates can be found at: \fBhttps://github.com/extremeshok/clamav-unofficial-sigs\fP .SH OPTIONS This script follows the standard GNU command line syntax. .LP $manresult .SH SEE ALSO .BR clamd (8), .BR clamscan (1) .SH COPYRIGHT Copyright (c) Adrian Jon Kriel :: admin@extremeshok.com .TP You are free to use, modify and distribute, however you may not remove this notice. .SH LICENSE BSD (Berkeley Software Distribution) .SH BUGS Report bugs to \fBhttps://github.com/extremeshok/clamav-unofficial-sigs\fP .SH AUTHOR Adrian Jon Kriel :: admin@extremeshok.com Originially based on Script provide by Bill Landry EOF fi echo "Completed: man installed, as file: $man_dir/$man_filename" } #generates a logrotate config and installs it function install_logrotate () { if [ -n "$pkg_mgr" ] || [ -n "$pkg_rm" ] ; then echo "This script (clamav-unofficial-sigs) was installed on the system via '$pkg_mgr'" exit 1 fi echo "" echo "Generating logrotate file for install...." #Use defined varibles or attempt to use default varibles if [ ! -n "$logrotate_user" ] ; then logrotate_user="$clam_user"; fi if [ ! -n "$logrotate_group" ] ; then logrotate_group="$clam_group"; fi if [ ! -n "$logrotate_log_file_full_path" ] ; then logrotate_log_file_full_path="$log_file_path/$log_file_name" fi if [ ! -e "$logrotate_dir/$logrotate_filename" ] ; then mkdir -p "$logrotate_dir" touch "$logrotate_dir/$logrotate_filename" 2>/dev/null fi if [ ! -w "$logrotate_dir/$logrotate_filename" ] ; then echo "ERROR: logrotate install aborted, as file not writable: $logrotate_dir/$logrotate_filename" else #Our template.. cat << EOF > "$logrotate_dir/$logrotate_filename" # https://eXtremeSHOK.com ###################################################### # This file contains the logrotate settings for clamav-unofficial-sigs.sh ################### # This is property of eXtremeSHOK.com # You are free to use, modify and distribute, however you may not remove this notice. # Copyright (c) Adrian Jon Kriel :: admin@extremeshok.com ################## # # Script updates can be found at: https://github.com/extremeshok/clamav-unofficial-sigs # # Originially based on: # Script provide by Bill Landry (unofficialsigs@gmail.com). # # License: BSD (Berkeley Software Distribution) # ################## # Automatically Generated: $(date) ################## # # This logrotate file will rotate the logs generated by the clamav-unofficial-sigs.sh # # To Adjust the logrotate values, edit your configs and run # bash clamav-unofficial-sigs.sh --install-logrotate to generate a new file. $logrotate_log_file_full_path { weekly rotate 4 missingok notifempty compress create 0644 $logrotate_user $logrotate_group } EOF fi echo "Completed: logrotate installed, as file: $logrotate_dir/$logrotate_filename" } #generates a cron config and installs it function install_cron () { if [ -n "$pkg_mgr" ] || [ -n "$pkg_rm" ] ; then echo "This script (clamav-unofficial-sigs) was installed on the system via '$pkg_mgr'" exit 1 fi echo "" echo "Generating cron file for install...." #Use defined varibles or attempt to use default varibles if [ ! -n "$cron_minute" ] ; then cron_minute=$(( ( RANDOM % 59 ) + 1 )); fi if [ ! -n "$cron_user" ] ; then cron_user="$clam_user"; fi if [ ! -n "$cron_bash" ] ; then cron_bash=$(which bash) fi if [ ! -n "$cron_script_full_path" ] ; then cron_script_full_path="$this_script_full_path" fi if [ ! -e "$cron_dir/$cron_filename" ] ; then mkdir -p "$cron_dir" touch "$cron_dir/$cron_filename" 2>/dev/null fi if [ ! -w "$cron_dir/$cron_filename" ] ; then echo "ERROR: cron install aborted, as file not writable: $cron_dir/$cron_filename" else #Our template.. cat << EOF > "$cron_dir/$cron_filename" # https://eXtremeSHOK.com ###################################################### # This file contains the cron settings for clamav-unofficial-sigs.sh ################### # This is property of eXtremeSHOK.com # You are free to use, modify and distribute, however you may not remove this notice. # Copyright (c) Adrian Jon Kriel :: admin@extremeshok.com ################## # # Script updates can be found at: https://github.com/extremeshok/clamav-unofficial-sigs # # Originially based on: # Script provide by Bill Landry (unofficialsigs@gmail.com). # # License: BSD (Berkeley Software Distribution) # ################## # Automatically Generated: $(date) ################## # # This cron file will execute the clamav-unofficial-sigs.sh script that # currently supports updating third-party signature databases provided # by Sanesecurity, SecuriteInfo, MalwarePatrol, OITC, etc. # # The script is set to run hourly, at a random minute past the hour, and the # script itself is set to randomize the actual execution time between # 60 - 600 seconds. To Adjust the cron values, edit your configs and run # bash clamav-unofficial-sigs.sh --install-cron to generate a new file. $cron_minute * * * * $cron_user [ -x $cron_script_full_path ] && $cron_bash $cron_script_full_path > /dev/null # https://eXtremeSHOK.com ###################################################### EOF fi echo "Completed: cron installed, as file: $cron_dir/$cron_filename" } #decode a third-party signature either by signature name function decode_third_party_signature_by_signature_name () { echo "" echo "Input a third-party signature name to decode (e.g: Sanesecurity.Junk.15248) or" echo "a hexadecimal encoded data string and press enter (do not include '.UNOFFICIAL'" echo "in the signature name nor add quote marks to any input string):" read -r input input=$(echo "$input" | tr -d "'" | tr -d '"') if echo "$input" | $grep_bin "\." > /dev/null ; then cd "$clam_dbs" || exit sig=$($grep_bin "$input:" ./*.ndb) if [ -n "$sig" ] ; then db_file=$(echo "$sig" | cut -d ':' -f1) echo "$input found in: $db_file" echo "$input signature decodes to:" echo "$sig" | cut -d ":" -f5 | perl -pe 's/([a-fA-F0-9]{2})|(\{[^}]*\}|\([^)]*\))/defined $2 ? $2 : chr(hex $1)/eg' else echo "Signature '$input' could not be found." echo "This script will only decode ClamAV 'UNOFFICIAL' third-Party," echo "non-image based, signatures as found in the *.ndb databases." fi else echo "Here is the decoded hexadecimal input string:" echo "$input" | perl -pe 's/([a-fA-F0-9]{2})|(\{[^}]*\}|\([^)]*\))/defined $2 ? $2 : chr(hex $1)/eg' fi } #Hexadecimal encode an entire input string function hexadecimal_encode_entire_input_string () { echo "" echo "Input the data string that you want to hexadecimal encode and then press enter. Do not include" echo "any quotes around the string unless you want them included in the hexadecimal encoded output:" read -r input echo "Here is the hexadecimal encoded input string:" echo "$input" | perl -pe 's/(.)/sprintf("%02lx", ord $1)/eg' } #Hexadecimal encode a formatted input string function hexadecimal_encode_formatted_input_string () { echo "" echo "Input a formated data string containing spacing fields '{}, (), *' that you want to hexadecimal" echo "encode, without encoding the spacing fields, and then press enter. Do not include any quotes" echo "around the string unless you want them included in the hexadecimal encoded output:" read -r input echo "Here is the hexadecimal encoded input string:" echo "$input" | perl -pe 's/(\{[^}]*\}|\([^)]*\)|\*)|(.)/defined $1 ? $1 : sprintf("%02lx", ord $2)/eg' } #GPG verify a specific Sanesecurity database file function gpg_verify_specific_sanesecurity_database_file () { #databasefile echo "" if [ "$1" ] ; then db_file=$(echo "$1" | awk -F '/' '{print $NF}') if [ -r "$work_dir_sanesecurity/$db_file" ] ; then echo "GPG signature testing database file: $work_dir_sanesecurity/$db_file" if [ -r "$work_dir_sanesecurity/$db_file".sig ] ; then "$gpg_bin" -q --trust-model always --no-default-keyring --homedir "$work_dir_gpg" --keyring "$work_dir_gpg"/ss-keyring.gpg --verify "$work_dir_sanesecurity"/"$db_file".sig "$work_dir_sanesecurity"/"$db_file" if [ "$?" != "0" ]; then "$gpg_bin" -q --always-trust --no-default-keyring --homedir "$work_dir_gpg" --keyring "$work_dir_gpg"/ss-keyring.gpg --verify "$work_dir_sanesecurity"/"$db_file".sig "$work_dir_sanesecurity"/"$db_file" if [ "$?" == "0" ]; then exit 0 else exit 1 fi else exit 0 fi else echo "Signature '$db_file.sig' cannot be found." fi else echo "File '$db_file' cannot be found or is not a Sanesecurity database file." echo "Only the following Sanesecurity and OITC databases can be GPG signature tested:" ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_sanesecurity" fi else xshok_pretty_echo_and_log "ERROR: Missing value for option" "=" exit 1 fi } #Output system and configuration information function output_system_configuration_information () { echo "" echo "*** SCRIPT VERSION ***" echo "$this_script_name $script_version ($script_version_date)" echo "*** SYSTEM INFORMATION ***" $uname_bin -a echo "*** CLAMSCAN LOCATION & VERSION ***" echo "$clamscan_bin" $clamscan_bin --version | head -1 echo "*** RSYNC LOCATION & VERSION ***" echo "$rsync_bin" $rsync_bin --version | head -1 if [ "$wget_bin" != "" ] ; then echo "*** WGET LOCATION & VERSION ***" echo "$wget_bin" $wget_bin --version | head -1 else echo "*** CURL LOCATION & VERSION ***" echo "$curl_bin" $curl_bin --version | head -1 fi echo "*** GPG LOCATION & VERSION ***" echo "$gpg_bin" $gpg_bin --version | head -1 echo "*** SCRIPT WORKING DIRECTORY INFORMATION ***" echo "$work_dir" echo "*** CLAMAV DIRECTORY INFORMATION ***" echo "$clam_dbs" echo "*** SCRIPT CONFIGURATION SETTINGS ***" if [ "$custom_config" != "no" ] ; then if [ -d "$custom_config" ] ; then # Assign the custom config dir and remove trailing / (removes / and //) echo "Custom Configuration Directory: $config_dir" else echo "Custom Configuration File: $custom_config" fi else echo "Configuration Directory: $config_dir" fi } #Make a signature database from an ascii file function make_signature_database_from_ascii_file () { echo "" echo " The '-m' script flag provides a way to create a ClamAV hexadecimal signature database (*.ndb) file from a list of data strings stored in a clear-text ascii file, with one data string entry per line. - Hexadecimal encoding can be either 'full' or 'formatted' on a per line basis: Full line encoding should be used if there are no formatted spacing entries [{}, (), *] included on the line. Prefix unformatted lines with: '-:' (no quote marks). Example: -:This signature contains no formatted spacing fields Encodes to: 54686973207369676e617475726520636f6e7461696e73206e6f20666f726d61747465642073706163696e67206669656c6473 Formatted line encoding should be used if there are user added spacing entries [{}, (), *] included on the line. Prefix formatted lines with '=:' (no quote marks). Example: =:This signature{-10}contains several(25|26|27)formatted spacing*fields Encodes to: 54686973207369676e6174757265{-10}636f6e7461696e73207365766572616c(25|26|27)666f726d61747465642073706163696e67*6669656c6473 Use 'full' encoding if you want to encode everything on the line [including {}, (), *] and 'formatted' encoding if you want to encode everything on the line except the formatted character spacing fields. The prefixes ('-:' and '=:') will be stripped from the line before hexadecimal encoding is done. If no prefix is found at the beginning of the line, full line encoding will be done (default). - It is assumed that the signatures will be created for email scanning purposes, thus the '4' target type is used and full file scanning is enabled (see ClamAV signatures.pdf for details). - Line numbering will be done automatically by the script. " | command sed 's/^ //g' echo -n "Do you wish to continue? " if xshok_prompt_confirm ; then echo -n "Enter the source file as /path/filename: " read -r source if [ -r "$source" ] ; then source_file=$(basename "$source") echo "What signature prefix would you like to use? For example: 'Phish.Domains'" echo "will create signatures that looks like: 'Phish.Domains.1:4:*:HexSigHere'" echo -n "Enter signature prefix: " read -r prefix path_file=$(echo "$source" | cut -d "." -f-1 | command sed 's/$/.ndb/') db_file=$(basename "$path_file") rm -f "$path_file" total=$(wc -l "$source" | cut -d " " -f1) line_num=1 while read -r line ; do line_prefix=$(echo "$line" | awk -F ':' '{print $1}') if [ "$line_prefix" = "-" ] ; then echo "$line" | cut -d ":" -f2- | perl -pe 's/(.)/sprintf("%02lx", ord $1)/eg' | command sed "s/^/$prefix\.$line_num:4:\*:/" >> "$path_file" elif [ "$line_prefix" = "=" ] ; then echo "$line" | cut -d ":" -f2- | perl -pe 's/(\{[^}]*\}|\([^)]*\)|\*)|(.)/defined $1 ? $1 : sprintf("%02lx", ord $2)/eg' | command sed "s/^/$prefix\.$line_num:4:\*:/" >> "$path_file" else echo "$line" | perl -pe 's/(.)/sprintf("%02lx", ord $1)/eg' | command sed "s/^/$prefix\.$line_num:4:\*:/" >> "$path_file" fi echo "Hexadecimal encoding $source_file line: $line_num of $total" line_num=$((line_num + 1)) done < "$source" else echo "Source file not found, exiting..." exit fi echo "Signature database file created at: $path_file" if $clamscan_bin --quiet -d "$path_file" "$work_dir_work_configs/scan-test.txt" 2>/dev/null ; then echo "Clamscan reports database integrity tested good." echo -n "Would you like to move '$db_file' into '$clam_dbs' and reload databases?" if xshok_prompt_confirm ; then if ! cmp -s "$path_file" "$clam_dbs/$db_file" ; then if $rsync_bin -pcqt "$path_file" "$clam_dbs" ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$db_file" perms chmod -f 0644 "$clam_dbs"/"$db_file" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$db_file" fi $clamd_restart_opt echo "Signature database '$db_file' was successfully implemented and ClamD databases reloaded." else echo "Failed to add/update '$db_file', ClamD database not reloaded." fi else echo "Database '$db_file' has not changed - skipping" fi else echo "No action taken." fi else echo "Clamscan reports that '$db_file' signature database integrity tested bad." fi fi } #Remove the clamav-unofficial-sigs script function remove_script () { echo "" if [ -n "$pkg_mgr" ] || [ -n "$pkg_rm" ] ; then echo "This script (clamav-unofficial-sigs) was installed on the system via '$pkg_mgr'" echo "use '$pkg_rm' to remove the script and all of its associated files and databases from the system." else cron_file_full_path="$cron_dir/$cron_filename" logrotate_file_full_path="$logrotate_dir/$logrotate_filename" man_file_full_path="$man_dir/$man_filename" echo "This will remove the workdir ($work_dir), logrotate file ($logrotate_file_full_path), cron file ($cron_file_full_path), man file ($man_file_full_path)" echo "Are you sure you want to remove the clamav-unofficial-sigs script and all of its associated files, third-party databases, and work directory from the system?" if xshok_prompt_confirm ; then echo "This can not be undone are you sure ?" if xshok_prompt_confirm ; then if [ -r "$work_dir_work_configs/purge.txt" ] ; then while read -r file ; do xshok_is_file "$file" && rm -f -- "$file" echo " Removed file: $file" done < "$work_dir_work_configs"/purge.txt if [ -r "$cron_file_full_path" ] ; then xshok_is_file "$cron_file_full_path" && rm -f "$cron_file_full_path" echo " Removed file: $cron_file_full_path" fi if [ -r "$logrotate_file_full_path" ] ; then xshok_is_file "$logrotate_file_full_path" && rm -f "$logrotate_file_full_path" echo " Removed file: $logrotate_file_full_path" fi if [ -r "$man_file_full_path" ] ; then xshok_is_file "$man_file_full_path" && rm -f "$man_file_full_path" echo " Removed file: $man_file_full_path" fi #rather keep the configs #rm -f -- "$default_config" && echo " Removed file: $default_config" #rm -f -- "$0" && echo " Removed file: $0" xshok_is_subdir "$work_dir" && rm -rf -- "$work_dir" && echo " Removed script working directories: $work_dir" echo " The clamav-unofficial-sigs script and all of its associated files, third-party" echo " databases, and work directories have been successfully removed from the system." else echo " Cannot locate 'purge.txt' file in $work_dir_work_configs." echo " Files and signature database will need to be removed manually." fi else echo "Aborted" fi else echo "Aborted" fi fi } #Clamscan integrity test a specific database file function clamscan_integrity_test_specific_database_file () { #databasefile echo "" if [ "$1" ] ; then input=$(echo "$1" | awk -F '/' '{print $NF}') db_file=$(find "$work_dir" -name "$input") if [ -r "$db_file" ] ; then echo "Clamscan integrity testing: $db_file" $clamscan_bin --quiet -d "$db_file" "$work_dir_work_configs/scan-test.txt" if [ "$?" -eq "0" ]; then echo "Clamscan reports that '$input' database integrity tested GOOD" exit 0 else echo "Clamscan reports that '$input' database integrity tested BAD" exit 1 fi else echo "File '$input' cannot be found." echo "Here is a list of third-party databases that can be clamscan integrity tested:" echo "=== Sanesecurity ===" ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_sanesecurity" echo "=== SecuriteInfo ===" ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_securiteinfo" echo "=== MalwarePatrol ===" ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_malwarepatrol" echo "=== Linux Malware Detect ===" ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_linuxmalwaredetect" echo "=== Linux Malware Detect ===" ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_yararulesproject" echo "=== User Defined Databases ===" ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_add" echo "Check the file name and try again..." fi else xshok_pretty_echo_and_log "ERROR: Missing value for option" "=" exit 1 fi } #output names of any third-party signatures that triggered during the HAM directory scan function output_signatures_triggered_during_ham_directory_scan () { echo "" if [ -n "$ham_dir" ] ; then if [ -r "$work_dir_work_configs/whitelist.hex" ] ; then echo "The following third-party signatures triggered hits during the HAM Directory scan:" $grep_bin -h -f "$work_dir_work_configs/whitelist.hex" "$work_dir"/*/*.ndb | cut -d ":" -f1 else echo "No third-party signatures have triggered hits during the HAM Directory scan." fi else echo "Ham directory scanning is not currently enabled in the script's configuration file." fi } #Adds a signature whitelist entry in the newer ClamAV IGN2 format function add_signature_whitelist_entry () { echo "" echo "Input a third-party signature name that you wish to whitelist due to false-positives" echo "and press enter (do not include '.UNOFFICIAL' in the signature name nor add quote" echo "marks to the input string):" read -r input if [ -n "$input" ] ; then cd "$clam_dbs" || exit input=$(echo "$input" | tr -d "'" | tr -d '"') sig_full=$($grep_bin -H "$input" ./*.*db) sig_name=$(echo "$sig_full" | cut -d ":" -f2) if [ -n "$sig_name" ] ; then if ! $grep_bin "$sig_name" my-whitelist.ign2 > /dev/null 2>&1 ; then cp -f my-whitelist.ign2 "$work_dir_work_configs" 2>/dev/null echo "$sig_name" >> "$work_dir_work_configs/my-whitelist.ign2" echo "$sig_full" >> "$work_dir_work_configs/tracker.txt" if $clamscan_bin --quiet -d "$work_dir_work_configs/my-whitelist.ign2" "$work_dir_work_configs/scan-test.txt" ; then if $rsync_bin -pcqt "$work_dir_work_configs/my-whitelist.ign2" "$clam_dbs" ; then perms chown -f "$clam_user:$clam_group" my-whitelist.ign2 if [ ! -s "$work_dir_work_configs/monitor-ign.txt" ] ; then # Create "monitor-ign.txt" file for clamscan database integrity testing. echo "This is the monitor ignore file..." > "$work_dir_work_configs/monitor-ign.txt" fi perms chmod -f 0644 my-whitelist.ign2 "$work_dir_work_configs/monitor-ign.txt" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/local.ign" fi clamscan_reload_dbs echo "Signature '$input' has been added to my-whitelist.ign2 and" echo "all databases have been reloaded. The script will track any changes" echo "to the offending signature and will automatically remove it if the" echo "signature is modified or removed from the third-party database." else echo "Failed to successfully update my-whitelist.ign2 file - SKIPPING." fi else echo "Clamscan reports my-whitelist.ign2 database integrity is bad - SKIPPING." fi else echo "Signature '$input' already exists in my-whitelist.ign2 - no action taken." fi else echo "Signature '$input' could not be found." echo "This script will only create a whitelise entry in my-whitelist.ign2 for ClamAV" echo "'UNOFFICIAL' third-Party signatures as found in the *.ndb *.hdb *.db databases." fi else echo "No input detected - no action taken." fi } #Clamscan reload database function clamscan_reload_dbs () { # Reload all clamd databases if updates detected and $reload_dbs" is set to "yes" if [ "$reload_dbs" = "yes" ] ; then if [ "$do_clamd_reload" != "0" ] ; then if [ "$do_clamd_reload" = "1" ] ; then xshok_pretty_echo_and_log "Update(s) detected, reloading ClamAV databases" "=" elif [ "$do_clamd_reload" = "2" ] ; then xshok_pretty_echo_and_log "Database removal(s) detected, reloading ClamAV databases" "=" elif [ "$do_clamd_reload" = "3" ] ; then xshok_pretty_echo_and_log "File 'local.ign' has changed, reloading ClamAV databases" "=" elif [ "$do_clamd_reload" = "4" ] ; then xshok_pretty_echo_and_log "File 'my-whitelist.ign2' has changed, reloading ClamAV databases" "=" else xshok_pretty_echo_and_log "Update(s) detected, reloading ClamAV databases" "=" fi if [[ $($clamd_reload_opt 2>&1) = *"ERROR"* ]] ; then xshok_pretty_echo_and_log "ERROR: Failed to reload, trying again" "-" if [ -r "$clamd_pid" ] ; then mypid=$(cat "$clamd_pid") kill -USR2 "$mypid" if [ $? -eq 0 ] ; then xshok_pretty_echo_and_log "ClamAV databases Reloaded" "=" else xshok_pretty_echo_and_log "ERROR: Failed to reload, forcing clamd to restart" "-" if [ -z "$clamd_restart_opt" ] ; then xshok_pretty_echo_and_log "WARNING: Check the script's configuration file, 'reload_dbs' enabled but no 'clamd_restart_opt'" "*" else $clamd_restart_opt xshok_pretty_echo_and_log "ClamAV Restarted" "=" fi fi else xshok_pretty_echo_and_log "ERROR: Failed to reload, forcing clamd to restart" "=" if [ -z "$clamd_restart_opt" ] ; then xshok_pretty_echo_and_log "WARNING: Check the script's configuration file, 'reload_dbs' enabled but no 'clamd_restart_opt'" "*" else $clamd_restart_opt xshok_pretty_echo_and_log "ClamAV Restarted" "=" fi fi else xshok_pretty_echo_and_log "ClamAV databases Reloaded" "=" fi else xshok_pretty_echo_and_log "No updates detected, ClamAV databases were not reloaded" "=" fi else xshok_pretty_echo_and_log "Database reload has been disabled in the configuration file" "=" fi } # If ClamD status check is enabled ("clamd_socket" variable is uncommented # and the socket path is correctly specified in "User Edit" section above), # then test to see if clamd is running or not. function check_clamav () { if [ -n "$clamd_socket" ] ; then if [ -S "$clamd_socket" ] ; then if [ "$(perl -e 'use IO::Socket::UNIX; print $IO::Socket::UNIX::VERSION,"\n"' 2>/dev/null)" ] ; then io_socket1=1 if [ "$(perl -MIO::Socket::UNIX -we '$s = IO::Socket::UNIX->new(shift); $s->print("PING"); print $s->getline; $s->close' "$clamd_socket" 2>/dev/null)" = "PONG" ] ; then io_socket2=1 xshok_pretty_echo_and_log "ClamD is running" "=" fi else socat="$(which socat 2>/dev/null)" if [ -n "$socat" ] && [ -x "$socat" ] ; then socket_cat1=1 if [ "$( (echo "PING"; sleep 1;) | socat - "$clamd_socket" 2>/dev/null)" = "PONG" ] ; then socket_cat2=1 xshok_pretty_echo_and_log "ClamD is running" "=" fi fi fi if [ -z "$io_socket1" ] && [ -z "$socket_cat1" ] ; then xshok_pretty_echo_and_log "WARNING: socat or perl module 'IO::Socket::UNIX' not found, cannot test if ClamD is running" "*" else if [ -z "$io_socket2" ] && [ -z "$socket_cat2" ] ; then xshok_pretty_echo_and_log "ALERT: CLAMD IS NOT RUNNING!" "=" if [ -n "$clamd_restart_opt" ] ; then xshok_pretty_echo_and_log "Attempting to start ClamD..." "-" if [ -n "$io_socket1" ] ; then $clamd_restart_opt > /dev/null && sleep 5 if [ "$(perl -MIO::Socket::UNIX -we '$s = IO::Socket::UNIX->new(shift); $s->print("PING"); print $s->getline; $s->close' "$clamd_socket" 2>/dev/null)" = "PONG" ] ; then xshok_pretty_echo_and_log "ClamD was successfully started" "=" else xshok_pretty_echo_and_log "ERROR: CLAMD FAILED TO START" "=" exit 1 fi else if [ -n "$socket_cat1" ] ; then $clamd_restart_opt > /dev/null && sleep 5 if [ "$( (echo "PING"; sleep 1;) | socat - "$clamd_socket" 2>/dev/null)" = "PONG" ] ; then xshok_pretty_echo_and_log "ClamD was successfully started" "=" else xshok_pretty_echo_and_log "ERROR: CLAMD FAILED TO START" "=" exit 1 fi fi fi fi fi fi else xshok_pretty_echo_and_log "WARNING: $clamd_socket is not a usable socket" "*" fi else xshok_pretty_echo_and_log "WARNING: clamd_socket is not defined in the configuration file" "*" fi } #function to check for a new version function check_new_version () { if [ "$wget_bin" != "" ] ; then latest_version="$($wget_bin https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/master/clamav-unofficial-sigs.sh -O - 2> /dev/null | $grep_bin "script""_version=" | cut -d\" -f2)" else latest_version="$($curl_bin https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/master/clamav-unofficial-sigs.sh 2> /dev/null | $grep_bin "script""_version=" | cut -d\" -f2)" fi if [ "$latest_version" ] ; then if [ ! "$latest_version" == "$script_version" ] ; then xshok_pretty_echo_and_log "New version : v$latest_version @ https://github.com/extremeshok/clamav-unofficial-sigs" "-" fi fi } #function for help and usage ##usage: # help_and_usage "1" - enables the man output formatting # help_and_usage - normal help output formatting function help_and_usage () { if [ "$1" ] ; then #option_format_start ofs="\fB" #option_format_end ofe="\fR" #option_format_blankline ofb=".TP" #option_format_tab_line oft=" " else #option_format_start ofs="${BOLD}" #option_format_end ofe="${NORM}\t" #option_format_blankline ofb="\n" #option_format_tab_line oft="\n\t" fi helpcontents=$(cat << EOF $ofs Usage: $(basename "$0") $ofe [OPTION] [PATH|FILE] $ofb $ofs -c, --config $ofe Use a specific configuration file or directory $oft eg: '-c /your/dir' or ' -c /your/file.name' $oft Note: If a directory is specified the directory must contain atleast: $oft master.conf, os.conf or user.conf $oft Default Directory: $config_dir $ofb $ofs -F, --force $ofe Force all databases to be downloaded, could cause ip to be blocked $ofb $ofs -h, --help $ofe Display this script's help and usage information $ofb $ofs -V, --version $ofe Output script version and date information $ofb $ofs -v, --verbose $ofe Be verbose, enabled when not run under cron $ofb $ofs -s, --silence $ofe Only output error messages, enabled when run under cron $ofb $ofs -d, --decode-sig $ofe Decode a third-party signature either by signature name $oft (eg: Sanesecurity.Junk.15248) or hexadecimal string. $oft This flag will 'NOT' decode image signatures $ofb $ofs -e, --encode-string $ofe Hexadecimal encode an entire input string that can $oft be used in any '*.ndb' signature database file $ofb $ofs -f, --encode-formatted $ofe Hexadecimal encode a formatted input string containing $oft signature spacing fields '{}, (), *', without encoding $oft the spacing fields, so that the encoded signature $oft can be used in any '*.ndb' signature database file $ofb $ofs -g, --gpg-verify $ofe GPG verify a specific Sanesecurity database file $oft eg: '-g filename.ext' (do not include file path) $ofb $ofs -i, --information $ofe Output system and configuration information for $oft viewing or possible debugging purposes $ofb $ofs -m, --make-database $ofe Make a signature database from an ascii file containing $oft data strings, with one data string per line. Additional $oft information is provided when using this flag $ofb $ofs -t, --test-database $ofe Clamscan integrity test a specific database file $oft eg: '-t filename.ext' (do not include file path) $ofb $ofs -o, --output-triggered $ofe If HAM directory scanning is enabled in the script's $oft configuration file, then output names of any third-party $oft signatures that triggered during the HAM directory scan $ofb $ofs -w, --whitelist $ofe Adds a signature whitelist entry in the newer ClamAV IGN2 $oft format to 'my-whitelist.ign2' in order to temporarily resolve $oft a false-positive issue with a specific third-party signature. $oft Script added whitelist entries will automatically be removed $oft if the original signature is either modified or removed from $oft the third-party signature database $ofb $ofs --check-clamav $ofe If ClamD status check is enabled and the socket path is correctly $oft specifiedthen test to see if clamd is running or not $ofb $ofs --install-all $ofe Install and generate the cron, logroate and man files, autodetects the values $oft based on your config files $ofb $ofs --install-cron $ofe Install and generate the cron file, autodetects the values $oft based on your config files $ofb $ofs --install-logrotate $ofe Install and generate the logrotate file, autodetects the $oft values based on your config files $ofb $ofs --install-man $ofe Install and generate the man file, autodetects the $oft values based on your config files $ofb $ofs --remove-script $ofe Remove the clamav-unofficial-sigs script and all of $oft its associated files and databases from the system $ofb EOF ) #this is very important... if [ "$1" ] ; then echo "${helpcontents//-/\\-}" else echo -e "$helpcontents" fi } ################################################################################ # MAIN PROGRAM ################################################################################ #Script Info script_version="5.4.1" script_version_date="20 July 2016" minimum_required_config_version="65" minimum_yara_clamav_version="0.99" #default config files config_dir="/etc/clamav-unofficial-sigs" config_files=("$config_dir/master.conf" "$config_dir/os.conf" "$config_dir/user.conf") #Initialise config_version="0" do_clamd_reload="0" comment_silence="no" logging_enabled="no" force_updates="no" enable_log="no" custom_config="no" we_have_a_config="0" ## Solaris which function returns garbage when the program is not found ## only define the new which function if running under Solaris if [ "$(uname -s)" = "SunOS" ] ; then which () { # use the switch -p to ignore ksh internal commands ksh whence -p "$@" } fi #Default Binaries & Commands clamd_reload_opt="clamdscan --reload" uname_bin=$(which uname) clamscan_bin=$(which clamscan) rsync_bin=$(which rsync) #detect support for wget if [ -x /usr/sfw/bin/wget ] ; then wget_bin="/usr/sfw/bin/wget" else wget_bin=$(which wget) fi if [ "$wget_bin" == "" ] ; then curl_bin=$(which curl) fi #detect supprot for gnu grep if [ -x /usr/gnu/bin/grep ] ; then grep_bin="/usr/gnu/bin/grep" else grep_bin=$(which grep) fi if [ -x /opt/csw/bin/gpg ] ; then gpg_bin="/opt/csw/bin/gpg" else gpg_bin=$(which gpg) fi if [ "$gpg_bin" == "" ] ; then gpg_bin=$(which gpg2) fi #Detect if terminal if [ -t 1 ] ; then #Set fonts ##Usage: echo "${BOLD}-a${NORM}" BOLD=$(tput bold) #REV=$(tput smso) NORM=$(tput sgr0) #Verbose force_verbose="yes" else #Null Fonts BOLD='' #REV='' NORM='' #silence force_verbose="no" fi # Generic command line options while true ; do case "$1" in -c | --config ) xshok_check_s2 "$2"; custom_config="$2"; shift 2; break ;; -F | --force ) force_updates="yes"; shift 1; break ;; -v | --verbose ) force_verbose="yes"; shift 1; break ;; -s | --silence ) force_verbose="no"; shift 1; break ;; * ) break ;; esac done #Set the verbosity if [ "$force_verbose" == "yes" ] ; then #verbose downloader_silence="no" rsync_silence="no" gpg_silence="no" comment_silence="no" else #silence downloader_silence="yes" rsync_silence="yes" gpg_silence="yes" comment_silence="yes" fi xshok_pretty_echo_and_log "" "#" "80" xshok_pretty_echo_and_log " eXtremeSHOK.com ClamAV Unofficial Signature Updater" xshok_pretty_echo_and_log " Version: v$script_version ($script_version_date)" xshok_pretty_echo_and_log " Required Configuration Version: v$minimum_required_config_version" xshok_pretty_echo_and_log " Copyright (c) Adrian Jon Kriel :: admin@extremeshok.com" xshok_pretty_echo_and_log "" "#" "80" # Generic command line options while true ; do case "$1" in -h | --help ) help_and_usage; exit; break ;; -V | --version ) exit; break ;; * ) break ;; esac done ## CONFIG LOADING AND ERROR CHECKING ############################################## if [ "$custom_config" != "no" ] ; then if [ -d "$custom_config" ] ; then # Assign the custom config dir and remove trailing / (removes / and //) config_dir=$(echo "$custom_config" | sed 's:/*$::') config_files=("$config_dir/master.conf" "$config_dir/os.conf" "$config_dir/user.conf") else config_files=("$custom_config") fi fi for config_file in "${config_files[@]}" ; do if [ -r "$config_file" ] ; then #exists and readable we_have_a_config="1" #config stripping xshok_pretty_echo_and_log "Loading config: $config_file" "=" if [ "$(uname -s)" = "SunOS" ] ; then #Solaris FIXES only, i had issues with running with a single command.. clean_config=$(command sed -e '/^#.*/d' "$config_file") # comment line clean_config=$(echo "$clean_config" | sed -e 's/#[[:space:]].*//') # comment line (duplicated) clean_config=$(echo "$clean_config" | sed -e '/^[[:blank:]]*#/d;s/#.*//') #comments at end of line clean_config=$(echo "$clean_config" | sed -e 's/^[ \t]*//;s/[ \t]*$//') #trailing and leading whitespace clean_config=$(echo "$clean_config" | sed -e '/^\s*$/d') #blank lines else # delete lines beginning with # # delete from ' #' to end of the line # delete from '# ' to end of the line # delete both trailing and leading whitespace # delete all trailing whitespace # delete all empty lines clean_config=$(command sed -e '/^#.*/d' -e 's/[[:space:]]#.*//' -e 's/#[[:space:]].*//' -e 's/^[ \t]*//;s/[ \t]*$//' -e '/^\s*$/d' "$config_file") fi ### config error checking # check "" are an even number config_check="${clean_config//[^\"]}" if [ $(( ${#config_check} % 2)) -eq 1 ] ; then xshok_pretty_echo_and_log "ERROR: Your configuration has errors, every \" requires a closing \"" "=" exit 1 fi # check there is an = for every set of "" #optional whitespace \s* between = and " config_check_vars=$(echo "$clean_config" | $grep_bin -c '=\s*\"' ) if [ $(( ${#config_check} / 2)) -ne "$config_check_vars" ] ; then xshok_pretty_echo_and_log "ERROR: Your configuration has errors, every = requires a pair of \"\"" "=" exit 1 fi #config loading for i in "${clean_config[@]}" ; do eval "$(echo "${i}" | command sed -e 's/[[:space:]]*$//' 2> /dev/null)" done fi done # Assign the log_file_path earlier and remove trailing / (removes / and //) log_file_path=$(echo "$log_file_path" | sed 's:/*$::') #Only start logging once all the configs have been loaded if [ "$logging_enabled" == "yes" ] ; then enable_log="yes" fi ## Make sure we have a readable config file if [ "$we_have_a_config" == "0" ] ; then xshok_pretty_echo_and_log "ERROR: Config file/s could NOT be read/loaded" "=" exit 1 fi #prevent some issues with an incomplete or only a user.conf being loaded if [ $config_version == "0" ] ; then xshok_pretty_echo_and_log "ERROR: Config file/s are missing important contents" "=" xshok_pretty_echo_and_log "Note: Possible fix would be to point the script to the dir with the configs" exit 1 fi #config version validation if [ $config_version -lt $minimum_required_config_version ] ; then xshok_pretty_echo_and_log "ERROR: Your config version $config_version is not compatible with the min required version $minimum_required_config_version" "=" exit 1 fi # Check to see if the script's "USER CONFIGURATION FILE" has been completed. if [ "$user_configuration_complete" != "yes" ] ; then xshok_pretty_echo_and_log "WARNING: SCRIPT CONFIGURATION HAS NOT BEEN COMPLETED" "*" xshok_pretty_echo_and_log "Please review the script configuration files." exit 1 fi # Assign the directories and remove trailing / (removes / and //) work_dir=$(echo "$work_dir" | sed 's:/*$::') #Allow overriding of all the individual workdirs, this is mainly to aid package maintainers if [ ! -n "$work_dir_sanesecurity" ] ; then work_dir_sanesecurity=$(echo "$work_dir/$sanesecurity_dir" | sed 's:/*$::') else work_dir_sanesecurity=$(echo "$work_dir_sanesecurity" | sed 's:/*$::') fi if [ ! -n "$work_dir_securiteinfo" ] ; then work_dir_securiteinfo=$(echo "$work_dir/$securiteinfo_dir" | sed 's:/*$::') else work_dir_securiteinfo=$(echo "$work_dir_securiteinfo" | sed 's:/*$::') fi if [ ! -n "$work_dir_linuxmalwaredetect" ] ; then work_dir_linuxmalwaredetect=$(echo "$work_dir/$linuxmalwaredetect_dir" | sed 's:/*$::') else work_dir_linuxmalwaredetect=$(echo "$work_dir_linuxmalwaredetect" | sed 's:/*$::') fi if [ ! -n "$work_dir_malwarepatrol" ] ; then work_dir_malwarepatrol=$(echo "$work_dir/$malwarepatrol_dir" | sed 's:/*$::') else work_dir_malwarepatrol=$(echo "$work_dir_malwarepatrol" | sed 's:/*$::') fi if [ ! -n "$work_dir_yararulesproject" ] ; then work_dir_yararulesproject=$(echo "$work_dir/$yararulesproject_dir" | sed 's:/*$::') else work_dir_yararulesproject=$(echo "$work_dir_yararulesproject" | sed 's:/*$::') fi if [ ! -n "$work_dir_add" ] ; then work_dir_add=$(echo "$work_dir/$add_dir" | sed 's:/*$::') else work_dir_add=$(echo "$work_dir_add" | sed 's:/*$::') fi if [ ! -n "$work_dir_work_configs" ] ; then work_dir_work_configs=$(echo "$work_dir/$work_dir_configs" | sed 's:/*$::') else work_dir_work_configs=$(echo "$work_dir_work_configs" | sed 's:/*$::') fi if [ ! -n "$work_dir_gpg" ] ; then work_dir_gpg=$(echo "$work_dir/$gpg_dir" | sed 's:/*$::') else work_dir_gpg=$(echo "$work_dir_gpg" | sed 's:/*$::') fi if [ ! -n "$work_dir_pid" ] ; then work_dir_pid=$(echo "$work_dir/$pid_dir" | sed 's:/*$::') else work_dir_pid=$(echo "$work_dir_pid" | sed 's:/*$::') fi # Assign defaults if not defined if [ ! -n "$cron_dir" ] ; then cron_dir="/etc/cron.d" fi cron_dir=$(echo "$cron_dir" | sed 's:/*$::') if [ ! -n "$cron_filename" ] ; then cron_filename="clamav-unofficial-sigs" fi if [ ! -n "$logrotate_dir" ] ; then logrotate_dir="/etc/logrotate.d" fi logrotate_dir=$(echo "$logrotate_dir" | sed 's:/*$::') if [ ! -n "$logrotate_filename" ] ; then logrotate_filename="clamav-unofficial-sigs" fi if [ ! -n "$man_dir" ] ; then man_dir="/usr/share/man/man8" fi man_dir=$(echo "$man_dir" | sed 's:/*$::') if [ ! -n "$man_filename" ] ; then man_filename="clamav-unofficial-sigs.8" fi if [ ! -n "$man_log_file_full_path" ] ; then man_log_file_full_path="$log_file_path/$log_file_name" fi ### SANITY checks #Check default Binaries & Commands are defined if [ "$clamd_reload_opt" == "" ] ; then xshok_pretty_echo_and_log "ERROR: Missing clamd_reload_opt" "=" exit 1 fi if [ "$uname_bin" == "" ] ; then xshok_pretty_echo_and_log "ERROR: uname (uname_bin) not found" "=" exit 1 fi if [ "$clamscan_bin" == "" ] ; then xshok_pretty_echo_and_log "ERROR: clamscan binary (clamscan_bin) not found" "=" exit 1 fi if [ "$rsync_bin" == "" ] ; then xshok_pretty_echo_and_log "ERROR: rsync binary (rsync_bin) not found" "=" exit 1 fi if [ "$wget_bin" == "" ] ; then if [ "$curl_bin" == "" ] ; then xshok_pretty_echo_and_log "ERROR: wget and curl binaries not found, script requires either wget or curl" "=" exit 1 fi fi if [ "$gpg_bin" == "" ] ; then xshok_pretty_echo_and_log "ERROR: gpg binary (gpg_bin) not found" "=" exit 1 fi #Check default directories are defined if [ "$work_dir" == "" ] ; then xshok_pretty_echo_and_log "ERROR: working directory (work_dir) not defined" "=" exit 1 fi # Reset the update timers to force a full update. if [ "$force_updates" == "yes" ] ; then xshok_pretty_echo_and_log "Force Updates: enabled" sanesecurity_update_hours="0" securiteinfo_update_hours="0" linuxmalwaredetect_update_hours="0" malwarepatrol_update_hours="0" yararulesproject_update_hours="0" additional_update_hours="0" fi # Enable pid file to prevent issues with multiple instances # opted not to use flock as it appears to have issues with some systems if [ "$enable_locking" == "yes" ] ; then xshok_mkdir_ownership "$work_dir_pid" pid_file_fullpath="$work_dir_pid/clamav-unofficial-sigs.pid" if [ -f "$pid_file_fullpath" ] ; then pid_file_pid=$(cat "$pid_file_fullpath") ps -p "$pid_file_pid" > /dev/null 2>&1 if [ $? -eq 0 ] ; then xshok_pretty_echo_and_log "ERROR: Only one instance can run at the same time." "=" exit 1 else xshok_create_pid_file "$pid_file_fullpath" fi else xshok_create_pid_file "$pid_file_fullpath" fi # run this wehen the script exits trap -- "rm -f $pid_file_fullpath" EXIT fi # Verify the clam_user and clam_group actually exists on the system if ! xshok_user_group_exists "$clam_user" "$clam_group" ; then xshok_pretty_echo_and_log "ERROR: Either the user: $clam_user and/or group: $clam_group does not exist on the system." "=" exit 1 fi # Silence rsync output and only report errors - useful if script is run via cron. if [ "$rsync_silence" = "yes" ] ; then rsync_output_level="--quiet" else rsync_output_level="--progress" fi # If the local rsync client supports the '--no-motd' flag, then enable it. if $rsync_bin --help | $grep_bin 'no-motd' > /dev/null ; then no_motd="--no-motd" fi # If the local rsync client supports the '--contimeout' flag, then enable it. if $rsync_bin --help | $grep_bin 'contimeout' > /dev/null ; then connect_timeout="--contimeout=$rsync_connect_timeout" fi # Silence wget output and only report errors - useful if script is run via cron. if [ "$downloader_silence" = "yes" ] ; then wget_output_level="--quiet" #--quiet curl_output_level="--silent --show-error" else wget_output_level="--no-verbose" curl_output_level="" fi #suppress ssl warnings if [ "$downloader_ignore_ssl" = "yes" ] ; then wget_insecure="--no-check-certificate" curl_insecure="--insecure" else wget_insecure="" curl_insecure="" fi # This scripts name and path this_script_name="$(basename "$0")" this_script_path="$( cd "$(dirname "$0")" ; pwd -P )" this_script_full_path="$this_script_path/$this_script_name" #set the script to 755 permissions if xshok_is_root ; then if [ "$setmode" == "yes" ] ; then if [ ! -x "$this_script_path/$this_script_name" ] ; then chmod 755 "$this_script_path/$this_script_name" xshok_pretty_echo_and_log "Fixing permission on $this_script_path/$this_script_name" "=" fi fi else #disable setmode setmode="no" fi ################################################################################ # MAIN LOGIC ################################################################################ while true; do case "$1" in -d | --decode-sig ) decode_third_party_signature_by_signature_name; exit; break ;; -e | --encode-string ) hexadecimal_encode_entire_input_string; exit; break ;; -f | --encode-formatted ) hexadecimal_encode_formatted_input_string; exit; break ;; -g | --gpg-verify ) xshok_check_s2 "$2"; gpg_verify_specific_sanesecurity_database_file "$2"; exit; break ;; -i | --information ) output_system_configuration_information; exit; break ;; -m | --make-database ) make_signature_database_from_ascii_file; exit; break ;; -t | --test-database ) xshok_check_s2 "$2"; clamscan_integrity_test_specific_database_file "$2"; exit; break ;; -o | --output-triggered ) output_signatures_triggered_during_ham_directory_scan; exit; break ;; -w | --whitelist ) add_signature_whitelist_entry; exit; break ;; --check-clamav ) check_clamav; exit; break ;; --install-all ) install_cron; install_logrotate; install_man; exit; break ;; --install-cron ) install_cron; exit; break ;; --install-logrotate ) install_logrotate; exit; break ;; --install-man ) install_man; exit; break ;; --remove-script ) remove_script; exit; break ;; * ) break ;; esac done xshok_pretty_echo_and_log "Preparing Databases" "=" # Check yararule support is available if [ "$enable_yararules" == "yes" ] ; then current_clamav_version=$($clamscan_bin -V | cut -d " " -f2 | cut -d "/" -f1 | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }') minimum_yara_clamav_version=$(echo "$minimum_yara_clamav_version" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }') #Check current clamav version against the minimum required version for yara support if [ "$current_clamav_version" -lt "$minimum_yara_clamav_version" ] ; then #older yararulesproject_enabled="no" enable_yararules="no" xshok_pretty_echo_and_log "Notice: Yararules Disabled due to clamav being older than the minimum required version" fi else yararulesproject_enabled="no" enable_yararules="no" fi # Generate the signature databases if [ "$sanesecurity_enabled" == "yes" ] ; then if [ -n "$sanesecurity_dbs" ] ; then if [ -n "$sanesecurity_dbs_rating" ] ; then sanesecurity_dbs="$(xshok_database "$sanesecurity_dbs" "$sanesecurity_dbs_rating")" else sanesecurity_dbs="$(xshok_database "$sanesecurity_dbs" "$default_dbs_rating")" fi fi fi if [ "$securiteinfo_enabled" == "yes" ] ; then if [ -n "$securiteinfo_dbs" ] ; then if [ -n "$securiteinfo_dbs_rating" ] ; then securiteinfo_dbs="$(xshok_database "$securiteinfo_dbs" "$securiteinfo_dbs_rating")" else securiteinfo_dbs="$(xshok_database "$securiteinfo_dbs" "$default_dbs_rating")" fi fi fi if [ "$linuxmalwaredetect_enabled" == "yes" ] ; then if [ -n "$linuxmalwaredetect_dbs" ] ; then if [ -n "$linuxmalwaredetect_dbs_rating" ] ; then linuxmalwaredetect_dbs="$(xshok_database "$linuxmalwaredetect_dbs" "$linuxmalwaredetect_dbs_rating")" else linuxmalwaredetect_dbs="$(xshok_database "$linuxmalwaredetect_dbs" "$default_dbs_rating")" fi fi fi if [ "$yararulesproject_enabled" == "yes" ] ; then if [ -n "$yararulesproject_dbs" ] ; then if [ -n "$yararulesproject_dbs_rating" ] ; then yararulesproject_dbs="$(xshok_database "$yararulesproject_dbs" "$yararulesproject_dbs_rating")" else yararulesproject_dbs="$(xshok_database "$yararulesproject_dbs" "$default_dbs_rating")" fi fi fi # Set the variables for MalwarePatrol if [ "$malwarepatrol_free" == "yes" ] ; then malwarepatrol_product_code="8" malwarepatrol_list="clamav_basic" else if [ -z $malwarepatrol_list ] ; then malwarepatrol_list="clamav_basic" fi if [ -z $malwarepatrol_product_code ] ; then # Not sure, it may be better to return an error. malwarepatrol_product_code=8 fi fi if [ $malwarepatrol_list == "clamav_basic" ] ; then malwarepatrol_db="malwarepatrol.db" else malwarepatrol_db="malwarepatrol.ndb" fi malwarepatrol_url="$malwarepatrol_url?product=$malwarepatrol_product_code&list=$malwarepatrol_list" # If "ham_dir" variable is set, then create initial whitelist files (skipped if first-time script run). test_dir="$work_dir/test" if [ -n "$ham_dir" ] && [ -d "$work_dir" ] && [ ! -d "$test_dir" ] ; then if [ -d "$ham_dir" ] ; then xshok_mkdir_ownership "$test_dir" cp -f "$work_dir"/*/*.ndb "$test_dir" $clamscan_bin --infected --no-summary -d "$test_dir" "$ham_dir"/* | command sed 's/\.UNOFFICIAL FOUND//' | awk '{print $NF}' >> "$work_dir_work_configs/whitelist.txt" $grep_bin -h -f "$work_dir_work_configs/whitelist.txt" "$test_dir"/* | cut -d "*" -f2 | sort | uniq > "$work_dir_work_configs/whitelist.hex" cd "$test_dir" || exit for db_file in * ; do [[ -e $db_file ]] || break # handle the case of no files $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$db_file" > "$db_file-tmp" mv -f "$db_file-tmp" "$db_file" if $clamscan_bin --quiet -d "$db_file" "$work_dir_work_configs/scan-test.txt" 2>/dev/null ; then if $rsync_bin -pcqt "$db_file" "$clam_dbs" ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$db_file" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$db_file" fi do_clamd_reload=1 fi fi done if [ -r "$work_dir_work_configs/whitelist.hex" ] ; then xshok_pretty_echo_and_log "Initial HAM directory scan whitelist file created in $work_dir_work_configs" else xshok_pretty_echo_and_log "No false-positives detected in initial HAM directory scan" fi else xshok_pretty_echo_and_log "WARNING: Cannot locate HAM directory: $ham_dir" xshok_pretty_echo_and_log "Skipping initial whitelist file creation. Fix 'ham_dir' path in config file" fi fi # Check to see if the working directories have been created. If not, create them. Otherwise, ignore and proceed with script. xshok_mkdir_ownership "$work_dir" xshok_mkdir_ownership "$work_dir_securiteinfo" xshok_mkdir_ownership "$work_dir_malwarepatrol" xshok_mkdir_ownership "$work_dir_linuxmalwaredetect" xshok_mkdir_ownership "$work_dir_sanesecurity" xshok_mkdir_ownership "$work_dir_yararulesproject" xshok_mkdir_ownership "$work_dir_work_configs" xshok_mkdir_ownership "$work_dir_gpg" xshok_mkdir_ownership "$work_dir_add" # Set secured access permissions to the GPG directory perms chmod -f 0700 "$work_dir_gpg" # If we haven't done so yet, download Sanesecurity public GPG key and import to custom keyring. if [ ! -s "$work_dir_gpg/publickey.gpg" ] ; then if [ "$wget_bin" != "" ] ; then #echo $wget_bin $wget_proxy_https $wget_proxy_http $wget_insecure $wget_output_level --connect-timeout="$downloader_connect_timeout" --random-wait --tries="$downloader_tries" --timeout="$downloader_max_time" --output-document="$work_dir_gpg/publickey.gpg" "$sanesecurity_gpg_url" $wget_bin $wget_proxy_https $wget_proxy_http $wget_insecure $wget_output_level --connect-timeout="$downloader_connect_timeout" --random-wait --tries="$downloader_tries" --timeout="$downloader_max_time" --output-document="$work_dir_gpg/publickey.gpg" "$sanesecurity_gpg_url" ret="$?" else #echo $curl_bin $curl_proxy $curl_insecure $curl_output_level --connect-timeout "$downloader_connect_timeout" --remote-time --location --retry "$downloader_tries" --max-time "$downloader_max_time" --output "$work_dir_gpg/publickey.gpg" "$sanesecurity_gpg_url" $curl_bin $curl_proxy $curl_insecure $curl_output_level --connect-timeout "$downloader_connect_timeout" --remote-time --location --retry "$downloader_tries" --max-time "$downloader_max_time" --output "$work_dir_gpg/publickey.gpg" "$sanesecurity_gpg_url" ret="$?" fi if [ "$ret" != "0" ] ; then xshok_pretty_echo_and_log "ALERT: Could not download Sanesecurity public GPG key" "*" exit 1 else xshok_pretty_echo_and_log "Sanesecurity public GPG key successfully downloaded" rm -f -- "$work_dir_gpg/ss-keyring.gp*" if ! $gpg_bin -q --no-options --no-default-keyring --homedir "$work_dir_gpg" --keyring "$work_dir_gpg/ss-keyring.gpg" --import "$work_dir_gpg/publickey.gpg" 2>/dev/null ; then xshok_pretty_echo_and_log "ALERT: could not import Sanesecurity public GPG key to custom keyring" "*" exit 1 else chmod -f 0644 "$work_dir_gpg/*.*" xshok_pretty_echo_and_log "Sanesecurity public GPG key successfully imported to custom keyring" fi fi fi # If custom keyring is missing, try to re-import Sanesecurity public GPG key. if [ ! -s "$work_dir_gpg/ss-keyring.gpg" ] ; then rm -f -- "$work_dir_gpg/ss-keyring.gp*" if ! $gpg_bin -q --no-options --no-default-keyring --homedir "$work_dir_gpg" --keyring "$work_dir_gpg/ss-keyring.gpg" --import "$work_dir_gpg/publickey.gpg" 2>/dev/null ; then xshok_pretty_echo_and_log "ALERT: Custom keyring MISSING or CORRUPT! Could not import Sanesecurity public GPG key to custom keyring" "*" exit 1 else chmod -f 0644 "$work_dir_gpg/*.*" xshok_pretty_echo_and_log "Sanesecurity custom keyring MISSING! GPG key successfully re-imported to custom keyring" fi fi # Database update check, time randomization section. This script now # provides support for both bash and non-bash enabled system shells. if [ "$enable_random" = "yes" ] ; then if [ -n "$RANDOM" ] ; then sleep_time=$((RANDOM * $((max_sleep_time - min_sleep_time)) / 32767 + min_sleep_time)) else sleep_time=0 while [ "$sleep_time" -lt "$min_sleep_time" ] || [ "$sleep_time" -gt "$max_sleep_time" ] ; do sleep_time=$(head -1 /dev/urandom | cksum | awk '{print $2}') done fi if [ ! -t 0 ] ; then xshok_pretty_echo_and_log "$(date) - Pausing database file updates for $sleep_time seconds..." sleep "$sleep_time" xshok_pretty_echo_and_log "$(date) - Pause complete, checking for new database files..." fi fi # Create "scan-test.txt" file for clamscan database integrity testing. if [ ! -s "$work_dir_work_configs/scan-test.txt" ] ; then echo "This is the clamscan test file..." > "$work_dir_work_configs/scan-test.txt" fi # If rsync proxy is defined in the config file, then export it for use. if [ -n "$rsync_proxy" ] ; then RSYNC_PROXY="$rsync_proxy" export RSYNC_PROXY fi # Create $current_dbsfiles containing lists of current and previously active 3rd-party databases # so that databases and/or backup files that are no longer being used can be removed. current_tmp="$work_dir_work_configs/current-dbs.tmp" current_dbs="$work_dir_work_configs/current-dbs.txt" if [ "$sanesecurity_enabled" == "yes" ] ; then # Create the Sanesecurity rsync "include" file (defines which files to download). sanesecurity_include_dbs="$work_dir_work_configs/ss-include-dbs.txt" if [ -n "$sanesecurity_dbs" ] ; then rm -f -- "$sanesecurity_include_dbs" "$work_dir_sanesecurity/*.sha256" for db in $sanesecurity_dbs ; do echo "$db" >> "$sanesecurity_include_dbs" echo "$db.sig" >> "$sanesecurity_include_dbs" echo "$work_dir_sanesecurity/$db" >> "$current_tmp" echo "$work_dir_sanesecurity/$db.sig" >> "$current_tmp" clamav_files done fi fi if [ "$securiteinfo_enabled" == "yes" ] ; then if [ -n "$securiteinfo_dbs" ] ; then for db in $securiteinfo_dbs ; do echo "$work_dir_securiteinfo/$db" >> "$current_tmp" clamav_files done fi fi if [ "$linuxmalwaredetect_enabled" == "yes" ] ; then if [ -n "$linuxmalwaredetect_dbs" ] ; then for db in $linuxmalwaredetect_dbs ; do echo "$work_dir_linuxmalwaredetect/$db" >> "$current_tmp" clamav_files done fi fi if [ "$malwarepatrol_enabled" == "yes" ] ; then if [ -n "$malwarepatrol_db" ] ; then echo "$work_dir_malwarepatrol/$malwarepatrol_db" >> "$current_tmp" clamav_files fi fi if [ "$yararulesproject_enabled" == "yes" ] ; then if [ -n "$yararulesproject_dbs" ] ; then for db in $yararulesproject_dbs ; do if echo "$db" | $grep_bin -q "/"; then db=$(echo "$db" | cut -d"/" -f2) fi echo "$work_dir_yararulesproject/$db" >> "$current_tmp" clamav_files done fi fi if [ "$additional_enabled" == "yes" ] ; then if [ -n "$additional_dbs" ] ; then for db in $additional_dbs ; do echo "$work_dir_add/$db" >> "$current_tmp" clamav_files done fi fi sort "$current_tmp" > "$current_dbs" 2>/dev/null rm -f "$current_tmp" # Remove 3rd-party databases and/or backup files that are no longer being used. if [ "$remove_disabled_databases" == "yes" ] ; then previous_dbs="$work_dir_work_configs/previous-dbs.txt" sort "$current_dbs" > "$previous_dbs" 2>/dev/null #do not remove the current_dbs #rm -f "$current_dbs" db_changes="$work_dir_work_configs/db-changes.txt" if [ ! -s "$previous_dbs" ] ; then cp -f "$current_dbs" "$previous_dbs" 2>/dev/null fi diff "$current_dbs" "$previous_dbs" 2>/dev/null | $grep_bin '>' | awk '{print $2}' > "$db_changes" if [ -r "$db_changes" ] ; then if $grep_bin -vq "bak" "$db_changes" 2>/dev/null ; then do_clamd_reload=2 fi while read -r file ; do rm -f -- "$file" xshok_pretty_echo_and_log "Unused/Disabled file removed: $file" done < "$db_changes" fi fi # Create "purge.txt" file for package maintainers to support package uninstall. purge="$work_dir_work_configs/purge.txt" cp -f "$current_dbs" "$purge" { echo "$work_dir_work_configs/current-dbs.txt" echo "$work_dir_work_configs/db-changes.txt" echo "$work_dir_work_configs/last-mbl-update.txt" echo "$work_dir_work_configs/last-si-update.txt" echo "$work_dir_work_configs/local.ign" echo "$work_dir_work_configs/monitor-ign.txt" echo "$work_dir_work_configs/my-whitelist.ign2" echo "$work_dir_work_configs/tracker.txt" echo "$work_dir_work_configs/previous-dbs.txt" echo "$work_dir_work_configs/scan-test.txt" echo "$work_dir_work_configs/ss-include-dbs.txt" echo "$work_dir_work_configs/whitelist.hex" echo "$work_dir_gpg/publickey.gpg" echo "$work_dir_gpg/secring.gpg" echo "$work_dir_gpg/ss-keyring.gpg*" echo "$work_dir_gpg/trustdb.gpg" echo "$log_file_path/$log_file_name*" echo "$work_dir_work_configs/purge.txt" } >> "$purge" # Check and save current system time since epoch for time related database downloads. # However, if unsuccessful, issue a warning that we cannot calculate times since epoch. if [ -n "$securiteinfo_dbs" ] || [ -n "$malwarepatrol_db" ] ; then current_time=$(date "+%s" 2> /dev/null) current_time="${current_time//[^0-9]/}" current_time="$((current_time + 0))" if [ "$current_time" -le 0 ] ; then current_time=$(perl -le print+time 2> /dev/null) fi if [ "$current_time" -le 0 ] ; then xshok_pretty_echo_and_log "WARNING: No support for 'date +%s' or 'perl' was not found , SecuriteInfo and MalwarePatrol updates bypassed" "=" securiteinfo_dbs="" malwarepatrol_db="" fi fi ################################################################ # Check for Sanesecurity database & GPG signature file updates # ################################################################ if [ "$sanesecurity_enabled" == "yes" ] ; then if [ -n "$sanesecurity_dbs" ] ; then ##if [ ${#sanesecurity_dbs[@]} -lt "1" ] ; then ##will not work due to compound array assignment if [ "$(xshok_array_count "$sanesecurity_dbs")" -lt "1" ] ; then xshok_pretty_echo_and_log "Failed sanesecurity_dbs config is invalid or not defined - SKIPPING" else if [ -r "$work_dir_work_configs/last-ss-update.txt" ] ; then last_sanesecurity_update=$(cat "$work_dir_work_configs/last-ss-update.txt") else last_sanesecurity_update="0" fi db_file="" update_interval=$((sanesecurity_update_hours * 3600)) time_interval=$((current_time - last_sanesecurity_update)) if [ "$time_interval" -ge $((update_interval - 600)) ] ; then echo "$current_time" > "$work_dir_work_configs/last-ss-update.txt" xshok_pretty_echo_and_log "Sanesecurity Database & GPG Signature File Updates" "=" xshok_pretty_echo_and_log "Checking for Sanesecurity updates..." sanesecurity_mirror_ips=$(dig +ignore +short "$sanesecurity_url") #add fallback to host if dig returns no records if [ "$(xshok_array_count "$sanesecurity_mirror_ips")" -lt 1 ] ; then sanesecurity_mirror_ips=$(host -t A "$sanesecurity_url" | sed -n '/has address/{s/.*address \([^ ]*\).*/\1/;p;}') fi if [ "$(xshok_array_count "$sanesecurity_mirror_ips")" -ge "1" ] ; then for sanesecurity_mirror_ip in $sanesecurity_mirror_ips ; do sanesecurity_mirror_name="" sanesecurity_mirror_name=$(dig +short -x "$sanesecurity_mirror_ip" | command sed 's/\.$//') #add fallback to host if dig returns no records if [ "$sanesecurity_mirror_name" == "" ] ; then sanesecurity_mirror_name=$(host "$sanesecurity_mirror_ip" | sed -n '/name pointer/{s/.*pointer \([^ ]*\).*\.$/\1/;p;}') fi sanesecurity_mirror_site_info="$sanesecurity_mirror_name $sanesecurity_mirror_ip" xshok_pretty_echo_and_log "Sanesecurity mirror site used: $sanesecurity_mirror_site_info" $rsync_bin $rsync_output_level $no_motd --files-from="$sanesecurity_include_dbs" -ctuz $connect_timeout --timeout="$rsync_max_time" "rsync://$sanesecurity_mirror_ip/sanesecurity" "$work_dir_sanesecurity" 2>/dev/null if [ "$?" -eq "0" ] ; then #the correct way sanesecurity_rsync_success="1" for db_file in $sanesecurity_dbs ; do if ! cmp -s "$work_dir_sanesecurity/$db_file" "$clam_dbs/$db_file" ; then xshok_pretty_echo_and_log "Testing updated Sanesecurity database file: $db_file" if ! $gpg_bin --trust-model always -q --no-default-keyring --homedir "$work_dir_gpg" --keyring "$work_dir_gpg/ss-keyring.gpg" --verify "$work_dir_sanesecurity/$db_file.sig" "$work_dir_sanesecurity/$db_file" 2>/dev/null ; then $gpg_bin --always-trust -q --no-default-keyring --homedir "$work_dir_gpg" --keyring "$work_dir_gpg/ss-keyring.gpg" --verify "$work_dir_sanesecurity/$db_file.sig" "$work_dir_sanesecurity/$db_file" 2>/dev/null ret="$?" else ret="0" fi if [ "$ret" -eq "0" ] ; then test "$gpg_silence" = "no" && xshok_pretty_echo_and_log "Sanesecurity GPG Signature tested good on $db_file database" true else xshok_pretty_echo_and_log "Sanesecurity GPG Signature test FAILED on $db_file database - SKIPPING" false fi if [ "$?" -eq "0" ] ; then db_ext=$(echo "$db_file" | cut -d "." -f2) if [ -z "$ham_dir" ] || [ "$db_ext" != "ndb" ] ; then if $clamscan_bin --quiet -d "$work_dir_sanesecurity/$db_file" "$work_dir_work_configs/scan-test.txt" 2>/dev/null ; then xshok_pretty_echo_and_log "Clamscan reports Sanesecurity $db_file database integrity tested good" true else xshok_pretty_echo_and_log "Clamscan reports Sanesecurity $db_file database integrity tested BAD" if [ "$remove_bad_database" == "yes" ] ; then if rm -f "$work_dir_sanesecurity/$db_file" ; then xshok_pretty_echo_and_log "Removed invalid database: $work_dir_sanesecurity/$db_file" fi fi false fi && (test "$keep_db_backup" = "yes" && cp -f "$clam_dbs/$db_file" "$clam_dbs/$db_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "$work_dir_sanesecurity/$db_file" "$clam_dbs" 2>/dev/null ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$db_file" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$db_file" fi xshok_pretty_echo_and_log "Successfully updated Sanesecurity production database file: $db_file" sanesecurity_update=1 do_clamd_reload=1 else xshok_pretty_echo_and_log "Failed to successfully update Sanesecurity production database file: $db_file - SKIPPING" false fi else $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$work_dir_sanesecurity/$db_file" > "$test_dir/$db_file" $clamscan_bin --infected --no-summary -d "$test_dir/$db_file" "$ham_dir"/* | command sed 's/\.UNOFFICIAL FOUND//' | awk '{print $NF}' > "$work_dir_work_configs/whitelist.txt" $grep_bin -h -f "$work_dir_work_configs/whitelist.txt" "$test_dir/$db_file" | cut -d "*" -f2 | sort | uniq >> "$work_dir_work_configs/whitelist.hex" $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$test_dir/$db_file" > "$test_dir/$db_file-tmp" mv -f "$test_dir/$db_file-tmp" "$test_dir/$db_file" if $clamscan_bin --quiet -d "$test_dir/$db_file" "$work_dir_work_configs/scan-test.txt" 2>/dev/null ; then xshok_pretty_echo_and_log "Clamscan reports Sanesecurity $db_file database integrity tested good" true else xshok_pretty_echo_and_log "Clamscan reports Sanesecurity $db_file database integrity tested BAD" ##DO NOT KILL THIS DB false fi && (test "$keep_db_backup" = "yes" && cp -f "$clam_dbs/$db_file" "$clam_dbs/$db_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "$test_dir/$db_file" "$clam_dbs" 2>/dev/null ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$db_file" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$db_file" fi xshok_pretty_echo_and_log "Successfully updated Sanesecurity production database file: $db_file" sanesecurity_update=1 do_clamd_reload=1 else xshok_pretty_echo_and_log "Failed to successfully update Sanesecurity production database file: $db_file - SKIPPING" fi fi fi fi done if [ "$sanesecurity_update" != "1" ] ; then xshok_pretty_echo_and_log "No Sanesecurity database file updates found" "-" break else break fi else xshok_pretty_echo_and_log "Connection to $sanesecurity_mirror_site_info failed - Trying next mirror site..." fi done if [ "$sanesecurity_rsync_success" != "1" ] ; then xshok_pretty_echo_and_log "Access to all Sanesecurity mirror sites failed - Check for connectivity issues" xshok_pretty_echo_and_log "or signature database name(s) misspelled in the script's configuration file." fi else xshok_pretty_echo_and_log "No Sanesecurity mirror sites found - Check for dns/connectivity issues" fi else xshok_pretty_echo_and_log "Sanesecurity Database File Updates" "=" time_remaining=$((update_interval - time_interval)) hours_left=$((time_remaining / 3600)) minutes_left=$((time_remaining % 3600 / 60)) xshok_pretty_echo_and_log "$sanesecurity_update_hours hours have not yet elapsed since the last sanesecurity update check" xshok_pretty_echo_and_log "No update check was performed at this time" "-" xshok_pretty_echo_and_log "Next check will be performed in approximately $hours_left hour(s), $minutes_left minute(s)" fi fi fi else if [ -n "$sanesecurity_dbs" ] ; then if [ "$remove_disabled_databases" == "yes" ] ; then xshok_pretty_echo_and_log "Removing disabled Sanesecurity Database files" for db_file in $sanesecurity_dbs ; do if [ -r "$work_dir_sanesecurity/$db_file" ] ; then rm -f "$work_dir_sanesecurity/$db_file"* do_clamd_reload=1 fi if [ -r "$clam_dbs/$db_file" ] ; then rm -f "$clam_dbs/$db_file" do_clamd_reload=1 fi done fi fi fi ############################################################################################################################################## # Check for updated SecuriteInfo database files every set number of hours as defined in the "USER CONFIGURATION" section of this script # ############################################################################################################################################## if [ "$securiteinfo_enabled" == "yes" ] ; then if [ "$securiteinfo_authorisation_signature" != "YOUR-SIGNATURE-NUMBER" ] ; then if [ -n "$securiteinfo_dbs" ] ; then if [ "$(xshok_array_count "$securiteinfo_dbs")" -lt "1" ] ; then xshok_pretty_echo_and_log "Failed securiteinfo_dbs config is invalid or not defined - SKIPPING" else rm -f "$work_dir_securiteinfo/*.gz" if [ -r "$work_dir_work_configs/last-si-update.txt" ] ; then last_securiteinfo_update=$(cat "$work_dir_work_configs/last-si-update.txt") else last_securiteinfo_update="0" fi db_file="" loop="" update_interval=$((securiteinfo_update_hours * 3600)) time_interval=$((current_time - last_securiteinfo_update)) if [ "$time_interval" -ge $((update_interval - 600)) ] ; then echo "$current_time" > "$work_dir_work_configs/last-si-update.txt" xshok_pretty_echo_and_log "SecuriteInfo Database File Updates" "=" xshok_pretty_echo_and_log "Checking for SecuriteInfo updates..." securiteinfo_updates="0" for db_file in $securiteinfo_dbs ; do if [ "$loop" = "1" ] ; then xshok_pretty_echo_and_log "---" fi xshok_pretty_echo_and_log "Checking for updated SecuriteInfo database file: $db_file" securiteinfo_db_update="0" if [ "$wget_bin" != "" ] ; then $wget_bin $wget_proxy_https $wget_proxy_http $wget_insecure $wget_output_level --connect-timeout="$downloader_connect_timeout" --random-wait --tries="$downloader_tries" --timeout="$downloader_max_time" --output-document="$work_dir_securiteinfo/$db_file" "$securiteinfo_url/$securiteinfo_authorisation_signature/$db_file" ret="$?" else $curl_bin $curl_proxy $curl_insecure $curl_output_level --connect-timeout "$downloader_connect_timeout" --remote-time --location --retry "$downloader_tries" --max-time "$downloader_max_time" --output "$work_dir_securiteinfo/$db_file" "$securiteinfo_url/$securiteinfo_authorisation_signature/$db_file" ret="$?" fi if [ "$ret" -eq "0" ] ; then loop="1" if ! cmp -s "$work_dir_securiteinfo/$db_file" "$clam_dbs/$db_file" ; then if [ "$?" -eq "0" ] ; then db_ext=$(echo "$db_file" | cut -d "." -f2) xshok_pretty_echo_and_log "Testing updated SecuriteInfo database file: $db_file" if [ -z "$ham_dir" ] || [ "$db_ext" != "ndb" ] then if $clamscan_bin --quiet -d "$work_dir_securiteinfo/$db_file" "$work_dir_work_configs/scan-test.txt" 2>/dev/null then xshok_pretty_echo_and_log "Clamscan reports SecuriteInfo $db_file database integrity tested good" true else xshok_pretty_echo_and_log "Clamscan reports SecuriteInfo $db_file database integrity tested BAD" if [ "$remove_bad_database" == "yes" ] ; then if rm -f "$work_dir_securiteinfo/$db_file" ; then xshok_pretty_echo_and_log "Removed invalid database: $work_dir_securiteinfo/$db_file" fi fi false fi && (test "$keep_db_backup" = "yes" && cp -f "$clam_dbs/$db_file" "$clam_dbs/$db_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "$work_dir_securiteinfo/$db_file" "$clam_dbs" 2>/dev/null ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$db_file" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$db_file" fi xshok_pretty_echo_and_log "Successfully updated SecuriteInfo production database file: $db_file" securiteinfo_updates=1 securiteinfo_db_update=1 do_clamd_reload=1 else xshok_pretty_echo_and_log "Failed to successfully update SecuriteInfo production database file: $db_file - SKIPPING" fi else $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$work_dir_securiteinfo/$db_file" > "$test_dir/$db_file" $clamscan_bin --infected --no-summary -d "$test_dir/$db_file" "$ham_dir"/* | command sed 's/\.UNOFFICIAL FOUND//' | awk '{print $NF}' > "$work_dir_work_configs/whitelist.txt" $grep_bin -h -f "$work_dir_work_configs/whitelist.txt" "$test_dir/$db_file" | cut -d "*" -f2 | sort | uniq >> "$work_dir_work_configs/whitelist.hex" $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$test_dir/$db_file" > "$test_dir/$db_file-tmp" mv -f "$test_dir/$db_file-tmp" "$test_dir/$db_file" if $clamscan_bin --quiet -d "$test_dir/$db_file" "$work_dir_work_configs/scan-test.txt" 2>/dev/null then xshok_pretty_echo_and_log "Clamscan reports SecuriteInfo $db_file database integrity tested good" true else xshok_pretty_echo_and_log "Clamscan reports SecuriteInfo $db_file database integrity tested BAD" rm -f "$work_dir_securiteinfo/$db_file" if [ "$remove_bad_database" == "yes" ] ; then if rm -f "$work_dir_securiteinfo/$db_file" ; then xshok_pretty_echo_and_log "Removed invalid database: $work_dir_securiteinfo/$db_file" fi fi false fi && (test "$keep_db_backup" = "yes" && cp -f "$clam_dbs/$db_file" "$clam_dbs/$db_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "$test_dir/$db_file" "$clam_dbs" 2>/dev/null ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$db_file" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$db_file" fi xshok_pretty_echo_and_log "Successfully updated SecuriteInfo production database file: $db_file" securiteinfo_updates=1 securiteinfo_db_update=1 do_clamd_reload=1 else xshok_pretty_echo_and_log "Failed to successfully update SecuriteInfo production database file: $db_file - SKIPPING" fi fi fi fi else xshok_pretty_echo_and_log "Failed connection to $securiteinfo_url - SKIPPED SecuriteInfo $db_file update" fi if [ "$securiteinfo_db_update" != "1" ] ; then xshok_pretty_echo_and_log "No updated SecuriteInfo $db_file database file found" "-" fi done if [ "$securiteinfo_updates" != "1" ] ; then xshok_pretty_echo_and_log "No SecuriteInfo database file updates found" "-" fi else xshok_pretty_echo_and_log "SecuriteInfo Database File Updates" "=" time_remaining=$((update_interval - time_interval)) hours_left=$((time_remaining / 3600)) minutes_left=$((time_remaining % 3600 / 60)) xshok_pretty_echo_and_log "$securiteinfo_update_hours hours have not yet elapsed since the last SecuriteInfo update check" xshok_pretty_echo_and_log "No update check was performed at this time" "-" xshok_pretty_echo_and_log "Next check will be performed in approximately $hours_left hour(s), $minutes_left minute(s)" fi fi fi fi else if [ -n "$securiteinfo_dbs" ] ; then if [ "$remove_disabled_databases" == "yes" ] ; then xshok_pretty_echo_and_log "Removing disabled SecuriteInfo Database files" for db_file in $securiteinfo_dbs ; do if [ -r "$work_dir_securiteinfo/$db_file" ] ; then rm -f "$work_dir_securiteinfo/$db_file" do_clamd_reload=1 fi if [ -r "$clam_dbs/$db_file" ] ; then rm -f "$clam_dbs/$db_file" do_clamd_reload=1 fi done fi fi fi ############################################################################################################################################## # Check for updated linuxmalwaredetect database files every set number of hours as defined in the "USER CONFIGURATION" section of this script ############################################################################################################################################## if [ "$linuxmalwaredetect_enabled" == "yes" ] ; then if [ -n "$linuxmalwaredetect_dbs" ] ; then if [ "$(xshok_array_count "$linuxmalwaredetect_dbs")" -lt "1" ] ; then xshok_pretty_echo_and_log "Failed linuxmalwaredetect_dbs config is invalid or not defined - SKIPPING" else rm -f "$work_dir_linuxmalwaredetect/*.gz" if [ -r "$work_dir_work_configs/last-linuxmalwaredetect-update.txt" ] ; then last_linuxmalwaredetect_update=$(cat "$work_dir_work_configs/last-linuxmalwaredetect-update.txt") else last_linuxmalwaredetect_update="0" fi db_file="" loop="" update_interval=$((linuxmalwaredetect_update_hours * 3600)) time_interval=$((current_time - last_linuxmalwaredetect_update)) if [ "$time_interval" -ge $((update_interval - 600)) ] ; then echo "$current_time" > "$work_dir_work_configs/last-linuxmalwaredetect-update.txt" xshok_pretty_echo_and_log "linuxmalwaredetect Database File Updates" "=" xshok_pretty_echo_and_log "Checking for linuxmalwaredetect updates..." linuxmalwaredetect_updates="0" for db_file in $linuxmalwaredetect_dbs ; do if [ "$loop" = "1" ] ; then xshok_pretty_echo_and_log "---" fi xshok_pretty_echo_and_log "Checking for updated linuxmalwaredetect database file: $db_file" linuxmalwaredetect_db_update="0" if [ "$wget_bin" != "" ] ; then $wget_bin $wget_proxy_https $wget_proxy_http $wget_insecure $wget_output_level --connect-timeout="$downloader_connect_timeout" --random-wait --tries="$downloader_tries" --timeout="$downloader_max_time" --output-document="$work_dir_linuxmalwaredetect/$db_file" "$linuxmalwaredetect_url/$db_file" ret="$?" else $curl_bin $curl_proxy $curl_insecure $curl_output_level --connect-timeout "$downloader_connect_timeout" --remote-time --location --retry "$downloader_tries" --max-time "$downloader_max_time" --output "$work_dir_linuxmalwaredetect/$db_file" "$linuxmalwaredetect_url/$db_file" ret="$?" fi if [ "$ret" -eq "0" ] ; then loop="1" if ! cmp -s "$work_dir_linuxmalwaredetect/$db_file" "$clam_dbs/$db_file" ; then if [ "$?" -eq "0" ] ; then db_ext=$(echo "$db_file" | cut -d "." -f2) xshok_pretty_echo_and_log "Testing updated linuxmalwaredetect database file: $db_file" if [ -z "$ham_dir" ] || [ "$db_ext" != "ndb" ] ; then if $clamscan_bin --quiet -d "$work_dir_linuxmalwaredetect/$db_file" "$work_dir_work_configs/scan-test.txt" 2>/dev/null then xshok_pretty_echo_and_log "Clamscan reports linuxmalwaredetect $db_file database integrity tested good" true else xshok_pretty_echo_and_log "Clamscan reports linuxmalwaredetect $db_file database integrity tested BAD" if [ "$remove_bad_database" == "yes" ] ; then if rm -f "$work_dir_linuxmalwaredetect/$db_file" ; then xshok_pretty_echo_and_log "Removed invalid database: $work_dir_linuxmalwaredetect/$db_file" fi fi false fi && (test "$keep_db_backup" = "yes" && cp -f "$clam_dbs/$db_file" "$clam_dbs/$db_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "$work_dir_linuxmalwaredetect/$db_file" "$clam_dbs" 2>/dev/null ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$db_file" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/local.ign" fi xshok_pretty_echo_and_log "Successfully updated linuxmalwaredetect production database file: $db_file" linuxmalwaredetect_updates=1 linuxmalwaredetect_db_update=1 do_clamd_reload=1 else xshok_pretty_echo_and_log "Failed to successfully update linuxmalwaredetect production database file: $db_file - SKIPPING" fi else $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$work_dir_linuxmalwaredetect/$db_file" > "$test_dir/$db_file" $clamscan_bin --infected --no-summary -d "$test_dir/$db_file" "$ham_dir"/* | command sed 's/\.UNOFFICIAL FOUND//' | awk '{print $NF}' > "$work_dir_work_configs/whitelist.txt" $grep_bin -h -f "$work_dir_work_configs/whitelist.txt" "$test_dir/$db_file" | cut -d "*" -f2 | sort | uniq >> "$work_dir_work_configs/whitelist.hex" $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$test_dir/$db_file" > "$test_dir/$db_file-tmp" mv -f "$test_dir/$db_file-tmp" "$test_dir/$db_file" if $clamscan_bin --quiet -d "$test_dir/$db_file" "$work_dir_work_configs/scan-test.txt" 2>/dev/null ; then xshok_pretty_echo_and_log "Clamscan reports linuxmalwaredetect $db_file database integrity tested good" true else xshok_pretty_echo_and_log "Clamscan reports linuxmalwaredetect $db_file database integrity tested BAD" if [ "$remove_bad_database" == "yes" ] ; then if rm -f "$work_dir_linuxmalwaredetect/$db_file" ; then xshok_pretty_echo_and_log "Removed invalid database: $work_dir_linuxmalwaredetect/$db_file" fi fi false fi && (test "$keep_db_backup" = "yes" && cp -f "$clam_dbs/$db_file" "$clam_dbs/$db_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "$test_dir/$db_file" "$clam_dbs" 2>/dev/null ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$db_file" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$db_file" fi xshok_pretty_echo_and_log "Successfully updated linuxmalwaredetect production database file: $db_file" linuxmalwaredetect_updates=1 linuxmalwaredetect_db_update=1 do_clamd_reload=1 else xshok_pretty_echo_and_log "Failed to successfully update linuxmalwaredetect production database file: $db_file - SKIPPING" fi fi fi fi else xshok_pretty_echo_and_log "WARNING: Failed connection to $linuxmalwaredetect_url - SKIPPED linuxmalwaredetect $db_file update" fi if [ "$linuxmalwaredetect_db_update" != "1" ] ; then xshok_pretty_echo_and_log "No updated linuxmalwaredetect $db_file database file found" fi done if [ "$linuxmalwaredetect_updates" != "1" ] ; then xshok_pretty_echo_and_log "No linuxmalwaredetect database file updates found" "-" fi else xshok_pretty_echo_and_log "linuxmalwaredetect Database File Updates" "=" time_remaining=$((update_interval - time_interval)) hours_left=$((time_remaining / 3600)) minutes_left=$((time_remaining % 3600 / 60)) xshok_pretty_echo_and_log "$linuxmalwaredetect_update_hours hours have not yet elapsed since the last linux malware detect update check" xshok_pretty_echo_and_log "No update check was performed at this time" "-" xshok_pretty_echo_and_log "Next check will be performed in approximately $hours_left hour(s), $minutes_left minute(s)" fi fi fi else if [ -n "$linuxmalwaredetect_dbs" ] ; then if [ "$remove_disabled_databases" == "yes" ] ; then xshok_pretty_echo_and_log "Removing disabled linuxmalwaredetect Database files" for db_file in $linuxmalwaredetect_dbs ; do if [ -r "$work_dir_linuxmalwaredetect/$db_file" ] ; then rm -f "$work_dir_linuxmalwaredetect/$db_file" do_clamd_reload=1 fi if [ -r "$clam_dbs/$db_file" ] ; then rm -f "$clam_dbs/$db_file" do_clamd_reload=1 fi done fi fi fi ########################################################################################################################################## # Download MalwarePatrol database file every set number of hours as defined in the "USER CONFIGURATION" section of this script. # ########################################################################################################################################## if [ "$malwarepatrol_enabled" == "yes" ] ; then if [ "$malwarepatrol_receipt_code" != "YOUR-RECEIPT-NUMBER" ] ; then if [ -n "$malwarepatrol_db" ] ; then if [ -r "$work_dir_work_configs/last-mbl-update.txt" ] ; then last_malwarepatrol_update=$(cat "$work_dir_work_configs/last-mbl-update.txt") else last_malwarepatrol_update="0" fi db_file="" update_interval=$((malwarepatrol_update_hours * 3600)) time_interval=$((current_time - last_malwarepatrol_update)) if [ "$time_interval" -ge $((update_interval - 600)) ] ; then echo "$current_time" > "$work_dir_work_configs"/last-mbl-update.txt xshok_pretty_echo_and_log "Checking for MalwarePatrol updates..." # Delete the old MBL (mbl.db) database file if it exists and start using the newer # format (mbl.ndb) database file instead. # test -e $clam_dbs/$malwarepatrol_db -o -e $clam_dbs/$malwarepatrol_db-bak && rm -f -- "$clam_dbs/mbl.d*" # remove the .db is th new format if ndb and # symetrically if [ "$malwarepatrol_db" == "malwarepatrol.db" ] && [ -f "$clam_dbs/malwarepatrol.ndb" ] ; then rm "$clam_dbs/malwarepatrol.ndb"; fi if [ "$malwarepatrol_db" == "malwarepatrol.ndb" ] && [ -f "$clam_dbs/malwarepatrol.db" ] ; then rm "$clam_dbs/malwarepatrol.db"; fi xshok_pretty_echo_and_log "MalwarePatrol $db_file Database File Update" "=" malwarepatrol_reloaded=0 if [ "$malwarepatrol_free" == "yes" ] ; then if [ "$wget_bin" != "" ] ; then $wget_bin $wget_proxy_https $wget_proxy_http $wget_insecure $wget_output_level --connect-timeout="$downloader_connect_timeout" --random-wait --tries="$downloader_tries" --timeout="$downloader_max_time" --output-document="$work_dir_malwarepatrol/$malwarepatrol_db" "$malwarepatrol_url&receipt=$malwarepatrol_receipt_code" ret="$?" else $curl_bin $curl_proxy $curl_insecure $curl_output_level --connect-timeout "$downloader_connect_timeout" --remote-time --location --retry "$downloader_tries" --max-time "$downloader_max_time" --output "$work_dir_malwarepatrol/$malwarepatrol_db" "$malwarepatrol_url&receipt=$malwarepatrol_receipt_code" ret="$?" fi if [ "$ret" -eq "0" ] ; then if ! cmp -s "$work_dir_malwarepatrol/$malwarepatrol_db" "$clam_dbs/$malwarepatrol_db" ; then if [ "$?" -eq "0" ] ; then malwarepatrol_reloaded=1 else malwarepatrol_reloaded=2 fi fi else # wget failed malwarepatrol_reloaded=-1 fi else # The not free branch if [ "$wget_bin" != "" ] ; then $wget_bin $wget_proxy_https $wget_proxy_http $wget_insecure $wget_output_level --connect-timeout="$downloader_connect_timeout" --random-wait --tries="$downloader_tries" --timeout="$downloader_max_time" --output-document="$work_dir_malwarepatrol/$malwarepatrol_db.md5" "$malwarepatrol_url&receipt=$malwarepatrol_receipt_code&hash=1" ret="$?" else $curl_bin $curl_proxy $curl_insecure $curl_output_level --connect-timeout "$downloader_connect_timeout" --remote-time --location --retry "$downloader_tries" --max-time "$downloader_max_time" --output "$work_dir_malwarepatrol/$malwarepatrol_db.md5" "$malwarepatrol_url&receipt=$malwarepatrol_receipt_code&hash=1" ret="$?" fi if [ "$ret" -eq "0" ] ; then if [ -f "$clam_dbs/$malwarepatrol_db" ] ; then malwarepatrol_md5=$(openssl md5 -r "$clam_dbs/$malwarepatrol_db" 2>/dev/null | cut -d" " -f1) if [ ! "$malwarepatrol_md5" ] ; then #fallback for missing -r option malwarepatrol_md5=$(openssl md5 "$clam_dbs/$malwarepatrol_db" 2>/dev/null | cut -d" " -f2) fi fi malwarepatrol_md5_new=$(cat "$work_dir_malwarepatrol/$malwarepatrol_db.md5") if [ -n "$malwarepatrol_md5_new" ] && [ "$malwarepatrol_md5" != "$malwarepatrol_md5_new" ] ; then if [ "$wget_bin" != "" ] ; then $wget_bin $wget_proxy_https $wget_proxy_http $wget_insecure $wget_output_level --connect-timeout="$downloader_connect_timeout" --random-wait --tries="$downloader_tries" --timeout="$downloader_max_time" --output-document="$work_dir_malwarepatrol/$malwarepatrol_db" "$malwarepatrol_url&receipt=$malwarepatrol_receipt_code" ret="$?" else $curl_bin $curl_proxy $curl_insecure $curl_output_level --connect-timeout "$downloader_connect_timeout" --remote-time --location --retry "$downloader_tries" --max-time "$downloader_max_time" --output "$work_dir_malwarepatrol/$malwarepatrol_db" "$malwarepatrol_url&receipt=$malwarepatrol_receipt_code" ret="$?" fi if [ "$ret" -eq "0" ] ; then malwarepatrol_reloaded=1 else # wget DB fail malwarepatrol_reloaded=-1 fi # wget DB fi # MD5 not equal else # wget MD5 fail malwarepatrol_reloaded=-1 fi # wget md5 fi case "$malwarepatrol_reloaded" in 1) # database was updated, need test and reload xshok_pretty_echo_and_log "Testing updated MalwarePatrol database file: $malwarepatrol_db" if $clamscan_bin --quiet -d "$work_dir_malwarepatrol/$malwarepatrol_db" "$work_dir_work_configs/scan-test.txt" 2>/dev/null ; then xshok_pretty_echo_and_log "Clamscan reports MalwarePatrol $malwarepatrol_db database integrity tested good" true else xshok_pretty_echo_and_log "Clamscan reports MalwarePatrol $malwarepatrol_db database integrity tested BAD" if [ "$remove_bad_database" == "yes" ] ; then if rm -f "$work_dir_malwarepatrol/$malwarepatrol_db" ; then xshok_pretty_echo_and_log "Removed invalid database: $work_dir_malwarepatrol/$malwarepatrol_db" fi fi false fi && (test "$keep_db_backup" = "yes" && cp -f "$clam_dbs/$malwarepatrol_db" "$clam_dbs/$malwarepatrol_db-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "$work_dir_malwarepatrol/$malwarepatrol_db" "$clam_dbs" 2>/dev/null ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$malwarepatrol_db" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$malwarepatrol_db" fi xshok_pretty_echo_and_log "Successfully updated MalwarePatrol production database file: $malwarepatrol_db" do_clamd_reload=1 else xshok_pretty_echo_and_log "Failed to successfully update MalwarePatrol production database file: $malwarepatrol_db - SKIPPING" fi ;; # The strange case when $? != 0 in the original 2) $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$work_dir_malwarepatrol/$malwarepatrol_db" > "$test_dir/$malwarepatrol_db" $clamscan_bin --infected --no-summary -d "$test_dir/$malwarepatrol_db" "$ham_dir"/* | command sed 's/\.UNOFFICIAL FOUND//' | awk '{print $NF}' > "$work_dir_work_configs/whitelist.txt" $grep_bin -h -f "$work_dir_work_configs/whitelist.txt" "$test_dir/$malwarepatrol_db" | cut -d "*" -f2 | sort | uniq >> "$work_dir_work_configs/whitelist.hex" $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$test_dir/$malwarepatrol_db" > "$test_dir/$malwarepatrol_db-tmp" mv -f "$test_dir/$malwarepatrol_db-tmp" "$test_dir/$malwarepatrol_db" if $clamscan_bin --quiet -d "$test_dir/$malwarepatrol_db" "$work_dir_work_configs/scan-test.txt" 2>/dev/null ; then xshok_pretty_echo_and_log "Clamscan reports MalwarePatrol $malwarepatrol_db database integrity tested good" true else xshok_pretty_echo_and_log "Clamscan reports MalwarePatrol $malwarepatrol_db database integrity tested BAD" if [ "$remove_bad_database" == "yes" ] ; then if rm -f "$test_dir/$malwarepatrol_db" ; then xshok_pretty_echo_and_log "Removed invalid database: $test_dir/$malwarepatrol_db" fi fi false fi && (test "$keep_db_backup" = "yes" && cp -f "$clam_dbs/$malwarepatrol_db" "$clam_dbs/$malwarepatrol_db-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "$test_dir/$malwarepatrol_db" "$clam_dbs" 2>/dev/null ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$malwarepatrol_db" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$malwarepatrol_db" fi xshok_pretty_echo_and_log "Successfully updated MalwarePatrol production database file: $malwarepatrol_db" do_clamd_reload=1 else xshok_pretty_echo_and_log "Failed to successfully update MalwarePatrol production database file: $malwarepatrol_db - SKIPPING" fi ;; 0) # The database did not update xshok_pretty_echo_and_log "MalwarePatrol signature database ($malwarepatrol_db) did not change - skipping" ;; -1) # wget failed xshok_pretty_echo_and_log "WARNING - Failed connection to $malwarepatrol_url - SKIPPED MalwarePatrol $malwarepatrol_db update" ;; esac else xshok_pretty_echo_and_log "MalwarePatrol Database File Update" "=" time_remaining=$((update_interval - time_interval)) hours_left=$((time_remaining / 3600)) minutes_left=$((time_remaining % 3600 / 60)) xshok_pretty_echo_and_log "$malwarepatrol_update_hours hours have not yet elapsed since the last MalwarePatrol download" xshok_pretty_echo_and_log "No database download was performed at this time" "-" xshok_pretty_echo_and_log "Next download will be performed in approximately $hours_left hour(s), $minutes_left minute(s)" fi fi fi else if [ -n "$malwarepatrol_db" ] ; then if [ "$remove_disabled_databases" == "yes" ] ; then xshok_pretty_echo_and_log "Removing disabled MalwarePatrol Database file" if [ -r "$work_dir_malwarepatrol/$malwarepatrol_db" ] ; then rm -f "$work_dir_malwarepatrol/$malwarepatrol_db" do_clamd_reload=1 fi if [ -r "$clam_dbs/$malwarepatrol_db" ] ; then rm -f "$clam_dbs/$malwarepatrol_db" do_clamd_reload=1 fi fi fi fi ############################################################################################################################################## # Check for updated yararulesproject database files every set number of hours as defined in the "USER CONFIGURATION" section of this script ############################################################################################################################################## if [ "$yararulesproject_enabled" == "yes" ] ; then if [ -n "$yararulesproject_dbs" ] ; then if [ "$(xshok_array_count "$yararulesproject_dbs")" -lt "1" ] ; then xshok_pretty_echo_and_log "Failed yararulesproject_dbs config is invalid or not defined - SKIPPING" else rm -f "$work_dir_yararulesproject/*.gz" if [ -r "$work_dir_work_configs/last-yararulesproject-update.txt" ] ; then last_yararulesproject_update=$(cat "$work_dir_work_configs/last-yararulesproject-update.txt") else last_yararulesproject_update="0" fi db_file="" loop="" update_interval=$((yararulesproject_update_hours * 3600)) time_interval=$((current_time - last_yararulesproject_update)) if [ "$time_interval" -ge $((update_interval - 600)) ] ; then echo "$current_time" > "$work_dir_work_configs/last-yararulesproject-update.txt" xshok_pretty_echo_and_log "Yara-Rules Database File Updates" "=" xshok_pretty_echo_and_log "Checking for yararulesproject updates..." yararulesproject_updates="0" for db_file in $yararulesproject_dbs ; do if echo "$db_file" | $grep_bin -q "/"; then yr_dir="/"$(echo "$db_file" | cut -d"/" -f1) db_file=$(echo "$db_file" | cut -d"/" -f2) else yr_dir="" fi if [ "$loop" = "1" ] ; then xshok_pretty_echo_and_log "---" fi xshok_pretty_echo_and_log "Checking for updated yararulesproject database file: $db_file" yararulesproject_db_update="0" if [ "$wget_bin" != "" ] ; then $wget_bin $wget_proxy_https $wget_proxy_http $wget_insecure $wget_output_level --connect-timeout="$downloader_connect_timeout" --random-wait --tries="$downloader_tries" --timeout="$downloader_max_time" --output-document="$work_dir_yararulesproject/$db_file" "$yararulesproject_url/$yr_dir/$db_file" ret="$?" else $curl_bin $curl_proxy $curl_insecure $curl_output_level --connect-timeout "$downloader_connect_timeout" --remote-time --location --retry "$downloader_tries" --max-time "$downloader_max_time" --output "$work_dir_yararulesproject/$db_file" "$yararulesproject_url/$yr_dir/$db_file" ret="$?" fi if [ "$ret" -eq "0" ] ; then loop="1" if ! cmp -s "$work_dir_yararulesproject/$db_file" "$clam_dbs/$db_file" ; then if [ "$?" -eq "0" ] ; then db_ext=$(echo "$db_file" | cut -d "." -f2) xshok_pretty_echo_and_log "Testing updated yararulesproject database file: $db_file" if [ -z "$ham_dir" ] || [ "$db_ext" != "ndb" ] ; then if $clamscan_bin --quiet -d "$work_dir_yararulesproject/$db_file" "$work_dir_work_configs/scan-test.txt" 2>/dev/null then xshok_pretty_echo_and_log "Clamscan reports yararulesproject $db_file database integrity tested good" true else xshok_pretty_echo_and_log "Clamscan reports yararulesproject $db_file database integrity tested BAD" if [ "$remove_bad_database" == "yes" ] ; then if rm -f "$work_dir_yararulesproject/$db_file" ; then xshok_pretty_echo_and_log "Removed invalid database: $work_dir_yararulesproject/$db_file" fi fi false fi && (test "$keep_db_backup" = "yes" && cp -f "$clam_dbs/$db_file" "$clam_dbs/$db_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "$work_dir_yararulesproject/$db_file" "$clam_dbs" 2>/dev/null ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$db_file" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$db_file" fi xshok_pretty_echo_and_log "Successfully updated yararulesproject production database file: $db_file" yararulesproject_updates=1 yararulesproject_db_update=1 do_clamd_reload=1 else xshok_pretty_echo_and_log "Failed to successfully update yararulesproject production database file: $db_file - SKIPPING" fi else $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$work_dir_yararulesproject/$db_file" > "$test_dir/$db_file" $clamscan_bin --infected --no-summary -d "$test_dir/$db_file" "$ham_dir"/* | command sed 's/\.UNOFFICIAL FOUND//' | awk '{print $NF}' > "$work_dir_work_configs/whitelist.txt" $grep_bin -h -f "$work_dir_work_configs/whitelist.txt" "$test_dir/$db_file" | cut -d "*" -f2 | sort | uniq >> "$work_dir_work_configs/whitelist.hex" $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$test_dir/$db_file" > "$test_dir/$db_file-tmp" mv -f "$test_dir/$db_file-tmp" "$test_dir/$db_file" if $clamscan_bin --quiet -d "$test_dir/$db_file" "$work_dir_work_configs/scan-test.txt" 2>/dev/null ; then xshok_pretty_echo_and_log "Clamscan reports yararulesproject $db_file database integrity tested good" true else xshok_pretty_echo_and_log "Clamscan reports yararulesproject $db_file database integrity tested BAD" if [ "$remove_bad_database" == "yes" ] ; then if rm -f "$work_dir_yararulesproject/$db_file" ; then xshok_pretty_echo_and_log "Removed invalid database: $work_dir_yararulesproject/$db_file" fi fi false fi && (test "$keep_db_backup" = "yes" && cp -f "$clam_dbs/$db_file" "$clam_dbs/$db_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "$test_dir/$db_file" "$clam_dbs" 2>/dev/null ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$db_file" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$db_file" fi xshok_pretty_echo_and_log "Successfully updated yararulesproject production database file: $db_file" yararulesproject_updates=1 yararulesproject_db_update=1 do_clamd_reload=1 else xshok_pretty_echo_and_log "Failed to successfully update yararulesproject production database file: $db_file - SKIPPING" fi fi fi fi else xshok_pretty_echo_and_log "WARNING: Failed connection to $yararulesproject_url - SKIPPED yararulesproject $db_file update" fi if [ "$yararulesproject_db_update" != "1" ] ; then xshok_pretty_echo_and_log "No updated yararulesproject $db_file database file found" fi done if [ "$yararulesproject_updates" != "1" ] ; then xshok_pretty_echo_and_log "No yararulesproject database file updates found" "-" fi else xshok_pretty_echo_and_log "Yara-Rules Database File Updates" "=" time_remaining=$((update_interval - time_interval)) hours_left=$((time_remaining / 3600)) minutes_left=$((time_remaining % 3600 / 60)) xshok_pretty_echo_and_log "$yararulesproject_update_hours hours have not yet elapsed since the last yararulesproject database update check" xshok_pretty_echo_and_log "No update check was performed at this time" "-" xshok_pretty_echo_and_log "Next check will be performed in approximately $hours_left hour(s), $minutes_left minute(s)" fi fi fi else if [ -n "$yararulesproject_dbs" ] ; then if [ "$remove_disabled_databases" == "yes" ] ; then xshok_pretty_echo_and_log "Removing disabled yararulesproject Database files" for db_file in $yararulesproject_dbs ; do if echo "$db_file" | $grep_bin -q "/"; then db_file=$(echo "$db_file" | cut -d"/" -f2) fi if [ -r "$work_dir_yararulesproject/$db_file" ] ; then rm -f "$work_dir_yararulesproject/$db_file" do_clamd_reload=1 fi if [ -r "$clam_dbs/$db_file" ] ; then rm -f "$clam_dbs/$db_file" do_clamd_reload=1 fi done fi fi fi ############################################################################################################################################## # Check for updated additional database files every set number of hours as defined in the "USER CONFIGURATION" section of this script ############################################################################################################################################## if [ "$additional_enabled" == "yes" ] ; then if [ -n "$additional_dbs" ] ; then if [ "$(xshok_array_count "$additional_dbs")" -lt "1" ] ; then xshok_pretty_echo_and_log "Failed additional_dbs config is invalid or not defined - SKIPPING" else rm -f "$work_dir_add/*.gz" if [ -r "$work_dir_work_configs/last-additional-update.txt" ] ; then last_additional_update=$(cat "$work_dir_work_configs/last-additional-update.txt") else last_additional_update="0" fi db_file="" loop="" update_interval=$((additional_update_hours * 3600)) time_interval=$((current_time - last_additional_update)) if [ "$time_interval" -ge $((update_interval - 600)) ] ; then echo "$current_time" > "$work_dir_work_configs/last-additional-update.txt" xshok_pretty_echo_and_log "Additional Database File Updates" "=" xshok_pretty_echo_and_log "Checking for additional updates..." additional_updates="0" for db_url in $additional_dbs ; do # left for future dir manipulation # if echo "$db_file" | $grep_bin -q "/"; then # add_dir="/"$(echo "$db_file" | cut -d"/" -f1) # db_file=$(echo "$db_file" | cut -d"/" -f2) # else # add_dir="" # fi db_file=$(basename "$db_url") if [ "$loop" = "1" ] ; then xshok_pretty_echo_and_log "---" fi xshok_pretty_echo_and_log "Checking for updated additional database file: $db_file" additional_db_update="0" if [ "$(echo "$db_url" | cut -d ":" -f1)" = "rsync" ] ; then $rsync_bin $rsync_output_level $no_motd -ctuz $connect_timeout --timeout="$rsync_max_time" --exclude=*.txt --exclude=*.sha256 --exclude=*.sig --exclude=*.gz "$db_url" "$work_dir_add" 2>/dev/null ret="$?" else if [ "$wget_bin" != "" ] ; then $wget_bin $wget_proxy_https $wget_proxy_http $wget_insecure $wget_output_level --connect-timeout="$downloader_connect_timeout" --random-wait --tries="$downloader_tries" --timeout="$downloader_max_time" --output-document="$work_dir_add/$db_file" "$db_url" ret="$?" else $curl_bin $curl_proxy $curl_insecure $curl_output_level --connect-timeout "$downloader_connect_timeout" --remote-time --location --retry "$downloader_tries" --max-time "$downloader_max_time" --output "$work_dir_add/$db_file" "$db_url" ret="$?" fi fi ##this needs enhancement for rsync, as it will only work with single files... maybe better to process each file inside work_dir_add in its own for loop. if [ "$ret" -eq "0" ] ; then loop="1" if ! cmp -s "$work_dir_add/$db_file" "$clam_dbs/$db_file" ; then if [ "$?" -eq "0" ] ; then db_ext=$(echo "$db_file" | cut -d "." -f2) xshok_pretty_echo_and_log "Testing updated additional database file: $db_file" if [ -z "$ham_dir" ] || [ "$db_ext" != "ndb" ] ; then if $clamscan_bin --quiet -d "$work_dir_add/$db_file" "$work_dir_work_configs/scan-test.txt" 2>/dev/null then xshok_pretty_echo_and_log "Clamscan reports additional $db_file database integrity tested good" true else xshok_pretty_echo_and_log "Clamscan reports additional $db_file database integrity tested BAD" if [ "$remove_bad_database" == "yes" ] ; then if rm -f "$work_dir_add/$db_file" ; then xshok_pretty_echo_and_log "Removed invalid database: $work_dir_add/$db_file" fi fi false fi && (test "$keep_db_backup" = "yes" && cp -f "$clam_dbs/$db_file" "$clam_dbs/$db_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "$work_dir_add/$db_file" "$clam_dbs" 2>/dev/null ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$db_file" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$db_file" fi xshok_pretty_echo_and_log "Successfully updated additional production database file: $db_file" additional_updates=1 additional_db_update=1 do_clamd_reload=1 else xshok_pretty_echo_and_log "Failed to successfully update additional production database file: $db_file - SKIPPING" fi else $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$work_dir_add/$db_file" > "$test_dir/$db_file" $clamscan_bin --infected --no-summary -d "$test_dir/$db_file" "$ham_dir"/* | command sed 's/\.UNOFFICIAL FOUND//' | awk '{print $NF}' > "$work_dir_work_configs/whitelist.txt" $grep_bin -h -f "$work_dir_work_configs/whitelist.txt" "$test_dir/$db_file" | cut -d "*" -f2 | sort | uniq >> "$work_dir_work_configs/whitelist.hex" $grep_bin -h -v -f "$work_dir_work_configs/whitelist.hex" "$test_dir/$db_file" > "$test_dir/$db_file-tmp" mv -f "$test_dir/$db_file-tmp" "$test_dir/$db_file" if $clamscan_bin --quiet -d "$test_dir/$db_file" "$work_dir_work_configs/scan-test.txt" 2>/dev/null ; then xshok_pretty_echo_and_log "Clamscan reports additional $db_file database integrity tested good" true else xshok_pretty_echo_and_log "Clamscan reports additional $db_file database integrity tested BAD" if [ "$remove_bad_database" == "yes" ] ; then if rm -f "$work_dir_add/$db_file" ; then xshok_pretty_echo_and_log "Removed invalid database: $work_dir_add/$db_file" fi fi false fi && (test "$keep_db_backup" = "yes" && cp -f "$clam_dbs/$db_file" "$clam_dbs/$db_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "$test_dir/$db_file" "$clam_dbs" 2>/dev/null ; then perms chown -f "$clam_user:$clam_group" "$clam_dbs/$db_file" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/$db_file" fi xshok_pretty_echo_and_log "Successfully updated additional production database file: $db_file" additional_updates=1 additional_db_update=1 do_clamd_reload=1 else xshok_pretty_echo_and_log "Failed to successfully update additional production database file: $db_file - SKIPPING" fi fi fi fi else xshok_pretty_echo_and_log "WARNING: Failed connection to $additional_url - SKIPPED additional $db_file update" fi if [ "$additional_db_update" != "1" ] ; then xshok_pretty_echo_and_log "No updated additional $db_file database file found" fi done if [ "$additional_updates" != "1" ] ; then xshok_pretty_echo_and_log "No additional database file updates found" "-" fi else xshok_pretty_echo_and_log "Additional Database File Updates" "=" time_remaining=$((update_interval - time_interval)) hours_left=$((time_remaining / 3600)) minutes_left=$((time_remaining % 3600 / 60)) xshok_pretty_echo_and_log "$additional_update_hours hours have not yet elapsed since the last additional database update check" xshok_pretty_echo_and_log "No update check was performed at this time" "-" xshok_pretty_echo_and_log "Next check will be performed in approximately $hours_left hour(s), $minutes_left minute(s)" fi fi fi else if [ -n "$additional_dbs" ] ; then if [ "$remove_disabled_databases" == "yes" ] ; then xshok_pretty_echo_and_log "Removing disabled additional Database files" for db_file in $additional_dbs ; do if echo "$db_file" | $grep_bin -q "/"; then db_file=$(echo "$db_file" | cut -d"/" -f2) fi if [ -r "$work_dir_add/$db_file" ] ; then rm -f "$work_dir_add/$db_file" do_clamd_reload=1 fi if [ -r "$clam_dbs/$db_file" ] ; then rm -f "$clam_dbs/$db_file" do_clamd_reload=1 fi done fi fi fi ################################################### # Generate whitelists ################################################### # Check to see if the local.ign file exists, and if it does, check to see if any of the script # added bypass entries can be removed due to offending signature modifications or removals. if [ -r "$clam_dbs/local.ign" ] && [ -s "$work_dir_work_configs/monitor-ign.txt" ] ; then ign_updated=0 cd "$clam_dbs" || exit cp -f local.ign "$work_dir_work_configs/local.ign" cp -f "$work_dir_work_configs/monitor-ign.txt" "$work_dir_work_configs/monitor-ign-old.txt" xshok_pretty_echo_and_log "" "=" "80" while read -r entry ; do sig_file=$(echo "$entry" | tr -d "\r" | awk -F ":" '{print $1}') sig_hex=$(echo "$entry" | tr -d "\r" | awk -F ":" '{print $NF}') sig_name_old=$(echo "$entry" | tr -d "\r" | awk -F ":" '{print $3}') sig_ign_old=$($grep_bin ":$sig_name_old" "$work_dir_work_configs/local.ign") sig_old=$(echo "$entry" | tr -d "\r" | cut -d ":" -f3-) sig_new=$($grep_bin -hwF ":$sig_hex" "$sig_file" | tr -d "\r" 2>/dev/null) sig_mon_new=$($grep_bin -HwF -n ":$sig_hex" "$sig_file" | tr -d "\r") if [ -n "$sig_new" ] ; then if [ "$sig_old" != "$sig_new" ] || [ "$entry" != "$sig_mon_new" ] ; then sig_name_new=$(echo "$sig_new" | tr -d "\r" | awk -F ":" '{print $1}') sig_ign_new=$(echo "$sig_mon_new" | cut -d ":" -f1-3) perl -i -ne "print unless /$sig_ign_old/" "$work_dir_work_configs/monitor-ign.txt" echo "$sig_mon_new" >> "$work_dir_work_configs/monitor-ign.txt" perl -p -i -e "s/$sig_ign_old/$sig_ign_new/" "$work_dir_work_configs/local.ign" xshok_pretty_echo_and_log "$sig_name_old hexadecimal signature is unchanged, however signature name and/or line placement" xshok_pretty_echo_and_log "in $sig_file has changed to $sig_name_new - updated local.ign to reflect this change." ign_updated=1 fi else perl -i -ne "print unless /$sig_ign_old/" "$work_dir_work_configs/monitor-ign.txt" "$work_dir_work_configs/local.ign" xshok_pretty_echo_and_log "$sig_name_old signature has been removed from $sig_file, entry removed from local.ign." ign_updated=1 fi done < "$work_dir_work_configs/monitor-ign-old.txt" if [ "$ign_updated" = "1" ] ; then if $clamscan_bin --quiet -d "$work_dir_work_configs/local.ign" "$work_dir_work_configs/scan-test.txt" then if $rsync_bin -pcqt "$work_dir_work_configs/local.ign" "$clam_dbs" then perms chown -f "$clam_user:$clam_group" "$clam_dbs/local.ign" perms chmod -f 0644 "$clam_dbs/local.ign" "$work_dir_work_configs/monitor-ign.txt" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/local.ign" fi do_clamd_reload=3 else xshok_pretty_echo_and_log "Failed to successfully update local.ign file - SKIPPING" fi else xshok_pretty_echo_and_log "Clamscan reports local.ign database integrity is bad - SKIPPING" fi else xshok_pretty_echo_and_log "No whitelist signature changes found in local.ign" "=" fi fi # Check to see if my-whitelist.ign2 file exists, and if it does, check to see if any of the script # added whitelist entries can be removed due to offending signature modifications or removals. if [ -r "$clam_dbs/my-whitelist.ign2" ] && [ -s "$work_dir_work_configs/tracker.txt" ] ; then ign2_updated=0 cd "$clam_dbs" || exit cp -f my-whitelist.ign2 "$work_dir_work_configs/my-whitelist.ign2" xshok_pretty_echo_and_log "" "=" "80" while read -r entry ; do sig_file=$(echo "$entry" | cut -d ":" -f1) sig_full=$(echo "$entry" | cut -d ":" -f2-) sig_name=$(echo "$entry" | cut -d ":" -f2) if ! $grep_bin -F "$sig_full" "$sig_file" > /dev/null 2>&1 ; then perl -i -ne "print unless /$sig_name$/" "$work_dir_work_configs/my-whitelist.ign2" perl -i -ne "print unless /:$sig_name:/" "$work_dir_work_configs/tracker-tmp.txt" xshok_pretty_echo_and_log "$sig_name signature no longer exists in $sig_file, whitelist entry removed from my-whitelist.ign2" ign2_updated=1 fi done < "$work_dir_work_configs/tracker.txt" mv -f "$work_dir_work_configs/tracker-tmp.txt" "$work_dir_work_configs/tracker.txt" xshok_pretty_echo_and_log "" "=" "80" if [ "$ign2_updated" = "1" ] then if $clamscan_bin --quiet -d "$work_dir_work_configs/my-whitelist.ign2" "$work_dir_work_configs/scan-test.txt" then if $rsync_bin -pcqt "$work_dir_work_configs/my-whitelist.ign2" "$clam_dbs" then perms chown -f "$clam_user:$clam_group" "$clam_dbs/my-whitelist.ign2" perms chmod -f 0644 "$clam_dbs/my-whitelist.ign2" "$work_dir_work_configs/tracker.txt" if [ "$selinux_fixes" == "yes" ] ; then restorecon "$clam_dbs/my-whitelist.ign2" restorecon "$work_dir_work_configs/tracker.txt" fi do_clamd_reload=4 else xshok_pretty_echo_and_log "Failed to successfully update my-whitelist.ign2 file - SKIPPING" fi else xshok_pretty_echo_and_log "Clamscan reports my-whitelist.ign2 database integrity is bad - SKIPPING" fi else xshok_pretty_echo_and_log "No whitelist signature changes found in my-whitelist.ign2" fi fi # Check for non-matching whitelist.hex signatures and remove them from the whitelist file (signature modified or removed). if [ -n "$ham_dir" ] ; then if [ -r "$work_dir_work_configs/whitelist.hex" ] ; then $grep_bin -h -f "$work_dir_work_configs/whitelist.hex" "$work_dir"/*/*.ndb | cut -d "*" -f2 | tr -d "\r" | sort | uniq > "$work_dir_work_configs/whitelist.tmp" mv -f "$work_dir_work_configs/whitelist.tmp" "$work_dir_work_configs/whitelist.hex" rm -f "$work_dir_work_configs/whitelist.txt" rm -f "$test_dir"/*.* xshok_pretty_echo_and_log "WARNING: Signature(s) triggered on HAM directory scan - signature(s) removed" "*" else xshok_pretty_echo_and_log "No signatures triggered on HAM directory scan" "=" fi fi # Set appropriate directory and file permissions to all production signature files # and set file access mode to 0644 on all working directory files. if [ "$setmode" = "yes" ] ; then xshok_pretty_echo_and_log "Setting permissions and ownership" "=" perms chown -f -R "$clam_user:$clam_group" "$work_dir" if ! find "$work_dir" -type f -exec chmod -f 0644 {} + 2>/dev/null ; then if ! find "$work_dir" -type f -print0 | xargs -0 chmod -f 0644 2>/dev/null ; then if ! find "$work_dir" -type f -print0 | xargs chmod -f 0644 2>/dev/null ; then find "$work_dir" -type f -exec chmod -f 0644 {} \; fi fi fi # If enabled, set file access mode for all production signature database files to 0644. perms chown -f -R "$clam_user:$clam_group" "$clam_dbs" if ! find "$clam_dbs" -type f -exec chmod -f 0644 {} + 2>/dev/null ; then if ! find "$clam_dbs" -type f -print0 | xargs -0 chmod -f 0644 2>/dev/null ; then if ! find "$clam_dbs" -type f -print0 | xargs chmod -f 0644 2>/dev/null ; then find "$clam_dbs" -type f -exec chmod -f 0644 {} \; fi fi fi fi # Reload all clamd databases clamscan_reload_dbs xshok_pretty_echo_and_log "Issue tracker : https://github.com/extremeshok/clamav-unofficial-sigs/issues" "-" check_new_version xshok_cleanup # And lastly we exit, Note: the exit is always on the 2nd last line exit $?