2 # shellcheck disable=SC2119
3 # shellcheck disable=SC2120
4 # shellcheck disable=SC2128
5 # shellcheck disable=SC2154
6 ################################################################################
7 # This is property of eXtremeSHOK.com
8 # You are free to use, modify and distribute, however you may not remove this notice.
9 # Copyright (c) Adrian Jon Kriel :: admin@extremeshok.com
10 # License: BSD (Berkeley Software Distribution)
11 ################################################################################
13 # Script updates can be found at: https://github.com/extremeshok/clamav-unofficial-sigs
15 # Originially based on Script provided by Bill Landry (unofficialsigs@gmail.com).
17 ################################################################################
19 # THERE ARE NO USER CONFIGURABLE OPTIONS IN THIS SCRIPT
20 # ALL CONFIGURATION OPTIONS ARE LOCATED IN THE INCLUDED CONFIGURATION FILE
22 ################################################################################
24 ###### ####### # # ####### ####### ####### ###### ### #######
25 # # # # ## # # # # # # # # #
26 # # # # # # # # # # # # # # #
27 # # # # # # # # # # ##### # # # #
28 # # # # # # # # # # # # # # #
29 # # # # # ## # # # # # # # #
30 ###### ####### # # ####### # ####### ###### ### #
32 ################################################################################
34 # Detect to make sure the entire script is avilable, fail if the script is missing contents
35 if [ "$(tail -n 1 "${0}" | head -n 1 | cut -c 1-7)" != "exit \$?" ] ; then
36 echo "FATAL ERROR: Script is incomplete, please redownload"
40 # Trap the keyboard interrupt (Ctrl + C)
41 trap xshok_control_c SIGINT
42 ################################################################################
44 ################################################################################
46 # Support user config settings for applying file and directory access permissions.
48 if [ -n "${clam_user}" ] && [ -n "${clam_group}" ] ; then
53 # Prompt a user if they should complete an action with Y or N
54 # Usage: xshok_prompt_confirm
55 # if xshok_prompt_confirm ; then
56 # xshok_prompt_confirm && echo "accepted"
57 # xshok_prompt_confirm && echo "yes" || echo "no"
58 # shellcheck disable=SC2120
59 function xshok_prompt_confirm() { # optional_message
60 message="${1:-Are you sure?}"
62 read -r -p "${message} [y/N]" response < /dev/tty
66 *) printf " \\033[31m %s \\n\\033[0m" "invalid input"
72 function xshok_create_pid_file() { # pid.file
75 if ! echo $$ > "${pidfile}" ; then
76 xshok_pretty_echo_and_log "ERROR: Could not create PID file: ${pidfile}"
80 xshok_pretty_echo_and_log "ERROR: Missing value for option"
85 # Intercept ctrl+c and calls the cleanup function
86 function xshok_control_c() {
88 xshok_pretty_echo_and_log "---------------| Exiting ... Please wait |---------------" "-"
94 function xshok_cleanup() {
95 # Wait for all processes to end
97 xshok_pretty_echo_and_log " Powered By https://eXtremeSHOK.com " "#"
101 # Check if the current running user is the root user, otherwise return false
102 function xshok_is_root() {
103 if [ "$(uname -s)" == "SunOS" ] ; then
104 id_bin="/usr/xpg4/bin/id"
106 id_bin="$(command -v id 2> /dev/null)"
108 if [ "$($id_bin -u)" == 0 ] ; then
115 # Check if its a file, otherwise return false
116 function xshok_is_file() { # filepath
118 if [ -f "${filepath}" ] ; then
121 return 1 ; # Not a file
125 # Check if filepath is a subdir, otherwise return false
126 # Usage: xshok_is_subdir "filepath"
127 # xshok_is_subdir "/root/" - false
128 # xshok_is_subdir "/usr/local/etc" && echo "yes" - yes
129 function xshok_is_subdir() { # filepath
130 shopt -s extglob; filepath="${filepath%%+(/)}"
131 if [ -d "$filepath" ] ; then
132 res="${filepath//[^\/]}"
133 if [ "${#res}" -gt 1 ] ; then
136 return 1 ; # Not a subdir
139 return 1 ; # Not a dir
143 # Create a dir and set the ownership
144 function xshok_mkdir_ownership() { # path
146 if ! mkdir -p "${1}" 2>/dev/null ; then
147 xshok_pretty_echo_and_log "ERROR: Could not create directory: ${1}"
150 perms chown -f "${clam_user}:${clam_group}" "${1}" > /dev/null 2>&1
152 xshok_pretty_echo_and_log "ERROR: Missing value for option"
157 # Check if a user and group exists on the system otherwise return false
159 # xshok_is_subdir "username" && echo "user found" || echo "no"
160 # xshok_is_subdir "username" "groupname" && echo "user and group found" || echo "no"
161 function xshok_user_group_exists() { # username groupname
162 if [ "$(uname -s)" == "SunOS" ] ; then
163 id_bin="/usr/xpg4/bin/id"
165 id_bin="$(command -v id 2> /dev/null)"
169 if [ "$(uname -s)" == "Darwin" ] ; then
170 #use ruby, as this is the best way. Ruby is always avilable as brew uses ruby
171 ruby -e 'require "etc"; puts Etc::getgrnam("_clamav").gid' > /dev/null 2>&1
174 getent_bin="$(command -v getent 2> /dev/null)"
175 $getent_bin group "${2}" >/dev/null 2>&1
181 if $id_bin -u "${1}" > /dev/null 2>&1 ; then
183 if [ "$ret" -eq 0 ] ; then
184 return 0 ; # User and group exists
186 return 1 ; # Group does NOT exist
189 return 0 ; # User exists
192 return 1 ; # User does NOT exist
195 xshok_pretty_echo_and_log "ERROR: Missing value for option"
200 # Handle comments with/out borders and logging.
202 # pretty_echo_and_log "one"
204 # pretty_echo_and_log "two" "-"
208 # pretty_echo_and_log "three" "=" "8"
212 # pretty_echo_and_log "" "/\" "7"
214 # type: e = error, w= warning, a = alert, n = notice
215 # will auto detect using the first word "error,warning,alert,notice"
216 # type e will make a == border
217 # type w will make a -- border
218 # type a will make a ** border
219 # type n will make a ++ border
220 function xshok_pretty_echo_and_log() { # "string" "repeating" "count" "type"
221 #detect if running under cron and silence
226 if [ "$comment_silence" != "yes" ] && [ "$force_verbose" != "yes" ]; then
228 comment_silence="yes"
231 # always show errors and alerts
232 if [ -z "$mytype" ] ; then
234 if [[ "$mystring" =~ "ERROR:" ]] || [[ "$mystring" =~ "ERROR " ]] ; then
236 elif [[ "$mystring" =~ "WARNING:" ]] || [[ "$mystring" =~ "WARNING " ]] ; then
238 elif [[ "$mystring" =~ "ALERT:" ]] || [[ "$mystring" =~ "ALERT " ]] ; then
240 elif [[ "$mystring" =~ "NOTICE:" ]] || [[ "$mystring" =~ "NOTICE " ]] ; then
244 if [ "$mytype" == "e" ] || [ "$mytype" == "a" ] ; then
247 # Handle comments is not silenced or type
248 if [ "$comment_silence" != "yes" ] ; then
249 if [ -z "$myrepeating" ] ; then
250 if [ "$mytype" == "e" ] ; then
252 elif [ "$mytype" == "w" ] ; then
254 elif [ "$mytype" == "a" ] ; then
256 elif [ "$mytype" == "n" ] ; then
260 if [ -z "$myrepeating" ] ; then
264 if [ -z "$mycount" ] ; then
265 mycount="${#mystring}"
267 for (( n = 0; n < mycount; n++ )) ; do
268 myvar="${myvar}${myrepeating}"
270 if [ -n "${mystring}" ] ; then
271 echo -e "${myvar}\\n${1}\\n${myvar}"
278 if [ "$enable_log" == "yes" ] ; then
282 mystring=${mystring//---}
284 if [ ! -z "$mystring" ] ; then
285 if [ ! -z "$log_pipe_cmd" ] ; then
286 echo "${mystring}" | $log_pipe_cmd
288 if [ ! -e "${log_file_path}/${log_file_name}" ] ; then
289 # xshok_mkdir_ownership "$log_file_path"
290 mkdir -p "$log_file_path"
291 touch "${log_file_path}/${log_file_name}" 2>/dev/null
292 perms chown -f "${clam_user}:${clam_group}" "${log_file_path}/${log_file_name}"
294 if [ ! -w "${log_file_path}/${log_file_name}" ] ; then
295 echo "WARNING: Logging Disabled, as file not writable: ${log_file_path}/${log_file_name}"
298 echo "$(date "+%b %d %T")" "${mystring}" >> "${log_file_path}/${log_file_name}"
305 # Check if the $2 value is not null and does not start with -
306 function xshok_check_s2() { # value1 value2
308 if [[ "${1}" =~ ^-.* ]] ; then
309 xshok_pretty_echo_and_log "ERROR: Missing value for option or value begins with -"
313 xshok_pretty_echo_and_log "ERROR: Missing value for option"
318 # Time remaining information function
319 function xshok_draw_time_remaining() { #time_remaining #update_hours #name
320 if [ "${1}" ] && [ "${2}" ] ; then
321 time_remaining="${1}"
322 hours_left="$((time_remaining / 3600))"
323 minutes_left="$((time_remaining % 3600 / 60))"
324 xshok_pretty_echo_and_log "${2} hours have not yet elapsed since the last ${3} update check"
325 xshok_pretty_echo_and_log "No update check was performed at this time" "-"
326 xshok_pretty_echo_and_log "Next check will be performed in approximately ${hours_left} hour(s), ${minutes_left} minute(s)"
331 function xshok_file_download() { #outputfile #url #notimestamp
332 if [ "$downloader_debug" == "yes" ] ; then
333 xshok_pretty_echo_and_log "url: ${2} >> outputfile: ${1} | ${3}"
335 if [ "${1}" ] && [ "${2}" ] ; then
336 if [ -n "$curl_bin" ] ; then
337 if [ -f "${1}" ] ; then
338 # shellcheck disable=SC2086
339 $curl_bin --fail --compressed $curl_proxy $curl_insecure $curl_output_level --connect-timeout "${downloader_connect_timeout}" --remote-time --location --retry "${downloader_tries}" --max-time "${downloader_max_time}" --time-cond "${1}" --output "${1}" "${2}" 2>&11
342 # shellcheck disable=SC2086
343 $curl_bin --fail --compressed $curl_proxy $curl_insecure $curl_output_level --connect-timeout "${downloader_connect_timeout}" --remote-time --location --retry "${downloader_tries}" --max-time "${downloader_max_time}" --output "${1}" "${2}" 2>&11
347 if [ ! "${3}" ] ; then
348 # the following is required because wget, cannot do --timestamping and --output-document together
352 output_dir="${output_file%/*}"
353 output_file="${output_file##*/}"
354 url_file="${url##*/}"
357 cd "${output_dir}" || exit
358 if [ "$output_file" != "$url_file" ] ; then
359 if [ ! -f "$url_file" ] ; then
360 if [ ! -f "$output_file" ] ; then
363 ln -s "$output_file" "$url_file"
364 wget_output_link="$url_file"
367 # shellcheck disable=SC2086
368 $wget_bin $wget_compression $wget_proxy $wget_insecure $wget_output_level --connect-timeout="${downloader_connect_timeout}" --random-wait --tries="${downloader_tries}" --timeout="${downloader_max_time}" --timestamping "${2}" 2>&12
370 if [ ! -n "$wget_output_link" ] ; then
371 if [ -L "$wget_output_link" ] ; then
372 rm -f "$wget_output_link"
375 cd "$this_dir" || exit
377 # shellcheck disable=SC2086
378 $wget_bin $wget_compression $wget_proxy $wget_insecure $wget_output_level --connect-timeout="${downloader_connect_timeout}" --random-wait --tries="${downloader_tries}" --timeout="${downloader_max_time}" --output-document="${1}" "${2}" 2>&12
386 # Handle list of database files
387 function clamav_files() {
388 echo "${clam_dbs}/${db}" >> "${current_tmp}"
389 if [ "$keep_db_backup" == "yes" ] ; then
390 echo "${clam_dbs}/${db}-bak" >> "${current_tmp}"
394 # Manage the databases and allow multi-dimensions as well as global overrides
395 # Since the datbases are basically a multi-dimentional associative arrays in bash
396 # ratings: LOW | MEDIUM | HIGH | REQUIRED | LOWONLY | MEDIUMONLY | LOWMEDIUMONLY | MEDIUMHIGHONLY | HIGHONLY | DISABLED
397 function xshok_database() { # rating database_array
399 current_rating="${1}"
400 declare -a current_dbs=( "${@:2}" )
402 declare -a new_dbs=( )
403 if [ -n "${current_dbs[0]}" ] ; then
404 if [ ${#current_dbs} -ge 1 ] ; then
405 for db_name in "${current_dbs[@]}" ; do
407 if [ "$enable_yararules" == "no" ] ; then # YARA rules are disabled
408 if [[ "$db_name" == *".yar"* ]] ; then # If it's the value you want to delete
409 continue # Skip to the next value
412 if [ -z "$current_rating" ] ; then # YARA rules are disabled
413 new_dbs+=( "$db_name" )
415 if [[ ! "$db_name" = *"|"* ]] ; then # This old format
416 new_dbs+=( "$db_name" )
418 db_name_rating="${db_name#*|}"
419 db_name="${db_name%|*}"
421 if [ "$db_name_rating" != "DISABLED" ] ; then
422 if [ "$db_name_rating" == "$current_rating" ] ; then
423 new_dbs+=( "$db_name" )
424 elif [ "$db_name_rating" == "REQUIRED" ] ; then
425 new_dbs+=( "$db_name" )
426 elif [ "$current_rating" == "LOW" ] ; then
427 if [ "$db_name_rating" == "LOWONLY" ] || [ "$db_name_rating" == "LOW" ] || [ "$db_name_rating" == "LOWMEDIUMONLY" ] ; then
428 new_dbs+=( "$db_name" )
430 elif [ "$current_rating" == "MEDIUM" ] ; then
431 if [ "$db_name_rating" == "MEDIUMONLY" ] || [ "$db_name_rating" == "MEDIUM" ] || [ "$db_name_rating" == "LOW" ] || [ "$db_name_rating" == "LOWMEDIUMONLY" ] || [ "$db_name_rating" == "MEDIUMHIGHONLY" ] ; then
432 new_dbs+=( "$db_name" )
434 elif [ "$current_rating" == "HIGH" ] ; then
435 if [ "$db_name_rating" == "HIGHONLY" ] || [ "$db_name_rating" == "HIGH" ] || [ "$db_name_rating" == "MEDIUM" ] || [ "$db_name_rating" == "LOW" ] || [ "$db_name_rating" == "MEDIUMHIGHONLY" ] ; then
436 new_dbs+=( "$db_name" )
438 elif [ "$current_rating" == "LOWONLY" ] ; then
439 if [ "$db_name_rating" == "LOWONLY" ] || [ "$db_name_rating" == "LOW" ] ; then
440 new_dbs+=( "$db_name" )
442 elif [ "$current_rating" == "MEDIUMONLY" ] ; then
443 if [ "$db_name_rating" == "MEDIUMONLY" ] || [ "$db_name_rating" == "MEDIUM" ] ; then
444 new_dbs+=( "$db_name" )
446 elif [ "$current_rating" == "LOWMEDIUMONLY" ] ; then
447 if [ "$db_name_rating" == "LOWMEDIUMONLY" ] || [ "$db_name_rating" == "LOW" ] || [ "$db_name_rating" == "MEDIUM" ] ; then
448 new_dbs+=( "$db_name" )
450 elif [ "$current_rating" == "MEDIUMHIGHONLY" ] ; then
451 if [ "$db_name_rating" == "MEDIUMHIGHONLY" ] || [ "$db_name_rating" == "MEDIUM" ] || [ "$db_name_rating" == "HIGH" ] ; then
452 new_dbs+=( "$db_name" )
454 elif [ "$current_rating" == "HIGHONLY" ] ; then
455 if [ "$db_name_rating" == "HIGHONLY" ] || [ "$db_name_rating" == "HIGH" ] ; then
456 new_dbs+=( "$db_name" )
465 echo "${new_dbs[@]}" | xargs # Remove extra whitespace
468 ################################################################################
469 # ADDITIONAL PROGRAM FUNCTIONS
470 ################################################################################
473 # Generates a man config and installs it
474 function install_man() {
476 if [ -n "$pkg_mgr" ] || [ -n "$pkg_rm" ] ; then
477 xshok_pretty_echo_and_log "This script (clamav-unofficial-sigs) was installed on the system via ${pkg_mgr}"
481 xshok_pretty_echo_and_log ""
482 xshok_pretty_echo_and_log "Generating man file for install...."
484 # Use defined varibles or attempt to use default varibles
486 if [ ! -e "${man_dir}/${man_filename}" ] ; then
488 touch "${man_dir}/${man_filename}" 2>/dev/null
490 if [ ! -w "${man_dir}/${man_filename}" ] ; then
491 xshok_pretty_echo_and_log "ERROR: man install aborted, as file not writable: ${man_dir}/${man_filename}"
497 manresult="$(help_and_usage "man")"
500 cat << EOF > "${man_dir}/${man_filename}"
502 .\\" Manual page for eXtremeSHOK.com ClamAV Unofficial Signature Updater
503 .TH clamav-unofficial-sigs 8 "${script_version_date}" "Version: ${script_version}" "SCRIPT COMMANDS"
505 clamav-unofficial-sigs \\- Download, test, and install third-party ClamAV signature databases.
507 .B clamav-unofficial-sigs
510 \\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.
512 Script updates can be found at: \\fBhttps://github.com/extremeshok/clamav-unofficial-sigs\\fP
514 This script follows the standard GNU command line syntax.
521 Copyright (c) Adrian Jon Kriel :: admin@extremeshok.com
523 You are free to use, modify and distribute, however you may not remove this notice.
525 BSD (Berkeley Software Distribution)
527 Report bugs to \\fBhttps://github.com/extremeshok/clamav-unofficial-sigs\\fP
529 Adrian Jon Kriel :: admin@extremeshok.com
530 Originially based on Script provide by Bill Landry
536 xshok_pretty_echo_and_log "Completed: man installed, as file: ${man_dir}/${man_filename}"
540 # Generate a logrotate config and install it
541 function install_logrotate() {
543 if [ -n "$pkg_mgr" ] || [ -n "$pkg_rm" ] ; then
544 xshok_pretty_echo_and_log "This script (clamav-unofficial-sigs) was installed on the system via ${pkg_mgr}"
548 xshok_pretty_echo_and_log ""
549 xshok_pretty_echo_and_log "Generating logrotate file for install...."
551 # Use defined varibles or attempt to use default varibles
553 if [ -z "$logrotate_user" ] ; then
554 logrotate_user="${clam_user}";
556 if [ -z "$logrotate_group" ] ; then
557 logrotate_group="${clam_group}";
559 if [ -z "$logrotate_log_file_full_path" ] ; then
560 logrotate_log_file_full_path="${log_file_path}/${log_file_name}"
564 if [ ! -e "${logrotate_dir}/${logrotate_filename}" ] ; then
565 mkdir -p "$logrotate_dir"
566 touch "${logrotate_dir}/${logrotate_filename}" 2>/dev/null
568 if [ ! -w "${logrotate_dir}/${logrotate_filename}" ] ; then
569 xshok_pretty_echo_and_log "ERROR: logrotate install aborted, as file not writable: ${logrotate_dir}/${logrotate_filename}"
572 cat << EOF > "${logrotate_dir}/${logrotate_filename}"
573 # https://eXtremeSHOK.com ######################################################
574 # This file contains the logrotate settings for clamav-unofficial-sigs.sh
576 # This is property of eXtremeSHOK.com
577 # You are free to use, modify and distribute, however you may not remove this notice.
578 # Copyright (c) Adrian Jon Kriel :: admin@extremeshok.com
581 # Script updates can be found at: https://github.com/extremeshok/clamav-unofficial-sigs
583 # Originially based on:
584 # Script provide by Bill Landry (unofficialsigs@gmail.com).
586 # License: BSD (Berkeley Software Distribution)
589 # Automatically Generated: $(date)
592 # This logrotate file will rotate the logs generated by the clamav-unofficial-sigs.sh
594 # To Adjust the logrotate values, edit your configs and run
595 # bash clamav-unofficial-sigs.sh --install-logrotate to generate a new file.
597 $logrotate_log_file_full_path {
603 create 0640 ${logrotate_user} ${logrotate_group}
609 xshok_pretty_echo_and_log "Completed: logrotate installed, as file: ${logrotate_dir}/${logrotate_filename}"
612 # Generate a cron config and install it
613 function install_cron() {
615 if [ -n "$pkg_mgr" ] || [ -n "$pkg_rm" ] ; then
616 xshok_pretty_echo_and_log "This script (clamav-unofficial-sigs) was installed on the system via {$pkg_mgr}"
620 xshok_pretty_echo_and_log ""
621 xshok_pretty_echo_and_log "Generating cron file for install...."
623 # Use defined varibles or attempt to use default varibles
624 if [ -z "$cron_minute" ] ; then
625 cron_minute="$(( ( RANDOM % 59 ) + 1 ))"
627 if [ -z "$cron_user" ] ; then
628 cron_user="${clam_user}";
630 if [ -z "$cron_bash" ] ; then
631 cron_bash="$(command -v bash 2> /dev/null)"
633 if [ -z "$cron_script_full_path" ] ; then
634 cron_script_full_path="$this_script_full_path"
636 if [ "$cron_sudo" == "yes" ] ; then
639 if [ ! -e "${cron_dir}/${cron_filename}" ] ; then
641 touch "${cron_dir}/${cron_filename}" 2>/dev/null
643 if [ ! -w "${cron_dir}/${cron_filename}" ] ; then
644 xshok_pretty_echo_and_log "ERROR: cron install aborted, as file not writable: ${cron_dir}/${cron_filename}"
647 cat << EOF > "${cron_dir}/${cron_filename}"
648 # https://eXtremeSHOK.com ######################################################
649 # This file contains the cron settings for clamav-unofficial-sigs.sh
651 # This is property of eXtremeSHOK.com
652 # You are free to use, modify and distribute, however you may not remove this notice.
653 # Copyright (c) Adrian Jon Kriel :: admin@extremeshok.com
656 # Script updates can be found at: https://github.com/extremeshok/clamav-unofficial-sigs
658 # Originially based on:
659 # Script provide by Bill Landry (unofficialsigs@gmail.com).
661 # License: BSD (Berkeley Software Distribution)
664 # Automatically Generated: $(date)
667 # This cron file will execute the clamav-unofficial-sigs.sh script that
668 # currently supports updating third-party signature databases provided
669 # by Sanesecurity, SecuriteInfo, MalwarePatrol, OITC, etc.
671 # The script is set to run hourly, at a random minute past the hour, and the
672 # script itself is set to randomize the actual execution time between
673 # 60 - 600 seconds. To Adjust the cron values, edit your configs and run
674 # bash clamav-unofficial-sigs.sh --install-cron to generate a new file.
676 $cron_minute * * * * ${cron_sudo} ${cron_user} [ -x ${cron_script_full_path} ] && ${cron_bash} ${cron_script_full_path}
678 # https://eXtremeSHOK.com ######################################################
683 xshok_pretty_echo_and_log "Completed: cron installed, as file: ${cron_dir}/${cron_filename}"
686 # Auto upgrade the master.conf and the
687 function xshok_upgrade() {
689 if [ "$allow_upgrades" == "no" ] ; then
690 xshok_pretty_echo_and_log "ERROR: --upgrade has been disabled, allow_upgrades=no"
693 if ! xshok_is_root ; then
694 xshok_pretty_echo_and_log "ERROR: Only root can run the upgrade"
698 xshok_pretty_echo_and_log "Checking for updates ..."
701 if [ -n "$curl_bin" ] ; then
702 # shellcheck disable=SC2086
703 latest_version="$($curl_bin --compressed $curl_proxy $curl_insecure $curl_output_level --connect-timeout "${downloader_connect_timeout}" --remote-time --location --retry "${downloader_tries}" --max-time "${downloader_max_time}" "https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/clamav-unofficial-sigs.sh" 2>&11 | $grep_bin "^script_version=" | head -n1 | cut -d '"' -f 2)"
704 # shellcheck disable=SC2086
705 latest_config_version="$($curl_bin --compressed $curl_proxy $curl_insecure $curl_output_level --connect-timeout "${downloader_connect_timeout}" --remote-time --location --retry "${downloader_tries}" --max-time "${downloader_max_time}" "https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/config/master.conf" 2>&11 | $grep_bin "^config_version=" | head -n1 | cut -d '"' -f 2)"
707 # shellcheck disable=SC2086
708 latest_version="$($wget_bin $wget_compression $wget_proxy $wget_insecure $wget_output_level --connect-timeout="${downloader_connect_timeout}" --random-wait --tries="${downloader_tries}" --timeout="${downloader_max_time}" "https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/clamav-unofficial-sigs.sh" -O - 2>&12 | $grep_bin "^script_version=" | head -n1 | cut -d '"' -f 2)"
709 # shellcheck disable=SC2086
710 latest_config_version="$($wget_bin $wget_compression $wget_proxy $wget_insecure $wget_output_level --connect-timeout="${downloader_connect_timeout}" --random-wait --tries="${downloader_tries}" --timeout="${downloader_max_time}" "https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/config/master.conf" -O - 2>&12 | $grep_bin "^config_version=" | head -n1 | cut -d '"' -f 2)"
713 # config_dir/master.conf
714 if [ "$latest_config_version" ] ; then
715 # shellcheck disable=SC2183,SC2086
716 if [ "$(printf "%02d%02d%02d%02d" ${latest_config_version//./ })" -gt "$(printf "%02d%02d%02d%02d" ${config_version//./ })" ] ; then
718 xshok_pretty_echo_and_log "ALERT: Upgrading config from v${config_version} to v${latest_config_version}"
719 if [ -w "${config_dir}/master.conf" ] && [ -f "${config_dir}/master.conf" ] ; then
720 echo "Downloading https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/config/master.conf"
721 xshok_file_download "${work_dir}/master.conf.tmp" "https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/config/master.conf" "notimestamp"
723 if [ "$ret" -ne 0 ] ; then
724 xshok_pretty_echo_and_log "ERROR: Could not download https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/config/master.conf"
727 if ! $grep_bin -m 1 "config_version" "${work_dir}/master.conf.tmp" > /dev/null 2>&1 ; then
728 echo "ERROR: Downloaded master.conf is incomplete, please re-run"
731 # Copy over permissions from old version
732 OCTAL_MODE="$(stat -c "%a" "${config_dir}/master.conf")"
733 xshok_pretty_echo_and_log "Running update process"
734 if ! mv -f "${work_dir}/master.conf.tmp" "${config_dir}/master.conf" ; then
735 xshok_pretty_echo_and_log "ERROR: failed moving ${work_dir}/master.conf.tmp to ${config_dir}/master.conf"
738 if ! chmod "$OCTAL_MODE" "${config_dir}/master.conf" ; then
739 xshok_pretty_echo_and_log "ERROR: unable to set permissions on ${config_dir}/master.conf"
742 xshok_pretty_echo_and_log "Completed"
744 xshok_pretty_echo_and_log "ERROR: ${config_dir}/master.conf is not a file or is not writable"
750 if [ "$latest_version" ] ; then
751 # shellcheck disable=SC2183,SC2086
752 if [ "$(printf "%02d%02d%02d%02d" ${latest_version//./ })" -gt "$(printf "%02d%02d%02d%02d" ${script_version//./ })" ] ; then
754 xshok_pretty_echo_and_log "ALERT: Upgrading script from v${script_version} to v${latest_version}"
755 if [ -w "${config_dir}/master.conf" ] && [ -f "${config_dir}/master.conf" ] ; then
756 echo "Downloading https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/clamav-unofficial-sigs.sh"
757 xshok_file_download "${work_dir}/clamav-unofficial-sigs.sh.tmp" "https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/clamav-unofficial-sigs.sh" "notimestamp"
759 if [ "$ret" -ne 0 ] ; then
760 xshok_pretty_echo_and_log "ERROR: Could not download https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/clamav-unofficial-sigs.sh"
763 # Detect to make sure the entire script is avilable, fail if the script is missing contents
764 if [ "$(tail -n 1 "${work_dir}/clamav-unofficial-sigs.sh.tmp" | head -n 1 | cut -c 1-7)" != "exit \$?" ] ; then
765 echo "ERROR: Downloaded clamav-unofficial-sigs.sh is incomplete, please re-run"
768 # Copy over permissions from old version
769 OCTAL_MODE="$(stat -c "%a" "${this_script_full_path}")"
771 xshok_pretty_echo_and_log "Inserting update process..."
772 # Generate the update script
773 cat > "${work_dir}/xshok_update_script.sh" << EOF
775 echo "Running update process"
776 # Overwrite old file with new
777 if ! mv -f "${work_dir}/clamav-unofficial-sigs.sh.tmp" "${this_script_full_path}" ; then
778 echo "ERROR: failed moving ${work_dir}/clamav-unofficial-sigs.sh.tmp to ${this_script_full_path}"
782 if ! chmod "$OCTAL_MODE" "${this_script_full_path}" ; then
783 echo "ERROR: unable to set permissions on ${this_script_full_path}"
788 # echo "---------------------"
789 # echo "Optional, run as root: "
790 # echo "clamav-unofficial-sigs.sh --install-all"
791 echo "---------------------"
792 echo "Run once as root: "
793 echo "clamav-unofficial-sigs.sh --force"
795 #remove the tmp script before exit
798 # Replaced with $0, so code will update and then call itself with the same parameters it had
800 bash_bin="$(command -v bash 2> /dev/null)"
801 exec "$bash_bin" "${work_dir}/xshok_update_script.sh"
802 echo "Running once as root"
804 xshok_pretty_echo_and_log "ERROR: ${config_dir}/master.conf is not a file or is not writable"
810 if [ "$found_upgrade" == "no" ] ; then
811 xshok_pretty_echo_and_log "No updates available"
816 # Decode a third-party signature either by signature name
817 function decode_third_party_signature_by_signature_name() {
818 xshok_pretty_echo_and_log ""
819 xshok_pretty_echo_and_log "Input a third-party signature name to decode (e.g: Sanesecurity.Junk.15248) or"
820 xshok_pretty_echo_and_log "a hexadecimal encoded data string and press enter:"
822 # Remove quotes and .UNOFFICIAL from the whitelist input string
823 input="$(echo "${input}" | tr -d "'" | tr -d '"' | tr -d '`')"
824 input=${input/\.UNOFFICIAL/}
825 if echo "${input}" | $grep_bin "\\." > /dev/null ; then
826 cd "$clam_dbs" || exit
827 sig="$($grep_bin "${input}:" ./*.ndb)"
828 if [ -n "$sig" ] ; then
830 xshok_pretty_echo_and_log "${input} found in: ${db_file}"
831 xshok_pretty_echo_and_log "${input} signature decodes to:"
832 xshok_pretty_echo_and_log "$sig" | cut -d ":" -f 5 | perl -pe 's/([a-fA-F0-9]{2})|(\{[^}]*\}|\([^)]*\))/defined $2 ? $2 : chr(hex $1)/eg'
834 xshok_pretty_echo_and_log "Signature ${input} could not be found."
835 xshok_pretty_echo_and_log "This script will only decode ClamAV 'UNOFFICIAL' third-Party,"
836 xshok_pretty_echo_and_log "non-image based, signatures as found in the *.ndb databases."
839 xshok_pretty_echo_and_log "Here is the decoded hexadecimal input string:"
840 echo "${input}" | perl -pe 's/([a-fA-F0-9]{2})|(\{[^}]*\}|\([^)]*\))/defined $2 ? $2 : chr(hex $1)/eg'
844 # Hexadecimal encode an entire input string
845 function hexadecimal_encode_entire_input_string() {
846 xshok_pretty_echo_and_log ""
847 xshok_pretty_echo_and_log "Input the data string that you want to hexadecimal encode and then press enter. Do not include"
848 xshok_pretty_echo_and_log "any quotes around the string unless you want them included in the hexadecimal encoded output:"
850 xshok_pretty_echo_and_log "Here is the hexadecimal encoded input string:"
851 echo "${input}" | perl -pe 's/(.)/sprintf("%02lx", ord $1)/eg'
854 # Hexadecimal encode a formatted input string
855 function hexadecimal_encode_formatted_input_string() {
856 xshok_pretty_echo_and_log ""
857 xshok_pretty_echo_and_log "Input a formated data string containing spacing fields '{}, (), *' that you want to hexadecimal"
858 xshok_pretty_echo_and_log "encode, without encoding the spacing fields, and then press enter. Do not include any quotes"
859 xshok_pretty_echo_and_log "around the string unless you want them included in the hexadecimal encoded output:"
861 xshok_pretty_echo_and_log "Here is the hexadecimal encoded input string:"
862 echo "${input}" | perl -pe 's/(\{[^}]*\}|\([^)]*\)|\*)|(.)/defined $1 ? $1 : sprintf("%02lx", ord $2)/eg'
865 # GPG verify a specific Sanesecurity database file
866 function gpg_verify_specific_sanesecurity_database_file() { # databasefile
867 xshok_pretty_echo_and_log ""
868 if [ "$enable_gpg" == "no" ] ; then
869 xshok_pretty_echo_and_log "GnuPG / signature verification disabled" "-"
872 db_file="$(echo "${1}" | awk -F "/" '{print $NF}')"
873 if [ -r "${work_dir_sanesecurity}/${db_file}" ] ; then
874 xshok_pretty_echo_and_log "GPG signature testing database file: ${work_dir_sanesecurity}/${db_file}"
875 if [ -r "${work_dir_sanesecurity}/${db_file}.sig" ] ; then
876 if ! "$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}" ; then
877 if "$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}" ; then
886 xshok_pretty_echo_and_log "Signature ${db_file}.sig cannot be found."
889 xshok_pretty_echo_and_log "File ${db_file} cannot be found or is not a Sanesecurity database file."
890 xshok_pretty_echo_and_log "Only the following Sanesecurity and OITC databases can be GPG signature tested:"
891 ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "${work_dir_sanesecurity}"
894 xshok_pretty_echo_and_log "ERROR: Missing value for option"
901 # Output system and configuration information
902 function output_system_configuration_information() {
903 xshok_pretty_echo_and_log ""
904 xshok_pretty_echo_and_log "*** SCRIPT INFORMATION ***"
905 xshok_pretty_echo_and_log "${this_script_name} ${script_version} (${script_version_date})"
906 xshok_pretty_echo_and_log "Master.conf Version: ${config_version}"
907 xshok_pretty_echo_and_log "Minimum required config: ${minimum_required_config_version}"
908 xshok_pretty_echo_and_log "*** SYSTEM INFORMATION ***"
910 xshok_pretty_echo_and_log "*** CLAMSCAN LOCATION & VERSION ***"
911 xshok_pretty_echo_and_log "${clamscan_bin}"
912 $clamscan_bin --version | head -1
913 xshok_pretty_echo_and_log "*** RSYNC LOCATION & VERSION ***"
914 xshok_pretty_echo_and_log "${rsync_bin}"
915 $rsync_bin --version | head -1
916 if [ -n "$curl_bin" ] ; then
917 xshok_pretty_echo_and_log "*** CURL LOCATION & VERSION ***"
918 xshok_pretty_echo_and_log "${curl_bin}"
919 $curl_bin --version | head -1
921 xshok_pretty_echo_and_log "*** WGET LOCATION & VERSION ***"
922 xshok_pretty_echo_and_log "${wget_bin}"
923 $wget_bin --version | head -1
925 if [ "$enable_gpg" == "yes" ] ; then
926 xshok_pretty_echo_and_log "*** GPG LOCATION & VERSION ***"
927 xshok_pretty_echo_and_log "${gpg_bin}"
928 $gpg_bin --version | head -1
930 xshok_pretty_echo_and_log "*** DIRECTORY INFORMATION ***"
931 xshok_pretty_echo_and_log "Working Directory: ${work_dir}"
932 xshok_pretty_echo_and_log "Clam Database Directory: ${clam_dbs}"
933 if [ "$custom_config" != "no" ] ; then
934 if [ -d "$custom_config" ] ; then
935 # Assign the custom config dir and remove trailing / (removes / and //)
936 xshok_pretty_echo_and_log "Custom Configuration Directory: ${custom_config}"
938 xshok_pretty_echo_and_log "Custom Configuration File: ${custom_config}"
941 xshok_pretty_echo_and_log "Configuration Directory: ${config_dir}"
943 xshok_pretty_echo_and_log ""
946 # Make a signature database from an ascii file
947 function make_signature_database_from_ascii_file() {
948 xshok_pretty_echo_and_log ""
950 The '-m' script flag provides a way to create a ClamAV hexadecimal signature database (*.ndb) file
951 from a list of data strings stored in a clear-text ascii file, with one data string entry per line.
953 - Hexadecimal encoding can be either 'full' or 'formatted' on a per line basis:
955 Full line encoding should be used if there are no formatted spacing entries [{}, (), *]
956 included on the line. Prefix unformatted lines with: '-:' (no quote marks).
960 -:This signature contains no formatted spacing fields
964 54686973207369676e617475726520636f6e7461696e73206e6f20666f726d61747465642073706163696e67206669656c6473
966 Formatted line encoding should be used if there are user added spacing entries [{}, (), *]
967 included on the line. Prefix formatted lines with '=:' (no quote marks).
971 =:This signature{-10}contains several(25|26|27)formatted spacing*fields
975 54686973207369676e6174757265{-10}636f6e7461696e73207365766572616c(25|26|27)666f726d61747465642073706163696e67*6669656c6473
977 Use 'full' encoding if you want to encode everything on the line [including {}, (), *] and 'formatted'
978 encoding if you want to encode everything on the line except the formatted character spacing fields.
980 The prefixes ('-:' and '=:') will be stripped from the line before hexadecimal encoding is done.
981 If no prefix is found at the beginning of the line, full line encoding will be done (default).
983 - It is assumed that the signatures will be created for email scanning purposes, thus the '4'
984 target type is used and full file scanning is enabled (see ClamAV signatures.pdf for details).
986 - Line numbering will be done automatically by the script.
987 " | command sed 's/^ //g'
988 echo -n "Do you wish to continue? "
989 if xshok_prompt_confirm ; then
991 echo -n "Enter the source file as /path/filename: "
993 if [ -r "$source" ] ; then
994 source_file="$(basename "$source")"
996 xshok_pretty_echo_and_log "What signature prefix would you like to use? For example: 'Phish.Domains'"
997 xshok_pretty_echo_and_log "will create signatures that looks like: 'Phish.Domains.1:4:*:HexSigHere'"
999 echo -n "Enter signature prefix: "
1001 path_file="$(echo "$source" | cut -d "." -f -1 | command sed 's/$/.ndb/')"
1002 db_file="$(basename "$path_file")"
1004 total="$(wc -l "$source" | cut -d " " -f 1)"
1007 while read -r line ; do
1008 line_prefix="$(echo "$line" | awk -F ":" '{print $1}')"
1009 if [ "$line_prefix" == "-" ] ; then
1010 echo "$line" | cut -d ":" -f 2- | perl -pe 's/(.)/sprintf("%02lx", ord $1)/eg' | command sed "s/^/$prefix\\.$line_num:4:\\*:/" >> "$path_file"
1011 elif [ "$line_prefix" == "=" ] ; then
1012 echo "$line" | cut -d ":" -f 2- | perl -pe 's/(\{[^}]*\}|\([^)]*\)|\*)|(.)/defined $1 ? $1 : sprintf("%02lx", ord $2)/eg' | command sed "s/^/$prefix\\.$line_num:4:\\*:/" >> "$path_file"
1014 echo "$line" | perl -pe 's/(.)/sprintf("%02lx", ord $1)/eg' | command sed "s/^/$prefix\\.$line_num:4:\\*:/" >> "$path_file"
1016 xshok_pretty_echo_and_log "Hexadecimal encoding ${source_file} line: ${line_num} of ${total}"
1017 line_num="$((line_num + 1))"
1020 xshok_pretty_echo_and_log "Source file not found, exiting..."
1025 xshok_pretty_echo_and_log "Signature database file created at: ${path_file}"
1026 if $clamscan_bin --quiet -d "$path_file" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
1028 xshok_pretty_echo_and_log "Clamscan reports database integrity tested good."
1030 echo -n "Would you like to move '${db_file}' into '${clam_dbs}' and reload databases?"
1031 if xshok_prompt_confirm ; then
1032 if ! cmp -s "$path_file" "${clam_dbs}/${db_file}" ; then
1033 if $rsync_bin -pcqt "$path_file" "$clam_dbs" ; then
1034 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
1035 perms chmod -f 0644 "$clam_dbs"/"$db_file"
1036 if [ "$selinux_fixes" == "yes" ] ; then
1037 restorecon "${clam_dbs}/${db_file}"
1041 xshok_pretty_echo_and_log "Signature database '${db_file}' was successfully implemented and ClamD databases reloading."
1044 xshok_pretty_echo_and_log "Failed to add/update '${db_file}', ClamD database not reloading."
1048 xshok_pretty_echo_and_log "Database '${db_file}' has not changed - skipping"
1052 xshok_pretty_echo_and_log "No action taken."
1056 xshok_pretty_echo_and_log "Clamscan reports that '${db_file}' signature database integrity tested bad."
1061 # Remove the clamav-unofficial-sigs script
1062 function remove_script() {
1063 xshok_pretty_echo_and_log ""
1064 if [ -n "$pkg_mgr" ] || [ -n "$pkg_rm" ] ; then
1065 xshok_pretty_echo_and_log "This script (clamav-unofficial-sigs) was installed on the system via '${pkg_mgr}'"
1066 xshok_pretty_echo_and_log "use '${pkg_rm}' to remove the script and all of its associated files and databases from the system."
1069 cron_file_full_path="${cron_dir}/${cron_filename}"
1070 logrotate_file_full_path="${logrotate_dir}/${logrotate_filename}"
1071 man_file_full_path="${man_dir}/${man_filename}"
1073 xshok_pretty_echo_and_log "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})"
1074 xshok_pretty_echo_and_log "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?"
1075 if xshok_prompt_confirm ; then
1076 xshok_pretty_echo_and_log "This can not be undone are you sure ?"
1077 if xshok_prompt_confirm ; then
1078 if [ -r "${work_dir_work_configs}/purge.txt" ] ; then
1080 while read -r file ; do
1081 xshok_is_file "$file" && rm -f -- "$file"
1082 xshok_pretty_echo_and_log " Removed file: ${file}"
1083 done < "${work_dir_work_configs}/purge.txt"
1084 if [ -r "$cron_file_full_path" ] ; then
1085 xshok_is_file "$cron_file_full_path" && rm -f "$cron_file_full_path"
1086 xshok_pretty_echo_and_log " Removed file: ${cron_file_full_path}"
1088 if [ -r "$logrotate_file_full_path" ] ; then
1089 xshok_is_file "$logrotate_file_full_path" && rm -f "$logrotate_file_full_path"
1090 xshok_pretty_echo_and_log " Removed file: ${logrotate_file_full_path}"
1092 if [ -r "$man_file_full_path" ] ; then
1093 xshok_is_file "$man_file_full_path" && rm -f "$man_file_full_path"
1094 xshok_pretty_echo_and_log " Removed file: ${man_file_full_path}"
1097 # Rather keep the configs
1098 #rm -f -- "$default_config" && echo " Removed file: $default_config"
1099 #rm -f -- "${0}" && echo " Removed file: $0"
1100 xshok_is_subdir "$work_dir" && rm -rf -- "${work_dir:?}" && echo " Removed script working directories: ${work_dir}"
1102 xshok_pretty_echo_and_log " The clamav-unofficial-sigs script and all of its associated files, third-party"
1103 xshok_pretty_echo_and_log " databases, and work directories have been successfully removed from the system."
1106 xshok_pretty_echo_and_log " Cannot locate 'purge.txt' file in ${work_dir_work_configs}."
1107 xshok_pretty_echo_and_log " Files and signature database will need to be removed manually."
1110 xshok_pretty_echo_and_log "Aborted"
1113 xshok_pretty_echo_and_log "Aborted"
1118 # Clamscan integrity test a specific database file
1119 function clamscan_integrity_test_specific_database_file() { # databasefile
1120 xshok_pretty_echo_and_log ""
1121 if [ "${1}" ] ; then
1122 input="$(echo "${1}" | awk -F "/" '{print $NF}')"
1123 db_file="$(find "$work_dir" -name "$input")"
1124 if [ -r "$db_file" ] ; then
1125 xshok_pretty_echo_and_log "Clamscan integrity testing: ${db_file}"
1126 if $clamscan_bin --quiet -d "$db_file" "${work_dir_work_configs}/scan-test.txt" ; then
1127 xshok_pretty_echo_and_log "Clamscan reports that '${input}' database integrity tested GOOD"
1130 xshok_pretty_echo_and_log "Clamscan reports that '${input}' database integrity tested BAD"
1134 xshok_pretty_echo_and_log "File '${input}' cannot be found."
1135 xshok_pretty_echo_and_log "Here is a list of third-party databases that can be clamscan integrity tested:"
1137 xshok_pretty_echo_and_log "=== Sanesecurity ==="
1138 ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_sanesecurity"
1140 xshok_pretty_echo_and_log "=== SecuriteInfo ==="
1141 ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_securiteinfo"
1143 xshok_pretty_echo_and_log "=== MalwarePatrol ==="
1144 ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_malwarepatrol"
1146 xshok_pretty_echo_and_log "=== Linux Malware Detect ==="
1147 ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_linuxmalwaredetect"
1149 xshok_pretty_echo_and_log "=== Linux Malware Detect ==="
1150 ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_yararulesproject"
1152 xshok_pretty_echo_and_log "=== User Defined Databases ==="
1153 ls --ignore "*.sig" --ignore "*.md5" --ignore "*.ign2" "$work_dir_add"
1155 xshok_pretty_echo_and_log "Check the file name and try again..."
1158 xshok_pretty_echo_and_log "ERROR: Missing value for option"
1163 # Output names of any third-party signatures that triggered during the HAM directory scan
1164 function output_signatures_triggered_during_ham_directory_scan() {
1165 xshok_pretty_echo_and_log ""
1166 if [ -n "$ham_dir" ] ; then
1167 if [ -r "${work_dir_work_configs}/whitelist.hex" ] ; then
1168 xshok_pretty_echo_and_log "The following third-party signatures triggered hits during the HAM Directory scan:"
1170 $grep_bin -h -f "${work_dir_work_configs}/whitelist.hex" "$work_dir"/*/*.ndb | cut -d ":" -f 1
1171 $grep_bin -h -f "${work_dir_work_configs}/whitelist.hex" "$work_dir"/*/*.db | cut -d "=" -f 1
1173 xshok_pretty_echo_and_log "No third-party signatures have triggered hits during the HAM Directory scan."
1176 xshok_pretty_echo_and_log "Ham directory scanning is not currently enabled in the script's configuration file."
1180 # Adds a signature whitelist entry in the newer ClamAV IGN2 format
1181 function add_signature_whitelist_entry() { #signature
1182 xshok_pretty_echo_and_log "Signature Whitelist" "="
1183 if [ -n "$1" ] ; then
1186 xshok_pretty_echo_and_log "Input a third-party signature name that you wish to whitelist and press enter"
1189 if [ -n "$input" ] ; then
1190 xshok_pretty_echo_and_log "Processing: ${input}"
1191 cd "$clam_dbs" || exit
1192 # Remove quotes and .UNOFFICIAL from the string
1193 input="$(echo "${input}" | tr -d "'" | tr -d '"' | tr -d '`"')"
1194 input=${input/\.UNOFFICIAL/}
1196 sig_full="$($grep_bin -H -m 1 "$input" ./*.*db)"
1197 sig_extension=${sig_full%%\:*}
1198 sig_extension=${sig_extension##*\.}
1199 shopt -s nocasematch
1200 if [ "$sig_extension" == "hdb" ] || [ "$sig_extension" == "hsb" ] || [ "$sig_extension" == "hdu " ] || [ "$sig_extension" == "hsu" ] || [ "$sig_extension" == "mdb" ] || [ "$sig_extension" == "msb" ] || [ "$sig_extension" == "mdu" ] || [ "$sig_extension" == "msu" ] ; then
1201 # Hash-based Signature Database
1206 sig_name="$(echo "$sig_full" | cut -d ":" -f $position | cut -d "=" -f 1)"
1208 if [ -n "$sig_name" ] ; then
1209 if ! $grep_bin -m 1 "$sig_name" my-whitelist.ign2 > /dev/null 2>&1 ; then
1210 cp -f -p my-whitelist.ign2 "$work_dir_work_configs" 2>/dev/null
1211 echo "$sig_name" >> "${work_dir_work_configs}/my-whitelist.ign2"
1212 echo "$sig_full" >> "${work_dir_work_configs}/tracker.txt"
1213 if $clamscan_bin --quiet -d "${work_dir_work_configs}/my-whitelist.ign2" "${work_dir_work_configs}/scan-test.txt" ; then
1214 if $rsync_bin -pcqt "${work_dir_work_configs}/my-whitelist.ign2" "$clam_dbs" ; then
1215 perms chown -f "${clam_user}:${clam_group}" my-whitelist.ign2
1217 if [ ! -s "${work_dir_work_configs}/monitor-ign.txt" ] ; then
1218 # Create "monitor-ign.txt" file for clamscan database integrity testing.
1219 echo "This is the monitor ignore file..." > "${work_dir_work_configs}/monitor-ign.txt"
1222 perms chmod -f 0644 my-whitelist.ign2 "${work_dir_work_configs}/monitor-ign.txt"
1223 if [ "$selinux_fixes" == "yes" ] ; then
1224 restorecon "${clam_dbs}/local.ign"
1229 xshok_pretty_echo_and_log "Signature '${input}' has been added to my-whitelist.ign2 and"
1230 xshok_pretty_echo_and_log "all databases have been reloaded. The script will track any changes"
1231 xshok_pretty_echo_and_log "to the offending signature and will automatically remove it if the"
1232 xshok_pretty_echo_and_log "signature is modified or removed from the third-party database."
1235 xshok_pretty_echo_and_log "Failed to successfully update my-whitelist.ign2 file - SKIPPING."
1239 xshok_pretty_echo_and_log "Clamscan reports my-whitelist.ign2 database integrity is bad - SKIPPING."
1243 xshok_pretty_echo_and_log "Signature '${input}' already exists in my-whitelist.ign2 - no action taken."
1247 xshok_pretty_echo_and_log "Signature '${input}' could not be found."
1249 xshok_pretty_echo_and_log "This script will only create a whitelise entry in my-whitelist.ign2 for ClamAV"
1250 xshok_pretty_echo_and_log "'UNOFFICIAL' third-Party signatures as found in the *.ndb *.hdb *.db databases."
1253 xshok_pretty_echo_and_log "No input detected - no action taken."
1257 # Clamscan reload database
1258 function clamscan_reload_dbs() {
1259 # Reload all clamd databases if updates detected and $reload_dbs" is set to "yes"
1260 if [ "$reload_dbs" == "yes" ] ; then
1261 if [ "$do_clamd_reload" != "0" ] ; then
1262 if [ "$do_clamd_reload" == "1" ] ; then
1263 xshok_pretty_echo_and_log "Update(s) detected, reloading ClamAV databases" "="
1264 elif [ "$do_clamd_reload" == "2" ] ; then
1265 xshok_pretty_echo_and_log "Database removal(s) detected, reloading ClamAV databases" "="
1266 elif [ "$do_clamd_reload" == "3" ] ; then
1267 xshok_pretty_echo_and_log "File 'local.ign' has changed, reloading ClamAV databases" "="
1268 elif [ "$do_clamd_reload" == "4" ] ; then
1269 xshok_pretty_echo_and_log "File 'my-whitelist.ign2' has changed, reloading ClamAV databases" "="
1271 xshok_pretty_echo_and_log "Update(s) detected, reloading ClamAV databases" "="
1274 if [[ "$($clamd_reload_opt 2>&1)" = *"ERROR"* ]] ; then
1275 xshok_pretty_echo_and_log "ERROR: Failed to reload, trying again"
1276 if [ -r "$clamd_pid" ] ; then
1277 mypid="$(cat "$clamd_pid")"
1279 if kill -USR2 "$mypid" ; then
1280 xshok_pretty_echo_and_log "ClamAV databases reloading" "="
1282 xshok_pretty_echo_and_log "ERROR: Failed to reload, forcing clamd to restart"
1283 if [ -z "$clamd_restart_opt" ] ; then
1284 xshok_pretty_echo_and_log "WARNING: Check the script's configuration file, 'reload_dbs' enabled but no 'clamd_restart_opt'"
1286 if $clamd_restart_opt > /dev/null ; then
1287 xshok_pretty_echo_and_log "ClamAV Restarted" "="
1289 xshok_pretty_echo_and_log "ClamAV NOT Restarted" "-"
1294 xshok_pretty_echo_and_log "ERROR: Failed to reload, forcing clamd to restart"
1295 if [ -z "$clamd_restart_opt" ] ; then
1296 xshok_pretty_echo_and_log "WARNING: Check the script's configuration file, 'reload_dbs' enabled but no 'clamd_restart_opt'"
1298 if $clamd_restart_opt > /dev/null ; then
1299 xshok_pretty_echo_and_log "ClamAV Restarted" "="
1301 xshok_pretty_echo_and_log "ClamAV NOT Restarted" "-"
1306 xshok_pretty_echo_and_log "ClamAV databases reloading" "="
1309 xshok_pretty_echo_and_log "No updates detected, ClamAV databases were not reloaded" "="
1312 xshok_pretty_echo_and_log "Database reload has been disabled in the configuration file" "="
1317 # If ClamD status check is enabled ("clamd_socket" variable is uncommented
1318 # and the socket path is correctly specified in "User Edit" section above),
1319 # then test to see if clamd is running or not.
1320 function check_clamav() {
1321 if [ -n "$clamd_socket" ] ; then
1322 if [ -S "$clamd_socket" ] ; then
1323 if [ "$(perl -e 'use IO::Socket::UNIX; print $IO::Socket::UNIX::VERSION,"\n"' 2>/dev/null)" ] ; then
1325 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
1327 xshok_pretty_echo_and_log "ClamD is running" "="
1330 socat="$(command -v socat 2>/dev/null)"
1331 if [ -n "$socat" ] && [ -x "$socat" ] ; then
1333 if [ "$( (echo "PING"; sleep 1;) | socat - "$clamd_socket" 2>/dev/null)" == "PONG" ] ; then
1335 xshok_pretty_echo_and_log "ClamD is running" "="
1339 if [ -z "$io_socket1" ] && [ -z "$socket_cat1" ] ; then
1340 xshok_pretty_echo_and_log "WARNING: socat or perl module 'IO::Socket::UNIX' not found, cannot test if ClamD is running"
1342 if [ -z "$io_socket2" ] && [ -z "$socket_cat2" ] ; then
1344 xshok_pretty_echo_and_log "ALERT: CLAMD IS NOT RUNNING!"
1345 if [ -n "$clamd_restart_opt" ] ; then
1346 xshok_pretty_echo_and_log "Attempting to start ClamD..." "-"
1347 if [ -n "$io_socket1" ] ; then
1348 $clamd_restart_opt > /dev/null && sleep 5
1349 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
1350 xshok_pretty_echo_and_log "ClamD was successfully started" "="
1352 xshok_pretty_echo_and_log "ERROR: CLAMD FAILED TO START"
1356 if [ -n "$socket_cat1" ] ; then
1357 $clamd_restart_opt > /dev/null && sleep 5
1358 if [ "$( (echo "PING"; sleep 1;) | socat - "$clamd_socket" 2>/dev/null)" == "PONG" ] ; then
1359 xshok_pretty_echo_and_log "ClamD was successfully started" "="
1361 xshok_pretty_echo_and_log "ERROR: CLAMD FAILED TO START"
1370 xshok_pretty_echo_and_log "WARNING: ${clamd_socket} is not a usable socket"
1373 xshok_pretty_echo_and_log "WARNING: clamd_socket is not defined in the configuration file"
1377 # Check for a new version
1378 function check_new_version() {
1380 if [ -n "$curl_bin" ] ; then
1381 # shellcheck disable=SC2086
1382 latest_version="$($curl_bin --compressed $curl_proxy $curl_insecure $curl_output_level --connect-timeout "${downloader_connect_timeout}" --remote-time --location --retry "${downloader_tries}" --max-time "${downloader_max_time}" "https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/clamav-unofficial-sigs.sh" 2>&11 | $grep_bin "^script_version=" | head -n1 | cut -d '"' -f 2)"
1383 # shellcheck disable=SC2086
1384 latest_config_version="$($curl_bin --compressed $curl_proxy $curl_insecure $curl_output_level --connect-timeout "${downloader_connect_timeout}" --remote-time --location --retry "${downloader_tries}" --max-time "${downloader_max_time}" "https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/config/master.conf" 2>&11 | $grep_bin "^config_version=" | head -n1 | cut -d '"' -f 2)"
1386 # shellcheck disable=SC2086
1387 latest_version="$($wget_bin $wget_compression $wget_proxy $wget_insecure $wget_output_level --connect-timeout="${downloader_connect_timeout}" --random-wait --tries="${downloader_tries}" --timeout="${downloader_max_time}" "https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/clamav-unofficial-sigs.sh" -O - 2>&12 | $grep_bin "^script_version=" | head -n1 | cut -d '"' -f 2)"
1388 # shellcheck disable=SC2086
1389 latest_config_version="$($wget_bin $wget_compression $wget_proxy $wget_insecure $wget_output_level --connect-timeout="${downloader_connect_timeout}" --random-wait --tries="${downloader_tries}" --timeout="${downloader_max_time}" "https://raw.githubusercontent.com/extremeshok/clamav-unofficial-sigs/${git_branch}/config/master.conf" -O - 2>&12 | $grep_bin "^config_version=" | head -n1 | cut -d '"' -f 2)"
1391 if [ "$latest_version" ] ; then
1392 # shellcheck disable=SC2183,SC2086
1393 if [ "$(printf "%02d%02d%02d%02d" ${latest_version//./ })" -gt "$(printf "%02d%02d%02d%02d" ${script_version//./ })" ] ; then
1394 xshok_pretty_echo_and_log "ALERT: New version : v${latest_version} @ https://github.com/extremeshok/clamav-unofficial-sigs"
1398 if [ "$latest_config_version" ] ; then
1399 # shellcheck disable=SC2183,SC2086
1400 if [ "$(printf "%02d%02d%02d%02d" ${latest_config_version//./ })" -gt "$(printf "%02d%02d%02d%02d" ${config_version//./ })" ] ; then
1401 xshok_pretty_echo_and_log "ALERT: New config version : v${latest_config_version} @ https://github.com/extremeshok/clamav-unofficial-sigs"
1406 if [ "$found_upgrade" == "yes" ] && [ "$allow_upgrades" == "yes" ] ; then
1407 xshok_pretty_echo_and_log "Quickly upgrade, run the following command as root:"
1408 xshok_pretty_echo_and_log "${this_script_name} --upgrade"
1413 # Display help and usage
1415 # help_and_usage "1" - enables the man output formatting
1416 # help_and_usage - normal help output formatting
1417 function help_and_usage() {
1419 if [ "${1}" ] ; then
1420 # option_format_start
1424 # option_format_blankline
1426 # option_format_tab_line
1429 # option_format_start
1433 # option_format_blankline
1435 # option_format_tab_line
1439 helpcontents="$(cat << EOF
1440 ${ofs} Usage: $(basename "$0") ${ofe} [OPTION] [PATH|FILE]
1442 ${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}
1444 ${ofs} -F, --force ${ofe} Force all databases to be downloaded, could cause ip to be blocked
1446 ${ofs} -h, --help ${ofe} Display this script's help and usage information
1448 ${ofs} -V, --version ${ofe} Output script version and date information
1450 ${ofs} -v, --verbose ${ofe} Be verbose, enabled when not run under cron
1452 ${ofs} -s, --silence ${ofe} Only output error messages, enabled when run under cron
1454 ${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
1456 ${ofs} -e, --encode-string ${ofe} Hexadecimal encode an entire input string that can ${oft} be used in any '*.ndb' signature database file
1458 ${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
1460 ${ofs} -g, --gpg-verify ${ofe} GPG verify a specific Sanesecurity database file ${oft} eg: '-g filename.ext' (do not include file path)
1462 ${ofs} -i, --information ${ofe} Output system and configuration information for ${oft} viewing or possible debugging purposes
1464 ${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
1466 ${ofs} -t, --test-database ${ofe} Clamscan integrity test a specific database file ${oft} eg: '-t filename.ext' (do not include file path)
1468 ${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
1470 ${ofs} -w, --whitelist <signature-name> ${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
1472 ${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
1474 ${ofs} --upgrade ${ofe} Upgrades this script and master.conf to the latest available version
1476 ${ofs} --install-all ${ofe} Install and generate the cron, logroate and man files, autodetects the values ${oft} based on your config files
1478 ${ofs} --install-cron ${ofe} Install and generate the cron file, autodetects the values ${oft} based on your config files
1480 ${ofs} --install-logrotate ${ofe} Install and generate the logrotate file, autodetects the ${oft} values based on your config files
1482 ${ofs} --install-man ${ofe} Install and generate the man file, autodetects the ${oft} values based on your config files
1484 ${ofs} --remove-script ${ofe} Remove the clamav-unofficial-sigs script and all of ${oft} its associated files and databases from the system
1487 )" # This is very important
1488 if [ "${1}" ] ; then
1489 echo "${helpcontents//-/\\-}"
1491 echo -e "$helpcontents"
1494 ################################################################################
1496 ################################################################################
1499 script_version="7.0.1"
1500 script_version_date="2020-01-25"
1501 minimum_required_config_version="91"
1502 minimum_yara_clamav_version="0.100"
1504 # Discover script: name, full_path and path
1505 this_script_full_path="${BASH_SOURCE[0]}"
1506 # follow the symlinks
1507 while [ -h "$this_script_full_path" ]; do
1508 this_script_path="$( cd -P "$( dirname "$this_script_full_path" )" >/dev/null 2>&1 && pwd )"
1509 this_script_full_path="$(readlink "$this_script_full_path")"
1510 # if relative symlink, then resolve the path
1511 if [[ $this_script_full_path != /* ]] ; then
1512 this_script_full_path="$this_script_path/$this_script_full_path"
1515 this_script_path="$( cd -P "$( dirname "$this_script_full_path" )" >/dev/null 2>&1 && pwd )"
1516 this_script_name="$(basename "$this_script_full_path")"
1518 if [ -z "$this_script_full_path" ] || [ -z "$this_script_path" ] || [ -z "$this_script_name" ] ; then
1519 echo "ERROR: could not determin script name and fullpath"
1523 #allow for other negatives besides no.
1524 #disabled_values_array=("0 no No NO false False FALSE off Off OFF disable Disable DISABLE disabled Disabled DISABLED")
1525 # if [[ " ${disabled_values_array[@]} " =~ " ${value} " ]]; then
1526 # # whatever you want to do when arr contains value
1529 # if [[ ! " ${disabled_values_array[@]} " =~ " ${value} " ]]; then
1530 # # whatever you want to do when arr doesn't contain value
1536 comment_silence="no"
1538 logging_enabled="no"
1543 we_have_a_config="0"
1546 # Attempt to scan for a valid config dir
1547 if [ -f "/etc/clamav-unofficial-sigs/master.conf" ] ; then
1548 config_dir="/etc/clamav-unofficial-sigs"
1549 elif [ -f "/usr/local/etc/clamav-unofficial-sigs/master.conf" ] ; then
1550 config_dir="/usr/local/etc/clamav-unofficial-sigs/"
1551 elif [ -f "/opt/zimbra/conf/clamav-unofficial-sigs/master.conf" ] ; then
1552 config_dir="/opt/zimbra/conf/clamav-unofficial-sigs/"
1554 xshok_pretty_echo_and_log "ERROR: config_dir (/etc/clamav-unofficial-sigs/master.conf) could not be found"
1557 # Default config files
1558 if [ -r "${config_dir}/master.conf" ] ; then
1559 config_files+=( "${config_dir}/master.conf" )
1561 xshok_pretty_echo_and_log "ERROR: ${config_dir}/master.conf is not readable"
1564 if [ -r "${config_dir}/os.conf" ] ; then
1565 config_files+=( "${config_dir}/os.conf" )
1567 #find the a suitable os.*.conf file
1568 os_config_number=$(find "$config_dir" -type f -iname "os.*.conf" | wc -l)
1569 if [ "$os_config_number" == "0" ] ; then
1570 xshok_pretty_echo_and_log "WARNING: no os.conf or os.*.conf found"
1571 elif [ "$os_config_number" == "1" ] ; then
1572 config_file="$(find "$config_dir" -type f -iname "os.*.conf" | head -n1)"
1573 if [ -r "${config_file}" ]; then
1574 config_files+=( "${config_file}" )
1576 xshok_pretty_echo_and_log "WARNING: ${config_file} is not readable"
1579 xshok_pretty_echo_and_log "WARNING: Too many os.*.conf configs found"
1582 if [ -r "${config_dir}/user.conf" ] ; then
1583 config_files+=( "${config_dir}/user.conf" )
1585 xshok_pretty_echo_and_log "WARNING: ${config_dir}/user.conf is not readable"
1588 # Solaris command -v function returns garbage when the program is not found
1589 # only define the new command -v function if running under Solaris
1590 if [ "$(uname -s)" == "SunOS" ] ; then
1592 # Use the switch -p to ignore ksh internal commands
1597 # Default Binaries & Commands
1598 uname_bin="$(command -v uname 2> /dev/null)"
1599 clamscan_bin="$(command -v clamscan 2> /dev/null)"
1600 rsync_bin="$(command -v rsync 2> /dev/null)"
1602 # Detect supprot for gnu grep
1603 if [ -x /usr/gnu/bin/grep ] ; then
1604 grep_bin="/usr/gnu/bin/grep"
1606 grep_bin="$(command -v grep 2> /dev/null)"
1608 # Detect support for tar
1609 if [ -z "$tar_bin" ]; then
1610 tar_bin="$(command -v tar 2> /dev/null)"
1612 # Detect support for curl
1613 if [ -z "$curl_bin" ]; then
1614 curl_bin="$(command -v curl 2> /dev/null)"
1616 # Detect support for wget
1617 if [ -z "$wget_bin" ]; then
1618 if [ -x /usr/sfw/bin/wget ] ; then
1619 wget_bin="/usr/sfw/bin/wget"
1621 wget_bin="$(command -v wget 2> /dev/null)"
1624 if [ -z "$wget_bin" ] && [ -z "$curl_bin" ]; then
1625 curl_bin="$(command -v curl 2> /dev/null)"
1626 if [ -z "$curl_bin" ] ; then
1627 xshok_pretty_echo_and_log "ERROR: both wget and curl commands are missing, One of them is required"
1632 if [ ! -z "$wget_bin" ] ; then
1633 # wget compression support
1634 if $wget_bin --help | $grep_bin -q "compression=TYPE" ; then
1635 wget_compression="--compression=auto"
1640 # Detect support for dig or host
1641 dig_bin="$(command -v dig 2> /dev/null)"
1642 if [ -z "$dig_bin" ] ; then
1643 host_bin="$(command -v host 2> /dev/null)"
1644 if [ -z "$host_bin" ] ; then
1645 xshok_pretty_echo_and_log "ERROR: both dig and host commands are missing, One of them is required"
1649 # Detect if terminal
1652 # Usage: echo "${BOLD}-a${NORM}"
1668 # Generic command line options
1671 -c|--config) xshok_check_s2 "${2}"; custom_config="${2}"; shift 2; break ;;
1672 -F|--force) force_updates="yes"; shift 1; break ;;
1673 -v|--verbose) force_verbose="yes"; shift 1; break ;;
1674 -s|--silence) force_verbose="no"; shift 1; break ;;
1680 if [ "$force_verbose" == "yes" ] ; then
1682 downloader_silence="no"
1685 comment_silence="no"
1688 downloader_silence="yes"
1691 comment_silence="yes"
1694 xshok_pretty_echo_and_log "" "#" "80"
1695 xshok_pretty_echo_and_log " eXtremeSHOK.com ClamAV Unofficial Signature Updater"
1696 xshok_pretty_echo_and_log " Version: v${script_version} (${script_version_date})"
1697 xshok_pretty_echo_and_log " Required Configuration Version: v${minimum_required_config_version}"
1698 xshok_pretty_echo_and_log " Copyright (c) Adrian Jon Kriel :: admin@extremeshok.com"
1699 xshok_pretty_echo_and_log "" "#" "80"
1701 # Generic command line options
1704 -h|--help) help_and_usage; exit ;;
1705 -V|--version) exit ;;
1710 # CONFIG LOADING AND ERROR CHECKING ##############################################
1711 if [ "$custom_config" != "no" ] ; then
1712 if [ -d "$custom_config" ] ; then
1713 # Assign the custom config dir and remove trailing / (removes / and //)
1714 shopt -s extglob; config_dir="${custom_config%%+(/)}"
1716 if [ -r "${config_dir}/master.conf" ] ; then
1717 config_files+=( "${config_dir}/master.conf" )
1719 xshok_pretty_echo_and_log "WARNING: ${config_dir}/master.conf not found"
1721 #find the a suitable os.conf or os.*.conf file
1722 config_file="$(find "$config_dir" -type f -iname "os.conf" -o -iname "os.*.conf" | tail -n1)"
1723 if [ -r "${config_file}" ] ; then
1724 config_files+=( "${config_file}" )
1726 xshok_pretty_echo_and_log "WARNING: ${config_dir}/os.conf not found"
1728 if [ -r "${config_dir}/user.conf" ] ; then
1729 config_files+=( "${config_dir}/user.conf" )
1731 xshok_pretty_echo_and_log "WARNING: ${config_dir}/user.conf not found"
1734 config_files=( "$custom_config" )
1738 for config_file in "${config_files[@]}" ; do
1739 if [ -r "$config_file" ] ; then # Exists and readable
1740 we_have_a_config="1"
1742 xshok_pretty_echo_and_log "Loading config: ${config_file}"
1744 if [ "$(uname -s)" == "SunOS" ] ; then
1745 # Solaris FIXES only, i had issues with running with a single command..
1746 clean_config="$(command sed -e '/^#.*/d' "$config_file")" # Comment line
1747 #clean_config="$(echo "$clean_config" | sed -e 's/#[[:space:]].*//')" # Comment line (duplicated)
1748 clean_config=${clean_config//\#*/} # Comment line (duplicated)
1749 clean_config="$(echo "$clean_config" | sed -e '/^[[:blank:]]*#/d;s/#.*//')" # Comments at end of line
1750 #clean_config="$(echo "$clean_config" | sed -e 's/^[ \t]*//;s/[ \t]*$//')" # trailing and leading whitespace
1751 clean_config="$(echo "$clean_config" | xargs)"
1752 clean_config="$(echo "$clean_config" | sed -e '/^\s*$/d')" # Blank lines
1754 elif [ "$(uname -s)" == "Darwin" ] ; then
1755 # MacOS / OS X fixes, had issues with running with a single command and with SunOS work around..
1756 clean_config="$(command sed -e '/^#.*/d' "$config_file")" # Comment line
1757 clean_config="$(echo "$clean_config" | sed -e 's/#[[:space:]].*//')" # Comment line (duplicated)
1758 clean_config="$(echo "$clean_config" | sed -e '/^[[:blank:]]*#/d;s/#.*//')" # Comments at end of line
1759 #clean_config="$(echo "$clean_config" | sed -e 's/^[ \t]*//;s/[ \t]*$//')" # trailing and leading whitespace
1760 #clean_config="$(echo "$clean_config" | xargs)"
1761 clean_config="$(echo "$clean_config" | sed -e '/^\s*$/d')" # Blank lines
1764 # Delete lines beginning with #
1765 # Delete from " #" to end of the line
1766 # Delete from "# " to end of the line
1767 # Delete both trailing and leading whitespace
1768 # Delete all trailing whitespace
1769 # Delete all empty lines
1770 clean_config="$(command sed -e '/^#.*/d' -e 's/[[:space:]]#.*//' -e 's/#[[:space:]].*//' -e 's/^[ \t]*//;s/[ \t]*$//' -e '/^\s*$/d' "$config_file")"
1774 clean_config="${clean_config//|/\\|}"
1776 # Config error checking
1777 # Check "" are an even number
1778 config_check="${clean_config//[^\"]}"
1779 if [ "$(( ${#config_check} % 2 ))" -eq 1 ] ; then
1780 xshok_pretty_echo_and_log "ERROR: Your configuration has errors, every \" requires a closing \""
1784 # Check there is an = for every set of "" optional whitespace \s* between = and "
1785 config_check_vars="$(echo "$clean_config" | $grep_bin -c '=\s*\"' )"
1787 if [ $(( ${#config_check} / 2 )) -ne "$config_check_vars" ] ; then
1788 xshok_pretty_echo_and_log "ERROR: Your configuration has errors, every = requires a pair of \"\""
1793 #clean_config="${clean_config//|/\|}"
1796 for i in "${clean_config[@]}" ; do
1797 eval "$(echo "${i}" | command sed -e 's/[[:space:]]*$//' 2> /dev/null)"
1803 # Assign the log_file_path earlier and remove trailing / (removes / and //)
1804 shopt -s extglob; log_file_path="${log_file_path%%+(/)}"
1805 # Only start logging once all the configs have been loaded
1806 if [ "$logging_enabled" == "yes" ] ; then
1810 # Make sure we have a readable config file
1811 if [ "$we_have_a_config" == "0" ] ; then
1812 xshok_pretty_echo_and_log "ERROR: Config file/s could NOT be read/loaded"
1813 xshok_pretty_echo_and_log "Note: Possible fix would be to checkl the config dir ${config_dir} exists and contains config files"
1817 # Prevent some issues with an incomplete or only a user.conf being loaded
1818 if [ "$config_version" == "0" ] ; then
1819 xshok_pretty_echo_and_log "ERROR: Config file/s are missing important contents"
1820 xshok_pretty_echo_and_log "Note: Possible fix would be to point the script to the dir with the configs"
1824 # Config version validation
1825 if [ "$config_version" -lt "$minimum_required_config_version" ] ; then
1826 xshok_pretty_echo_and_log "ERROR: Your config version ${config_version} is not compatible with the min required version ${minimum_required_config_version}"
1830 # Check to see if the script's "USER CONFIGURATION FILE" has been completed.
1831 if [ "$user_configuration_complete" != "yes" ] ; then
1832 xshok_pretty_echo_and_log "WARNING: SCRIPT CONFIGURATION HAS NOT BEEN COMPLETED"
1833 xshok_pretty_echo_and_log "Please review the script configuration files"
1834 xshok_pretty_echo_and_log "and uncomment the following line in user.conf"
1835 xshok_pretty_echo_and_log "#user_configuration_complete=\"yes\""
1839 # Assign the directories and remove trailing / (removes / and //)
1840 shopt -s extglob; work_dir="${work_dir%%+(/)}"
1842 # Allow overriding of all the individual workdirs, this is mainly to aid package maintainers
1843 if [ -z "$work_dir_sanesecurity" ] ; then
1844 work_dir_sanesecurity="$(echo "${work_dir}/${sanesecurity_dir}" | sed 's:/*$::')"
1846 shopt -s extglob; work_dir_sanesecurity="${work_dir_sanesecurity%%+(/)}"
1848 if [ -z "$work_dir_securiteinfo" ] ; then
1849 work_dir_securiteinfo="$(echo "${work_dir}/${securiteinfo_dir}" | sed 's:/*$::')"
1851 shopt -s extglob; work_dir_securiteinfo="${work_dir_securiteinfo%%+(/)}"
1853 if [ -z "$work_dir_linuxmalwaredetect" ] ; then
1854 work_dir_linuxmalwaredetect="$(echo "${work_dir}/${linuxmalwaredetect_dir}" | sed 's:/*$::')"
1856 shopt -s extglob; work_dir_malwarepatrol="${work_dir_malwarepatrol%%+(/)}"
1858 if [ -z "$work_dir_malwarepatrol" ] ; then
1859 work_dir_malwarepatrol="$(echo "${work_dir}/${malwarepatrol_dir}" | sed 's:/*$::')"
1861 shopt -s extglob; work_dir_malwarepatrol="${work_dir_malwarepatrol%%+(/)}"
1863 if [ -z "$work_dir_urlhaust" ] ; then
1864 work_dir_urlhaus="$(echo "${work_dir}/${urlhaus_dir}" | sed 's:/*$::')"
1866 shopt -s extglob; work_dir_urlhaus="${work_dir_urlhaus%%+(/)}"
1868 if [ -z "$work_dir_yararulesproject" ] ; then
1869 work_dir_yararulesproject="$(echo "${work_dir}/${yararulesproject_dir}" | sed 's:/*$::')"
1871 shopt -s extglob; work_dir_yararulesproject="${work_dir_yararulesproject%%+(/)}"
1873 if [ -z "$work_dir_add" ] ; then
1874 work_dir_add="$(echo "${work_dir}/${add_dir}" | sed 's:/*$::')"
1876 shopt -s extglob; work_dir_add="${work_dir_add%%+(/)}"
1878 if [ -z "$work_dir_work_configs" ] ; then
1879 work_dir_work_configs="$(echo "${work_dir}/${work_dir_configs}" | sed 's:/*$::')"
1881 shopt -s extglob; work_dir_work_configs="${work_dir_work_configs%%+(/)}"
1883 if [ -z "${work_dir_gpg}" ] ; then
1884 work_dir_gpg="$(echo "${work_dir}/${gpg_dir}" | sed 's:/*$::')"
1886 shopt -s extglob; work_dir_gpg="${work_dir_gpg%%+(/)}"
1889 if [ -z "$work_dir_pid" ] ; then
1890 work_dir_pid="$(echo "${work_dir}/${pid_dir}" | sed 's:/*$::')"
1892 shopt -s extglob; work_dir_pid="${work_dir_pid%%+(/)}"
1895 # Assign defaults if not defined
1896 if [ -z "$cron_dir" ] ; then
1897 cron_dir="/etc/cron.d"
1899 shopt -s extglob; cron_dir="${cron_dir%%+(/)}"
1900 if [ -z "$cron_filename" ] ; then
1901 cron_filename="clamav-unofficial-sigs"
1903 if [ -z "$logrotate_dir" ] ; then
1904 logrotate_dir="/etc/logrotate.d"
1906 shopt -s extglob; logrotate_dir="${logrotate_dir%%+(/)}"
1907 if [ -z "$logrotate_filename" ] ; then
1908 logrotate_filename="clamav-unofficial-sigs"
1910 if [ -z "$man_dir" ] ; then
1911 man_dir="/usr/share/man/man8"
1913 shopt -s extglob; man_dir="${man_dir%%+(/)}"
1914 if [ -z "$man_filename" ] ; then
1915 man_filename="clamav-unofficial-sigs.8"
1917 if [ -z "$man_log_file_full_path" ] ; then
1918 man_log_file_full_path="${log_file_path}/${log_file_name}"
1920 # dont assign , but remove trailing /
1921 shopt -s extglob; clam_dbs="${clam_dbs%%+(/)}"
1923 # Force wget over curl.
1924 if [ ! -z "$wget_bin" ] && [ "$force_wget" == "yes" ] ; then
1925 xshok_pretty_echo_and_log "NOTICE: Forcing wget"
1930 # Check default Binaries & Commands are defined
1931 if [ "$reload_dbs" == "yes" ] ; then
1932 if [ -z "$clamd_reload_opt" ] ; then
1933 xshok_pretty_echo_and_log "ERROR: Missing clamd_reload_opt"
1937 if [ -z "$uname_bin" ] ; then
1938 xshok_pretty_echo_and_log "ERROR: uname (uname_bin) not found"
1941 if [ -z "$clamscan_bin" ] ; then
1942 if [ "${1}" != "--remove-script" ] ; then
1943 xshok_pretty_echo_and_log "ERROR: clamscan binary (clamscan_bin) not found"
1947 if [ -z "$rsync_bin" ] ; then
1948 xshok_pretty_echo_and_log "ERROR: rsync binary (rsync_bin) not found"
1951 if [ -z "$curl_bin" ] ; then
1952 if [ -z "$wget_bin" ] ; then
1953 xshok_pretty_echo_and_log "ERROR: wget and curl binaries not found, script requires either wget or curl"
1957 # Check if GPG is enabled and the binary is found
1958 if [ "$enable_gpg" == "yes" ] ; then
1959 if [ -z "$gpg_bin" ] ; then
1960 if [ -x /opt/csw/bin/gpg ] ; then
1961 gpg_bin="/opt/csw/bin/gpg"
1963 gpg_bin="$(command -v gpg 2> /dev/null)"
1965 if [ -z "$gpg_bin" ] ; then
1966 gpg_bin="$(command -v gpg2 2> /dev/null)"
1969 if [ -z "$gpg_bin" ] ; then
1972 if [ ! -x "$gpg_bin" ] ; then
1976 if [ "$enable_gpg" != "yes" ] ; then
1977 xshok_pretty_echo_and_log "NOTICE: GnuPG / signature verification disabled"
1979 # Check default directories are defined
1980 if [ -z "$work_dir" ] ; then
1981 xshok_pretty_echo_and_log "ERROR: working directory (work_dir) not defined"
1984 if [ -z "$clam_dbs" ] ; then
1985 xshok_pretty_echo_and_log "ERROR: clam database directory (clam_dbs) not defined"
1988 # Check default directories are writable
1989 if [ -e "$work_dir" ] ; then
1990 if [ ! -w "$work_dir" ] ; then
1991 xshok_pretty_echo_and_log "ERROR: working directory (work_dir) not writable ${work_dir}"
1995 if [ ! -w "$clam_dbs" ] ; then
1996 xshok_pretty_echo_and_log "ERROR: clam database directory (clam_dbs) not writable ${clam_dbs}"
2000 # Reset the update timers to force a full update.
2001 if [ "$force_updates" == "yes" ] ; then
2002 xshok_pretty_echo_and_log "NOTICE: forcing updates"
2003 sanesecurity_update_hours="0"
2004 securiteinfo_update_hours="0"
2005 linuxmalwaredetect_update_hours="0"
2006 malwarepatrol_update_hours="0"
2007 yararulesproject_update_hours="0"
2008 additional_update_hours="0"
2011 # Enable pid file to prevent issues with multiple instances
2012 # opted not to use flock as it appears to have issues with some systems
2013 if [ "$enable_locking" == "yes" ] ; then
2014 xshok_mkdir_ownership "$work_dir_pid"
2015 pid_file_fullpath="$work_dir_pid/clamav-unofficial-sigs.pid"
2016 if [ -f "$pid_file_fullpath" ] ; then
2017 pid_file_pid="$(cat "$pid_file_fullpath")"
2018 if ps -p "$pid_file_pid" > /dev/null 2>&1 ; then
2019 xshok_pretty_echo_and_log "ERROR: Only one instance can run at the same time."
2022 xshok_create_pid_file "$pid_file_fullpath"
2025 xshok_create_pid_file "$pid_file_fullpath"
2027 # Run this wehen the script exits
2028 trap -- "rm -f $pid_file_fullpath" EXIT
2031 # Verify the clam_user and clam_group actually exists on the system
2032 if ! xshok_user_group_exists "${clam_user}" "${clam_group}" ; then
2033 xshok_pretty_echo_and_log "ERROR: Either the user: ${clam_user} and/or group: ${clam_group} does not exist on the system."
2037 # If the local rsync client supports the "--no-motd" flag, then enable it.
2038 if $rsync_bin --help | $grep_bin -q "no-motd" > /dev/null ; then
2042 # If the local rsync client supports the "--contimeout" flag, then enable it.
2043 if $rsync_bin --help | $grep_bin -q "contimeout" > /dev/null ; then
2044 connect_timeout="--contimeout=${rsync_connect_timeout}"
2047 if [ "$debug" == "yes" ] ; then
2048 downloader_debug="yes"
2049 clamscan_debug="yes"
2054 # Show clamscan errors
2055 if [ "$clamscan_debug" == "yes" ] ; then
2061 if [ "$curl_debug" == "yes" ] ; then
2067 if [ "$wget_debug" == "yes" ] ; then
2073 if [ "$rsync_debug" == "yes" ] ; then
2079 # Silence wget output and only report errors - useful if script is run via cron.
2080 if [ "$downloader_silence" == "yes" ] && [ "$downloader_debug" != "yes" ] ; then
2081 wget_output_level="--quiet"
2082 curl_output_level="--silent --show-error"
2084 wget_output_level="--no-verbose"
2085 curl_output_level=""
2088 # Silence rsync output and only report errors - useful if script is run via cron.
2089 if [ "$rsync_silence" == "yes" ] && [ "$rsync_debug" != "yes" ] ; then
2090 rsync_output_level="--quiet"
2092 rsync_output_level="--progress"
2095 # Suppress ssl warnings
2096 if [ "$downloader_ignore_ssl" == "yes" ] ; then
2097 wget_insecure="--no-check-certificate"
2098 curl_insecure="--insecure"
2104 # Set the script to 755 permissions
2105 if xshok_is_root ; then
2106 if [ "$setmode" == "yes" ] ; then
2107 if [ ! -x "${this_script_path}/${this_script_name}" ] ; then
2108 chmod 755 "${this_script_path}/${this_script_name}"
2109 xshok_pretty_echo_and_log "Fixing permission on ${this_script_path}/${this_script_name}" "="
2116 ################################################################################
2118 ################################################################################
2122 -d|--decode-sig) decode_third_party_signature_by_signature_name; exit ;;
2123 -e|--encode-string) hexadecimal_encode_entire_input_string; exit ;;
2124 -f|--encode-formatted) hexadecimal_encode_formatted_input_string; exit ;;
2125 -g|--gpg-verify) xshok_check_s2 "${2}"; gpg_verify_specific_sanesecurity_database_file "${2}"; exit ;;
2126 -i|--information) output_system_configuration_information; exit ;;
2127 -m|--make-database) make_signature_database_from_ascii_file; exit ;;
2128 -t|--test-database) xshok_check_s2 "${2}"; clamscan_integrity_test_specific_database_file "${2}"; exit ;;
2129 -o|--output-triggered) output_signatures_triggered_during_ham_directory_scan; exit ;;
2130 -w|--whitelist) add_signature_whitelist_entry "${2}"; exit ;;
2131 --check-clamav) check_clamav; exit ;;
2132 --upgrade) xshok_upgrade; exit ;;
2133 --install-all) install_cron; install_logrotate; install_man; exit ;;
2134 --install-cron) install_cron; exit ;;
2135 --install-logrotate) install_logrotate; exit ;;
2136 --install-man) install_man; exit ;;
2137 --remove-script) remove_script; exit ;;
2142 xshok_pretty_echo_and_log "Preparing Databases" "="
2144 # Check yararule support is available
2145 if [ "$enable_yararules" == "yes" ] ; then
2146 current_clamav_version="$($clamscan_bin -V | cut -d " " -f 2 | cut -d "/" -f 1 | awk -F "." '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }')"
2147 minimum_yara_clamav_version="$(echo "$minimum_yara_clamav_version" | awk -F "." '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }')"
2148 # Check current clamav version against the minimum required version for yara support
2149 if [ "$current_clamav_version" -lt "$minimum_yara_clamav_version" ] ; then # Older
2150 yararulesproject_enabled="no"
2151 enable_yararules="no"
2152 xshok_pretty_echo_and_log "Yararules Disabled due to clamav being older than the minimum required version"
2155 yararulesproject_enabled="no"
2156 enable_yararules="no"
2159 # Generate the signature databases
2160 if [ "$sanesecurity_enabled" == "yes" ] ; then
2161 if [ -n "$sanesecurity_dbs" ] ; then
2162 if [ -n "$sanesecurity_dbs_rating" ] ; then
2163 temp_db="$(xshok_database "$sanesecurity_dbs_rating" "${sanesecurity_dbs[@]}")"
2165 temp_db="$(xshok_database "$default_dbs_rating" "${sanesecurity_dbs[@]}")"
2167 sanesecurity_dbs=( )
2168 #sanesecurity_dbs=( $temp_db )
2169 read -r -a sanesecurity_dbs <<< "$temp_db"
2172 if [ "$securiteinfo_enabled" == "yes" ] ; then
2173 if [ -n "$securiteinfo_dbs" ] ; then
2174 if [ -n "$securiteinfo_dbs_rating" ] ; then
2175 temp_db="$(xshok_database "$securiteinfo_dbs_rating" "${securiteinfo_dbs[@]}")"
2177 temp_db="$(xshok_database "$default_dbs_rating" "${securiteinfo_dbs[@]}")"
2179 securiteinfo_dbs=( )
2180 #securiteinfo_dbs=( $temp_db )
2181 read -r -a securiteinfo_dbs <<< "$temp_db"
2184 if [ "$linuxmalwaredetect_enabled" == "yes" ] ; then
2185 if [ -n "$linuxmalwaredetect_dbs" ] ; then
2186 if [ -n "$linuxmalwaredetect_dbs_rating" ] ; then
2187 temp_db="$(xshok_database "$linuxmalwaredetect_dbs_rating" "${linuxmalwaredetect_dbs[@]}")"
2189 temp_db="$(xshok_database "$default_dbs_rating" "${linuxmalwaredetect_dbs[@]}")"
2191 linuxmalwaredetect_dbs=( )
2192 #linuxmalwaredetect_dbs=( $temp_db )
2193 read -r -a linuxmalwaredetect_dbs <<< "$temp_db"
2196 if [ "$yararulesproject_enabled" == "yes" ] ; then
2197 if [ -n "$yararulesproject_dbs" ] ; then
2198 if [ -n "$yararulesproject_dbs_rating" ] ; then
2199 temp_db="$(xshok_database "$yararulesproject_dbs_rating" "${yararulesproject_dbs[@]}")"
2201 temp_db="$(xshok_database "$default_dbs_rating" "${yararulesproject_dbs[@]}")"
2203 yararulesproject_dbs=( )
2204 #yararulesproject_dbs=( $temp_db )
2205 read -r -a yararulesproject_dbs <<< "$temp_db"
2208 if [ "$urlhaus_enabled" == "yes" ] ; then
2209 if [ -n "$urlhaus_dbs" ] ; then
2210 if [ -n "$urlhaus_dbs_rating" ] ; then
2211 temp_db="$(xshok_database "$urlhaus_dbs_rating" "${urlhaus_dbs[@]}")"
2213 temp_db="$(xshok_database "$default_dbs_rating" "${urlhaus_dbs[@]}")"
2216 #urlhaus_dbs=( $temp_db )
2217 read -r -a urlhaus_dbs <<< "$temp_db"
2220 # Set the variables for MalwarePatrol
2221 if [ "$malwarepatrol_product_code" != "8" ] ; then
2222 # assumption, free product code is always 8 (non-free product code is never 8)
2223 malwarepatrol_free="no"
2225 if [ "$malwarepatrol_free" == "yes" ] ; then
2226 malwarepatrol_product_code="8"
2227 malwarepatrol_list="clamav_basic"
2229 if [ -z $malwarepatrol_list ] ; then
2230 malwarepatrol_list="clamav_basic"
2232 if [ -z $malwarepatrol_product_code ] ; then
2233 # Not sure, it may be better to return an error.
2234 malwarepatrol_product_code=8
2238 if [ $malwarepatrol_list == "clamav_basic" ] ; then
2239 malwarepatrol_db="malwarepatrol.db"
2241 malwarepatrol_db="malwarepatrol.ndb"
2243 malwarepatrol_url="${malwarepatrol_url}?receipt=${malwarepatrol_receipt_code}&product=${malwarepatrol_product_code}&list=${malwarepatrol_list}"
2245 # If "ham_dir" variable is set, then create initial whitelist files (skipped if first-time script run).
2246 test_dir="$work_dir/test"
2247 if [ -n "$ham_dir" ] && [ -d "$work_dir" ] && [ ! -d "$test_dir" ] ; then
2248 if [ -d "$ham_dir" ] ; then
2249 xshok_mkdir_ownership "$test_dir"
2250 cp -f -p "$work_dir"/*/*.ndb "$test_dir"
2251 cp -f -p "$work_dir"/*/*.db "$test_dir"
2252 $clamscan_bin --infected --no-summary -d "$test_dir" "$ham_dir"/* | command sed 's/\.UNOFFICIAL FOUND//' | awk '{print $NF}' >> "${work_dir_work_configs}/whitelist.txt"
2253 $grep_bin -h -f "${work_dir_work_configs}/whitelist.txt" "${test_dir}/*.ndb" | cut -d "*" -f 2 | sort | uniq > "${work_dir_work_configs}/whitelist.hex"
2254 $grep_bin -h -f "${work_dir_work_configs}/whitelist.txt" "${test_dir}/*.db" | cut -d "=" -f 2 | awk '{ printf("=%s\n", $1);}' | sort | uniq >> "${work_dir_work_configs}/whitelist.hex"
2255 cd "$test_dir" || exit
2256 for db_file in * ; do
2257 [[ -e ${db_file} ]] || break # Handle the case of no files
2258 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "$db_file" > "$db_file-tmp"
2259 mv -f "$db_file-tmp" "$db_file"
2260 if $clamscan_bin --quiet -d "$db_file" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
2261 if $rsync_bin -pcqt "$db_file" "$clam_dbs" ; then
2262 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
2263 if [ "$selinux_fixes" == "yes" ] ; then
2264 restorecon "${clam_dbs}/${db_file}"
2270 if [ -r "${work_dir_work_configs}/whitelist.hex" ] ; then
2271 xshok_pretty_echo_and_log "Initial HAM directory scan whitelist file created in ${work_dir_work_configs}"
2273 xshok_pretty_echo_and_log "No false-positives detected in initial HAM directory scan"
2276 xshok_pretty_echo_and_log "WARNING: Cannot locate HAM directory: ${ham_dir}"
2277 xshok_pretty_echo_and_log "Skipping initial whitelist file creation. Fix 'ham_dir' path in config file"
2281 # Check to see if the working directories have been created. If not, create them. Otherwise, ignore and proceed with script.
2282 xshok_mkdir_ownership "$work_dir"
2283 xshok_mkdir_ownership "$work_dir_securiteinfo"
2284 xshok_mkdir_ownership "$work_dir_malwarepatrol"
2285 xshok_mkdir_ownership "$work_dir_linuxmalwaredetect"
2286 xshok_mkdir_ownership "$work_dir_sanesecurity"
2287 xshok_mkdir_ownership "$work_dir_yararulesproject"
2288 xshok_mkdir_ownership "$work_dir_work_configs"
2289 xshok_mkdir_ownership "${work_dir_gpg}"
2290 xshok_mkdir_ownership "$work_dir_add"
2292 # Set secured access permissions to the GPG directory
2293 perms chmod -f 0700 "${work_dir_gpg}"
2295 if [ "$enable_gpg" == "yes" ] ; then
2296 # If we haven't done so yet, download Sanesecurity public GPG key and import to custom keyring.
2297 if [ ! -s "${work_dir_gpg}/publickey.gpg" ] ; then
2298 xshok_file_download "${work_dir_gpg}/publickey.gpg" "$sanesecurity_gpg_url"
2300 if [ "$ret" -ne 0 ] ; then
2301 xshok_pretty_echo_and_log "ALERT: Could not download Sanesecurity public GPG key"
2304 xshok_pretty_echo_and_log "Sanesecurity public GPG key successfully downloaded"
2305 rm -f -- "${work_dir_gpg}/ss-keyring.gp*"
2306 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
2307 xshok_pretty_echo_and_log "ALERT: could not import Sanesecurity public GPG key to custom keyring"
2310 chmod -f 0644 "${work_dir_gpg}/*.*"
2311 xshok_pretty_echo_and_log "Sanesecurity public GPG key successfully imported to custom keyring"
2315 # If custom keyring is missing, try to re-import Sanesecurity public GPG key.
2316 if [ ! -s "${work_dir_gpg}/ss-keyring.gpg" ] ; then
2317 rm -f -- "${work_dir_gpg}/ss-keyring.gp*"
2318 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
2319 xshok_pretty_echo_and_log "ALERT: Custom keyring MISSING or CORRUPT! Could not import Sanesecurity public GPG key to custom keyring"
2322 chmod -f 0644 "${work_dir_gpg}/*.*"
2323 xshok_pretty_echo_and_log "Sanesecurity custom keyring MISSING! GPG key successfully re-imported to custom keyring"
2328 # Database update check, time randomization section. This script now
2329 # provides support for both bash and non-bash enabled system shells.
2330 if [ "$enable_random" == "yes" ] ; then
2331 if [ -n "$RANDOM" ] ; then
2332 sleep_time="$((RANDOM * $((max_sleep_time - min_sleep_time)) / 32767 + min_sleep_time))"
2335 while [ "$sleep_time" -lt "$min_sleep_time" ] || [ "$sleep_time" -gt "$max_sleep_time" ] ; do
2336 sleep_time="$(head -n 1 /dev/urandom | cksum | awk '{print $2}')"
2339 if [ ! -t 0 ] ; then
2340 xshok_pretty_echo_and_log "$(date) - Pausing database file updates for $sleep_time seconds..."
2342 xshok_pretty_echo_and_log "$(date) - Pause complete, checking for new database files..."
2346 # Create "scan-test.txt" file for clamscan database integrity testing.
2347 if [ ! -s "${work_dir_work_configs}/scan-test.txt" ] ; then
2348 echo "This is the clamscan test file..." > "${work_dir_work_configs}/scan-test.txt"
2351 if [ -z "$git_branch" ] ; then
2355 # If rsync proxy is defined in the config file, then export it for use.
2356 if [ -n "$rsync_proxy" ] ; then
2357 RSYNC_PROXY="$rsync_proxy"
2361 # Create $current_dbsfiles containing lists of current and previously active 3rd-party databases
2362 # so that databases and/or backup files that are no longer being used can be removed.
2363 current_tmp="${work_dir_work_configs}/current-dbs.tmp"
2365 current_dbs_file="${work_dir_work_configs}/current-dbs.txt"
2367 if [ "$sanesecurity_enabled" == "yes" ] ; then
2368 # Create the Sanesecurity rsync "include" file (defines command -v files to download).
2369 sanesecurity_include_dbs="${work_dir_work_configs}/ss-include-dbs.txt"
2370 if [ -n "${sanesecurity_dbs[0]}" ] ; then
2371 rm -f -- "${sanesecurity_include_dbs}" "${work_dir_sanesecurity}/*.sha256"
2372 for db_file in "${sanesecurity_dbs[@]}" ; do
2373 echo "$db_file" >> "${sanesecurity_include_dbs}"
2374 echo "${db_file}.sig" >> "${sanesecurity_include_dbs}"
2375 echo "${work_dir_sanesecurity}/${db_file}" >> "${current_tmp}"
2376 echo "${work_dir_sanesecurity}/${db_file}.sig" >> "${current_tmp}"
2381 if [ "$securiteinfo_enabled" == "yes" ] ; then
2382 if [ -n "${securiteinfo_dbs[0]}" ] ; then
2383 for db in "${securiteinfo_dbs[@]}" ; do
2384 echo "${work_dir_securiteinfo}/${db}" >> "${current_tmp}"
2389 if [ "$linuxmalwaredetect_enabled" == "yes" ] ; then
2390 if [ -n "${linuxmalwaredetect_dbs[0]}" ] ; then
2391 for db in "${linuxmalwaredetect_dbs[@]}" ; do
2392 echo "${work_dir_linuxmalwaredetect}/${db}" >> "${current_tmp}"
2397 if [ "$malwarepatrol_enabled" == "yes" ] ; then
2398 if [ -n "$malwarepatrol_db" ] ; then
2399 echo "${work_dir_malwarepatrol}/${malwarepatrol_db}" >> "${current_tmp}"
2403 if [ "$yararulesproject_enabled" == "yes" ] ; then
2404 if [ -n "${yararulesproject_dbs[0]}" ] ; then
2405 for db in "${yararulesproject_dbs[@]}" ; do
2406 if echo "$db" | $grep_bin -q "/" ; then
2407 db="$(echo "$db" | cut -d "/" -f 2)"
2409 echo "${work_dir_yararulesproject}/${db}" >> "${current_tmp}"
2414 if [ "$additional_enabled" == "yes" ] ; then
2415 if [ -n "$additional_dbs" ] ; then
2416 for db in "${additional_dbs[@]}" ; do
2417 echo "${work_dir_add}/${db}" >> "${current_tmp}"
2422 sort "${current_tmp}" > "$current_dbs_file" 2>/dev/null
2423 rm -f "${current_tmp}"
2425 # Remove 3rd-party databases and/or backup files that are no longer being used.
2426 if [ "$remove_disabled_databases" == "yes" ] ; then
2427 previous_dbs="${work_dir_work_configs}/previous-dbs.txt"
2428 sort "$current_dbs_file" > "$previous_dbs" 2>/dev/null
2429 # Do not remove the current_dbs_file
2430 #rm -f "$current_dbs_file"
2432 db_changes="${work_dir_work_configs}/db-changes.txt"
2433 if [ ! -s "$previous_dbs" ] ; then
2434 cp -f -p "$current_dbs_file" "$previous_dbs" 2>/dev/null
2436 diff "$current_dbs_file" "$previous_dbs" 2>/dev/null | $grep_bin ">" | awk '{print $2}' > "$db_changes"
2437 if [ -r "$db_changes" ] ; then
2438 if $grep_bin -vq "bak" "$db_changes" 2>/dev/null ; then
2441 while read -r file ; do
2443 xshok_pretty_echo_and_log "Unused/Disabled file removed: ${file}"
2444 done < "$db_changes"
2448 # Create "purge.txt" file for package maintainers to support package uninstall.
2449 purge="${work_dir_work_configs}/purge.txt"
2450 cp -f -p "$current_dbs_file" "$purge"
2452 echo "${work_dir_work_configs}/current-dbs.txt"
2453 echo "${work_dir_work_configs}/db-changes.txt"
2454 echo "${work_dir_work_configs}/last-mbl-update.txt"
2455 echo "${work_dir_work_configs}/last-si-update.txt"
2456 echo "${work_dir_work_configs}/local.ign"
2457 echo "${work_dir_work_configs}/monitor-ign.txt"
2458 echo "${work_dir_work_configs}/my-whitelist.ign2"
2459 echo "${work_dir_work_configs}/tracker.txt"
2460 echo "${work_dir_work_configs}/previous-dbs.txt"
2461 echo "${work_dir_work_configs}/scan-test.txt"
2462 echo "${work_dir_work_configs}/ss-include-dbs.txt"
2463 echo "${work_dir_work_configs}/whitelist.hex"
2464 echo "${work_dir_gpg}/publickey.gpg"
2465 echo "$work_dir_gpg/secring.gpg"
2466 echo "${work_dir_gpg}/ss-keyring.gpg*"
2467 echo "$work_dir_gpg/trustdb.gpg"
2468 echo "${log_file_path}/${log_file_name}*"
2469 echo "${work_dir_work_configs}/purge.txt"
2472 # Check and save current system time since epoch for time related database downloads.
2473 # However, if unsuccessful, issue a warning that we cannot calculate times since epoch.
2474 if [ -n "${securiteinfo_dbs[0]}" ] || [ -n "$malwarepatrol_db" ] ; then
2475 current_time="$(date "+%s" 2> /dev/null)"
2476 current_time="${current_time//[^0-9]/}"
2477 current_time="$((current_time + 0))"
2478 if [ "$current_time" -le 0 ] ; then
2479 current_time="$(perl -le print+time 2> /dev/null)"
2481 if [ "$current_time" -le 0 ] ; then
2482 xshok_pretty_echo_and_log "WARNING: No support for 'date +%s' or 'perl' was not found , SecuriteInfo and MalwarePatrol updates bypassed"
2487 ################################################################
2488 # Check for Sanesecurity database & GPG signature file updates #
2489 ################################################################
2490 if [ "$sanesecurity_enabled" == "yes" ] ; then
2491 if [ -n "${sanesecurity_dbs[0]}" ] ; then
2492 if [ ${#sanesecurity_dbs} -lt 1 ] ; then
2493 xshok_pretty_echo_and_log "Failed sanesecurity_dbs config is invalid or not defined - SKIPPING"
2495 if [ -r "${work_dir_work_configs}/last-ss-update.txt" ] ; then
2496 last_sanesecurity_update="$(cat "${work_dir_work_configs}/last-ss-update.txt")"
2498 last_sanesecurity_update="0"
2501 update_interval="$((sanesecurity_update_hours * 3600))"
2502 time_interval="$((current_time - last_sanesecurity_update))"
2503 if [ "$time_interval" -ge $((update_interval - 600)) ] ; then
2504 echo "$current_time" > "${work_dir_work_configs}/last-ss-update.txt"
2505 xshok_pretty_echo_and_log "Sanesecurity Database & GPG Signature File Updates" "="
2506 xshok_pretty_echo_and_log "Checking for Sanesecurity updates..."
2507 # shellcheck disable=SC2086
2508 sanesecurity_mirror_ips="$(dig $dig_proxy +ignore +short "$sanesecurity_url")"
2509 # Add fallback to host if dig returns no records
2510 if [ ${#sanesecurity_mirror_ips} -lt 1 ] ; then
2511 # shellcheck disable=SC2086
2512 sanesecurity_mirror_ips="$(host $host_proxy -t A "$sanesecurity_url" | sed -n '/has address/{s/.*address \([^ ]*\).*/\1/;p;}')"
2515 if [ ${#sanesecurity_mirror_ips} -ge 1 ] ; then
2516 for sanesecurity_mirror_ip in $sanesecurity_mirror_ips ; do
2517 sanesecurity_mirror_name=""
2518 # shellcheck disable=SC2086
2519 sanesecurity_mirror_name="$(dig $dig_proxy +short -x "$sanesecurity_mirror_ip" | command sed 's/\.$//')"
2520 # Add fallback to host if dig returns no records
2521 if [ -z "$sanesecurity_mirror_name" ] ; then
2522 # shellcheck disable=SC2086
2523 sanesecurity_mirror_name="$(host $host_proxy "$sanesecurity_mirror_ip" | sed -n '/name pointer/{s/.*pointer \([^ ]*\).*\.$/\1/;p;}')"
2525 sanesecurity_mirror_site_info="$sanesecurity_mirror_name $sanesecurity_mirror_ip"
2526 xshok_pretty_echo_and_log "Sanesecurity mirror site used: ${sanesecurity_mirror_site_info}"
2527 # shellcheck disable=SC2086
2528 $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>&13
2530 if [ "$ret" -eq 0 ] || [ "$ret" -eq 23 ] ; then # The correct way, 23 is some files were not transfered, can be ignored and we can assume a success
2531 sanesecurity_rsync_success="1"
2532 for db_file in "${sanesecurity_dbs[@]}" ; do
2533 if ! cmp -s "${work_dir_sanesecurity}/${db_file}" "${clam_dbs}/${db_file}" ; then
2534 xshok_pretty_echo_and_log "Testing updated Sanesecurity database file: ${db_file}"
2536 if [ "$enable_gpg" == "yes" ] ; then
2537 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
2538 $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
2543 if [ "$ret" -eq 0 ] ; then
2544 test "$gpg_silence" = "no" && xshok_pretty_echo_and_log "Sanesecurity GPG Signature tested good on ${db_file} database"
2546 xshok_pretty_echo_and_log "Sanesecurity GPG Signature test FAILED on ${db_file} database - SKIPPING"
2549 if [ "$ret" -eq 0 ] ; then
2550 db_ext="${db_file#*.}"
2551 if [ -z "$ham_dir" ] || [ "$db_ext" != "ndb" ] ; then
2552 if $clamscan_bin --quiet -d "${work_dir_sanesecurity}/${db_file}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
2553 xshok_pretty_echo_and_log "Clamscan reports Sanesecurity ${db_file} database integrity tested good"
2556 xshok_pretty_echo_and_log "Clamscan reports Sanesecurity ${db_file} database integrity tested BAD"
2557 if [ "$remove_bad_database" == "yes" ] ; then
2558 if rm -f "${work_dir_sanesecurity}/${db_file}" ; then
2559 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_sanesecurity}/${db_file}"
2563 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${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>&13 ; then
2564 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
2565 if [ "$selinux_fixes" == "yes" ] ; then
2566 restorecon "${clam_dbs}/${db_file}"
2569 xshok_pretty_echo_and_log "Successfully updated Sanesecurity production database file: ${db_file}"
2570 sanesecurity_update=1
2573 xshok_pretty_echo_and_log "Failed to successfully update Sanesecurity production database file: ${db_file} - SKIPPING"
2577 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${work_dir_sanesecurity}/${db_file}" > "${test_dir}/${db_file}"
2578 $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"
2579 $grep_bin -h -f "${work_dir_work_configs}/whitelist.hex" "${test_dir}/${db_file}" | cut -d "*" -f 2 | sort | uniq >> "${work_dir_work_configs}/whitelist.hex-tmp"
2580 mv -f "${work_dir_work_configs}/whitelist.hex-tmp" "${work_dir_work_configs}/whitelist.hex"
2581 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${test_dir}/${db_file}" > "${test_dir}/${db_file}-tmp"
2582 mv -f "${test_dir}/${db_file}-tmp" "${test_dir}/${db_file}"
2583 if $clamscan_bin --quiet -d "${test_dir}/${db_file}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
2584 xshok_pretty_echo_and_log "Clamscan reports Sanesecurity ${db_file} database integrity tested good"
2587 xshok_pretty_echo_and_log "Clamscan reports Sanesecurity ${db_file} database integrity tested BAD"
2588 # DO NOT KILL THIS DB
2590 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${clam_dbs}/${db_file}" "${clam_dbs}/${db}_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "${test_dir}/${db_file}" "$clam_dbs" 2>&13 ; then
2591 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
2592 if [ "$selinux_fixes" == "yes" ] ; then
2593 restorecon "${clam_dbs}/${db_file}"
2595 xshok_pretty_echo_and_log "Successfully updated Sanesecurity production database file: ${db_file}"
2596 sanesecurity_update=1
2599 xshok_pretty_echo_and_log "Failed to successfully update Sanesecurity production database file: ${db_file} - SKIPPING"
2605 if [ ! "$sanesecurity_update" == "1" ] ; then
2606 xshok_pretty_echo_and_log "No Sanesecurity database file updates found" "-"
2612 xshok_pretty_echo_and_log "Connection to ${sanesecurity_mirror_site_info} failed - Trying next mirror site..."
2615 if [ ! "$sanesecurity_rsync_success" == "1" ] ; then
2616 xshok_pretty_echo_and_log "Access to all Sanesecurity mirror sites failed - Check for connectivity issues"
2617 xshok_pretty_echo_and_log "or signature database name(s) misspelled in the script's configuration file."
2620 xshok_pretty_echo_and_log "No Sanesecurity mirror sites found - Check for dns/connectivity issues"
2623 xshok_pretty_echo_and_log "Sanesecurity Database File Updates" "="
2624 xshok_draw_time_remaining "$((update_interval - time_interval))" "$sanesecurity_update_hours" "Sanesecurity"
2629 if [ -n "${sanesecurity_dbs[0]}" ] ; then
2630 if [ "$remove_disabled_databases" == "yes" ] ; then
2631 xshok_pretty_echo_and_log "Removing disabled Sanesecurity Database files"
2632 for db_file in "${sanesecurity_dbs[@]}" ; do
2633 if echo "$db_file" | $grep_bin -q "|" ; then
2634 db_file="${db_file%|*}"
2636 if [ -r "${work_dir_sanesecurity}/${db_file}" ] ; then
2637 xshok_pretty_echo_and_log "Removing ${work_dir_sanesecurity}/${db_file}"
2638 rm -f "${work_dir_sanesecurity}/${db_file}"
2641 if [ -r "${clam_dbs}/${db_file}" ] ; then
2642 xshok_pretty_echo_and_log "Removing ${clam_dbs}/${db_file}"
2643 rm -f "${clam_dbs}/${db_file}"
2651 ##############################################################################################################################################
2652 # Check for updated SecuriteInfo database files every set number of hours as defined in the "USER CONFIGURATION" section of this script #
2653 ##############################################################################################################################################
2654 if [ "$securiteinfo_enabled" == "yes" ] ; then
2655 if [ "$securiteinfo_authorisation_signature" != "YOUR-SIGNATURE-NUMBER" ] ; then
2656 if [ -n "${securiteinfo_dbs[0]}" ] ; then
2657 if [ ${#securiteinfo_dbs} -lt 1 ] ; then
2658 xshok_pretty_echo_and_log "Failed securiteinfo_dbs config is invalid or not defined - SKIPPING"
2660 rm -f "${work_dir_securiteinfo}/*.gz"
2661 if [ -r "${work_dir_work_configs}/last-si-update.txt" ] ; then
2662 last_securiteinfo_update="$(cat "${work_dir_work_configs}/last-si-update.txt")"
2664 last_securiteinfo_update="0"
2668 update_interval="$((securiteinfo_update_hours * 3600))"
2669 time_interval="$((current_time - last_securiteinfo_update))"
2670 if [ "$time_interval" -ge "$((update_interval - 600))" ] ; then
2671 echo "$current_time" > "${work_dir_work_configs}/last-si-update.txt"
2672 xshok_pretty_echo_and_log "SecuriteInfo Database File Updates" "="
2673 xshok_pretty_echo_and_log "Checking for SecuriteInfo updates..."
2674 securiteinfo_updates="0"
2675 for db_file in "${securiteinfo_dbs[@]}" ; do
2676 if [ "$loop" == "1" ] ; then
2677 xshok_pretty_echo_and_log "---"
2679 xshok_pretty_echo_and_log "Checking for updated SecuriteInfo database file: ${db_file}"
2680 securiteinfo_db_update="0"
2681 xshok_file_download "${work_dir_securiteinfo}/${db_file}" "${securiteinfo_url}/${securiteinfo_authorisation_signature}/${db_file}"
2683 if [ "$ret" -eq 0 ] ; then
2685 if ! cmp -s "${work_dir_securiteinfo}/${db_file}" "${clam_dbs}/${db_file}" ; then
2686 db_ext="${db_file#*.}"
2688 xshok_pretty_echo_and_log "Testing updated SecuriteInfo database file: ${db_file}"
2689 if [ -z "$ham_dir" ] || [ "$db_ext" != "ndb" ] ; then
2690 if $clamscan_bin --quiet -d "${work_dir_securiteinfo}/${db_file}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
2691 xshok_pretty_echo_and_log "Clamscan reports SecuriteInfo ${db_file} database integrity tested good"
2694 xshok_pretty_echo_and_log "Clamscan reports SecuriteInfo ${db_file} database integrity tested BAD"
2695 if [ "$remove_bad_database" == "yes" ] ; then
2696 if rm -f "${work_dir_securiteinfo}/${db_file}" ; then
2697 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_securiteinfo}/${db_file}"
2701 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${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>&13 ; then
2702 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
2703 if [ "$selinux_fixes" == "yes" ] ; then
2704 restorecon "${clam_dbs}/${db_file}"
2706 xshok_pretty_echo_and_log "Successfully updated SecuriteInfo production database file: ${db_file}"
2707 securiteinfo_updates=1
2708 securiteinfo_db_update=1
2711 xshok_pretty_echo_and_log "Failed to successfully update SecuriteInfo production database file: ${db_file} - SKIPPING"
2714 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${work_dir_securiteinfo}/${db_file}" > "${test_dir}/${db_file}"
2715 $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"
2716 $grep_bin -h -f "${work_dir_work_configs}/whitelist.txt" "${test_dir}/${db_file}" | cut -d "*" -f 2 | sort | uniq >> "${work_dir_work_configs}/whitelist.hex"
2717 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${test_dir}/${db_file}" > "${test_dir}/${db_file}-tmp"
2718 mv -f "${test_dir}/${db_file}-tmp" "${test_dir}/${db_file}"
2719 if $clamscan_bin --quiet -d "${test_dir}/${db_file}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
2720 xshok_pretty_echo_and_log "Clamscan reports SecuriteInfo ${db_file} database integrity tested good"
2723 xshok_pretty_echo_and_log "Clamscan reports SecuriteInfo ${db_file} database integrity tested BAD"
2724 rm -f "${work_dir_securiteinfo}/${db_file}"
2725 if [ "$remove_bad_database" == "yes" ] ; then
2726 if rm -f "${work_dir_securiteinfo}/${db_file}" ; then
2727 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_securiteinfo}/${db_file}"
2731 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${clam_dbs}/${db_file}" "${clam_dbs}/${db}_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "${test_dir}/${db_file}" "$clam_dbs" 2>&13 ; then
2732 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
2733 if [ "$selinux_fixes" == "yes" ] ; then
2734 restorecon "${clam_dbs}/${db_file}"
2736 xshok_pretty_echo_and_log "Successfully updated SecuriteInfo production database file: ${db_file}"
2737 securiteinfo_updates=1
2738 securiteinfo_db_update=1
2741 xshok_pretty_echo_and_log "Failed to successfully update SecuriteInfo production database file: ${db_file} - SKIPPING"
2746 xshok_pretty_echo_and_log "Failed connection to ${securiteinfo_url} - SKIPPED SecuriteInfo ${db_file} update"
2748 if [ "$securiteinfo_db_update" != "1" ] ; then
2749 xshok_pretty_echo_and_log "No updated SecuriteInfo ${db_file} database file found" "-"
2752 if [ "$securiteinfo_updates" != "1" ] ; then
2753 xshok_pretty_echo_and_log "No SecuriteInfo database file updates found" "-"
2756 xshok_pretty_echo_and_log "SecuriteInfo Database File Updates" "="
2757 xshok_draw_time_remaining "$((update_interval - time_interval))" "$securiteinfo_update_hours" "SecuriteInfo"
2763 if [ -n "$securiteinfo_dbs" ] ; then
2764 if [ "$remove_disabled_databases" == "yes" ] ; then
2765 xshok_pretty_echo_and_log "Removing disabled SecuriteInfo Database files"
2766 for db_file in "${securiteinfo_dbs[@]}" ; do
2767 if echo "$db_file" | $grep_bin -q "|" ; then
2768 db_file="${db_file%|*}"
2770 if [ -r "${work_dir_securiteinfo}/${db_file}" ] ; then
2771 xshok_pretty_echo_and_log "Removing ${work_dir_securiteinfo}/${db_file}"
2772 rm -f "${work_dir_securiteinfo}/${db_file}"
2775 if [ -r "${clam_dbs}/${db_file}" ] ; then
2776 xshok_pretty_echo_and_log "Removing ${clam_dbs}/${db_file}"
2777 rm -f "${clam_dbs}/${db_file}"
2785 ##############################################################################################################################################
2786 # Check for updated LinuxMalwareDetect database files every set number of hours as defined in the "USER CONFIGURATION" section of this script
2787 ##############################################################################################################################################
2788 if [ "$linuxmalwaredetect_enabled" == "yes" ] ; then
2789 if [ -n "${linuxmalwaredetect_dbs[0]}" ] ; then
2790 if [ ${#linuxmalwaredetect_dbs} -lt 1 ] ; then
2791 xshok_pretty_echo_and_log "Failed linuxmalwaredetect_dbs config is invalid or not defined - SKIPPING"
2793 rm -f "${work_dir_linuxmalwaredetect}/*.gz"
2794 if [ -r "${work_dir_work_configs}/last-linuxmalwaredetect-update.txt" ] ; then
2795 last_linuxmalwaredetect_update="$(cat "${work_dir_work_configs}/last-linuxmalwaredetect-update.txt")"
2797 last_linuxmalwaredetect_update="0"
2801 update_interval="$((linuxmalwaredetect_update_hours * 3600))"
2802 time_interval="$((current_time - last_linuxmalwaredetect_update))"
2803 if [ "$time_interval" -ge "$((update_interval - 600))" ] ; then
2804 echo "$current_time" > "${work_dir_work_configs}/last-linuxmalwaredetect-update.txt"
2806 xshok_pretty_echo_and_log "LinuxMalwareDetect Database File Updates" "="
2807 xshok_pretty_echo_and_log "Checking for LinuxMalwareDetect updates..."
2809 # Check for a new version
2811 if [ -n "$curl_bin" ] ; then
2812 # shellcheck disable=SC2086
2813 latest_linuxmalwaredetect_version="$($curl_bin --compressed $curl_proxy $curl_insecure $curl_output_level --connect-timeout "${downloader_connect_timeout}" --remote-time --location --retry "${downloader_tries}" --max-time "${downloader_max_time}" "$linuxmalwaredetect_version_url" 2>&11 | head -n1 | xargs)"
2815 # shellcheck disable=SC2086
2816 latest_linuxmalwaredetect_version="$($wget_bin $wget_compression $wget_proxy $wget_insecure $wget_output_level --connect-timeout="${downloader_connect_timeout}" --random-wait --tries="${downloader_tries}" --timeout="${downloader_max_time}" "$linuxmalwaredetect_version_url" -O - 2>&12 | $grep_bin "^script_version=" | head -n1 | xargs)"
2819 if [ "$latest_linuxmalwaredetect_version" ] ; then
2820 # shellcheck disable=SC2183,SC2086
2821 if [ -f "${work_dir_linuxmalwaredetect}/current_linuxmalwaredetect_version" ] ; then
2822 current_linuxmalwaredetect_version="$(head -n1 "${work_dir_linuxmalwaredetect}/current_linuxmalwaredetect_version" | xargs)"
2824 current_linuxmalwaredetect_version="-1"
2826 if [ "$latest_linuxmalwaredetect_version" != "$current_linuxmalwaredetect_version" ] ; then
2827 xshok_pretty_echo_and_log "LinuxMalwareDetect Database File Updates" "="
2832 if [ "$found_upgrade" == "yes" ] ; then
2833 xshok_file_download "${work_dir_linuxmalwaredetect}/sigpack.tgz" "${linuxmalwaredetect_sigpack_url}"
2835 if [ "$ret" -eq 0 ] ; then
2836 # shellcheck disable=SC2035
2837 $tar_bin --strip-components=1 --wildcards --overwrite -xzf "${work_dir_linuxmalwaredetect}/sigpack.tgz" --directory "${work_dir_linuxmalwaredetect}" */rfxn.*
2838 for db_file in "${linuxmalwaredetect_dbs[@]}" ; do
2839 if [ "$loop" == "1" ] ; then
2840 xshok_pretty_echo_and_log "---"
2843 if ! cmp -s "${work_dir_linuxmalwaredetect}/${db_file}" "${clam_dbs}/${db_file}" ; then
2844 db_ext="${db_file#*.}"
2846 xshok_pretty_echo_and_log "Testing updated LinuxMalwareDetect database file: ${db_file}"
2847 if [ -z "$ham_dir" ] || [ "$db_ext" != "ndb" ] ; then
2848 if $clamscan_bin --quiet -d "${work_dir_linuxmalwaredetect}/${db_file}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
2849 xshok_pretty_echo_and_log "Clamscan reports LinuxMalwareDetect ${db_file} database integrity tested good"
2852 xshok_pretty_echo_and_log "Clamscan reports LinuxMalwareDetect ${db_file} database integrity tested BAD"
2853 if [ "$remove_bad_database" == "yes" ] ; then
2854 if rm -f "${work_dir_linuxmalwaredetect}/${db_file}" ; then
2855 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_linuxmalwaredetect}/${db_file}"
2859 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${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>&13 ; then
2860 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
2861 if [ "$selinux_fixes" == "yes" ] ; then
2862 restorecon "${clam_dbs}/local.ign"
2864 xshok_pretty_echo_and_log "Successfully updated LinuxMalwareDetect production database file: ${db_file}"
2867 xshok_pretty_echo_and_log "Failed to successfully update LinuxMalwareDetect production database file: ${db_file} - SKIPPING"
2870 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${work_dir_linuxmalwaredetect}/${db_file}" > "${test_dir}/${db_file}"
2871 $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"
2872 $grep_bin -h -f "${work_dir_work_configs}/whitelist.txt" "${test_dir}/${db_file}" | cut -d "*" -f 2 | sort | uniq >> "${work_dir_work_configs}/whitelist.hex"
2873 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${test_dir}/${db_file}" > "${test_dir}/${db_file}-tmp"
2874 mv -f "${test_dir}/${db_file}-tmp" "${test_dir}/${db_file}"
2875 if $clamscan_bin --quiet -d "${test_dir}/${db_file}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
2876 xshok_pretty_echo_and_log "Clamscan reports LinuxMalwareDetect ${db_file} database integrity tested good"
2879 xshok_pretty_echo_and_log "Clamscan reports LinuxMalwareDetect ${db_file} database integrity tested BAD"
2880 if [ "$remove_bad_database" == "yes" ] ; then
2881 if rm -f "${work_dir_linuxmalwaredetect}/${db_file}" ; then
2882 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_linuxmalwaredetect}/${db_file}"
2886 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${clam_dbs}/${db_file}" "${clam_dbs}/${db}_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "${test_dir}/${db_file}" "$clam_dbs" 2>&13 ; then
2887 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
2888 if [ "$selinux_fixes" == "yes" ] ; then
2889 restorecon "${clam_dbs}/${db_file}"
2891 xshok_pretty_echo_and_log "Successfully updated LinuxMalwareDetect production database file: ${db_file}"
2894 xshok_pretty_echo_and_log "Failed to successfully update LinuxMalwareDetect production database file: ${db_file} - SKIPPING"
2900 #save the current version
2901 echo "$latest_linuxmalwaredetect_version" > "${work_dir_linuxmalwaredetect}/current_linuxmalwaredetect_version"
2904 xshok_pretty_echo_and_log "WARNING: Failed connection to ${linuxmalwaredetect_sigpack_url} - SKIPPED LinuxMalwareDetect update"
2907 xshok_pretty_echo_and_log "No LinuxMalwareDetect database file updates found" "-"
2910 xshok_pretty_echo_and_log "LinuxMalwareDetect Database File Updates" "="
2911 xshok_draw_time_remaining "$((update_interval - time_interval))" "$linuxmalwaredetect_update_hours" "linuxmalwaredetect"
2916 if [ -n "${linuxmalwaredetect_dbs[0]}" ] ; then
2917 if [ "$remove_disabled_databases" == "yes" ] ; then
2918 xshok_pretty_echo_and_log "Removing disabled LinuxMalwareDetect Database files"
2920 if [ -f "${work_dir_linuxmalwaredetect}/current_linuxmalwaredetect_version" ] ; then
2921 rm -f "${work_dir_linuxmalwaredetect}/current_linuxmalwaredetect_version"
2923 if [ -f "${work_dir_linuxmalwaredetect}/sigpack.tgz" ] ; then
2924 rm -f "${work_dir_linuxmalwaredetect}/sigpack.tgz"
2927 for db_file in "${linuxmalwaredetect_dbs[@]}" ; do
2928 if echo "$db_file" | $grep_bin -q "|" ; then
2929 db_file="${db_file%|*}"
2931 if [ -r "${work_dir_linuxmalwaredetect}/${db_file}" ] ; then
2932 xshok_pretty_echo_and_log "Removing ${work_dir_linuxmalwaredetect}/${db_file}"
2933 rm -f "${work_dir_linuxmalwaredetect}/${db_file}"
2936 if [ -r "${clam_dbs}/${db_file}" ] ; then
2937 xshok_pretty_echo_and_log "Removing ${clam_dbs}/${db_file}"
2938 rm -f "${clam_dbs}/${db_file}"
2947 #########################################################################################################################################
2948 # Download MalwarePatrol database file every set number of hours as defined in the "USER CONFIGURATION" section of this script. #
2949 ##########################################################################################################################################
2950 if [ "$malwarepatrol_enabled" == "yes" ] ; then
2951 if [ "$malwarepatrol_receipt_code" != "YOUR-RECEIPT-NUMBER" ] ; then
2952 if [ -n "${malwarepatrol_db}" ] ; then
2953 rm -f "${work_dir_malwarepatrol}/*.gz"
2954 if [ -r "${work_dir_work_configs}/last-mbl-update.txt" ] ; then
2955 last_malwarepatrol_update="$(cat "${work_dir_work_configs}/last-mbl-update.txt")"
2957 last_malwarepatrol_update="0"
2960 update_interval="$((malwarepatrol_update_hours * 3600))"
2961 time_interval="$((current_time - last_malwarepatrol_update))"
2962 if [ "$time_interval" -ge "$((update_interval - 600))" ] ; then
2963 echo "$current_time" > "${work_dir_work_configs}/last-mbl-update.txt"
2964 xshok_pretty_echo_and_log "MalwarePatrol Database File Updates" "="
2965 xshok_pretty_echo_and_log "Checking for MalwarePatrol updates..."
2966 malwarepatrol_updates="0"
2968 # Cleanup any not required database files
2969 if [ "$malwarepatrol_db" == "malwarepatrol.db" ] && [ -f "${clam_dbs}/malwarepatrol.ndb" ] ; then
2970 rm -f "${clam_dbs}/malwarepatrol.ndb";
2972 if [ "$malwarepatrol_db" == "malwarepatrol.ndb" ] && [ -f "${clam_dbs}/malwarepatrol.db" ] ; then
2973 rm -f "${clam_dbs}/malwarepatrol.db";
2976 if [ "$loop" == "1" ] ; then
2977 xshok_pretty_echo_and_log "---"
2979 xshok_pretty_echo_and_log "Checking for updated MalwarePatrol database file: ${malwarepatrol_db}"
2980 malwarepatrol_db_update="0"
2982 xshok_file_download "${work_dir_malwarepatrol}/${malwarepatrol_db}" "${malwarepatrol_url}&receipt=${malwarepatrol_receipt_code}"
2985 if [ "$ret" -eq 0 ] ; then
2987 if ! cmp -s "${work_dir_malwarepatrol}/${malwarepatrol_db}" "${clam_dbs}/${malwarepatrol_db}" ; then
2988 db_ext="${malwarepatrol_db#*.}"
2990 xshok_pretty_echo_and_log "Testing updated MalwarePatrol database file: ${malwarepatrol_db}"
2991 if [ -z "$ham_dir" ] || [ "$db_ext" != "ndb" ] ; then
2992 if $clamscan_bin --quiet -d "${work_dir_malwarepatrol}/${malwarepatrol_db}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
2993 xshok_pretty_echo_and_log "Clamscan reports MalwarePatrol ${malwarepatrol_db} database integrity tested good"
2996 xshok_pretty_echo_and_log "Clamscan reports MalwarePatrol ${malwarepatrol_db} database integrity tested BAD"
2997 if [ "$remove_bad_database" == "yes" ] ; then
2998 if rm -f "${work_dir_malwarepatrol}/${malwarepatrol_db}" ; then
2999 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_malwarepatrol}/${malwarepatrol_db}"
3003 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${clam_dbs}/${malwarepatrol_db}" "${clam_dbs}/${db}_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "${work_dir_malwarepatrol}/${malwarepatrol_db}" "$clam_dbs" 2>&13 ; then
3004 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${malwarepatrol_db}"
3005 if [ "$selinux_fixes" == "yes" ] ; then
3006 restorecon "${clam_dbs}/${malwarepatrol_db}"
3008 xshok_pretty_echo_and_log "Successfully updated MalwarePatrol production database file: ${malwarepatrol_db}"
3009 malwarepatrol_updates=1
3010 malwarepatrol_db_update=1
3013 xshok_pretty_echo_and_log "Failed to successfully update MalwarePatrol production database file: ${malwarepatrol_db} - SKIPPING"
3016 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${work_dir_malwarepatrol}/${malwarepatrol_db}" > "${test_dir}/${malwarepatrol_db}"
3017 $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"
3018 $grep_bin -h -f "${work_dir_work_configs}/whitelist.txt" "${test_dir}/${malwarepatrol_db}" | cut -d "*" -f 2 | sort | uniq >> "${work_dir_work_configs}/whitelist.hex"
3019 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${test_dir}/${malwarepatrol_db}" > "${test_dir}/${malwarepatrol_db}-tmp"
3020 mv -f "${test_dir}/${malwarepatrol_db}-tmp" "${test_dir}/${malwarepatrol_db}"
3021 if $clamscan_bin --quiet -d "${test_dir}/${malwarepatrol_db}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
3022 xshok_pretty_echo_and_log "Clamscan reports MalwarePatrol ${malwarepatrol_db} database integrity tested good"
3025 xshok_pretty_echo_and_log "Clamscan reports MalwarePatrol ${malwarepatrol_db} database integrity tested BAD"
3026 rm -f "${work_dir_malwarepatrol}/${malwarepatrol_db}"
3027 if [ "$remove_bad_database" == "yes" ] ; then
3028 if rm -f "${work_dir_malwarepatrol}/${malwarepatrol_db}" ; then
3029 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_malwarepatrol}/${malwarepatrol_db}"
3033 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${clam_dbs}/${malwarepatrol_db}" "${clam_dbs}/${db}_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "${test_dir}/${malwarepatrol_db}" "$clam_dbs" 2>&13 ; then
3034 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${malwarepatrol_db}"
3035 if [ "$selinux_fixes" == "yes" ] ; then
3036 restorecon "${clam_dbs}/${malwarepatrol_db}"
3038 xshok_pretty_echo_and_log "Successfully updated MalwarePatrol production database file: ${malwarepatrol_db}"
3039 malwarepatrol_updates=1
3040 malwarepatrol_db_update=1
3043 xshok_pretty_echo_and_log "Failed to successfully update MalwarePatrol production database file: ${malwarepatrol_db} - SKIPPING"
3048 xshok_pretty_echo_and_log "Failed connection to ${malwarepatrol_url} - SKIPPED MalwarePatrol ${malwarepatrol_db} update"
3050 if [ "$malwarepatrol_db_update" != "1" ] ; then
3051 xshok_pretty_echo_and_log "No updated MalwarePatrol ${malwarepatrol_db} database file found" "-"
3053 if [ "$malwarepatrol_updates" != "1" ] ; then
3054 xshok_pretty_echo_and_log "No MalwarePatrol database file updates found" "-"
3057 xshok_pretty_echo_and_log "MalwarePatrol Database File Updates" "="
3058 xshok_draw_time_remaining "$((update_interval - time_interval))" "$malwarepatrol_update_hours" "malwarepatrol"
3063 if [ -n "$malwarepatrol_dbs" ] ; then
3064 if [ "$remove_disabled_databases" == "yes" ] ; then
3065 xshok_pretty_echo_and_log "Removing disabled MalwarePatrol Database files"
3066 if [ -r "${work_dir_malwarepatrol}/${malwarepatrol_db}" ] ; then
3067 xshok_pretty_echo_and_log "Removing ${work_dir_malwarepatrol}/${malwarepatrol_db}"
3068 rm -f "${work_dir_malwarepatrol}/${malwarepatrol_db}"
3071 if [ -r "${clam_dbs}/${malwarepatrol_db}" ] ; then
3072 xshok_pretty_echo_and_log "Removing ${clam_dbs}/${malwarepatrol_db}"
3073 rm -f "${clam_dbs}/${malwarepatrol_db}"
3080 ##############################################################################################################################################
3081 # Check for updated urlhaus database files every set number of hours as defined in the "USER CONFIGURATION" section of this script
3082 ##############################################################################################################################################
3083 if [ "$urlhaus_enabled" == "yes" ] ; then
3084 if [ -n "${urlhaus_dbs[0]}" ] ; then
3085 if [ ${#urlhaus_dbs} -lt 1 ] ; then
3086 xshok_pretty_echo_and_log "Failed urlhaus_dbs config is invalid or not defined - SKIPPING"
3088 rm -f "${work_dir_urlhaus}/*.gz"
3089 if [ -r "${work_dir_work_configs}/last-urlhaus-update.txt" ] ; then
3090 last_urlhaus_update="$(cat "${work_dir_work_configs}/last-urlhaus-update.txt")"
3092 last_urlhaus_update="0"
3096 update_interval="$((urlhaus_update_hours * 3600))"
3097 time_interval="$((current_time - last_urlhaus_update))"
3098 if [ "$time_interval" -ge "$((update_interval - 600))" ] ; then
3099 echo "$current_time" > "${work_dir_work_configs}/last-urlhaus-update.txt"
3101 xshok_pretty_echo_and_log "Yara-Rules Database File Updates" "="
3102 xshok_pretty_echo_and_log "Checking for urlhaus updates..."
3104 for db_file in "${urlhaus_dbs[@]}" ; do
3105 if echo "$db_file" | $grep_bin -q "/" ; then
3106 yr_dir="/$(echo "$db_file" | cut -d "/" -f 1)"
3107 db_file="$(echo "$db_file" | cut -d "/" -f 2)"
3110 if [ "$loop" == "1" ] ; then
3111 xshok_pretty_echo_and_log "---"
3113 xshok_pretty_echo_and_log "Checking for updated urlhaus database file: ${db_file}"
3114 urlhaus_db_update="0"
3115 if xshok_file_download "${work_dir_urlhaus}/${db_file}" "${urlhaus_url}/${db_file}" ; then
3117 if ! cmp -s "${work_dir_urlhaus}/${db_file}" "${clam_dbs}/${db_file}" ; then
3118 db_ext="${db_file#*.}"
3119 xshok_pretty_echo_and_log "Testing updated urlhaus database file: ${db_file}"
3120 if [ -z "$ham_dir" ] || [ "$db_ext" != "ndb" ] ; then
3121 if $clamscan_bin --quiet -d "${work_dir_urlhaus}/${db_file}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
3122 xshok_pretty_echo_and_log "Clamscan reports urlhaus ${db_file} database integrity tested good"
3125 xshok_pretty_echo_and_log "Clamscan reports urlhaus ${db_file} database integrity tested BAD"
3126 if [ "$remove_bad_database" == "yes" ] ; then
3127 if rm -f "${work_dir_urlhaus}/${db_file}" ; then
3128 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_urlhaus}/${db_file}"
3132 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${clam_dbs}/${db_file}" "${clam_dbs}/${db}_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "${work_dir_urlhaus}/${db_file}" "$clam_dbs" 2>&13 ; then
3133 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
3134 if [ "$selinux_fixes" == "yes" ] ; then
3135 restorecon "${clam_dbs}/${db_file}"
3137 xshok_pretty_echo_and_log "Successfully updated urlhaus production database file: ${db_file}"
3142 xshok_pretty_echo_and_log "Failed to successfully update urlhaus production database file: ${db_file} - SKIPPING"
3145 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${work_dir_urlhaus}/${db_file}" > "${test_dir}/${db_file}"
3146 $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"
3147 $grep_bin -h -f "${work_dir_work_configs}/whitelist.txt" "${test_dir}/${db_file}" | cut -d "*" -f 2 | sort | uniq >> "${work_dir_work_configs}/whitelist.hex"
3148 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${test_dir}/${db_file}" > "${test_dir}/${db_file}-tmp"
3149 mv -f "${test_dir}/${db_file}-tmp" "${test_dir}/${db_file}"
3150 if $clamscan_bin --quiet -d "${test_dir}/${db_file}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
3151 xshok_pretty_echo_and_log "Clamscan reports urlhaus ${db_file} database integrity tested good"
3154 xshok_pretty_echo_and_log "Clamscan reports urlhaus ${db_file} database integrity tested BAD"
3155 if [ "$remove_bad_database" == "yes" ] ; then
3156 if rm -f "${work_dir_urlhaus}/${db_file}" ; then
3157 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_urlhaus}/${db_file}"
3161 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${clam_dbs}/${db_file}" "${clam_dbs}/${db}_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "${test_dir}/${db_file}" "$clam_dbs" 2>&13 ; then
3162 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
3163 if [ "$selinux_fixes" == "yes" ] ; then
3164 restorecon "${clam_dbs}/${db_file}"
3166 xshok_pretty_echo_and_log "Successfully updated urlhaus production database file: ${db_file}"
3171 xshok_pretty_echo_and_log "Failed to successfully update urlhaus production database file: ${db_file} - SKIPPING"
3177 xshok_pretty_echo_and_log "WARNING: Failed connection to $urlhaus_url - SKIPPED urlhaus ${db_file} update"
3179 if [ "$urlhaus_db_update" != "1" ] ; then
3180 xshok_pretty_echo_and_log "No updated urlhaus ${db_file} database file found"
3183 if [ "$urlhaus_updates" != "1" ] ; then
3184 xshok_pretty_echo_and_log "No urlhaus database file updates found" "-"
3188 xshok_pretty_echo_and_log "Yara-Rules Database File Updates" "="
3189 xshok_draw_time_remaining "$((update_interval - time_interval))" "$urlhaus_update_hours" "urlhaus"
3194 if [ -n "${urlhaus_dbs[0]}" ] ; then
3195 if [ "$remove_disabled_databases" == "yes" ] ; then
3196 xshok_pretty_echo_and_log "Removing disabled urlhaus Database files"
3197 for db_file in "${urlhaus_dbs[@]}" ; do
3198 if echo "$db_file" | $grep_bin -q "/" ; then
3199 db_file="$(echo "$db_file" | cut -d "/" -f 2)"
3201 if echo "$db_file" | $grep_bin -q "|" ; then
3202 db_file="${db_file%|*}"
3204 if [ -r "${work_dir_urlhaus}/${db_file}" ] ; then
3205 rm -f "${work_dir_urlhaus}/${db_file}"
3208 if [ -r "${clam_dbs}/${db_file}" ] ; then
3209 rm -f "${clam_dbs}/${db_file}"
3217 ##############################################################################################################################################
3218 # Check for updated yararulesproject database files every set number of hours as defined in the "USER CONFIGURATION" section of this script
3219 ##############################################################################################################################################
3220 if [ "$yararulesproject_enabled" == "yes" ] ; then
3221 if [ -n "${yararulesproject_dbs[0]}" ] ; then
3222 if [ ${#yararulesproject_dbs} -lt 1 ] ; then
3223 xshok_pretty_echo_and_log "Failed yararulesproject_dbs config is invalid or not defined - SKIPPING"
3225 rm -f "${work_dir_yararulesproject}/*.gz"
3226 if [ -r "${work_dir_work_configs}/last-yararulesproject-update.txt" ] ; then
3227 last_yararulesproject_update="$(cat "${work_dir_work_configs}/last-yararulesproject-update.txt")"
3229 last_yararulesproject_update="0"
3233 update_interval="$((yararulesproject_update_hours * 3600))"
3234 time_interval="$((current_time - last_yararulesproject_update))"
3235 if [ "$time_interval" -ge "$((update_interval - 600))" ] ; then
3236 echo "$current_time" > "${work_dir_work_configs}/last-yararulesproject-update.txt"
3238 xshok_pretty_echo_and_log "Yara-Rules Database File Updates" "="
3239 xshok_pretty_echo_and_log "Checking for yararulesproject updates..."
3240 yararulesproject_updates="0"
3241 for db_file in "${yararulesproject_dbs[@]}" ; do
3242 if echo "$db_file" | $grep_bin -q "/" ; then
3243 yr_dir="/$(echo "$db_file" | cut -d "/" -f 1)"
3244 db_file="$(echo "$db_file" | cut -d "/" -f 2)"
3247 if [ "$loop" == "1" ] ; then
3248 xshok_pretty_echo_and_log "---"
3250 xshok_pretty_echo_and_log "Checking for updated yararulesproject database file: ${db_file}"
3251 yararulesproject_db_update="0"
3252 if xshok_file_download "${work_dir_yararulesproject}/${db_file}" "$yararulesproject_url/$yr_dir/${db_file}" ; then
3254 if ! cmp -s "${work_dir_yararulesproject}/${db_file}" "${clam_dbs}/${db_file}" ; then
3255 db_ext="${db_file#*.}"
3256 xshok_pretty_echo_and_log "Testing updated yararulesproject database file: ${db_file}"
3257 if [ -z "$ham_dir" ] || [ "$db_ext" != "ndb" ] ; then
3258 if $clamscan_bin --quiet -d "${work_dir_yararulesproject}/${db_file}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
3259 xshok_pretty_echo_and_log "Clamscan reports yararulesproject ${db_file} database integrity tested good"
3262 xshok_pretty_echo_and_log "Clamscan reports yararulesproject ${db_file} database integrity tested BAD"
3263 if [ "$remove_bad_database" == "yes" ] ; then
3264 if rm -f "${work_dir_yararulesproject}/${db_file}" ; then
3265 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_yararulesproject}/${db_file}"
3269 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${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>&13 ; then
3270 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
3271 if [ "$selinux_fixes" == "yes" ] ; then
3272 restorecon "${clam_dbs}/${db_file}"
3274 xshok_pretty_echo_and_log "Successfully updated yararulesproject production database file: ${db_file}"
3275 yararulesproject_updates=1
3276 yararulesproject_db_update=1
3279 xshok_pretty_echo_and_log "Failed to successfully update yararulesproject production database file: ${db_file} - SKIPPING"
3282 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${work_dir_yararulesproject}/${db_file}" > "${test_dir}/${db_file}"
3283 $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"
3284 $grep_bin -h -f "${work_dir_work_configs}/whitelist.txt" "${test_dir}/${db_file}" | cut -d "*" -f 2 | sort | uniq >> "${work_dir_work_configs}/whitelist.hex"
3285 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${test_dir}/${db_file}" > "${test_dir}/${db_file}-tmp"
3286 mv -f "${test_dir}/${db_file}-tmp" "${test_dir}/${db_file}"
3287 if $clamscan_bin --quiet -d "${test_dir}/${db_file}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
3288 xshok_pretty_echo_and_log "Clamscan reports yararulesproject ${db_file} database integrity tested good"
3291 xshok_pretty_echo_and_log "Clamscan reports yararulesproject ${db_file} database integrity tested BAD"
3292 if [ "$remove_bad_database" == "yes" ] ; then
3293 if rm -f "${work_dir_yararulesproject}/${db_file}" ; then
3294 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_yararulesproject}/${db_file}"
3298 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${clam_dbs}/${db_file}" "${clam_dbs}/${db}_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "${test_dir}/${db_file}" "$clam_dbs" 2>&13 ; then
3299 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
3300 if [ "$selinux_fixes" == "yes" ] ; then
3301 restorecon "${clam_dbs}/${db_file}"
3303 xshok_pretty_echo_and_log "Successfully updated yararulesproject production database file: ${db_file}"
3304 yararulesproject_updates=1
3305 yararulesproject_db_update=1
3308 xshok_pretty_echo_and_log "Failed to successfully update yararulesproject production database file: ${db_file} - SKIPPING"
3314 xshok_pretty_echo_and_log "WARNING: Failed connection to $yararulesproject_url - SKIPPED yararulesproject ${db_file} update"
3316 if [ "$yararulesproject_db_update" != "1" ] ; then
3317 xshok_pretty_echo_and_log "No updated yararulesproject ${db_file} database file found"
3320 if [ "$yararulesproject_updates" != "1" ] ; then
3321 xshok_pretty_echo_and_log "No yararulesproject database file updates found" "-"
3325 xshok_pretty_echo_and_log "Yara-Rules Database File Updates" "="
3326 xshok_draw_time_remaining "$((update_interval - time_interval))" "$yararulesproject_update_hours" "yararulesproject"
3331 if [ -n "${yararulesproject_dbs[0]}" ] ; then
3332 if [ "$remove_disabled_databases" == "yes" ] ; then
3333 xshok_pretty_echo_and_log "Removing disabled yararulesproject Database files"
3334 for db_file in "${yararulesproject_dbs[@]}" ; do
3335 if echo "$db_file" | $grep_bin -q "/" ; then
3336 db_file="$(echo "$db_file" | cut -d "/" -f 2)"
3338 if echo "$db_file" | $grep_bin -q "|" ; then
3339 db_file="${db_file%|*}"
3341 if [ -r "${work_dir_yararulesproject}/${db_file}" ] ; then
3342 rm -f "${work_dir_yararulesproject}/${db_file}"
3345 if [ -r "${clam_dbs}/${db_file}" ] ; then
3346 rm -f "${clam_dbs}/${db_file}"
3354 ##############################################################################################################################################
3355 # Check for updated additional database files every set number of hours as defined in the "USER CONFIGURATION" section of this script
3356 ##############################################################################################################################################
3357 if [ "$additional_enabled" == "yes" ] ; then
3358 if [ -n "$additional_dbs" ] ; then
3359 if [ ${#additional_dbs} -lt 1 ] ; then
3360 xshok_pretty_echo_and_log "Failed additional_dbs config is invalid or not defined - SKIPPING"
3362 rm -f "${work_dir_add}/*.gz"
3363 if [ -r "${work_dir_work_configs}/last-additional-update.txt" ] ; then
3364 last_additional_update="$(cat "${work_dir_work_configs}/last-additional-update.txt")"
3366 last_additional_update="0"
3370 update_interval="$((additional_update_hours * 3600))"
3371 time_interval="$((current_time - last_additional_update))"
3372 if [ "$time_interval" -ge "$((update_interval - 600))" ] ; then
3373 echo "$current_time" > "${work_dir_work_configs}/last-additional-update.txt"
3375 xshok_pretty_echo_and_log "Additional Database File Updates" "="
3376 xshok_pretty_echo_and_log "Checking for additional updates..."
3377 additional_updates="0"
3378 for db_url in "${additional_dbs[@]}" ; do
3379 # Left for future dir manipulation
3380 # if echo "$db_file" | $grep_bin -q "/" ; then
3381 # add_dir="/$(echo "$db_file" | cut -d "/" -f 1)"
3382 # db_file="$(echo "$db_file" | cut -d "/" -f 2)"
3387 #cleanup any leading and trailing whitespace.
3388 db_url="$(echo -e "$db_url" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
3390 db_file="$(basename "$db_url")"
3392 if [ "$loop" == "1" ] ; then
3393 xshok_pretty_echo_and_log "---"
3395 xshok_pretty_echo_and_log "Checking for updated additional database file: ${db_file}"
3397 additional_db_update="0"
3399 if [ "${db_url%:*}" == "rsync" ] ; then
3400 # shellcheck disable=SC2086
3401 $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>&13
3404 xshok_file_download "${work_dir_add}/${db_file}" "$db_url"
3408 # This needs enhancement for rsync, as it will only work with single files...
3409 # Maybe better to process each file inside work_dir_add in its own for loop.
3410 if [ "$ret" -eq 0 ] ; then
3412 if ! cmp -s "${work_dir_add}/${db_file}" "${clam_dbs}/${db_file}" ; then
3413 db_ext="${db_file#*.}"
3414 xshok_pretty_echo_and_log "Testing updated additional database file: ${db_file}"
3415 if [ -z "$ham_dir" ] || [ "$db_ext" != "ndb" ] ; then
3416 if $clamscan_bin --quiet -d "${work_dir_add}/${db_file}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
3417 xshok_pretty_echo_and_log "Clamscan reports additional ${db_file} database integrity tested good"
3420 xshok_pretty_echo_and_log "Clamscan reports additional ${db_file} database integrity tested BAD"
3421 if [ "$remove_bad_database" == "yes" ] ; then
3422 if rm -f "${work_dir_add}/${db_file}" ; then
3423 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_add}/${db_file}"
3427 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${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>&13 ; then
3428 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
3429 if [ "$selinux_fixes" == "yes" ] ; then
3430 restorecon "${clam_dbs}/${db_file}"
3432 xshok_pretty_echo_and_log "Successfully updated additional production database file: ${db_file}"
3433 additional_updates=1
3434 additional_db_update=1
3437 xshok_pretty_echo_and_log "Failed to successfully update additional production database file: ${db_file} - SKIPPING"
3440 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${work_dir_add}/${db_file}" > "${test_dir}/${db_file}"
3441 $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"
3442 if [[ "${work_dir_add}/${db_file}" == *.db ]] ; then
3443 $grep_bin -h -f "${work_dir_work_configs}/whitelist.hex" "${test_dir}/${db_file}" | cut -d "=" -f 2 | awk '{ printf("=%s\n", $1);}' |sort | uniq >> "${work_dir_work_configs}/whitelist.hex-tmp"
3444 mv -f "${work_dir_work_configs}/whitelist.hex-tmp" "${work_dir_work_configs}/whitelist.hex"
3446 $grep_bin -h -f "${work_dir_work_configs}/whitelist.hex" "${test_dir}/${db_file}" | cut -d "=" -f 2 | sort | uniq >> "${work_dir_work_configs}/whitelist.hex-tmp"
3447 mv -f "${work_dir_work_configs}/whitelist.hex-tmp" "${work_dir_work_configs}/whitelist.hex"
3449 $grep_bin -h -v -f "${work_dir_work_configs}/whitelist.hex" "${test_dir}/${db_file}" > "${test_dir}/${db_file}-tmp"
3450 mv -f "${test_dir}/${db_file}-tmp" "${test_dir}/${db_file}"
3451 if $clamscan_bin --quiet -d "${test_dir}/${db_file}" "${work_dir_work_configs}/scan-test.txt" 2>&10 ; then
3452 xshok_pretty_echo_and_log "Clamscan reports additional ${db_file} database integrity tested good"
3455 xshok_pretty_echo_and_log "Clamscan reports additional ${db_file} database integrity tested BAD"
3456 if [ "$remove_bad_database" == "yes" ] ; then
3457 if rm -f "${work_dir_add}/${db_file}" ; then
3458 xshok_pretty_echo_and_log "Removed invalid database: ${work_dir_add}/${db_file}"
3462 fi && (test "$keep_db_backup" = "yes" && cp -f -p "${clam_dbs}/${db_file}" "${clam_dbs}/${db}_file-bak" 2>/dev/null ; true) && if $rsync_bin -pcqt "${test_dir}/${db_file}" "$clam_dbs" 2>&13 ; then
3463 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/${db_file}"
3464 if [ "$selinux_fixes" == "yes" ] ; then
3465 restorecon "${clam_dbs}/${db_file}"
3467 xshok_pretty_echo_and_log "Successfully updated additional production database file: ${db_file}"
3468 additional_updates=1
3469 additional_db_update=1
3472 xshok_pretty_echo_and_log "Failed to successfully update additional production database file: ${db_file} - SKIPPING"
3477 xshok_pretty_echo_and_log "WARNING: Failed connection to ${db_url} - SKIPPED additional ${db_file} update"
3479 if [ "$additional_db_update" != "1" ] ; then
3480 xshok_pretty_echo_and_log "No updated additional ${db_file} database file found"
3483 if [ "$additional_updates" != "1" ] ; then
3484 xshok_pretty_echo_and_log "No additional database file updates found" "-"
3487 xshok_pretty_echo_and_log "Additional Database File Updates" "="
3488 xshok_draw_time_remaining "$((update_interval - time_interval))" "$additional_update_hours" "additionaldatabaseupdate"
3493 if [ -n "$additional_dbs" ] ; then
3494 if [ "$remove_disabled_databases" == "yes" ] ; then
3495 xshok_pretty_echo_and_log "Removing disabled additional Database files"
3496 for db_file in "${additional_dbs[@]}" ; do
3497 if echo "$db_file" | $grep_bin -q "/" ; then
3498 db_file="$(echo "$db_file" | cut -d "/" -f 2)"
3500 if [ -r "${work_dir_add}/${db_file}" ] ; then
3501 rm -f "${work_dir_add}/${db_file}"
3504 if [ -r "${clam_dbs}/${db_file}" ] ; then
3505 rm -f "${clam_dbs}/${db_file}"
3513 ###################################################
3514 # Generate whitelists
3515 ###################################################
3516 # Check to see if the local.ign file exists, and if it does, check to see if any of the script
3517 # added bypass entries can be removed due to offending signature modifications or removals.
3518 if [ -r "${clam_dbs}/local.ign" ] && [ -s "${work_dir_work_configs}/monitor-ign.txt" ] ; then
3520 cd "$clam_dbs" || exit
3521 cp -f -p local.ign "${work_dir_work_configs}/local.ign"
3522 cp -f -p "${work_dir_work_configs}/monitor-ign.txt" "${work_dir_work_configs}/monitor-ign-old.txt"
3524 xshok_pretty_echo_and_log "" "=" "80"
3525 while read -r entry ; do
3526 sig_file="$(echo "$entry" | tr -d "\\r" | awk -F ":" '{print $1}')"
3527 sig_hex="$(echo "$entry" | tr -d "\\r" | awk -F ":" '{print $NF}')"
3528 sig_name_old="$(echo "$entry" | tr -d "\\r" | awk -F ":" '{print $3}')"
3529 sig_ign_old="$($grep_bin ":$sig_name_old" "${work_dir_work_configs}/local.ign")"
3530 sig_old="$(echo "$entry" | tr -d "\\r" | cut -d ":" -f 3-)"
3531 sig_new="$($grep_bin -hwF ":$sig_hex" "$sig_file" | tr -d "\\r" 2>/dev/null)"
3532 sig_mon_new="$($grep_bin -HwF -n ":$sig_hex" "$sig_file" | tr -d "\\r")"
3533 if [ -n "$sig_new" ] ; then
3534 if [ "$sig_old" != "$sig_new" ] || [ "$entry" != "$sig_mon_new" ] ; then
3535 sig_name_new="$(echo "$sig_new" | tr -d "\\r" | awk -F ":" '{print $1}')"
3536 sig_ign_new="$(echo "$sig_mon_new" | cut -d ":" -f 1-3)"
3537 perl -i -ne "print unless /$sig_ign_old/" "${work_dir_work_configs}/monitor-ign.txt"
3538 echo "$sig_mon_new" >> "${work_dir_work_configs}/monitor-ign.txt"
3539 perl -p -i -e "s/$sig_ign_old/$sig_ign_new/" "${work_dir_work_configs}/local.ign"
3540 xshok_pretty_echo_and_log "${sig_name_old} hexadecimal signature is unchanged, however signature name and/or line placement"
3541 xshok_pretty_echo_and_log "in ${sig_file} has changed to ${sig_name_new} - updated local.ign to reflect this change."
3545 perl -i -ne "print unless /$sig_ign_old/" "${work_dir_work_configs}/monitor-ign.txt" "${work_dir_work_configs}/local.ign"
3547 xshok_pretty_echo_and_log "${sig_name_old} signature has been removed from ${sig_file}, entry removed from local.ign."
3550 done < "${work_dir_work_configs}/monitor-ign-old.txt"
3551 if [ "$ign_updated" == "1" ] ; then
3552 if $clamscan_bin --quiet -d "${work_dir_work_configs}/local.ign" "${work_dir_work_configs}/scan-test.txt" ; then
3553 if $rsync_bin -pcqt "${work_dir_work_configs}/local.ign" "$clam_dbs" ; then
3554 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/local.ign"
3555 perms chmod -f 0644 "${clam_dbs}/local.ign" "${work_dir_work_configs}/monitor-ign.txt"
3556 if [ "$selinux_fixes" == "yes" ] ; then
3557 restorecon "${clam_dbs}/local.ign"
3561 xshok_pretty_echo_and_log "Failed to successfully update local.ign file - SKIPPING"
3564 xshok_pretty_echo_and_log "Clamscan reports local.ign database integrity is bad - SKIPPING"
3567 xshok_pretty_echo_and_log "No whitelist signature changes found in local.ign" "="
3571 # Check to see if my-whitelist.ign2 file exists, and if it does, check to see if any of the script
3572 # added whitelist entries can be removed due to offending signature modifications or removals.
3573 if [ -r "${clam_dbs}/my-whitelist.ign2" ] && [ -s "${work_dir_work_configs}/tracker.txt" ] ; then
3575 cd "$clam_dbs" || exit
3576 cp -f -p my-whitelist.ign2 "${work_dir_work_configs}/my-whitelist.ign2"
3578 xshok_pretty_echo_and_log "" "=" "80"
3580 while read -r entry ; do
3581 sig_file="$(echo "$entry" | cut -d ":" -f 1)"
3582 sig_full="$(echo "$entry" | cut -d ":" -f 2-)"
3583 sig_name="$(echo "$entry" | cut -d ":" -f 2)"
3584 if ! $grep_bin -F "$sig_full" "$sig_file" > /dev/null 2>&1 ; then
3585 perl -i -ne "print unless /$sig_name$/" "${work_dir_work_configs}/my-whitelist.ign2"
3586 perl -i -ne "print unless /:$sig_name:/" "${work_dir_work_configs}/tracker-tmp.txt"
3588 xshok_pretty_echo_and_log "${sig_name} signature no longer exists in ${sig_file}, whitelist entry removed from my-whitelist.ign2"
3591 done < "${work_dir_work_configs}/tracker.txt"
3592 if [ -f "${work_dir_work_configs}/tracker-tmp.txt" ] ; then
3593 mv -f "${work_dir_work_configs}/tracker-tmp.txt" "${work_dir_work_configs}/tracker.txt"
3597 xshok_pretty_echo_and_log "" "=" "80"
3598 if [ "$ign2_updated" == "1" ] ; then
3599 if $clamscan_bin --quiet -d "${work_dir_work_configs}/my-whitelist.ign2" "${work_dir_work_configs}/scan-test.txt" ; then
3600 if $rsync_bin -pcqt "${work_dir_work_configs}/my-whitelist.ign2" "$clam_dbs" ; then
3601 perms chown -f "${clam_user}:${clam_group}" "${clam_dbs}/my-whitelist.ign2"
3602 perms chmod -f 0644 "${clam_dbs}/my-whitelist.ign2" "${work_dir_work_configs}/tracker.txt"
3603 if [ "$selinux_fixes" == "yes" ] ; then
3604 restorecon "${clam_dbs}/my-whitelist.ign2"
3605 restorecon "${work_dir_work_configs}/tracker.txt"
3609 xshok_pretty_echo_and_log "Failed to successfully update my-whitelist.ign2 file - SKIPPING"
3612 xshok_pretty_echo_and_log "Clamscan reports my-whitelist.ign2 database integrity is bad - SKIPPING"
3615 xshok_pretty_echo_and_log "No whitelist signature changes found in my-whitelist.ign2"
3619 # Check for non-matching whitelist.hex signatures and remove them from the whitelist file (signature modified or removed).
3620 if [ -n "$ham_dir" ] ; then
3621 if [ -r "${work_dir_work_configs}/whitelist.hex" ] ; then
3622 $grep_bin -h -f "${work_dir_work_configs}/whitelist.hex" "$work_dir"/*/*.ndb | cut -d "*" -f 2 | tr -d "\\r" | sort | uniq > "${work_dir_work_configs}/whitelist.tmp"
3623 $grep_bin -h -f "${work_dir_work_configs}/whitelist.hex" "$work_dir"/*/*.db | cut -d "=" -f 2 | awk '{ printf("=%s\n", $1);}' | sort | uniq >> "${work_dir_work_configs}/whitelist.tmp"
3624 mv -f "${work_dir_work_configs}/whitelist.tmp" "${work_dir_work_configs}/whitelist.hex"
3625 rm -f "${work_dir_work_configs}/whitelist.txt"
3626 rm -f "${test_dir}/*.*"
3627 xshok_pretty_echo_and_log "WARNING: Signature(s) triggered on HAM directory scan - signature(s) removed"
3629 xshok_pretty_echo_and_log "No signatures triggered on HAM directory scan" "="
3632 # Set appropriate directory and file permissions to all production signature files
3633 # and set file access mode to 0644 on all working directory files.
3635 if [ "$setmode" == "yes" ] ; then
3636 xshok_pretty_echo_and_log "Setting permissions and ownership" "="
3637 perms chown -f -R "${clam_user}:${clam_group}" "$work_dir"
3638 if ! find "$work_dir" -type f -exec chmod -f 0644 "{}" "+" 2>/dev/null ; then
3639 if ! find "$work_dir" -type f -print0 | xargs -0 chmod -f 0644 2>/dev/null ; then
3640 find "$work_dir" -type f -exec chmod -f 0644 "{}" ";"
3644 # If enabled, set file access mode for all production signature database files to 0644.
3645 perms chown -f -R "${clam_user}:${clam_group}" "$clam_dbs"
3646 if ! find "$clam_dbs" -type f -exec chmod -f 0644 "{}" "+" 2>/dev/null ; then
3647 if ! find "$clam_dbs" -type f -print0 | xargs -0 chmod -f 0644 2>/dev/null ; then
3648 find "$clam_dbs" -type f -exec chmod -f 0644 "{}" ";"
3653 # Reload all clamd databases
3656 xshok_pretty_echo_and_log "Issue tracker : https://github.com/extremeshok/clamav-unofficial-sigs/issues" "-"
3658 if [ "$allow_update_checks" != "no" ] ; then
3660 if [ -r "${work_dir_work_configs}/last-version-check.txt" ] ; then
3661 last_version_check="$(cat "${work_dir_work_configs}/last-version-check.txt")"
3663 last_version_check="0"
3666 update_check_interval="$((update_check_hours * 3600))"
3667 time_interval="$((current_time - last_version_check))"
3668 if [ "$time_interval" -ge $((update_check_interval - 600)) ] ; then
3669 echo "$current_time" > "${work_dir_work_configs}/last-version-check.txt"
3677 # Set the permission of the log file, to fix any permission errors, this is done to fix cron errors after running the script as root.
3678 if xshok_is_root ; then
3679 if [ "$enable_log" == "yes" ] ; then
3680 # check if the file is owned by root (the current user)
3681 if [ -O "${log_file_path}/${log_file_name}" ] ; then
3682 # checks the file is writable and a file (not a symlink/link)
3683 if [ -w "${log_file_path}/${log_file_name}" ] && [ -f "${log_file_path}/${log_file_name}" ] ; then
3684 perms chown -f "${clam_user}:${clam_group}" "${log_file_path}/${log_file_name}"
3690 # And lastly we exit, Note: the exit is always on the 2nd last line