CHips L MINI SHELL

CHips L pro

Current Path : /proc/self/root/proc/2/root/usr/local/maldetect.bk15949/internals/
Upload File :
Current File : //proc/self/root/proc/2/root/usr/local/maldetect.bk15949/internals/functions

##
# Linux Malware Detect v1.6.4
#             (C) 2002-2019, R-fx Networks <proj@r-fx.org>
#             (C) 2019, Ryan MacDonald <ryan@r-fx.org>
# This program may be freely redistributed under the terms of the GNU GPL v2
##
#
lbreakifs() {
	if [ "$1" == "set" ]; then
                IFS=$(echo -en "\n\b")
	else
		unset IFS
	fi		
}

prerun() {
    
    startdir=$(pwd);
    
	if [ ! "$(whoami)" == "root" ]; then
		if [ -z "$scan_user_access" ] || [ "$scan_user_access" == "0" ]; then
			args="$@"
			if [[ "$args" =~ "modsec" ]]; then
				echo "1 maldet: OK"
				exit
			fi
			header
			echo "public scanning is currently disabled (scan_user_access=0), please contact your system administrator to enable scan_user_access in $cnffile."
			exit 1
		fi
		pub=1
		user="$(whoami)"
		quardir="$userbasedir/$user/quar"
		sessdir="$userbasedir/$user/sess"
		tmpdir="$userbasedir/$user/tmp"
		scan_tmpdir_paths=""
		hits_history="$sessdir/hits.hist"
		quar_history="$sessdir/quarantine.hist"
		clean_history="$sessdir/clean.hist"
		suspend_history="$sessdir/suspend.hist"
		monitor_scanned_history="$sessdir/monitor.scanned.hist"
		if [ ! -d "$userbasedir/$user/tmp" ]; then
			header
			echo "public scanning is enabled (scan_user_access=1) but paths do not exist, please contact your system administrator to run '$0 --mkpubpaths' or wait for cron.pub to execute in ~10 minutes."
			exit 1
		fi
		maldet_log="$userbasedir/$user/event_log"
		clamscan_log="$userbasedir/$user/clamscan_log"
                mkdir -p $quardir $sessdir $tmpdir 2> /dev/null
		chmod 711 $userbasedir 2> /dev/null
		touch $maldet_log 2> /dev/null
		chown -R ${user}.root $userbasedir/$user 2> /dev/null
		chmod 750 $userbasedir/$user $quardir $sessdir $tmpdir 2> /dev/null
		chmod 640 $maldet_log 2> /dev/null
		cd $tmpdir
	else
		echo $ver > $lmd_version_file
	fi
	
	if [ ! -d "$sigdir" ]; then
		mkdir -p $sigdir
		chmod 755 $sigdir
	fi
	if [ ! -d "$logdir" ]; then
		mkdir -p $logdir
		chmod 755 $logdir
	fi
	if [ ! -d "$tmpdir" ]; then
		mkdir -p $tmpdir
		chmod 755 $tmpdir
	else
		chmod 755 $tmpdir
	fi
	if [ ! -d "$sessdir" ]; then
		mkdir -p $sessdir
		chmod 750 $sessdir
	fi
	if [ ! -d "$quardir" ]; then
		mkdir -p $quardir
		chmod 750 $quardir
	fi
	
	if [ -z "$md5sum" ]; then
		header
		echo "could not find required binary md5sum, aborting."
		exit 1
	fi
	
	if [ -z "$od" ]; then
		header
		echo "could not find required binary od, aborting."
		exit 1
	fi
	
	if [ -z "$find" ]; then
		header
		echo "could not find required binary find, aborting."
		exit 1
	fi
	
	if [ -z "$perl" ]; then
		header
		echo "could not find required binary perl, aborting."
		exit 1
	fi
	
	if [ "$email_alert" == "1" ] && [ ! -f "$mail" ] && [ ! -f "$sendmail" ]; then
		email_alert=0
	fi
	
	if [ ! -f "$sig_user_hex_file" ]; then
		touch $sig_user_hex_file
		chmod 644 $sig_user_hex_file
	fi
	
	if [ ! -f "$sig_user_md5_file" ]; then
		touch $sig_user_md5_file
		chmod 644 $sig_user_md5_file
	fi
	
	if [ "$scan_hexfifo" == "1" ]; then
		mkfifo=`which mkfifo 2> /dev/null`
		if [ ! -f "$mkfifo" ]; then
			scan_hexfifo=0
		else
			if [ -f "$mkfifo" ] && [ ! -p "$hex_fifo_path" ]; then
				$mkfifo -m 666 $hex_fifo_path
			fi
		fi
	fi
	
	if [ "$user" == "root" ]; then
		$sed -i -e '/^$/d' $ignore_paths $ignore_sigs $ignore_inotify $ignore_file_ext
	fi

	if [ -z "$EDITOR" ]; then
		defedit=`which nano 2> /dev/null`
		if [ -z "$defedit" ]; then
			EDITOR=vi
		else
			EDITOR=nano
		fi
	fi

	if [ ! "$scan_cpunice" ]; then
		scan_cpunice=19
	fi

	if [ ! "$scan_ionice" ]; then
		scan_ionice=6
	fi
	
	if [ -f "$nice" ]; then
		nice_command="$nice -n $scan_cpunice"
	fi
	if [ -f "$ionice" ] && [ ! -d "/proc/vz" ]; then
		nice_command="$nice_command $ionice -c2 -n $scan_ionice"
	fi
	if [ -f "$cpulimit" ] && [ "$scan_cpulimit" -gt 2> /dev/null "0" ]; then
		max_cpulimit=$[$(grep -E -w processor /proc/cpuinfo -c)*100]
		if [ "$scan_cpulimit" -gt "$max_cpulimit" ]; then
			scan_cpulimit="0"
		else
			nice_command="$cpulimit -l $scan_cpulimit $nice_command"
		fi
	fi

	if [ -z "$cron_daily_scan" ]; then
		cron_daily_scan=1
	fi
}

eout() {
	msg="$1"
	stdout="$2"
	appn=maldet
	if [ ! -d "$logdir" ]; then
		mkdir -p $logdir ; chmod 700 $logdir
	fi
	if [ ! -f "$maldet_log" ]; then
		touch $maldet_log
	fi
	log_size=`$wc -l $maldet_log | awk '{print$1}'`
	if [ "$log_size" -ge "20000" ]; then
		trim=1000
		printf "%s\n" "$trim,${log_size}d" w | ed -s $maldet_log 2> /dev/null
	fi
	if [ ! "$msg" == "" ]; then
		echo "$(date +"%b %d %H:%M:%S") $(hostname -s) $appn($$): $msg" >> $maldet_log
		if [ ! -z "$stdout" ]; then
			echo "$appn($$): $msg"
		fi
	fi
}

trap_exit() {
	if [ "$svc" == "m" ]; then
		echo
		eout "{glob} monitor interrupt by user, sending kill." 1
		monitor_kill
		exit 1
	elif [ "$svc" == "a" ] || [ "$svc" == "r" ] || [ "$svc" == "f" ]; then
		echo
		gen_report
		if [ ! "$tot_hits" == "0" ]; then
			if [ "$email_ignore_clean" == "1" ] && [ ! "$tot_hits" == "$tot_cl" ]; then
				genalert file $nsess
			elif [ "$email_ignore_clean" == "0" ]; then
				genalert file $nsess
			fi
		fi
		mv $scan_session $nsess_hits 2> /dev/null
		rm -f $clamscan_results $find_results $runtime_hdb $runtime_hexstrings $runtime_ndb $scan_session $tmpdir/.find_killed.$scanid $tmpdir/.tmp* $tmpdir/.tmpf* $tmpf 2> /dev/null
		eout "{glob} scan interrupt by user, aborting scan..." 1
		eout "{scan} scan report saved, to view run: maldet --report $datestamp.$$" 1
		if [ "$quarantine_hits" == "0" ] && [ ! "$tot_hits" == "0" ]; then
			eout "{glob} quarantine is disabled! set quarantine_hits=1 in $cnffile or to quarantine results run: maldet -q $datestamp.$$" 1
		fi
		exit
	fi
}

clean_exit() {
	mv -f $scan_session $nsess_hits 2> /dev/null
	rm -f $clamscan_results $find_results $list $runtime_hdb $runtime_hexstrings $runtime_ndb $scan_session $tmpdir/.find_killed.$scanid $tmpdir/.tmp* $tmpdir/.tmpf* $tmpf 0 2> /dev/null
}

get_remote_file() {
	# $1 = URI, $2 = local service identifier, $3 boolean verbose
	get_uri="$1"
	service="$2"
	verbose="$3"
	save_path="$4"
	unset return_file
	if [ "$hscan" ]; then
		unset verbose
	fi
	if [ -z "$get_uri" ]; then
		eout "{internal} missing or invalid URI passed to get_remote_file()" 1
		break
	fi
	if [ -z "$service" ]; then
		svc="internal"
	else
		svc="$service"
	fi

	if [ -f "$curl" ] || [ -f "/usr/bin/curl" ]; then
		get_type="curl"
		if [ -z "$curl" ]; then
			get_bin="/usr/bin/curl"
		else
			get_bin="$curl"
		fi
	elif [ -f "$wget" ] || [ -f "/usr/bin/wget" ]; then
		get_type="wget"
		if [ -z "$wget" ]; then
			get_bin="/usr/bin/wget"
		else
			get_bin="$wget"
		fi
	else
		eout "{internal} could not find curl or wget binaries for remote file downloads, fatal error!"
		exit 1
	fi

	if [ "$lmd_referer" ] && [ "$get_type" == "curl" ]; then
		id="--referer ${lmd_referer}:curl"
	elif [ "$lmd_referer" ] && [ "$get_type" == "wget" ]; then
		id="--referer=${lmd_referer}:wget"
	fi

	if [ "$get_type" == "curl" ]; then
		if [ "$web_proxy" ]; then
			get_proxy_arg="-x http://$web_proxy"
		fi
		get_opts="-s $get_proxy_arg --connect-timeout $remote_uri_timeout --retry $remote_uri_retries $id"
		get_output_arg='-o'
	elif [ "$get_type" == "wget" ]; then
		if [ "$web_proxy" ]; then
			get_proxy_arg="-e http_proxy=$web_proxy -e https_proxy=$web_proxy"
		fi
		get_opts="-q $get_proxy_arg --timeout=$remote_uri_timeout --tries=$remote_uri_retries $id"
		get_output_arg='-O'
	fi

	if [ "$save_path" ]; then
		tmpf="$save_path"
	else
		tmpf="$tmpdir/.tmpf_get.${RANDOM}"
		touch $tmpf ; chmod 600 $tmpf
		get_file=`echo "$get_uri" | tr '/' '\n' | tail -n1`
	fi

	$get_bin $get_opts "$get_uri" $get_output_arg "$tmpf" || get_return=$?

	if [ ! -f "$tmpf" ] || [ ! -s "$tmpf" ]; then
		eout "{$svc} could not download $get_uri, please try again later." $verbose
		unset return_file
	else
		eout "{$svc} downloaded $get_uri"
		return_file="$tmpf"
	fi

}

import_user_sigs() {
	if [ "$import_custsigs_md5_url" ]; then
		get_remote_file "$import_custsigs_md5_url" "importsigs" "1"
		if [ -f "$return_file" ]; then
			cp -f $return_file $sig_user_md5_file
			eout "{importsigs} imported custom signature data from $import_custsigs_md5_url"
		fi
	fi
	if [ "$import_custsigs_hex_url" ]; then
		get_remote_file "$import_custsigs_hex_url" "importsigs" "1"
		if [ -f "$return_file" ]; then
			cp -f $return_file $sig_user_hex_file
			eout "{importsigs} imported custom signature data from $import_custsigs_hex_url"
		fi
	fi
}

import_conf() {
	current_utime=`date +"%s"`
	if [ -z "$import_config_expire" ]; then
		import_config_expire=43200
	fi
	if [ -f "$sessdir/.import_conf.utime" ]; then
		import_utime=`cat $sessdir/.import_conf.utime`
		if [ -z "$import_utime" ]; then
			import_utime="0"
		fi
		import_diff=$[current_utime-import_utime]
		if [ "$import_diff" -lt "$import_config_expire" ]; then
			import_config_skip="1"
			eout "{importconf} configuration expire value has not lapsed (${import_diff}/${import_config_expire}), using cache."
			import_conf_cached=1
		fi
	fi
	if [ "$import_config_url" ]; then
		if [ -z "$import_config_skip" ]; then
			get_remote_file "$import_config_url" "importconf" "1"
			if [ -f "$return_file" ]; then
				cp -f $return_file $sessdir/.import_conf.cache
				echo "$current_utime" > $sessdir/.import_conf.utime
			fi
		fi
		if [ -f "$sessdir/.import_conf.cache" ]; then
			source $cnf
			source $intcnf
			source $sessdir/.import_conf.cache
			if [ "$import_conf_cached" ]; then
				eout "{importconf} imported configuration from $import_config_url (cached)"
			else
				eout "{importconf} imported configuration from $import_config_url"
			fi
		fi
	fi
}

clamav_linksigs() {
	cpath="$1"
	if [ -d "$cpath" ]; then
		rm -f $cpath/rfxn.{hdb,ndb,yara} 2> /dev/null ; cp -f $sigdir/rfxn.{hdb,ndb,yara} $cpath/ 2> /dev/null
		rm -f $cpath/lmd.user.* 2> /dev/null ; cp -f $sigdir/lmd.user.ndb $sigdir/lmd.user.hdb $cpath/ 2> /dev/null
	fi
}

usage_short() {
cat <<EOF
signature set: $sig_version
usage maldet [-h|--help] [-a|--scan-all PATH] [-r|--scan-recent PATH DAYS]
      [-f|--file-list PATH] [-i|--include-regex] [-x|--exclude-regex]
      [-b|--background] [-m|--monitor] [-k|--kill-monitor] [-c|--checkout]
      [-q|--quarantine] [-s|--restore] [-n|--clean] [-l|--log] [-e|--report]
      [-u|--update-sigs] [-d|--update-ver]
EOF
}

usage_long() {
cat<<EOF
signature set: $sig_version
usage $0 [ OPTION ]
    -b, --background
      Execute operations in the background, ideal for large scans
      e.g: maldet -b -r /home/?/public_html 7

    -u, --update-sigs [--force]
       Update malware detection signatures from rfxn.com

    -d, --update-ver [--force]
       Update the installed version from rfxn.com

    -f, --file-list
       Scan files or paths defined in line spaced file
       e.g: maldet -f /root/scan_file_list

    -r, --scan-recent PATH DAYS
       Scan files created/modified in the last X days (default: 7d, wildcard: ?)
       e.g: maldet -r /home/?/public_html 2

    -a, --scan-all PATH
       Scan all files in path (default: /home, wildcard: ?)
       e.g: maldet -a /home/?/public_html

    -i, --include-regex REGEX
       Include paths/files from file list based on supplied posix-egrep regular
       expression.
       e.g: To include only paths named wp-content and files ending in .php:
       --include-regex ".*/wp-content/.*|.*.php$"

    -x, --exclude-regex REGEX
       Exclude paths/files from file list based on supplied posix-egrep regular
       expression.
       e.g: To exclude paths containing 'wp-content/w3tc/' and core files:
       --exclude-regex ".*wp-content/w3tc/.*|.*core.[0-9]+$"

    -m, --monitor USERS|PATHS|FILE|RELOAD
       Run maldet with inotify kernel level file create/modify monitoring
       If USERS is specified, monitor user homedirs for UID's > 500
       If FILE is specified, paths will be extracted from file, line spaced
       If PATHS are specified, must be comma spaced list, NO WILDCARDS!
       e.g: maldet --monitor users
       e.g: maldet --monitor /root/monitor_paths
       e.g: maldet --monitor /home/mike,/home/ashton

    -k, --kill-monitor
       Terminate inotify monitoring service

    -c, --checkout FILE
       Upload suspected malware to rfxn.com for review & hashing into signatures

    -l, --log
       View maldet log file events

    -e, --report SCANID email
       View scan report of most recent scan or of a specific SCANID and optionally
       e-mail the report to a supplied e-mail address
       e.g: maldet --report
       e.g: maldet --report list
       e.g: maldet --report 050910-1534.21135
       e.g: maldet --report SCANID user@domain.com

    -s, --restore FILE|SCANID
       Restore file from quarantine queue to orginal path or restore all items from
       a specific SCANID
       e.g: maldet --restore $varlibpath/quarantine/config.php.23754
       e.g: maldet --restore 050910-1534.21135

    -q, --quarantine SCANID
       Quarantine all malware from report SCANID
       e.g: maldet --quarantine 050910-1534.21135

    -n, --clean SCANID
       Try to clean & restore malware hits from report SCANID
       e.g: maldet --clean 050910-1534.21135

    -U, --user USER
       Set execution under specified user, ideal for restoring from user quarantine or
       to view user reports.
       e.g: maldet --user nobody --report
       e.g: maldet --user nobody --restore 050910-1534.21135

    -co, --config-option VAR1=VALUE,VAR2=VALUE,VAR3=VALUE
       Set or redefine the value of $cnffile config options
       e.g: maldet --config-option email_addr=you@domain.com,quarantine_hits=1

    -p, --purge
       Clear logs, quarantine queue, session and temporary data.

    --web-proxy IP:PORT
       Enable use of HTTP/HTTPS proxy for all remote URL calls. 
EOF
}

clean() {
	file="$1"
	file_signame="$2"
	file_owner="$3"
	file_chmod="$4"
	file_size="$5"
	file_md5="$6"

	sh_hitname=`echo $hitname | sed -r -e 's/\{(HEX|MD5|CAV|YARA)\}//' -e 's/\.[0-9]+$//'`
	if [ -d "$cldir" ] && [ "$quarantine_clean" == "1" ] && [ "$quarantine_hits" == "1" ] && [ -f "$file" ]; then
		if [ -f "$cldir/$sh_hitname" ] || [ -f "$cldir/custom.$sh_hitname" ] && [ -f "${file}.info" ]; then
			file_path=`grep -E -v '\#' ${file}.info | cut -d':' -f9`
			eout "{clean} restoring $file for cleaning attempt" 1
			restore "$file" >> /dev/null 2>&1
			if [ -f "$cldir/$sh_hitname" ]; then
				eout "{clean} attempting to clean $file_path with $sh_hitname rule" 1
				$cldir/$sh_hitname "$file_path" "$file_signame" "$file_owner" "$file_chmod" "$file_size" "$file_md5"
			fi
			if [ -f "$cldir/custom.$sh_hitname" ]; then
				eout "{clean} attempting to clean $file_path with custom.$sh_hitname rule" 1
				$cldir/custom.$sh_hitname "$file_path" "$file_signame" "$file_owner" "$file_chmod" "$file_size" "$file_md5"
			fi
			eout "{clean} rescanning $file_path for malware hits" 1
			clean_state="1"
			scan_stage1 "$file_path" >> /dev/null 2>&1
			unset clean_state
			if [ -f "$file_path" ]; then
				echo "$file_path" >> $sessdir/clean.$$
				echo "$file_path" >> $clean_history
				eout "{clean} clean successful on $file_path" 1
			else
				eout "{clean} clean failed on $file_path and returned to quarantine" 1
			fi
		elif [ -f "$cldir/$sh_hitname" ] || [ -f "$cldir/custom.$sh_hitname" ] && [ -f "$file" ]; then
			file_path="$file"
			if [ -f "$cldir/$sh_hitname" ]; then
				eout "{clean} attempting to clean $file with $sh_hitname rule" 1
				$cldir/$sh_hitname "$file_path"
			fi
			if [ -f "$cldir/custom.$sh_hitname" ]; then
				eout "{clean} attempting to clean $file with custom.$sh_hitname rule" 1
				$cldir/custom.$sh_hitname "$file_path"
			fi
			eout "{clean} scanning $file for malware hits"
			clean_state="1"
			unset clean_failed
			scan_stage1 "$file_path" 1 >> /dev/null 2>&1
			unset clean_state
			if [ "$clean_failed" == "1" ]; then
				eout "{clean} clean failed on $file" 1
			else
				echo "$file" >> $sessdir/clean.$$
				echo "$file_path" >> $clean_history
				eout "{clean} clean successful on $file" 1
			fi
		else
			eout "{clean} could not find clean rule for hit $sh_hitname or file $file no longer exists." 1
		fi
	else
		if [ "$quarantine_clean" == "1" ] && [ "$quarantine_hits" == "1" ]; then
			eout "file path error on $file, aborting."
			exit
		else
			eout "quarantine_clean and quarantine_hits are disabled; skipped file $file"
		fi
	fi
}

quar_get_filestat() {
	fstat="$1"
	if [ -f "$fstat" ]; then
		# owner:group:mode:size(b):md5:atime(epoch):mtime(epoch):ctime(epoch):file(path)
                file_owner=`grep -E -v '\#' "$fstat" | awk -F':' '{print$1}'`
                file_group=`grep -E -v '\#' "$fstat" | awk -F':' '{print$2}'`
                file_mode=`grep -E -v '\#' "$fstat"  | awk -F':' '{print$3}'`
                file_size=`grep -E -v '\#' "$fstat"  | awk -F':' '{print$4}'`
                md5_hash=`grep -E -v '\#' "$fstat"   | awk -F':' '{print$5}'`
		file_atime=`grep -E -v '\#' "$fstat"   | awk -F':' '{print$6}'`
		file_mtime=`grep -E -v '\#' "$fstat"   | awk -F':' '{print$7}'`
		file_ctime=`grep -E -v '\#' "$fstat"   | awk -F':' '{print$8}'`
                file_path=`grep -E -v '\#' "$fstat"  | cut -d':' -f9`
	fi
}

restore() {
        file="$1"
        fname=`basename "$file"`
        if [ -f "$quardir/$file" ] && [ -f "$quardir/${file}.info" ]; then
		quar_get_filestat "$quardir/${file}.info"
                chown ${file_owner}.${file_group} "$quardir/$file" >> /dev/null 2>&1
                chmod $file_mode "$quardir/$file" >> /dev/null 2>&1
                mv -f "$quardir/$file" "$file_path"
		touch -m --date=@${file_mtime} "$file_path"
                eout "{restore} quarantined file $file restored to $file_path" 1
        elif [ -f "$file" ] && [ -f "${file}.info" ]; then
		quar_get_filestat "${file}.info"
                chown ${file_owner}.${file_group} "$file" >> /dev/null 2>&1
                chmod $file_mode "$file" >> /dev/null 2>&1
                mv -f "$file" "$file_path"
		touch -m --date=@${file_mtime} "$file_path"
                eout "{restore} quarantined file $file restored to $file_path" 1
        else
                eout "{restore} invalid file or could not be found" 1
        fi
}

restore_hitlist() {
	hitlist="$sessdir/session.hits.$1"
	if [ -f "$hitlist" ]; then
		lbreakifs set
		is_autoquar=`tail -n1 $hitlist | awk -F'>' '{print$2}' | grep -E -v '^$' | sed 's/.//'`
		if [ "$is_autoquar" ]; then
			for file in `cat $hitlist | cut -d':' -f2 | cut -d'>' -f2 | sed 's/.//'`; do
				if [ -f "$file" ]; then
					restore "$file"
				fi
			done
		elif [ ! "$is_autoquar" ]; then
			for file in `cat $hitlist | cut -d':' -f2 | sed 's/.//'`; do
				quar_file=`cat $quar_history | grep -E -w "$file" | cut -d':' -f8 | tail -n1`
				restore "$quar_file"
			done
		else
			eout "{restore} could not find a valid hit list to restore." 1
		fi
		lbreakifs unset
	fi
}

clean_hitlist() {
        if [ "$quarantine_clean" == "0" ] || [ "$quarantine_hits" == "0" ]; then
                eout "{clean} quarantine_clean and/or quarantine_hits are disabled, nothing to do here." 1
                exit 0
        fi

        scanid="$1"
        hitlist="$sessdir/session.hits.$scanid"
        if [ -f "$hitlist" ]; then
                is_quared=`egrep '=>' $hitlist`
                if [ ! "$is_quared" ]; then
                        lbreakifs set
                        for file in `cat $hitlist | cut -d':' -f2 | sed 's/.//'`; do
                                get_filestat "$file" 1
                                hitname=`cat $hitlist | grep $file | awk '{print$1}'`
                                if [ ! "$md5_hash" ]; then
                                        md5_hash=`eval $md5sum \"$file\" | awk '{print$1}'`
                                fi
                                clean "$file" "$hitname" "$file_owner.$file_group" "$file_mode" "$file_size" "$md5_hash"
                        done
                        lbreakifs unset
                else
                        lbreakifs set
                        for file in `cat $hitlist | cut -d'>' -f2 | sed 's/.//'`; do
                                quar_get_filestat "${file}.info" 1
                                hitname=`cat $hitlist | grep $file | awk '{print$1}'`
                                if [ ! "$md5_hash" ]; then
                                        md5_hash=`eval $md5sum \"$file\" | awk '{print$1}'`
                                fi
                                clean "$file" "$hitname" "$file_owner.$file_group" "$file_mode" "$file_size" "$md5_hash"
                        done
                        lbreakifs unset
                fi
        else
                eout "{clean} invalid scanid $scanid or unknown error, aborting." 1
                exit
        fi
}

view_report() {
	rid="$1"
	if [ "$rid" == "list" ]; then
		tmpf="$tmpdir/.areps$$"
		for file in `ls $sessdir/session.[0-9]* 2> /dev/null`; do
			SCANID=`cat $file | grep "SCAN ID" | sed 's/SCAN ID/SCANID/'`
			FILES=`cat $file | grep "TOTAL FILES" | sed 's/TOTAL //'`
			HITS=`cat $file | grep "TOTAL HITS" | sed 's/TOTAL //'`
			CLEAN=`cat $file | grep "TOTAL CLEANED" | sed 's/TOTAL //'`
			TIME=`cat $file | grep -E "^TIME|^STARTED" | sed -e 's/TIME: //' -e 's/STARTED: //' | awk '{print$1,$2,$3,$4}'`
			TIME_U=`date -d "$TIME" "+%s" 2> /dev/null`
                        ETIME=`cat $file | grep "ELAPSED" | awk '{print$1,$2}' | sed 's/ELAPSED/RUNTIME/'`
			if [ -z "$ETIME" ]; then
				ETIME="RUNTIME: unknown"
			fi
			if [ ! -z "$SCANID" ] && [ ! -z "$TIME" ]; then
				clean_zero=`echo $CLEAN | awk '{print$2}'`
				if [ -z "$clean_zero" ]; then
					CLEAN="CLEANED:  0"
				fi
				echo "$TIME_U | $TIME | $SCANID | $ETIME | $FILES | $HITS | $CLEAN" >> $tmpf
			fi
		done
		if [ -f "$tmpf" ]; then
			if [ "$OSTYPE" == "FreeBSD" ]; then
				cat $tmpf | sort -k1 -n | cut -d'|' -f2-7 | column -t | more
			else
				cat $tmpf | sort -k1 -n | tac | cut -d'|' -f2-7 | column -t | more
			fi
			rm -f $tmpf 2> /dev/null
			exit 0
		else
			echo  "error no report data found"
			exit 1
		fi
	fi
	if [ -f "$sessdir/session.$rid" ] && [ ! -z "$(echo $2 | grep '\@')" ]; then
	    if [ -f "$mail" ]; then
		    cat $sessdir/session.$rid | $mail -s "$email_subj" "$2"
		elif [ -f "$sendmail" ]; then
		    if ! grep -q "SUBJECT: " "$sessdir/session.$rid"; then
		        echo -e "SUBJECT: $email_subj\n$(cat $sessdir/session.$rid)" > $sessdir/session.$rid
		    fi
		    cat $sessdir/session.$rid | $sendmail -t "$2"
		else
		    eout "{scan} no \$mail or \$sendmail binaries found, e-mail alerts disabled."
		    exit
		fi

        eout "{report} report ID $rid sent to $2" 1
		exit
	fi
	if [ "$rid" == "" ] && [ -f "$sessdir/session.last" ]; then
		rid=`cat $sessdir/session.last`
		$EDITOR $sessdir/session.$rid
	elif [ -f "$sessdir/session.$rid" ]; then
		$EDITOR $sessdir/session.$rid
	else
		echo "{report} no report found, aborting."
		exit
	fi
}

view() {
	echo "Viewing last 50 lines from $maldet_log:"
	tail -n 50 $maldet_log
}

purge() {
	:> $maldet_log
	rm -f $tmpdir/* $quardir/* $sessdir/* 2> /dev/null
	eout "{glob} logs and quarantine data cleared by user request (-p)" 1
}


quarantine_suspend_user() {
	file="$1"
	get_filestat "$file"
	user="$file_owner"
	user_id=`id -u $user`
	if [ ! "$user" == "" ] && [ "$user_id" -ge "$quarantine_suspend_user_minuid" ]; then
		if [ -f "/scripts/suspendacct" ]; then
			if [ ! -f "/var/cpanel/suspended/$user" ]; then
				/scripts/suspendacct $user "maldet --report $datestamp.$$" >> /dev/null 2>&1
				eout "{quar} account $user cpanel suspended" 1
				echo "$user" >> $sessdir/suspend.users.$$
				echo "$user" >> $suspend_history
			fi
		else
			if [ "$(grep $user /etc/passwd | cut -d':' -f7 | grep /bin/false)" == "" ]; then
				/usr/sbin/usermod -s /bin/false $user >> /dev/null 2>&1
				eout "{quar} account $user suspended; set 'usermod -s /bin/false'"
				echo "$user" >> $sessdir/suspend.users.$$
				echo "$user" >> $suspend_history
			fi
		fi
	fi
}

get_filestat() {
	file="$1"
	times="$2"
	if [ "$OSTYPE" == "FreeBSD" ]; then
		file_owner=`$stat -f '%Su' "$file"`
		file_group=`$stat -f '%Sg' "$file"`
		file_mode=`$stat -f '%p' "$file" | sed 's/^.//'`
		file_size=`$stat -f '%Z' "$file"`
		md5_hash=`eval $md5sum \"$file\" | awk '{print$1}'`
		if [ "$times" ]; then
			# atime mtime ctime (since epoch)
			file_times=`$stat -f '%a:%m:%c' "$file"`
		fi
	else
		file_owner=`$stat -c '%U' "$file"`
		file_group=`$stat -c '%G' "$file"`
		file_mode=`$stat -c '%a' "$file"`
		file_size=`$stat -c '%s' "$file"`
		md5_hash=`eval $md5sum \"$file\" | awk '{print$1}'`
		if [ "$times" ]; then
			# atime mtime ctime (since epoch)
			file_times=`$stat -c '%X:%Y:%Z' "$file"`
		fi
	fi
}

record_hit() {
	file="$1"
	hitname="$2"
	if [ -f "$file" ]; then
		get_filestat "$file" 1
		file_name=`basename "$file" 2> /dev/null`
		if [ ! "$md5_hash" ]; then
			md5_hash=`eval $md5sum \"$file\" | awk '{print$1}'`
		fi
		eout "{hit} malware hit $hitname found for $file"
		echo "${utime}:${hostid}:${hitname}:${md5_hash}:${file_size}:${file_owner}.${file_group}:${file_mode}:${file_times}:${file}" >> $hits_history
	fi
}

quarantine() {
	file="$1"
	hitname="$2"
	file_name=`basename "$file"`
	if [ -f "$file" ] && [ -d "$quardir" ]; then
		if [ "$quarantine_hits" == "1" ]; then
			file_namewc=`echo $file_name | $wc -m`
			rnd="${RANDOM}${RANDOM}"
			if [ "$quarantine_suspend_user" == "1" ]; then
				quarantine_suspend_user "$file"
			fi
			chattr -ia "$file"
			mv "$file" "$quardir/$file_name.$rnd"
			touch --no-create "$quardir/$file_name.$rnd"
			if [ "$pub" == "1" ]; then
				chmod 400 "$quardir/$file_name.$rnd"
			else
				chmod 000 "$quardir/$file_name.$rnd"
				chown root.root "$quardir/$file_name.$rnd"
			fi
			echo -e "# owner:group:mode:size(b):md5:atime(epoch):mtime(epoch):ctime(epoch):file(path)\n$file_owner:$file_group:$file_mode:$file_size:$md5_hash:$file_times:$file" > $quardir/$file_name.$rnd.info
			eout "{quar} malware quarantined from '$file' to '$quardir/$file_name.$rnd'"
			echo "$utime:$hitname:$file:$file_owner:$file_group:$md5_hash:$file_size:$quardir/$file_name.$rnd" >> $quar_history
			if [ ! -z "$scan_session" ]; then
				echo "$hitname : $file => $quardir/$file_name.$rnd" >> $scan_session
			fi
			if [ "$quarantine_clean" == "1" ] && [ ! "$clean_state" == "1" ]; then
				unset clean_state
				clean "$quardir/$file_name.$rnd" "$hitname" "$file_owner.$file_group" "$file_mode" "$file_size" "$md5_hash" "$file"
			fi
		else
			if [ ! -z "$scan_session" ]; then
				echo "$hitname : $file" >> $scan_session
			fi
		fi
	else
		eout "{quar} fatal error handling '$file'"
	fi
}

quar_hitlist() {
	hitlist="$sessdir/session.hits.$1"
	if [ -f "$hitlist" ]; then
		lbreakifs set
		for file in `cat $hitlist | cut -d':' -f2 | sed 's/.//'`; do
			if [ -f "$file" ]; then
				get_filestat "$file" 1
				file_name=`basename "$file"`
				file_namewc=`echo "$file_name" | $wc -m`
				file_hitname=`egrep -m1 "$file" $hitlist | awk '{print$1}'`
				if [ ! "$md5_hash" ]; then
					md5_hash=`eval $md5sum \"$file\" | awk '{print$1}'`
				fi
				if [ "$pub" == "1" ]; then
					chattr -ia "$file" >> /dev/null 2>&1
					chmod 400 "$file"
				else
					chattr -ia "$file"
					chmod 000 "$file"
				fi
				rnd="${RANDOM}${RANDOM}"
				mv "$file" "$quardir/$file_name.$rnd"
				touch --no-create "$quardir/$file_name.$rnd"
				echo -e "# owner:group:mode:size(b):md5:atime(epoch):mtime(epoch):ctime(epoch):file(path)\n$file_owner:$file_group:$file_mode:$file_size:$md5_hash:$file_times:$file" > $quardir/$file_name.$rnd.info
				eout "{quar} malware quarantined from '$file' to '$quardir/$file_name.$rnd'" 1
				echo "$utime:$file_hitname:$file:$file_owner:$file_group:$md5_hash:$file_size:$quardir/$file_name.$rnd" >> $quar_history
				if [ "$quarantine_suspend_user" == "1" ]; then
					quarantine_suspend_user "$file"
				fi
				if [ "$quarantine_clean" == "1" ] && [ ! "$clean_state" == "1" ]; then
					unset clean_state
					hitname=`cat $hitlist | grep $file | awk '{print$1}'`
					clean "$quardir/$file_name.$rnd" "$hitname" "$file_owner.$file_group" "$file_mode" "$file_size" "$md5_hah" "$file"
				fi
				
			fi
		done
		lbreakifs unset
	else
		echo "{quar} invalid quarantine hit list, aborting."
		exit
	fi
}

clamselector() {
        scan_max_filesize=`cat $sig_md5_file | cut -d':' -f2 | sort -n | tail -n1`
        if [ "$scan_max_filesize" -gt "1" 2> /dev/null ]; then
                scan_max_filesize=$[scan_max_filesize+1]
                clamscan_max_filesize="${scan_max_filesize}"
                scan_max_filesize="${scan_max_filesize}c"
        else
                scan_max_filesize="2048k"
                clamscan_max_filesize="2592000"
        fi

        if [ "$scan_clamscan" == "1" ]; then
                trim_log $clamscan_log 10000 1
                for dpath in $clamav_paths; do
                        if [ -f "${dpath}/main.cld" ] || [ -f "${dpath}/main.cvd" ]; then
                                clamav_db="-d $dpath"
                        fi
                done

                isclamd=`pgrep -x clamd 2> /dev/null`
                isclamd_root=`pgrep -x -u root clamd 2> /dev/null`
                if [ "$isclamd" ] && [ "$isclamd_root" ]; then
                        clamd=1
                        clambin="clamdscan"
                        clamopts="$clamdscan_extraopts"
                elif [ "$isclamd" ] && [ ! "$isclamd_root" ]; then
                        clamd=1
                        clambin="clamdscan"
                        clamopts="--fdpass $clamdscan_extraopts"
                else
                        clambin="clamscan"
                        clamopts="$clamscan_extraopts --max-filesize=$clamscan_max_filesize --max-scansize=$[clamscan_max_filesize*2] -d $runtime_hdb -d $runtime_ndb $clamav_db -r"
                        if [ "$monitor_mode" ]; then
                                inotify_sleep="120"
                                eout "{mon} warning clamd service not running; force-set monitor mode file scanning to every 120s"
                        fi

                fi

                if [ -f "/usr/local/cpanel/3rdparty/bin/$clambin" ]; then
                        clamscan="/usr/local/cpanel/3rdparty/bin/$clambin"
                elif [ -f "$(which $clambin 2> /dev/null)" ]; then
                        clamscan=`which $clambin 2> /dev/null`
                else
                        scan_clamscan="0"
                fi
                if [ "$clamd" ] && [ "$scan_clamscan" == "1" ]; then
                        ## test clamdscan for errors as not all 'running' instances of clamd are indicative of working setup
                        clamd_test=`$clamscan --fdpass --quiet --no-summary /etc/passwd 2> /dev/null || echo $?`
                        if [ ! -z "$clamd_test" ]; then
                                clamd=0
                                clambin="clamscan"
                                clamopts="$clamscan_extraopts --max-filesize=$clamscan_max_filesize --max-scansize=$[clamscan_max_filesize*2] -d $runtime_hdb -d $runtime_ndb $clamav_db -r"
                                if [ -f "/usr/local/cpanel/3rdparty/bin/$clambin" ]; then
                                        clamscan="/usr/local/cpanel/3rdparty/bin/$clambin"
                                elif [ -f "$(which $clambin 2> /dev/null)" ]; then
                                        clamscan=`which $clambin 2> /dev/null`
                                else
                                        scan_clamscan="0"
                                fi
                        fi
                fi
        fi

}

scan() {
	scan_start_hr=`date +"%b %e %Y %H:%M:%S %z"`
	scan_start=`date +"%s"`
	lbreakifs set
	spath=$(for i in `echo "$1" | tr '?' '*' | tr ',' '\n'`; do echo "\"$(printf %q $i)\""; done | tr '\n' ' ' | sed 's/.$//')
	lbreakifs unset
	days="$2"
	scanid="$datestamp.$$"
	if [ "$file_list" ]; then
		spath="\"$file_list\""
	elif [ ! -f "$find" ]; then
		eout "{scan} could not locate find command" 1
		clean_exit
		exit 1
	fi
	if [ -f "$spath" ] && [ -z "$file_list" ]; then
		single_filescan=1
	fi
	
	if [ ! -f "$sig_md5_file" ]; then
		eout "{scan} required signature file not found ($sig_md5_file), try running -u|--update, aborting!" 1
		clean_exit
		exit 1
	fi
	if [ ! -f "$sig_hex_file" ]; then
		eout "{scan} required signature file not found ($sig_hex_file), try running -u|--update, aborting!" 1
		clean_exit
		exit 1
	fi
	if [ ! -f "$ignore_paths" ]; then
		touch $ignore_paths
		chmod 640 $ignore_paths
	elif [ ! -f "$ignore_sigs" ]; then
		touch $ignore_sigs
		chmod 640 $ignore_sigs
	fi
		
	if [ ! "$days" == "all" ] && [ -z "$file_list" ]; then
		val=`echo $days | grep "[[:alpha:]]"`
		if [ ! -z "$val" ]; then
			eout "{scan} days value must be numeric value in the range of 1 - 90, reverting to default (7)." 1
			days=7
		elif [ "$days" -gt "90" ]; then
			eout "{scan} days value must be numeric value in the range of 1 - 90, reverting to default (7)." 1
			days=7
		fi
	fi
	
	if [ ! "${spath:1:1}" = "/" ]; then
		eout "{scan} must use absolute path, provided relative path $spath" 1
		exit
	fi

	scan_session="$tmpdir/.sess.$$"
	find_results="$tmpdir/.find.$$"
	touch $find_results
	touch $scan_session
	
	sigignore
	gensigs
	if [ "$scan_clamscan" == "1" ]; then
		clamselector
	fi
	
	hex_sigs=`$wc -l $sig_hex_file | awk '{print$1}'`
	md5_sigs=`$wc -l $sig_md5_file | awk '{print$1}'`
	yara_sigs=`grep -E -c ^rule $sig_yara_file | awk '{print$1}'`
	user_hex_sigs=`$wc -l $sig_user_hex_file | awk '{print$1}'`
	user_md5_sigs=`$wc -l $sig_user_md5_file | awk '{print$1}'`
	user_sigs=$[user_hex_sigs+user_md5_sigs]
	tot_sigs=$[md5_sigs+hex_sigs+user_hex_sigs+user_md5_sigs+yara_sigs]
	if [ -z "$hscan" ]; then
		eout "{scan} signatures loaded: $tot_sigs ($md5_sigs MD5 | $hex_sigs HEX | $yara_sigs YARA | $user_sigs USER)" 1
	fi
	if [ -f "$ignore_file_ext" ]; then
		if [ ! "$(cat $ignore_file_ext)" == "" ]; then
			for i in `cat $ignore_file_ext`; do
				if [ "$ignore_fext" == "" ]; then
					ignore_fext="-not -iname \"*$i\""
				else
					ignore_fext="$ignore_fext -not -iname \"*$i\""
				fi
			done
		fi
	fi
	if [ "$scan_ignore_root" == "1" ]; then
		ignore_root="-not -uid 0 -not -gid 0"
	fi
	if [ "$scan_ignore_user" ]; then
		for i in `echo $scan_ignore_user | tr ', ' ' '`; do
			if [ "$ignore_user" == "" ]; then
				ignore_user="-not -user $i"
			else
				ignore_user="$ignore_user -not -user $i"
			fi
		done
	fi
	if [ "$scan_ignore_group" ]; then
		for i in `echo $scan_ignore_group | tr ', ' ' '`; do
			if [ "$ignore_group" == "" ]; then
				ignore_group="-not -group $i"
			else
				ignore_group="$ignore_group -not -group $i"
			fi
		done
	fi
	if [ "$scan_tmpdir_paths" ] && [ -z "$hscan" ] && [ -z "$single_filescan" ]; then
		spath_tmpdirs="$scan_tmpdir_paths"
	fi
		
	if [ "$file_list" ]; then
		cat $file_list | grep -E -vf $ignore_paths > $find_results
	else
		if [ "$single_filescan" ]; then
			find_recentops=""
		elif [ "$days" == "all" ]; then
			if [ -z "$hscan" ]; then
				eout "{scan} building file list for $hrspath, this might take awhile..." 1
			fi
			find_recentops=""
		else
			rscan=1
			if [ -z "$hscan" ]; then
				eout "{scan} building file list for $hrspath of new/modified files from last $days days, this might take awhile..." 1
			fi
			find_recentopts="\( -mtime -$days -o -ctime -$days \)"
		fi
		
		if [ -z "$scan_find_timeout" ];then
			scan_find_timeout=0
		fi
		if [ "$scan_find_timeout" -ge "60" ]; then
			echo -e "sleep $scan_find_timeout\ntouch $tmpdir/.find_killed.$scanid\npkill -f lmd_find" > $tmpdir/.lmd_find_sleep.$$
			sh -c "sh $tmpdir/.lmd_find_sleep.$$ >> /dev/null 2>&1 &" >> /dev/null 2>&1 &
			rm -f $tmpdir/.lmd_find_sleep.$$ 2> /dev/null
			eout "{scan} setting maximum execution time for 'find' file list: ${scan_find_timeout}sec" 1
		fi
                if [ -z "$hscan" ]; then
			eout "{scan} setting nice scheduler priorities for all operations: cpunice $scan_cpunice , ionice $scan_ionice" 1
		fi
		file_list_start=`date +"%s"`
		tmpscandir="$tmpdir/scan.$RANDOM"
		mkdir -p "$tmpscandir" ; chmod 700 $tmpscandir ; cd $tmpscandir
		eout "{scan} executed eval $nice_command $find $spath $spath_tmpdirs -maxdepth $scan_max_depth $find_opts -type f $find_recentopts -size +${scan_min_filesize}c -size -$scan_max_filesize $include_regex -not -perm 000 $exclude_regex $ignore_fext $ignore_root $ignore_user $ignore_group"
		eval $nice_command $find /lmd_find/ $(echo $spath) $spath_tmpdirs -maxdepth $scan_max_depth $find_opts -type f $find_recentopts -size +${scan_min_filesize}c -size -$scan_max_filesize $include_regex -not -perm 000 $exclude_regex $ignore_fext $ignore_root $ignore_user $ignore_group 2> /dev/null | grep -E -vf $ignore_paths > $find_results
		cd $tmpdir
		rm -rf $tmpscandir
		if [ "$rscan" = "1" ] && [ "$scan_export_filelist" == "1" ]; then
			rm -f  $tmpdir/.find_results.* 2> /dev/null ; cp $find_results $tmpdir/.find_results.shared.$$ 2> /dev/null
			ln -fs $tmpdir/.find_results.shared.$$ $tmpdir/find_results.last 2> /dev/null
		fi
		file_list_end=`date +"%s"`
		file_list_et=$[file_list_end-file_list_start]
		if [ -f "$tmpdir/.find_killed.$scanid" ]; then
			rm -f $tmpdir/.find_killed.$scanid
			echo && eout "{scan} file list 'find' operation reached maximum execution time (${scan_find_timeout}sec) and was terminated" 1
		else
			pkill -f lmd_find_sleep >> /dev/null 2>&1
		fi
	fi
	if [ ! -f "$find_results" ] || [ ! -s "$find_results" ]; then
		if [ -z "$hscan" ]; then
			if [ "$days" == "all" ]; then
				eout "{scan} scan returned empty file list; check that path exists and contains files in scope of configuration." 1
				rm -f $find_results $scan_session $runtime_ndb $runtime_hdb $runtime_hexstrings $clamscan_results $tmpdir/.tmpf*
				exit 0
			else
				eout "{scan} scan returned empty file list; check that path exists, contains files in days range or files in scope of configuration." 1
				rm -f $find_results $scan_session $runtime_ndb $runtime_hdb $runtime_hexstrings $clamscan_results
				exit 0
			fi
		fi
	fi
	
	res_col="1"
	move_to_col="echo -en \\033[${res_col}G"
	tot_files=`$wc -l $find_results | awk '{print$1}'`
	if [ -z "$hscan" ] && [ -z "$single_filescan" ]; then
		if [ "$file_list" ]; then
			eout "{scan} user supplied file list '$file_list', found $tot_files files..." 1
		else
			eout "{scan} file list completed in ${file_list_et}s, found $tot_files files..." 1
		fi
	fi
	touch $sessdir/clean.$$
	if [ ! -f "$scan_session" ]; then
		touch $scan_session
	fi
	
	if [ ! -z "$hscan" ]; then
		eout "{scan.hook} scan of $spath in progress (id: $datestamp.$$)"
	fi
	cnt=0
	if [ -z "$mail" ] && [ -z "$sendmail" ]; then
		eout "{scan} no \$mail or \$sendmail binaries found, e-mail alerts disabled."
	fi
	if [ -f "$clamscan" ] && [ "$scan_clamscan" == "1" ]; then
		if [ -z "$hscan" ]; then
			eout "{scan} found clamav binary at $clamscan, using clamav scanner engine..." 1
		fi
		if [ "$string_length_scan" == "1" ]; then
			if [ -z "$hscan" ]; then
				eout "{scan} preprocessing file list for string length hits..." 1
				scan_strlen list "$find_results" >> /dev/null 2>&1
			fi
		fi
		if [ -z "$hscan" ]; then
			eout "{scan} scan of $hrspath ($tot_files files) in progress..." 1
		fi

		echo "$(date +"%b %d %H:%M:%S") $(hostname -s) clamscan start"  >> $clamscan_log
		clamscan_results="$tmpdir/.clamscan.$$"
		echo "$(date +"%b %d %H:%M:%S") $(hostname -s) executed: $nice_command $clamscan $clamopts --infected --no-summary -f $find_results" >> $clamscan_log
		$nice_command $clamscan $clamopts --infected --no-summary -f $find_results > $clamscan_results 2>> $clamscan_log
		clamscan_return=$?
		if [ "$clamscan_return" == "2" ]; then
			if [ "$quarantine_on_error" == "0" ] || [ -z "$quarantine_on_error" ]; then
				quarantine_hits=0
				eout "{scan} clamscan returned an error, check $clamscan_log for details; quarantine_on_error=0 or unset, quarantine has been disabled!" 1
			else
				eout "{scan} clamscan returned an error, check $clamscan_log for details!" 1
			fi
		fi
		clamscan_fatal_error=`grep -m1 'no reply from clamd' $clamscan_results`
		if [ "$clamscan_fatal_error" ]; then
			quarantine_hits=0
                        eout "{scan} clamscan returned a fatal error in scan results, check $clamscan_log for details; quarantine has been disabled!" 1
		fi
		echo "$(date +"%b %d %H:%M:%S") $(hostname -s) clamscan end return $clamscan_return"  >> $clamscan_log

		lbreakifs set
		for hit in `grep -E -v 'ERROR$|lstat()|no reply from clamd' $clamscan_results | sed -e 's/.UNOFFICIAL//' -e 's/ FOUND$//' | awk -F':' '{print$2":"$1}' | sed 's/.//'`; do
			file=`echo "$hit" | cut -d':' -f2`
			signame=`echo "$hit" | cut -d':' -f1`
			if [ ! -z "$(echo $signame | grep -E 'YARA')" ]; then
                                signame=`echo "$signame" | sed 's/YARA\./{YARA}/'`
                        elif [ -z "$(echo $signame | grep -E 'HEX|MD5')" ]; then
                                signame="{CAV}$signame"
			fi
			ignore_hit=`echo $signame | grep -E -vf $ignore_sigs`
			if [ ! -z "$ignore_hit" ]; then
			 record_hit "$file" "$signame"
			 quarantine "$file" "$signame"
			 if [ ! "$set_background" == "1" ]; then
				tot_hits=`$wc -l $scan_session | awk '{print$1}'`
				tot_cl=`$wc -l $sessdir/clean.$$ | awk '{print$1}'`
				if [ -z "$hscan" ]; then
					echo -en "\\033[${res_col}G" && echo -n "maldet($$): {scan} processing scan results for hits: $tot_hits hits $tot_cl cleaned"
				fi
				cnt="$tot_files"
			 fi
			fi
			unset ignore_hit
		done
		lbreakifs unset
		echo "$(date +"%b %d %H:%M:%S") $(hostname -s) clamscan end"  >> $clamscan_log
	else
		if [ -z "$hscan" ]; then
			eout "{scan} scan of $hrspath ($tot_files files) in progress..." 1
		fi
		lbreakifs set
		if [ ! -f "$scan_session" ]; then
			touch $scan_session
		fi
		
		while read rpath; do
			((cnt++))
			if [ -z "$hscan" ] && [ ! "$set_background" == "1" ] && [ -z "$single_filescan" ]; then
				tot_hit=`$wc -l $scan_session | awk '{print$1}'`
				cl_hit=`$wc -l $sessdir/clean.$$ | awk '{print$1}'`
				echo -en "\\033[${res_col}G" && echo -n "maldet($$): {scan} $cnt/$tot_files files scanned: $tot_hit hits $cl_hit cleaned"
			fi
			if [ -f "$rpath" ]; then
				scan_stage1 "$rpath" >> /dev/null 2>&1
			fi
			
		done < $find_results
		lbreakifs unset
	fi
	
	if [ -z "$hscan" ]; then
		if [ ! "$set_background" == "1" ] && [ "$scan_clamscan" == "0" ] && [ -z "$single_filescan" ]; then
			echo
		fi
	fi
	scan_end_hr=`date +"%b %e %Y %H:%M:%S %z"`
	scan_end=`date +"%s"`
	scan_et=$[scan_end-scan_start]
	scan_et_nofl=$[scan_et-file_list_et]
	tot_hits=`$wc -l $scan_session | awk '{print$1}'`
	tot_cl=`$wc -l $sessdir/clean.$$ | awk '{print$1}'`
	gen_report
	
	if [ ! -z "$hscan" ]; then
		if [ ! "$tot_hits" == "0" ]; then
			echo "0 maldet: $hitname $spath"
			eout "{scan.hook} results returned FAIL hit found on $spath (id: $datestamp.$$)"
		else
			echo "1 maldet: OK"
			eout "{scan.hook} results returned OK on $spath (id: $datestamp.$$)"
		fi
	else
		if [ -z "$hscan" ]; then
			echo
		fi
		eout "{scan} scan completed on $hrspath: files $tot_files, malware hits $tot_hits, cleaned hits $tot_cl, time ${scan_et}s" 1
		eout "{scan} scan report saved, to view run: maldet --report $datestamp.$$" 1
		if [ "$quarantine_hits" == "0" ] && [ ! "$tot_hits" == "0" ]; then
			eout "{scan} quarantine is disabled! set quarantine_hits=1 in $cnffile or to quarantine results run: maldet -q $datestamp.$$" 1
		fi
	fi
	
	if [ ! "$tot_hits" == "0" ]; then
		if [ "$email_ignore_clean" == "1" ] && [ ! "$tot_hits" == "$tot_cl" ]; then
			genalert file $nsess
		elif [ "$email_ignore_clean" == "0" ]; then
			genalert file $nsess
		fi
	fi
	mv $scan_session $nsess_hits
	rm -f $find_results $scan_session $runtime_ndb $runtime_hdb $runtime_hexstrings $clamscan_results
}

scan_strlen() {
	type="$1"
	file="$2"
	if [ "$string_length_scan" == "1" ] && [ "$type" == "file" ]; then
		flen=`$wc -L $file 2> /dev/null | awk '{print$1}'`
		if [ "$flen" -ge "$string_length" ]; then
			eout "{strlen} malware string length hit on $file"
			quarantine "$file" "{SA}stat.strlength"
		fi
	elif [ "$string_length_scan" == "1" ] && [ "$type" == "list" ]; then
		list="$tmpdir/.strlen.flist.$$"
		cp $file $list
		sed -i -e "s/'/\\\\'/g" $list
		cat $list | xargs wc -L 2> /dev/null | grep -vw total >> $list.strlen
		awk "{if (\$1>=$string_length) print\$2}" $list.strlen >> $list.hits
		for i in `cat $list.hits`; do
			if [ -f "$i" ]; then
				eout "{strlen} malware string length hit on $i"
				quarantine "$i" "{SA}stat.strlength"
			fi
		done
		rm -f $list*
	fi
}

scan_stage1() {
	file="$1"
	clean_check="$2"
	hash=`eval $md5sum \"$file\" | awk '{print$1}'`
	if [ -z "$runtime_hexstrings" ]; then
		sigignore
		gensigs
	fi
	if  [ ! -z "$hash" ]; then
		val_hash=`grep -m1 $hash $sig_user_md5_file $sig_md5_file`
		if [ ! -z "$val_hash" ]; then
			md5_hit="$hash"
			md5_hitname=`echo $val_hash | cut -d':' -f4`
			md5_hash="$hash"
			if [ "$clean_check" == "1" ]; then
				clean_failed=1
			else
	                        record_hit "$file" "$md5_hitname"
				quarantine "$file" "$md5_hitname"
			fi
			unset val_hash md5_hit md5_hitname md5_hash
		else
			if [ -f "$file" ]; then
				scan_stage2 "$file" $clean_check >> /dev/null 2>&1
			fi
			if [ -f "$file" ]; then
				scan_strlen file "$file" >> /dev/null 2>&1
			fi
		fi
	else
		eout "{scan} error could not read or hash $file, do we have permission?"
	fi
}

scan_stage2() {
	file="$1"
	clean_check="$2"
	if [ -z "$ftype" ]; then
		if [ -p "$hex_fifo_path" ] && [ "$scan_hexfifo" == "1" ]; then
			if [ "$OSTYPE" == "FreeBSD" ]; then
				$od -v -N$scan_hexfifo_depth -tx1 "$file" | cut -c12-256 | tr -d ' \n' > $hex_fifo_path 2>&1 &
			else
				$od -v -w64 -N$scan_hexfifo_depth -tx1 "$file" | cut -c9-256 | tr -d '\n ' > $hex_fifo_path 2>&1 &
			fi
			val_hex=`$perl $hex_fifo_script $runtime_hexstrings`
		else
			if [ "$OSTYPE" == "FreeBSD" ]; then
				val_hex=`$perl $runtime_hexstrings $hex_string_script $($od -v -N$scan_hexdepth -tx1 "$file" | cut -c12-256 | tr -d ' \n')`
			else
				val_hex=`$perl $runtime_hexstrings $hex_string_script $($od -v -w$scan_hexdepth -N$scan_hexdepth -tx1 "$file" | tr -d '\n ')`
			fi
		fi
		if [ ! -z "$val_hex" ]; then
			hex_hit=`echo $val_hex | awk '{print$1}'`
			hex_hitname=`echo $val_hex | awk '{print$2}'`
			if [ "$clean_check" == "1" ]; then
				clean_failed=1
			else
                                record_hit "$file" "$hex_hitname"
				quarantine "$file" "$hex_hitname"
			fi
			unset val_hex hex_hit hex_hitname
		fi
	fi
}

gen_report() {
	if [ -f "$scan_session" ]; then
		tot_hits=`$wc -l $scan_session | awk '{print$1}'`
		nsess_hits="$sessdir/session.hits.$datestamp.$$"
		echo "$datestamp.$$" > $sessdir/session.last
		nsess="$sessdir/session.$datestamp.$$"
		tmpf="$nsess"
		. $email_template
	fi
}

trim_log() {
	log="$1"
	logtrim="$2"
	if [ -f "$log" ]; then
		log_size=`$wc -l $log | awk '{print$1}'`
		if [ "$log_size" -gt "$logtrim" 2> /dev/null ]; then
			trim=$[logtrim/10]
			printf "%s\n" "$trim,${log_size}d" w | ed -s $log 2> /dev/null
		fi
	elif [ ! -f "$log" ] && [ "$3" == "1" ]; then
		touch $log ; chmod 640 $log
	fi
}

genalert() {
	type="$1"
	file="$2"
        if [ "$email_alert" == "1" ] || [ "$type" == "digest" ] || [ "$type" == "daily" ]; then
		if [ "$type" == "file" ] && [ -f "$file" ]; then
			if [ -f "$mail" ]; then
                cat $file | $mail -s "$email_subj" $email_addr
            elif [ -f "$sendmail" ]; then
                if ! grep -q "SUBJECT: " "$file"; then
                    echo -e "SUBJECT: $email_subj\n$(cat $file)" > $file
                fi
                cat $file | $sendmail -t $email_addr
            else
                eout "{scan} no \$mail or \$sendmail binaries found, e-mail alerts disabled."
            fi
			if [ ! "$(whoami)" == "root" ] && [ -z "$(echo $2 | grep '\@')" ]; then
				if [ -z "$hscan" ]; then
					eout "{alert} sent scan report to config default $email_addr" 1
					eout "{alert} send scan report to an alternate address with: maldet --report $datestamp.$$ you@domain.com" 1
				else
					eout "{alert} sent scan report to config default $email_addr"
				fi
			else
				if [ -z "$hscan" ]; then
					eout "{alert} sent scan report to $email_addr" 1
				fi
			fi
		elif [ "$type" == "daily" ] || [ "$type" == "digest" ]; then
			inotify_start_time=`ps -p $(ps -A -o 'pid cmd' | grep -E maldetect | grep -E inotifywait | awk '{print$1}' | head -n1) -o lstart= 2> /dev/null`
			scan_start_hr=`date -d "$inotify_start_time" +"%b %e %Y %H:%M:%S %z"`
			scan_start_elapsed=$(($(date +'%s')-$(date -d "$scan_start_hr" +'%s')))
			inotify_run_time=`echo $(($scan_start_elapsed/86400))d:$(($(($scan_start_elapsed - $scan_start_elapsed/86400*86400))/3600))h:$(($(($scan_start_elapsed - $scan_start_elapsed/86400*86400))%3600/60))m:$(($(($scan_start_elapsed - $scan_start_elapsed/86400*86400))%60))s`

			rm -f $tmpdir/.digest.alert.hits $tmpdir/.digest.clean.hits $tmpdir/.digest.monitor.alert $tmpdir/.digest.susp.hits

			scanid="$datestamp.$$"
			scan_session=`cat $sessdir/session.monitor.current`

			$tlog $scan_session digest.alert > $tmpdir/.digest.alert.hits
			$tlog $clean_history digest.clean.alert > $tmpdir/.digest.clean.hits
			$tlog $monitor_scanned_history digest.monitor.alert > $tmpdir/.digest.monitor.alert
			$tlog $suspend_history digest.susp.alert > $tmpdir/.digest.susp.hits

			tot_hits=`$wc -l $tmpdir/.digest.alert.hits | awk '{print$1}'`
			tot_cl=`$wc -l $tmpdir/.digest.clean.hits | awk '{print$1}'`
			tot_files=`$wc -l $tmpdir/.digest.monitor.alert | awk '{print$1}'`
			tot_susp=`$wc -l $tmpdir/.digest.susp.hits | awk '{print$1}'`

			trim_log $monitor_scanned_history 50000
			trim_log $clean_history 50000
			trim_log $suspend_history 50000

			$tlog $sessdir/session.hits.$datestamp.$$ digest.alert >> /dev/null 2>&1
			$tlog $clean_history digest.clean.alert >> /dev/null 2>&1
			$tlog $monitor_scanned_history digest.monitor.alert >> /dev/null 2>&1
			$tlog $suspend_history digest.susp.alert >> /dev/null 2>&1

			if [ ! -z "$(cat $tmpdir/.digest.alert.hits)" ]; then
				tmpf="$tmpdir/.alert.$RANDOM.$$"
				if [ "$tot_hits" -gt "$tot_files" ]; then
					tot_files="$tot_hits"
				fi
				. $email_template
				cp $tmpf $sessdir/session.$scanid
				grep -E '^{.*}' $sessdir/session.$scanid > $sessdir/session.hits.$scanid
				echo "$scanid" > $sessdir/session.last
				email_subj="${email_subj}: monitor summary"
				if [ -f "$mail" ]; then
					cat $tmpf | $mail -s "$email_subj" $email_addr
					eout "{alert} sent $type alert to $email_addr"
		                elif [ -f "$sendmail" ]; then
					if ! grep -q "SUBJECT: " "$tmpf"; then
						echo -e "SUBJECT: $email_subj\n$(cat $tmpf)" > $tmpf
					fi
					cat $tmpf | $sendmail -t $email_addr
					eout "{alert} sent $type alert to $email_addr"
				else
					eout "{scan} no \$mail or \$sendmail binaries found, e-mail alerts disabled."
				fi
				rm -f $tmpf $tmpdir/.digest.alert.hits $tmpdir/.digest.clean.hits $tmpdir/.digest.monitor.alert $tmpdir/.digest.susp.hits
			fi
		else
			eout "{alert} file input error, alert discarded."
		fi
		
	fi

	if [ "$slack_alert" == "1" ]; then
		if [ "$type" == "file" ] && [ -f "$file" ]; then
			slack_response=$(curl -s -F "token=$slack_token" -F "file=@$file" -F "filename=$slack_subj" -F "channels=$slack_channels" -X POST https://slack.com/api/files.upload | grep -oP '^{"ok":true')
			if [ "$slack_response" ]; then
				eout "{alert} scan report sent to slack channel(s): $slack_channels" 0
			else
				eout "{alert} could not upload scan report to slack channel(s), alert discarded" 1
			fi
		fi
	fi
}


monitor_kill() {
	touch $tmpdir/stop_monitor
	inotify_pid=`pgrep -f inotify.paths.[0-9]+`
	if [ -f "$tmpdir/monitor.pid" ]; then
		monitor_pid=`cat $tmpdir/monitor.pid`
		exit_code="0"
	else
		exit_code="1"
	fi
	monitor_pgid=`ps -p "$monitor_pid" -o pgid= | tr -d ' '`
	kill -9 -- $inotify_pid -$monitor_pgid >> /dev/null 2>&1
	exit $exit_code
}

monitor_cycle() {
        if [ "$BASHPID" ]; then
                echo "$BASHPID" > $tmpdir/monitor.pid
        else
                pgrep maldet > $tmpdir/monitor.pid
        fi
	inotify_cycle_runtime=0
	while [ ! -f "$tmpdir/stop_monitor" ]; do
		inotify_pid=`pgrep -f inotify.paths.[0-9]+`
		if [ -z "$inotify_pid" ]; then
			eout "{mon} no inotify process found, exiting (are we a zombie process?)" 1
			exit
		fi
		log_size=`$wc -l $inotify_log | awk '{print$1}'`
		if [ "$log_size" -ge "$inotify_trim" ]; then
			trim=$(($log_size - 1000))
			log_chars=`printf "%s\n" "1,${trim}p" | ed -s $inotify_log 2> /dev/null | wc -c`
			tlog_new=$(( `cat $inspath/tmp/inotify` - $log_chars ))
			echo $tlog_new > $inspath/tmp/inotify
			printf "%s\n" "1,${trim}d" w | ed -s $inotify_log 2> /dev/null
			eout "{mon} inotify log file trimmed"
		fi
		if [ "$inotify_cycle_runtime" -ge "$inotify_reloadtime" ] || [ -f "$inspath/reload_monitor" ]; then
			if [ -f "$inspath/reload_monitor" ]; then
				rm -f $inspath/reload_monitor
			fi
			source $cnf
			source $intcnf
			import_conf
			inotify_cycle_runtime=0
		        if [ -f "$ignore_file_ext" ]; then
		                if [ ! "$(cat $ignore_file_ext)" == "" ]; then
		                        for i in `cat $ignore_file_ext`; do
		                                if [ "$ignore_fext" == "" ]; then
		                                        ignore_fext="-not -iname \"*$i\""
		                                else
		                                        ignore_fext="$ignore_fext -not -iname \"*$i\""
		                                fi
		                        done
		                fi
		        fi
		        if [ "$scan_ignore_root" == "1" ]; then
		                ignore_root="-not -uid 0 -not -gid 0"
		        fi
		        if [ "$scan_ignore_user" ]; then
		                for i in `echo $scan_ignore_user | tr ', ' ' '`; do
		                        if [ "$ignore_user" == "" ]; then
		                                ignore_user="-not -user $i"
		                        else
		                                ignore_user="$ignore_user -not -user $i"
		                        fi
		                done
		        fi
		        if [ "$scan_ignore_group" ]; then
		                for i in `echo $scan_ignore_group | tr ', ' ' '`; do
		                        if [ "$ignore_group" == "" ]; then
		                                ignore_group="-not -group $i"
		                        else
		                                ignore_group="$ignore_group -not -group $i"
		                        fi
		                done
		        fi
			eout "{mon} reloaded configuration data" 1
		fi
		sleep $inotify_sleep
		inotify_cycle_runtime=$[inotify_sleep+inotify_cycle_runtime]
		sigignore 1
		gensigs
		if [ "$scan_clamscan" == "1" ]; then
			monitor_mode=1
			clamselector
       		fi
		monitor_check
	done
		rm -f $tmpdir/stop_monitor
		eout "{mon} monitoring terminated by user, inotify killed."
		exit
}

monitor_check() {
                monitor_scanlist="$tmpdir/.monitor.scan.${RANDOM}${RANDOM}"
		touch $monitor_scanlist ; chmod 600 $monitor_scanlist
		$tlog $inotify_log inotify | grep -E "CREATE|MODIFY|MOVED_FROM|MOVED_TO" | grep -E -v '/.. ' | awk '{print$1}' | sort | uniq > $monitor_scanlist
		if [ "$scan_clamscan" == "1" ]; then
	                clamscan_results="$tmpdir/.clamscan.result.${RANDOM}${RANDOM}"
			touch $clamscan_results ; chmod 600 $clamscan_results
	                $nice_command $clamscan $clamopts --infected --no-summary -f $monitor_scanlist > $clamscan_results 2>> $clamscan_log || clamscan_return=$?
			if [ "$inotify_verbose" == "1" ]; then
				for file in `cat $monitor_scanlist | tr ' ' '%'`; do
					file=`echo $file | tr '%' ' '`
					eout "{mon} inotify clamav file scan on $file"
				done
			fi
			lbreakifs set
                	for hit in `grep -E -v 'ERROR$|lstat()' $clamscan_results | sed -e 's/.UNOFFICIAL//' -e 's/ FOUND$//' | awk -F':' '{print$2":"$1}' | sed 's/.//'`; do
	                        file=`echo "$hit" | cut -d':' -f2`
        	                signame=`echo "$hit" | cut -d':' -f1`
	                        if [ ! -z "$(echo $signame | grep -E 'YARA')" ]; then
                        	        signame=`echo "$signame" | sed 's/YARA\./{YARA}/'`
                	        elif [ -z "$(echo $signame | grep -E 'HEX|MD5')" ]; then
        	                        signame="{CAV}$signame"
	                        fi
	                        ignore_hit=`echo $signame | grep -E -vf $ignore_sigs`
				if [ -f "$file" ] && [ ! -z "$ignore_hit" ]; then
	                        	record_hit "$file" "$signame"
	        	                quarantine "$file" "$signame"
				fi
				unset ignore_hit
                	done
			lbreakifs unset
			scanned_count=`wc -l $monitor_scanlist | awk '{print$1}'`
			eout "{mon} scanned ${scanned_count} new/changed files with clamav engine"
			rm -f $clamscan_results $monitor_scanlist
		else
			for file in `cat $monitor_scanlist | tr ' ' '%'`; do
				file=`echo $file | tr '%' ' '`
				if [ -f "$file" ]; then
					for fscan in `$nice_command $find "$file" -maxdepth 1 $find_opts -type f -size +${scan_min_filesize}c -size -$scan_max_filesize -not -perm 000 $ignore_fext $ignore_root $ignore_user $ignore_group 2> /dev/null`; do
						if [ "$inotify_verbose" == "1" ]; then
							eout "{mon} inotify native file scan on $file"
						fi
						echo "$file" >> $monitor_scanned_history
						scan_stage1 "$fscan" >> /dev/null 2>&1
					done
				fi
			done
			scanned_count=`wc -l $monitor_scanlist | awk '{print$1}'`
			eout "{mon} scanned ${scanned_count} new/changed files with native engine"
			rm -f $clamscan_results $monitor_scanlist
		fi
}

monitor_init() {
	inopt="$1"
	scan_session="$sessdir/session.hits.$datestamp.$$"
	touch $scan_session
	echo "$scan_session" > $sessdir/session.monitor.current
	
	if [ "$inopt" == "" ]; then
		eout "invalid usage of -m|--monitor, aborting." 1
		exit
	fi
	
	if [ ! -f "$inotify" ]; then
		eout "{mon} could not find inotifywait command, install yum package inotify-tools or download from https://github.com/rvoicilas/inotify-tools/wiki/" 1
		exit
	fi
	
	if [ -f "/boot/System.map-$(uname -r)" ]; then
		ksup=`grep -i inotify_ /boot/System.map-$(uname -r)`
		if [ -z "$ksup" ]; then
			eout "{mon} kernel does not support inotify(), aborting." 1
			exit
		fi
	elif [ -f "/boot/config-$(uname -r)" ]; then
		ksup=`grep -m1 CONFIG_INOTIFY /boot/config-$(uname -r)`
		if [ -z "$ksup" ]; then
			eout "{mon} kernel does not support inotify(), aborting." 1
			exit
		fi
	fi
	
	inotify_pid=`pgrep -f inotify.paths.[0-9]+`
	if [ ! -z "$inotify_pid" ]; then
		eout "{mon} existing inotify process detected (try -k): $inotify_pid" 1
		exit
	fi
	
	rm -f $tmpdir/stop_monitor $tmpdir/inotifywait.pid
	
	if [ -f "/proc/sys/fs/inotify/max_user_instances" ] && [ -f "/proc/sys/fs/inotify/max_user_watches" ]; then
		cur_user_watches=`cat /proc/sys/fs/inotify/max_user_watches`
		cur_user_instances=`cat /proc/sys/fs/inotify/max_user_instances`
	else
		eout "{mon} could not find fs.inotify.max_user_instances|watches tunable files, aborting." 1
		exit
	fi
	users_tot=`cat /etc/passwd | grep -ic home`
	inotify_user_watches=$[inotify_base_watches*users_tot]
	
	if [ "$cur_user_instances" -lt "$inotify_user_instances" ]; then
		eout "{mon} set inotify max_user_instances to $inotify_user_instances" 1
		echo $inotify_user_instances > /proc/sys/fs/inotify/max_user_instances
	fi
	if [ "$cur_user_watches" -lt "$inotify_user_watches" ]; then
		eout "{mon} set inotify max_user_watches to $inotify_user_watches" 1
		echo $inotify_user_watches > /proc/sys/fs/inotify/max_user_watches
	fi
	
	icnt=0
	inotify_fpaths="$sessdir/inotify.paths.$$"
	rm -f $inotify_fpaths
	touch $inotify_log
	chmod 640 $inotify_log
	
	if [ "$(echo $inopt | grep -iE 'user(s?)')" ]; then
		for i in `cat /etc/passwd | cut -d':' -f1,3,6 | sort`; do
			user=`echo $i | cut -d':' -f1`
			user_id=`echo $i | cut -d':' -f2`
			user_home=`echo $i | cut -d':' -f3`
			icnt=$[icnt+1]
			if [ "$user_id" -ge "$inotify_minuid" ]; then
				if [ ! -z "$inotify_docroot" ] && [ -d "$user_home" ]; then
				 lbreakifs set
				 for docroot in `echo $inotify_docroot | tr ', ' '\n'`; do
					if [ -d "$user_home/$docroot" ]; then
						echo "$user_home/$docroot" >> $inotify_fpaths
						eout "{mon} added $user_home/$docroot to inotify monitoring array" 1
					fi
				 done
				 lbreakifs unset
				elif [ -d "$user_home" ]; then
					echo "$user_home" >> $inotify_fpaths
					eout "{mon} added $user_home to inotify monitoring array" 1
				else
					eout "{mon} could not find any suitable user home paths"
				fi
			fi
		done
		
		if [ -d "/dev/shm" ]; then
			echo "/dev/shm" >> $inotify_fpaths
			eout "{mon} added /dev/shm to inotify monitoring array" 1
		fi
		if [ -d "/var/tmp" ]; then
			echo "/var/tmp" >> $inotify_fpaths
			eout "{mon} added /var/tmp to inotify monitoring array" 1
		fi
		if [ -d "/tmp" ]; then
			echo "/tmp" >> $inotify_fpaths
			eout "{mon} added /tmp to inotify monitoring array" 1
		fi
	elif [ -f "$inopt" ]; then
		tot_paths=`$wc -l $inopt | awk '{print$1}'`
		if [ "$tot_paths" == "0" ]; then
			eout "{mon} no paths specified in $inopt, aborting." 1
			exit
		fi
		for i in `cat $inopt`; do
			if [ -d "$i" ]; then
				eout "{mon} added $i to inotify monitoring array" 1
				echo "$i" >> $inotify_fpaths
			else
				eout "{mon} ignored invalid path $i" 1
			fi
		done
		
	elif [ -d "$inopt" ] || [ "$(echo $inopt | grep -E ".*,.*")" ]; then
		for i in `echo $inopt | tr ',' '\n'`; do
			if [ -d "$i" ]; then
				eout "{mon} added $i to inotify monitoring array" 1
				echo "$i" >> $inotify_fpaths
			else
				eout "{mon} invalid path $i specified, ignoring." 1
			fi
		done
	else
		eout "{mon} no valid option or invalid file/path provided, aborting." 1
		exit
	fi
	
	if [ -f "$ignore_inotify" ] && [ -s "$ignore_inotify" ]; then
		for igfile in `cat $ignore_inotify | grep -vE '^$'`; do
			if [ "$igregexp" ]; then
				igregexp="$igregexp|$igfile"
			else
				igregexp="($igfile"
			fi
		done
		if [ "$igregexp" ]; then
			igregexp="$igregexp)"
			exclude="--exclude $igregexp"
		fi
	fi
	
	tot_paths=`$wc -l $inotify_fpaths | awk '{print$1}'`
	eout "{mon} starting inotify process on $tot_paths paths, this might take awhile..." 1

        if [ ! "$inotify_cpunice" ]; then
                inotify_cpunice=19
        fi
        if [ ! "$inotify_ionice" ]; then
                inotify_ionice=6
        fi

        if [ -f "$nice" ]; then
                nice_command="$nice -n $inotify_cpunice"
        fi
        if [ -f "$ionice" ]; then
                nice_command="$nice_command $ionice -c2 -n $inotify_ionice"
        fi
        if [ -f "$cpulimit" ] && [ "$inotify_cpulimit" -gt 2> /dev/null "0" ]; then
                max_cpulimit=$[$(grep -E -w processor /proc/cpuinfo -c)*100]
                if [ "$inotify_cpulimit" -gt "$max_cpulimit" ]; then
                        scan_cpulimit="0"
		else
	                nice_command="$cpulimit -l $scan_cpulimit -i $nice_command"
                fi
        fi

	$nice_command $inotify -r --fromfile $inotify_fpaths $exclude --timefmt "%d %b %H:%M:%S" --format "%w%f %e %T" -m -e create,move,modify >> $inotify_log 2>&1 &
	sleep 2
	inotify_pid=`pgrep -f inotify.paths.[0-9]+`
	if [ -z "$inotify_pid" ]; then
		eout "{mon} no inotify process found, check $inotify_log for errors." 1
		exit
	else
		eout "{mon} inotify startup successful (pid: $inotify_pid)" 1
		eout "{mon} inotify monitoring log: $inotify_log" 1
		echo "$inotify_pid" > $tmpdir/inotifywait.pid
	fi
	monitor_cycle >> /dev/null 2>&1 &
}

checkout() {
	file="$1"
	host=ftp.rfxn.com
	user=anonymous
	passwd=anonymous
	upath=incoming
	
	cfile="$startdir/$file"
	if [ -f "$cfile" ]; then
		file="$cfile"
	fi
	
	if [ -f "$file" ]; then
		
		filename=`basename "$file" | tr -d '[:cntrl:]' | tr -d '[:space:]'`
		if [ -z "$filename" ]; then
			storename="$storename_prefix"
		else
			storename="$storename_prefix.$filename"
		fi
		
		eout "{checkout} uploading $file to $host" 1
		
(ftp -v -n -p -i $host || ftp -v -n -i $host) << EOT
user $user@rfxn.com $passwd
prompt
cd $upath
lcd $lcd
binary
put "$file" "$storename.bin"
ascii
put "$file" "$storename.ascii"
bye
EOT
		
	elif [ -d "$file" ]; then
		tmpf="$tmpdir/.co$$"
		find $file -type f > $tmpf
		cofiles=`wc -l $tmpf | awk '{print$1}'`
		if [ "$cofiles" -ge "25" ]; then
			eout "{checkout} path $file contains $cofiles, limit of 50 file uploads, aborting!" 1
			rm -f $tmpf
		fi
		for i in `cat $tmpf`; do
			filename=`basename "$i" | tr -d '[:cntrl:]' | tr -d '[:space:]'`
			if [ -z "$filename" ]; then
				storename="$storename_prefix"
			else
				storename="$storename_prefix.$filename"
			fi
(ftp -v -n -p -i $host || ftp -v -n -i $host) << EOT
user $user $passwd
prompt
cd $upath
lcd $lcd
binary
put "$i" "$storename.bin"
ascii
put "$i" "$storename.ascii"
bye
EOT
		done
	fi
	
	
}

gensigs() {
	runtime_ndb="$tmpdir/.runtime.user.$$.ndb"
	runtime_hdb="$tmpdir/.runtime.user.$$.hdb"
	runtime_hexstrings="$tmpdir/.runtime.hexsigs.$$"
	rm -f $runtime_ndb $runtime_hdb $runtime_hexstrings 2> /dev/null
	ln -fs $runtime_ndb $sigdir/lmd.user.ndb 2> /dev/null
	ln -fs $runtime_hdb $sigdir/lmd.user.hdb 2> /dev/null
	if [ -s "$sig_user_hex_file" ]; then
		cat "$sig_hex_file" "$sig_user_hex_file" | grep -vE '^\s*$' > $runtime_hexstrings
	else
		cat "$sig_hex_file" > $runtime_hexstrings
	fi
        for cp in $clamav_paths; do
        	clamav_linksigs "$cp"
        done
	
	if [ "$scan_clamscan" == "1" ]; then
		if [ -s "$sig_user_hex_file" ]; then
			for i in `cat $sig_user_hex_file | sed 's/{HEX}//' | tr ':' '%' | grep -vE "^\s*$"`; do
				name=`echo $i | tr '%' ' ' | awk '{print$2}'`
				hex=`echo $i | tr '%' ' ' | awk '{print$1}'`
				if [ ! -z "$name" ] && [ ! -z "$hex" ]; then
					echo "{HEX}$name:0:*:$hex" >> $runtime_ndb
				fi
			done
			cat $sig_cav_hex_file >> $runtime_ndb
		else
			cp $sig_cav_hex_file $runtime_ndb
		fi
		if [ -s "$sig_user_md5_file" ]; then
			cat "$sig_user_md5_file" "$sig_md5_file" | grep -vE "^\s*$" | sort -u > $runtime_hdb
		else
			cp "$sig_cav_md5_file" "$runtime_hdb"
		fi
	fi
}

sigignore() {
	sil="$1"
	chk=`$wc -l $ignore_sigs | awk '{print$1}'`
	if [ ! "$chk" == "0" ]; then
		cat $sig_hex_file | grep -E -vf $ignore_sigs > $sig_hex_file.new
		mv $sig_hex_file.new $sig_hex_file
		cat $sig_md5_file | grep -E -vf $ignore_sigs > $sig_md5_file.new
		mv $sig_md5_file.new $sig_md5_file
		chmod 640 $sig_md5_file $sig_hex_file
		if [ "$sil" == "1" ] || [ "$hscan" == "1" ]; then
			eout "{glob} processed $chk signature ignore entries"
		else
			eout "{glob} processed $chk signature ignore entries" 1
		fi
	fi
}


lmdup() {
	tmpwd="$tmpdir/.lmdup.$RANDOM.$$"
	upstreamver="$tmpwd/.lmdup_vercheck.$$"
	mkdir -p $tmpwd ; chmod 700 $tmpwd

	if [ "$lmdup_beta" ]; then
		lmd_hash_url="${lmd_hash_url}.beta"
		lmd_version_url="${lmd_version_url}.beta"
		lmd_current_tgzfile="maldetect-beta.tar.gz"
	fi
	
	eout "{update} checking for available updates..." 1
        get_remote_file "$lmd_version_url" "update" "1"
	upstreamver="$return_file"	
	if [ -s "$upstreamver" ]; then
		installedver=`echo $ver | tr -d '.'`
		if [ "$(echo $installedver | wc -L)" -eq "2" ]; then
			installedver="${installedver}0"
		fi
		upstreamver_readable=`cat $upstreamver`
		upstreamver=`cat $upstreamver | tr -d '.'`
		if [ "$(echo $upstreamver | wc -L)" -eq "2" ]; then
			upstreamver="${upstreamver}0"
		fi
		if [ "$upstreamver" -gt "$installedver" ]; then
			eout "{update} new version $upstreamver_readable found, updating..." 1
			doupdate=1
		elif [ "$lmdup_force" ]; then
			eout "{update} version update with --force requested, updating..." 1
			doupdate=1
		elif [ "$autoupdate_version_hashed" == "1" ]; then
			eout "{update} hashing install files and checking against server..." 1
			eval $md5sum $inspath/maldet $intfunc | awk '{print$1}' | tr '\n' ' ' | tr -d ' ' > $lmd_hash_file
			upstreamhash="$tmpwd/.lmdup_hashcheck$$"
		        get_remote_file "$lmd_hash_url" "update" "1"
			upstreamhash="$return_file"
			if [ -s "$upstreamhash" ]; then
				installed_hash=`cat $lmd_hash_file`
				current_hash=`cat $upstreamhash`
				if [ ! "$installed_hash" == "$current_hash" ]; then
					eout "{update} version check shows latest but hash check failed, forcing update..." 1
					doupdate=1
				else
					eout "{update} latest version already installed." 1
				fi
			else
				eout "{update} could not download upstream hash file ($lmd_hash_url), please try again later." 1
				cd $inspath ; rm -rf $tmpwd
				clean_exit
				exit 1
			fi
		else
			eout "{update} no updates available, latest version already installed." 1
		fi
	else
		eout "{update} could not download version file from server, please try again later." 1
		cd $inspath ; rm -rf $tmpwd
		clean_exit
		exit 1
	fi
	if [ "$doupdate" ]; then
		cd $tmpwd/

                get_remote_file "${lmd_current_tgzbase_url}/${lmd_current_tgzfile}" "update" "1" "$tmpwd/${lmd_current_tgzfile}"
                get_remote_file "${lmd_current_tgzbase_url}/${lmd_current_tgzfile}.md5" "update" "1" "$tmpwd/${lmd_current_tgzfile}.md5"

		if [ -s "$tmpwd/${lmd_current_tgzfile}.md5" ] && [ -s "$tmpwd/${lmd_current_tgzfile}" ]; then
			upstream_md5=`cat $tmpwd/${lmd_current_tgzfile}.md5 | awk '{print$1}'`
			local_md5=`eval $md5sum $tmpwd/${lmd_current_tgzfile} | awk '{print$1}'`
			if [ ! "$upstream_md5" == "$local_md5" ]; then
				eout "{update} unable to verify md5sum of ${lmd_current_tgzfile}, update failed!" 1
				cd $inspath ; rm -rf $tmpwd
				clean_exit
				exit 1
			else
				eout "{update} verified md5sum of ${lmd_current_tgzfile}" 1
			fi
		else
			eout "{update} could not download ${lmd_current_tgzfile} or .md5, please try again later." 1
			cd $inspath ; rm -rf $tmpwd
			clean_exit
			exit 1
		fi
		if [ -s "$tmpwd/${lmd_current_tgzfile}" ]; then
			tar xfz ${lmd_current_tgzfile}
			rm -f ${lmd_current_tgzfile} ${lmd_current_tgzfile}.md5
			cd maldetect-${upstreamver_readable}
			chmod 750 install.sh
			sh -c './install.sh' >> /dev/null 2>&1
			cp -f $inspath.last/sigs/custom.* $sigdir/ 2> /dev/null
			cp -f $inspath.last/clean/custom.* $inspath/clean/ 2> /dev/null
			eout "{update} completed update v$ver ${installed_hash:0:6} => v$upstreamver_readable ${upstream_md5:0:6}, running signature updates..." 1
			$inspath/maldet --update 1
			eout "{update} update and config import completed" 1
		else
			eout "{update} could not download ${lmd_current_tgzfile}, please try again later." 1
			cd $inspath ; rm -rf $tmpwd
			clean_exit
			exit 1
		fi
	fi
	cd $inspath ; rm -rf $tmpwd
}

sigup() {
	eout "{sigup} performing signature update check..." 1
	
        tmpwd="$tmpdir/.sigup.$RANDOM.$$"
        mkdir -p $tmpwd ; chmod 700 $tmpwd

	import_user_sigs
	
	if [ -z "$sig_version" ]; then
		eout "{sigup} could not determine signature version" 1
		sig_version=0
	else
		eout "{sigup} local signature set is version $sig_version" 1
	fi
	
        get_remote_file "$sig_version_url" "sigup" "1"
	upstream_sigver="$return_file"

	if [ ! -f "$upstream_sigver" ] || [ ! -s "$upstream_sigver" ]; then
		eout "{sigup} could not download signature data from server, please try again later." 1
		clean_exit
		exit 1
	else
		nver=`cat $upstream_sigver`
	fi
	
	if [ -f "$sig_md5_file" ]; then
		lines_md5=`$wc -l $sig_md5_file | awk '{print$1}'`
	else
		lines_md5=0
	fi
	if [ -f "$sig_hex_file" ]; then
		lines_hex=`$wc -l $sig_hex_file | awk '{print$1}'`
	else
		lines_hex="0"
	fi
	
	if [ ! -f "$sig_md5_file" ] || [ ! -f "$sig_hex_file" ]; then
		sig_version=2012010100000
		eout "{sigup} signature files missing or corrupted, forcing update..." 1
	elif [ "$lines_md5" -lt "1000" ] || [ "$lines_hex" -lt "1000" ]; then
		sig_version=2012010100000
		eout "{sigup} signature files corrupted, forcing update..." 1
	elif [ "$sigup_force" ]; then
		sig_version=2012010100000
		eout "{sigup} signature update with --force requested, forcing update..." 1
	fi
	
	if [ "$nver" != "$sig_version" ]; then
		cd $tmpwd/
		tar=`which tar 2> /dev/null`
		eout "{sigup} new signature set $nver available" 1
		
		eout "{sigup} downloading $sig_sigpack_url" 1
		get_remote_file "$sig_sigpack_url" "sigup" "1" "$tmpwd/maldet-sigpack.tgz"
	        get_remote_file "${sig_sigpack_url}.md5" "sigup" "1" "$tmpwd/maldet-sigpack.tgz.md5"

		eout "{sigup} downloading $sig_clpack_url" 1

		get_remote_file "$sig_clpack_url" "sigup" "1" "$tmpwd/maldet-clean.tgz"
		get_remote_file "${sig_clpack_url}.md5" "sigup" "1" "$tmpwd/maldet-clean.tgz.md5"
		
		if [ -f "$tmpwd/maldet-sigpack.tgz.md5" ]; then
			sigpack_md5=`eval $md5sum maldet-sigpack.tgz | awk '{print$1}'`
			sigpack_goodmd5=`cat maldet-sigpack.tgz.md5 | awk '{print$1}'`
			if [ ! "$sigpack_md5" == "$sigpack_goodmd5" ]; then
				eout "{sigup} unable to verify md5sum of maldet-sigpack.tgz, please try again or contact proj@rfxn.com" 1
				sigpackfail=1
			else
				eout "{sigup} verified md5sum of maldet-sigpack.tgz" 1
				if [ -f "$tmpwd/maldet-sigpack.tgz" ] && [ -s "$tmpwd/maldet-sigpack.tgz" ]; then
					tar xfz $tmpwd/maldet-sigpack.tgz 2> /dev/null
					if [ -d "$tmpwd/sigs" ]; then
						mkdir -p $sigdir.old 2> /dev/null
						rm -f $sigdir.old/* 2> /dev/null
						cp -f $sigdir/* $sigdir.old/ 2> /dev/null
						cp -f $tmpwd/sigs/* $sigdir 2> /dev/null
						eout "{sigup} unpacked and installed maldet-sigpack.tgz" 1
						for cp in $clamav_paths; do
							clamav_linksigs "$cp"
						done
						killall -SIGUSR2 clamd 2> /dev/null
					else
						eout "{sigup} something went wrong unpacking $sig_sigpack_url, aborting!" 1
						sigpackfail=1
					fi
				else
					eout "{sigup} could not download $sig_sigpack_url" 1
					sigpackfail=1
				fi
			fi
		else
			eout "{sigup} could not download ${sig_sigpack_url}.md5" 1
			sigpackfail=1
		fi
		
		if [ -f "$tmpwd/maldet-clean.tgz.md5" ]; then
			clpack_md5=`eval $md5sum maldet-clean.tgz | awk '{print$1}'`
			clpack_goodmd5=`cat maldet-clean.tgz.md5 | awk '{print$1}'`
			if [ ! "$clpack_md5" == "$clpack_goodmd5" ]; then
				eout "{sigup} unable to verify md5sum of maldet-clean.tgz, please try again or contact proj@rfxn.com" 1
				clpackfail=1
			else
				eout "{sigup} verified md5sum of maldet-clean.tgz" 1
				if [ -f "$tmpwd/maldet-clean.tgz" ] && [ -s "$tmpwd/maldet-clean.tgz" ]; then
					tar xfz $tmpwd/maldet-clean.tgz
					cp -f $tmpwd/clean/* $cldir
					eout "{sigup} unpacked and installed maldet-clean.tgz" 1
				else
					eout "{sigup} error handling $sig_clpack_url, file is either missing or zero sized, aborting!" 1
					clpackfail=1
				fi
			fi
		else
			eout "{sigup} could not download ${sig_sigpack_url}.md5" 1
			clpackfail=1
		fi
		
		if [ "$sigpackfail" ]; then
			cd $inspath
			rm -rf $tmpwd
			clean_exit
			exit 1
		else
			eout "{sigup} signature set update completed" 1
			sigignore
			
			hex_sigs=`$wc -l $sig_hex_file | awk '{print$1}'`
			md5_sigs=`$wc -l $sig_md5_file | awk '{print$1}'`
			yara_sigs=`grep -E -c ^rule $sig_yara_file | awk '{print$1}'`
			if [ ! -f "$sig_user_md5_file" ]; then
				user_hex_sigs=0
			else
				user_hex_sigs=`$wc -l $sig_user_hex_file | awk '{print$1}'`
			fi
			if [ ! -f "$sig_user_hex_file" ]; then
				user_md5_sigs=0
			else
				user_md5_sigs=`$wc -l $sig_user_md5_file | awk '{print$1}'`
			fi
			user_sigs=$[user_hex_sigs+user_md5_sigs]
			
			tot_sigs=$[md5_sigs+hex_sigs+user_hex_sigs+user_md5_sigs+yara_sigs]
			eout "{sigup} $tot_sigs signatures ($md5_sigs MD5 | $hex_sigs HEX | $yara_sigs YARA | $user_sigs USER)" 1
		fi
		cd $inspath
		rm -rf $tmpwd
	else
		eout "{sigup} latest signature set already installed" 1
		cd $inspath
		rm -rf $tmpwd
	fi
}


postrun() {
	rm -f $find_results $scan_session $runtime_ndb $runtime_hdb $runtime_hexstrings $clamscan_results $tmpdir/.tmpf* 2> /dev/null
	if [ ! "$tot_hits" ]; then
		exit 0
	elif [ "$tot_hits" == "0" ]; then
		exit 0
	elif [ "$tot_hits" -ge "1" ]; then
		exit 2
	fi
}

Copyright 2K16 - 2K18 Indonesian Hacker Rulez