v2.0.1 | Mar 25 2026:

  -- New Features --

[New] Monitor mode: supervisor model replaces double-fork; 12 pre-existing defects resolved (graceful shutdown, crash recovery, session rotation, event filter, PID guard, ClamAV cache); issue #454, #447, #459
[New] Config: digest_interval, digest_escalate_hits, monitor_paths_extra for monitor mode
[New] TSV canonical session format: 11-field hit records replace plaintext session files;
      session_legacy_compat config (auto/0/1) for backward compatibility
[New] JSON report output: --json-report [SCANID|list|newest] renders TSV sessions as
      JSON (v1.0 schema); --format text|json|html and --mailto ADDRESS
[New] Compound signature (csig) scanning: multi-pattern boolean logic (AND/OR/threshold),
      case-insensitive matching (i:), wide UTF-16LE matching (w:), bounded gap wildcards
      ({N-M}); csig.dat and custom.csig.dat; scan_csig config var
[New] SHA-256 hash-based scanning: CPU hardware acceleration auto-detection (SHA-NI on
      x86, SHA2 on ARM); scan_hashtype config (auto/sha256/md5/both); sha256v2.dat
      signature file; ClamAV .hsb integration with version gate (>= 0.97);
      custom.sha256.dat for user-defined sigs
[New] Native batch scan engine: 43x faster HEX+CSIG; parallel grep workers;
      micro-chunked processing (scan_hex_chunk_size config); Perl dependency removed
[New] Batch hit processing: unified bulk operations replace per-hit fork loops across
      all scan engines; batched chattr/chmod/chown for quarantine
[New] Native YARA scanning: scan_yara=1 enables YARA as independent scan stage with
      yara or yr (YARA-X) binary; custom.yara and custom.yara.d/ drop-in directory;
      compiled rules via yarac, --scan-list batch scanning; issue #392, #277, #239
[New] Email alerts reimagined: HTML+text dual-format with template engine ({{TOKEN}}
      placeholders); SMTP relay support (smtp_relay, smtp_from, smtp_user, smtp_pass);
      email_format config (text/html/both); Slack Block Kit, Telegram MarkdownV2,
      Discord embed templates; on-demand HTML rendering from session data
[New] Discord alerting: discord_alert and discord_webhook_url config; scan reports
      uploaded via Discord webhook multipart upload
[New] Shared library integrations: alert_lib, elog_lib (structured event logging with
      audit trail), tlog_lib (incremental log tracking), pkg_lib (packaging primitives)
[New] ClamAV signature validation gate: clamscan -d validates sig files before
      deployment; sigup() SIGUSR2 reload gated on validation success; issue #467
[New] sigup_interval: independent 6-hourly signature update cron job via
      /etc/cron.d/maldet-sigup; --cron-sigup handler; configurable interval (0 to disable)
[New] cron.watchdog: weekly watchdog script for independent fallback signature updates
[New] cron.daily: explicit cPanel addon/subdomain document root detection via
      /etc/userdatadomains; Bitrix panel detection; issue #268, #381
[New] -v/--version flag displays version information and exits 0
[New] scan_clamscan and scan_yara support 'auto' mode for runtime binary detection
[New] Hook scanning API: modsec/ftp/proftpd/exim/generic mode dispatch; --list/--stdin
      batch; rate limit; sig masking
[New] Hook escalation: immediate alert on hit threshold; deduplicated with digest
[New] Hook digest and reporting: --digest on-demand alerts; --report hooks with
      time/mode filters
[New] --test-alert {scan|digest} {email|slack|telegram|discord}: send test alert with
      synthetic data through the real rendering pipeline; channel isolation; root-only gate
[New] Audit log: 7 event types (purge, update, alert_failed, hookscan source/rate metadata)
[New] importconf: config migration extracted from install.sh for shared use
[New] RPM and DEB packaging: FHS-compliant layout with backward-compatible symlink farm
[New] Package install tests: FHS layout, symlink farm, permissions verification
[New] Symlink farm enforcement: static manifest ships with RPM/DEB; pkg_fhs_verify_farm
      auto-detects and repairs broken symlinks at startup
[New] FHS fallback sourcing: maldet boots from /usr/lib/maldet when legacy symlinks broken
[New] Portable source-tree execution: run maldet directly from git clone or tarball without
      install.sh; auto-detects inspath from script location; LMD_BASEDIR env override
[New] Scan lifecycle management: --kill, --pause/--unpause, --stop/--continue for running
      scans; -L/--list-active shows running/paused/stopped scans (text/json/tsv);
      --maintenance rotates history, compresses sessions, archives by month; session index
      for O(1) report listing; scan.meta tracks per-scan state; scan_meta_cleanup_age config
[New] SCANID format validation: ^[0-9]{6}-[0-9]{4}\.[0-9]+$ regex enforced at all 5 CLI
      entry points (--kill, --pause, --unpause, --stop, --continue)
[New] -e list: redesigned columnar output with header row; --all flag shows full scan
      history (default: recent 14 entries); QUAR column; stopped/checkpointed scans visible
      between active and history sections (text and JSON); pager when --all on TTY;
      JSON active array; FreeBSD sort support
[New] Logrotate config: /etc/logrotate.d/maldet rotates event_log, clamscan_log, and
      audit.log weekly (12 rotations); inotify_log excluded (managed by --maintenance);
      installed only when logrotate is available; RPM/DEB: %config(noreplace)
[New] post-scan hook: configurable script execution after scan completion;
      supports args/file/json output tiers, sync/async execution, timeout
      with SIGTERM/SIGKILL, elog audit trail, min_hits threshold, scan type filter;
      scan_start epoch in JSON payload (LMD_SCAN_START env); issue #477
[New] ignore_inotify: two-file union model — LMD-managed defaults
      ($inspath/internals/ignore_inotify.defaults) refreshed for systemd-private
      tmpdirs, modern MariaDB, PostgreSQL, Redis, ClamAV runtime; user-owned
      ignore_inotify retained for site overrides; dead legacy regex defaults
      replaced (broken since _monitor_escape_ere change); issue #480
[New] monitor_scan_owner_filters config variable: when 0 (default), monitor mode
      admits all files regardless of owner so root-owned malware is not silently
      dropped; when 1, scan_ignore_root/user/group ownership filters are applied
      in monitor mode (opt-in); issue #485
[New] tests/uat/05-monitor-mode.bats: UAT scenario asserting monitor quarantines
      a root-owned EICAR dropped into a webuser-owned docroot under reporter's
      config (scan_ignore_root=1 + monitor_scan_owner_filters=0 default);
      regression test closing the coverage hole that let rc1..rc3 ship with the
      filter bug; issue #485

  -- Changes --

[Change] slop: remove 15 unused LMD_<STEM>_VERSION sub-lib constants +
         paired shellcheck disable=SC2034 suppressions; set at sub-lib
         extraction, never consumed by any code, test, packaging, or
         doc surface; _LMD_<STEM>_LOADED source guards (distinct symbols)
         remain as the idempotent-sourcing mechanism; round 3 slop audit

[New] _monitor_to_ere_entry(): semantic dispatch helper for ignore_inotify
      entry preparation (defaults-always-escape, user-raw-or-literal:)
[Change] tests/48-monitor-ignore-regex.bats: integration coverage for
      ignore_inotify ERE + literal: prefix + ignore_paths monitor-mode
      consistency + malformed-regex symmetry; issue #484
[Change] docs: ignore_inotify ERE-default + literal: prefix semantics
      across ignore_inotify header, README §7, maldet.1 FILES; issue #484
[Change] tests: prune two tautological assertions — the
         "uninstall.sh delegates service removal to pkg_service_uninstall"
         grep-for-token check in 01-install-cli.bats (string presence, not
         behavior) and the "ignore_inotify.defaults is installed at
         internals path" existence check in 47-ignore-inotify-defaults.bats
         (adjacent "has non-comment entries" test already fails if the
         file is missing)
[Change] monitor: log filtered-cycle event count when all events dropped by
         tier-2 scan filter (_event_count > 0 but _tot_files == 0); issue #485
[Change] tests/helpers/uat-lmd.bash: de-duplicate Dockerfile-level
         scan_ignore_root="0" bake — remove redundant sed from
         uat_lmd_install and add opt-in uat_lmd_disable_root_filter
         helper so each UAT caller explicitly documents its
         dependency on the override; all 19 existing UAT callers
         migrated (effective value unchanged — still 0 via
         Dockerfile bake + explicit helper call); unblocks issue-485
         UAT which re-sets scan_ignore_root=1 to exercise the
         production default; issue #485
[Change] docs: conf.maldet scan_ignore_root comment cross-references monitor carve-out;
         README.md scan_ignore_root row notes monitor exception, new
         monitor_scan_owner_filters row added to monitor config table;
         maldet.1 MONITOR MODE gains carve-out paragraph (issue #485 rationale,
         monitor_scan_owner_filters semantics) and Monitoring config group
         listing updated; issue #485
[Change] Vendored libs synced to canonical: tlog_lib 2.0.6, alert_lib 1.0.7, elog_lib 1.0.6, pkg_lib 1.0.10 (zero functional change)
[Change] Alert templates: consolidate summary into headers; drop "TOTAL" prefix from
         labels (HITS/CLEANED/QUARANTINED); add quarantine metrics; aligned column spacing
[Change] Hook scans write to rolling hook.hits.log instead of creating session files;
         genalert suppressed for hook scans
[Change] HTML email rendered on-demand at send time from current templates; persistent
         .html session files no longer stored; responsive layout with Outlook compatibility
[Change] CLI: modifier flags (-x, -i, -hscan, -qd, -co, --format, --mailto) are now
         position-independent; -co uses in-memory parser; -qd with non-existent
         directory exits 1
[Change] Rename sig_import_*_url config variables (from import_custsigs_*_url) for
         sig_* namespace consistency; compat.conf migration maps old names
[Change] scan_workers default changed from "0" to "auto"; "0" silently accepted as
         auto for backward compat
[Change] Update verification prefers SHA-256 over MD5; graceful MD5 fallback when
         sha256sum absent
[Change] maldet.service: EnvironmentFile changed from conf.maldet to
         /etc/sysconfig/maldet or /etc/default/maldet; init script uses -b daemonization
[Change] -E/--dump-report suppressed from help; case handler retained for backward compat
[Change] inotify_verbose config variable removed; per-file ClamAV logging was
         superseded by batch engine log messages with no in-code consumer
[Change] telegram_file_caption config variable removed; was unreferenced — the
         Telegram file upload passes an empty caption
[Change] Scan engine: HEX+CSIG merged into single worker pass; scan stage reorder
         (strlen runs last); bulk awk HEX classifier
[Change] gensigs: awk compiler for faster signature compilation; dead helpers removed
[Change] _scan_progress(): plain newline-terminated output in non-TTY contexts;
         ANSI escape sequences gated behind TTY check; logarithmic backoff reduces
         progress I/O on non-native engines (ClamAV, YARA); watchdog semantics for
         engine health monitoring
[Change] install.sh: delegate config/state migration to importconf
[Change] scan_hexdepth default reduced from 524288 (512 KB) to 262144 (256 KB); covers
         98.9% of HEX patterns with YARA backstop for remaining 1.1%; importconf migration
         for old default
[Change] FHS log path: /var/log/maldet/ is now the authoritative log directory for all
         install methods; $inspath/logs is a backward-compatible symlink; install.sh
         migrates existing logs on upgrade (cp -a, preserves timestamps/permissions)
[Change] --maintenance: session compression age raised from 1 hour to 30 days;
         archive age raised from 30 days to 90 days; scan_meta_cleanup_age default
         raised from 24 to 48 hours; new config variables maint_compress_age,
         maint_archive_age (both disableable with 0)
[Change] cron.daily: run --maintenance after sigup/versionup for automated history
         rotation and session cleanup; hardcoded log paths replaced with $maldet_log
[Change] Lifecycle JSON (-L --format json): "scan_id" is now the canonical field name;
         "scanid" remains as a deprecated alias for one release cycle and will be
         removed in v2.1.0. Consumers should switch to "scan_id"; issue #482
[Change] Lifecycle JSON (-L --format json): "workers" field type normalized to
         unquoted number to match the field's underlying integer value; issue #482
[Change] _json_escape_string: promoted to lmd.lib.sh shared utilities so all JSON
         emitters (scan list, active lifecycle, post-scan hook, ELK dispatch) share
         one helper; sibling _json_escape_var out-parameter helper for hot loops
         that must avoid a subshell fork per iteration; issue #482
[Change] --json-report list: active[]/stopped[] gain ppid + hashtype fields from
         scan.meta; reports[] gains derived completed_epoch (started_epoch +
         elapsed_seconds, null when inputs missing); field ordering normalized
         across all three arrays (identity → process → location → time →
         config → metrics)
[Change] --json-report list schema 1.1: top-level scanner block ({name, version,
         sig_version}) and host block ({hostname, host_id}) mirror per-scan
         JSON schema; field renames for parity with per-scan JSON — hashtype
         → hash_type, hits → total_hits, elapsed → elapsed_seconds; stopped[]
         stopped_hr → stopped for symmetry with started/started_epoch pattern
         (internal meta/checkpoint field names unchanged); active[]/stopped[]
         add quarantine_enabled (boolean, from scan.meta) and null total_cleaned/
         total_quarantined (post-scan actions not yet determined mid-scan);
         stopped[] adds engine + sig_version parity with active[]; reports[]
         adds sig_version + quarantine_enabled (null for pre-bump rows and
         legacy plaintext sessions)
[Change] scan.meta: new quarantine_enabled field written by _lifecycle_write_meta
         from $quarantine_hits; _lifecycle_read_meta parses into
         _meta_quarantine_enabled
[Change] maldet.1, README.md: schema 1.2 docs — new JSON OUTPUT subsection
         in maldet.1 documenting the uniform top-level shape; --json-report
         description extended; session.index FILES entry describes 14-field
         v2 schema with back-compat note for v1; README.md JSON references
         updated v1.0 → v1.2
[Change] --json-report SCANID schema 1.2: per-scan JSON shape now mirrors
         --json-report list — top-level keys are {schema_version, scanner,
         host, reports[single]}; reports[0] carries scan_id (was scan.id),
         started_epoch + completed_epoch (NEW), and the existing per-scan
         fields (path, started, completed, elapsed_seconds, total_files,
         total_hits, total_cleaned, total_quarantined, quarantine_enabled,
         hits[], summary{}); scanner block at top level adds engine +
         hash_type alongside name/version/sig_version; legacy plaintext
         sessions emit the same shape with reports[0].source="legacy" and
         scanner.{engine,hash_type,version,sig_version}=null
[Change] --json-report list schema_version 1.1→1.2: top-level "version" key
         renamed to "schema_version" and bumped to "1.2"; reports[] entries
         now carry "completed" (string from session.index field 12),
         "engine" (field 13), "hash_type" (field 14) for parity with
         per-scan JSON; pre-v1.2 index rows and pass-2 legacy plaintext
         sessions emit literal JSON null (never "-", never empty)
[Change] session.index v1.2 readers: text path (view_report list) and JSON
         list pass-1 extend their IFS=read named-vars lists with
         _ix_completed_hr / _ix_engine / _ix_hashtype to consume the new
         fields without spillage; pass-2 legacy reader unchanged (predates
         v1.2 fields, will emit JSON null in Phase 4 emission step)
[Change] session.index schema 1.2: bumped 11→14 fields (completed_hr + engine
         + hash_type appended as fields 12-14); header sentinel #LMD_INDEX:v1
         → v2 for explicit consumer-side detection (readers tolerate both);
         _session_index_append accepts 14 args (11-arg calls default fields
         12-14 to "-"); _session_index_rebuild wires through previously-
         discarded TSV throwaway vars _r_end_hr/_r_engine/_r_hashtype
[Change] session.index schema bumped 9→11 fields (sig_version + quarantine_enabled
         appended as fields 10 + 11); _session_index_append accepts 11 args
         (9-arg calls default fields 10-11 to "-" and "0"); _session_index_rebuild
         emits 11 fields from TSV session headers; readers tolerate old 8/9-field
         rows via existing backward-compat shim
[Change] lmd_lifecycle.sh: remove dead stage_started meta-schema parser case
         and initializer (no code ever wrote stage_started to any meta file)
[Change] lmd_scan.sh, lmd_quarantine.sh: remove unused local variables (_total
         in _wait_workers_with_progress, fname in restore, _filtered_sess/_ql
         in _batch_quarantine)
[Change] conf.maldet / maldet.1: correct post_scan_hook_timeout documentation — prior
         text claimed a 5-second grace period before SIGKILL, but timeout(1) is invoked
         without --kill-after, so a hook that traps SIGTERM will run indefinitely; pr#478

  -- Bug Fixes --

[Fix] monitor: restore v1.6.6 ERE semantics for ignore_inotify entries;
      introduce literal: per-entry prefix for opt-in escape of paths
      containing regex metachars; issue #484
[Fix] monitor: ignore_paths now uses grep -E -vf (ERE) to match scan-mode
      semantics; fixes silent regression from awk index() substring
      filter introduced by monitor-mode redesign; issue #484
[Fix] ignore_inotify.defaults: re-add "scantemp." (trailing-dot-safe) for
      ClamAV scan-temp directory noise; trailing dot prevents matching
      user files named scantemplate.*; issue #484, #104, #431

[Fix] monitor: ownership filters (scan_ignore_root/user/group) unconditionally
      excluded root-owned files in monitor mode; root-owned malware drops silently
      produced 0 quarantine hits despite detection; gated behind new
      monitor_scan_owner_filters toggle (default 0 = filters off); issue #485
[Fix] monitor: union-load ignore_inotify + ignore_inotify.defaults; new _monitor_load_ignore_inotify_union helper skips blanks+comments, dedupes across both files; issue #480
[Fix] --json-report list: path field parity with text mode; unified JSON escaping
      across reports[]/active[]/stopped[]; dedup+escape rewrite eliminates O(N^2)
      hang at ~20K sessions (82s → 1.7s); active[] gains lifecycle schema
      (eta/workers/sig_version/progress); stopped[] gains elapsed; issue #482
[Fix] --json-report list: reports[] now globally sorted by started_epoch
      (newest first) across TSV index + legacy-session passes (pre-fix emitted
      index entries in append-order then legacy, producing visible date
      inversions); reports[]/active[]/stopped[] all gain started_epoch integer;
      stopped[] gains stopped_epoch; pass-2 glob skips legacy session.*.html
      artifacts (fixes 12s+ hangs on installs with pre-on-demand-HTML files);
      issue #483
[Fix] clamav_linksigs: guard mktemp staging failure to prevent writing signature
      files into the filesystem root. When mktemp -d fails, the empty _staging
      variable caused "cp -f ... /" as root; pr#478
[Fix] _json_escape_string: replaced sed pipeline with bash parameter expansion;
      fixes FreeBSD breakage (sed="$sed -E" execve) and multi-newline escaping
      for post_scan_hook JSON payloads; pr#478
[Fix] DEB: override_dh_fixperms restores 640/750 modes (72 files incl.
      conf.maldet.hookscan.default, /etc/default/maldet, and 15 sub-library shell
      files) after debhelper normalizes executables to 755 and non-executables
      to 644; RPM uses %attr() and is unaffected; pr#478
[Fix] --test-alert digest: seed $tmpdir/digest.hook.alert cursor to _orig_size
      so first-run tlog_read dispatches synthetic hits on fresh installs; prevents
      real-hit leakage into test email and re-send on next real digest; pr#478
[Fix] Hook validation: world-writable detection used broken glob extraction that always
      returned empty string; replaced with bash substring to correctly extract last octal
      digit; pr#478
[Fix] Scan lifecycle JSON: workers field emitted unquoted "auto" string producing invalid
      JSON; now resolves to integer before writing scan.meta; pr#478
[Fix] Report list: --format tsv silently returned text output; now returns explicit error
      directing users to --report active for TSV output; pr#478
[Fix] Background scans (-b): scan process recorded parent shell PID ($$) instead of
      actual forked PID (BASHPID); --kill/--pause/--stop targeted wrong process; scan.meta
      now stores ns_pid separately from pid for correct liveness/signal delivery
[Fix] Scan progress: clear TTY progress line before stage-transition output to
      prevent overwritten/garbled text when scan moves between stages
[Fix] -L/--list-active: elapsed time showed 0h 00m for running scans; now
      computed live from scan start epoch instead of reading the completed-only
      meta field
[Fix] Checkpoint resume: eval replaced with printf -v and options gated through
      -co allowlist; rejects PATH, IFS, LD_PRELOAD from tampered checkpoint files
[Fix] CLI error messages (--user, -s, -q, -n, unrecognized option) now write to
      stderr; -co validation failure now exits instead of continuing silently
[Fix] checkout: returns error when file/directory not found (was silent return 0)
[Fix] smtp-relay: guard html_file before cat on text-format emails (was cat "")
[Fix] JSON report list hang: index-first hybrid eliminates O(N) per-file glob on servers
      without session.index; legacy plaintext sessions preserved
[Fix] Package manifests: add lmd_lifecycle.sh to RPM spec, DEB rules, symlink-manifest
[Fix] Scan pause: suppress console progress and elapsed timer during --pause; elapsed
      excludes paused duration
[Fix] CSIG compiler: reject invalid && separator and universal subsigs in OR groups
[Fix] install.sh: detect supervisor and legacy monitor; graceful stop+restart on upgrade;
      man page compression on fresh install; backup robustness; no longer kills inotify
      monitoring; Slackware init per rc.NAME convention; preserve hookscan config and
      pub/ state; issue #414
[Fix] purge() dotfile glob: replace * glob with find -delete to catch dotfiles in
      tmp/quarantine/sess
[Fix] Quarantine: correct scan ID in report warning; TOCTOU mv exit code check; inode
      naming replaces $RANDOM; batch signature name; colon truncation; -q batch summary
      now prints to stdout; issue #399
[Fix] Temp file leaks: cleanup .alert_html.* after email dispatch; add clean.$$ and
      suspend.users.$$ to _scan_cleanup() rm list
[Fix] Restore orphan: remove .info metadata after successful quarantine restore
[Fix] Scan: extract hitname from session TSV for hook output
[Fix] ClamAV: sig deployment permissions 644, empty sig cleanup, linksigs ordering,
      version-gated .hsb; artifacts cleaned from data dirs when ClamAV disabled;
      MD5 merge format corrected for custom user signatures; _count_signatures()
      counts from on-disk files instead of runtime variables
[Fix] --report: recognize "latest" as alias for "newest"
[Fix] -e list: strip timezone offset from TSV session timestamps for consistent alignment
[Fix] get_remote_file: track temp files (.tmpf_get.*) and clean up at end of remote
      operations
[Fix] sigup: write downloaded version to maldet.sigs.ver to prevent CDN desync
      repeated downloads
[Fix] Scan engine: isolate worker temp files using parent PID namespace to prevent
      concurrent scan conflicts
[Fix] scan(): exit 1 when all provided scan paths do not exist
[Fix] Hash scanning: handle md5sum/sha256sum backslash-escaped filenames
[Fix] Alerting: Slack migrated from deprecated files.upload API; Telegram /bot prefix;
      token security via curl -K; genalert() state isolation; issue #387, #458, #461, #426
[Fix] Security: _safe_source_conf() allowlist (79 vars); conf.maldet 0640; dirs 750;
      remote config RCE prevention; semver validation prevents directory traversal;
      hookscan.sh validates ModSecurity filenames; --user validates against path traversal;
      JSON injection prevention; email header injection prevention
[Fix] view_report(): on-demand text rendering from TSV; "newest" and empty scan ID
      resolve to most recent session; issue #336
[Fix] sigignore(): moved to runtime copies in gensigs(); signatures no longer
      irrecoverably lost between signature updates
[Fix] CLI robustness: 19 bare exit statements given explicit codes; -c, -x, -i, -q,
      -n, -s, --web-proxy reject missing/empty arguments; issue #366
[Fix] FreeBSD: detection via uname -s; id -u (POSIX); restore() touch -t for mtime;
      portable command cp/mv/rm throughout; scan_strlen guard (wc -L is GNU-only)
[Fix] clamselector(): logs warning on clamd test failure instead of silently switching;
      no longer overwrites user scan_max_filesize; issue #452, #410
[Fix] cron.daily: flock lock leak to backgrounded scans; lockfile prevents overlapping
      runs; config errors propagate to cron; issue #373
[Fix] find/ignore: ignore_file_ext, --exclude-regex, --include-regex, ignore_paths
      converted to bash arrays; scan_ignore_user/group handles non-existent entries;
      issue #446, #438, #450, #72, #335, #440
[Fix] Alert rendering: hit type regex handles {MD5}/{CSIG}/{SHA256} prefixes; empty
      quarpath field shift in text reports; empty SUMMARY_* tokens in single-hit messaging
[Fix] tlog trim cursor unit mismatch: purge() and monitor_cycle() subtracted byte
      count from line-count cursor; issue #227; replace ed dependency; issue #308
[Fix] Miscellaneous portability: mktemp replaces $RANDOM/$$; command -v replaces
      which; grep -E replaces egrep; POSIX ':' chown separator; hardcoded binary
      paths replaced with command -v discovered variables
[Fix] restore() and restore_hitlist(): return exit 1 on all error paths
[Fix] YARA rules no longer counted as active when no engine available (YARA(no engine))
[Fix] Quarantine restore: quote $file_mode in chmod to prevent misinterpretation
      when .info file is corrupt or has fewer than 9 fields
[Fix] Packaging: tar fallback excludes pkg/ directory (was pkg/build only)
[Fix] RPM/DEB: packages now run signature update on fresh install (was missing);
      migrate core sig files from tarball installs; link ClamAV sigs and signal
      clamd reload; shared pkg-postinst.sh for install.sh post-install parity
[Fix] RPM/DEB %pre: defensive detection for dir-vs-symlink cpio conflict; install
      no longer fails with "rename failed - Is a directory" when prior install.sh
      or partial install left real directories at symlink-target paths

v1.6.6.1 | Feb 25 2025:
[Fix] find_recentopts incorrectly escaping find options to the right of ( -mtime .. -ctime ); previously normalized by eval; issue #440, pr#442
[Fix] persist configuration value inotify_docroot between upgrades; issue #439

v1.6.6 | Feb 19 2025:
[Fix] replaced eval usage in dynamic execution to improve security; thank you for responsible disclosure from barrebas
[Fix] malware notification emails to ignore inactive siteworx users; pr #425
[New] add reporting support for telegram channel; pr #378
[New] add statistics collection and sending to ELK; pr #359
[Fix] prune ignore_paths with find -prune; pr #423, issue #433
[Fix] suppress excessive clamav temporary file inotify alerts by adding '/tmp/.*scantemp.*' to ignore_inotify; issue #431, #104
[Fix] consistent cron.daily file sourcing to allow configuration overrides; issue #401, #115

v1.6.5 | Mar 27 2023:
[Fix] monitor mode white space detection; issue #354
[Change] event_log/clamscan_log now record year in timestamp; issue #352
[Change] -p|--purge will now trim the inotify_log; issue #350
[New] -E|--dump-report to dump reports to stdout; pr #362
[Fix] monitor mode will now fail to start if 'ed' is not installed; issue #350
 inotify_log requires in-place inode pruning to prevent exponential growth
[Fix] inotify kernel support on debian11 checking only System.map; pr #398
[Fix] human-readable path not displaying on -a|--scan-all default path scan (/home); #407
[Change] default scoped scan adjusted from /var/www/html to /var/www to make sure we scope all www content; #404
[Fix] compare md5 on ignore_sigs between monitor mode cycles and only regenerate signatures on file changes; #397
[New] add detect_control_panel function to files/internals/functions to determine installed control panel; pr #409
[New] add get_panel_contacts to files/internals/functions to discover contact emails; pr #409
[New] add configuration options for From, Subject, Reply-To headers on alert emails; pr #409
[New] add flag to enable these alerts (requires email_alert to be enabled as well); pr #409
[New] add internal configuration to set the user alert template location; pr #409
[New] add a base template that will be used to create emails to control panel contacts; pr #409
[Change] ambiguous restore error modified to include file name
[Fix] adjusted ftp.rfxn.com checkout credentials; #390
[Fix] systemd unit file not copying properly; #371, #413
[Fix] monitor mode dependency failures on 'ed' not properly logging to be captured by unit file; #395
[Fix] newer versions of cpulimit explicitly enforce the usage of '--' to define where cpulimit options end; #395

v1.6.4 | Mar 18 2019:
[New] add quarantine_on_error variable to control quarantine behavior when scanner engines such as ClamAV encounter an error
[New] add support for slack alerts; pr #240 mostafahussein
[New] add ability to disable cron via conf.maldet; issue #260 / pr #300 , #304 sporks5000
[New] add cleaner rule for php.malware.magentocore_ccskim and an alias of as php_malware_hexinject for associated yara rule
[Change] update cron.daily for ispmanager5; pr #305 yogsottot
[Change] normalize variable naming of pr #300 , #304
[Change] validate cron_daily_scan is set; otherwise default to 1
[Change] update importconf for cron_daily_scan block
[Change] don't need "find" if given a file list; pr# 303 sporks5000
[Change] rename ambiguous internal variables related to user signatures
[Change] removed clamscan_return code capture from piped logic of clam(d)scan execution; now always capture return code, even on good exits
[Change] scan results now explicitly exclude any occurrences of files related to 'no reply from clamd' errors
[Change] add backward compatibility for renamed internals.conf variables
[Change] removed legacy $verbose tagging at the end of eout() calls
[Change] modified cleaner rules to set their own PATH scoping
[Change] file_stat() has been renamed get_filestat to match associated quar_get_filestat function naming
[Change] get_file_stat() will now grab md5 hash of files to avoid superfluous md5sum calls
[Change] added inotify elapsed run time to scan report output
[Change] adjust '-e|--report' output for etime value and spacing
[Change] force email_ignore_clean=1 to stop the most common email requested issue
[Fix] hitname not logging to quarantine.hist on manual quarantine run against scanid; issue #319
[Fix] typo in PR #300; missing '; then' on elif
[Fix] set default_monitor_mode to resolve issue #311 systemd service passing $default_monitor_mode as a literal string to the service
[Fix] sad mail/sendmail validation logic, fix issue #316
[Fix] normalized scan start time output in scan reports when inotify monitoring is used
[Fix] scan report list summary to always display an etime value, even if null
[Fix] ad-hoc clean calls from clean_hitlist() was not executing sigignore and gensigs functions causing clean tasks to fail due to missing variables; issue #203
[Fix] adjust semantics of comma and spaced variables being passed to '-co|--config-option'; pr #298 sporks5000
[Fix] modified quarantine_hits to force disable if clamdscan explicitly encounters a 'no reply from clamd' fatal error
[Fix] modified install.sh 'ps' execution to be BSD compliant
[Fix] clean function was not properly stripping {CAV} and {YARA} prefixes from signature names when executing cleaner rules
[Fix] clean function was not properly handling signature names with both underscores and periods
[Fix] refactored clean_hitlist() & clean() functions to resolve pathing errors when cleaning previous session hits; issue #203
[Fix] ignore_inotify file exist/empty file negative match; issue #330
[Fix] operator issue cron.daily #331
[Fix] install.sh $ver required major numbering; renamed to ver_major so that session preservation semantics continue to work

v1.6.3 | Sep 01 2018:
[Fix] ensure clamscan_max_filesize is always set; pr #296
[Fix] remove escaping from inotifywait exclude regexp; pr #246 issue #205
[Fix] always set a value for monitor mode systemd unit; pr #257
[Fix] quar_get_filestat variable collisions during restore operations
[Fix] quarantine files could be prematurely deleted, during 'cron.daily/maldet', on distributions where the 'mv' command
 preserves origin file mtime; call 'touch' on quarantined files to set current mtime post-move to quarantine path; issue #294
[Fix] update tlog inotify tracking file before trimming to prevent rescan loop; pr #292
[Fix] revert pruning empty lines from signature files to 1.6.1 behavior
[Fix] usage semantics of cd'ing to a wildcard path on newer versions of Bash were causing version updates to fail; we now explicitly
 'cd' to maldetect-${upstreamver}
[Fix] spelling corrections; pr# 269
[Change] update	importconf text to reflect monitor mode	on systemd behavior
[Change] on restore actions, reset restored files to original mtime value
[Change] increase default remote_uri timeout from 10s to 30s
[Change] increase default remote_uri tries from 3 to 4
[Change] added base_domain variable to internals.conf
[Change] cleanup .tgz/.md5 files on version updates mid-flight to prevent potential 'cd: too many arguments' errors
[Change] trim inotify log from beginning instead of end	of file; pr #292
[Change] user mode scanning no longer scans system temporary paths; issue #283
[Change] improve regexp of scan start time values for '-e|--list' output
[Change] added '--beta' flag to '-d|--update-ver' to support pulling down beta release of LMD
[Change] stage v1.6.3 release; update version and date stamps
[Kudos] Thank you to those that contributed pull requests and issues during this release cycle. PR contributions from:
 sporks5000
 jsoref
 Joshua-Snapp
 mkubenka
 jkronza
 AnnopAlias

v1.6.2 | Jul 13 2017:
[Fix] signature updates using get_remote_file() would incorrect write temporary update files into /; issue #242
[Fix] added 'which curl' and 'which wget' for variable scoping of binary locations into internals.conf; issue #237
[New] added support to send email through 'sendmail' binary as alternative to 'mail'; pr #241 & issue #238

v1.6.1 | May 28 2017:
[New] added conf.maldet option cron_prune_days to configure cron.daily pruning max age of quar/sess/tmp data; issue #197
[New] added curl support, as new default, into get_remote_file; wget support is preserved secondary to curl; issue #200
[New] added --force option on -u|--update-sigs
[New] added --force option on -d|--update-ver
[New] added empty lines cleaner for runtime signatures and sorting of hdb for better performance; pr #223
[Change] modified default prune interval of quarantine/sess/tmp data from older than 7d to 21d
[Change] set email alerts to disabled when -z $mail / issue verbose warning on CLI; issue #220
[Change] scan_export_filelist feature had no real need to be limited to just cron runs;
 modified so when set, it will export find results for all '-r|--recent' scans
[Change] updated help and README to reflect '--force' option on '-u|--update-sigs' and '-d|--update-ver'
[Change] post-change to get_remote_file(); signature version file was truncating with tmp file for maldet-clean
[Change] replaced all calls of wget with get_remote_file()
[Change] refactored get_remote_file() to be more generic / not depend on wget
[Change] increased default values for wget --timeout from 5 to 10 seconds
[Change] replace egrep with posix 'grep -E'; direct invocation of egrep/fgrep is deprecated; pr #214
[Fix] modified sourcing of conf files and order of precedence in mald…et.sh init script to properly
 treat default_monitor_mode being defined in conf.maldet; issue #224
[Fix] escape quotes within eval md5sum command as fix for issues #230 and #216
[Fix] test condition for systemd was generating unary errors on older versions of bash; pr #36
[Fix] systemd based systems were skipping addition of sysconfig entry; pr #36
[Fix] install.sh find operation to prune old install backups was generating error when no previous installs existed
[Fix] wgetopt was single quoted making the variables inside of it strings, set double quotes
[Fix] potential out of memory issue while scanning a large set of files on native LMD scanner; pr #223
[Fix] -f option issue with relative path message; pr #223
[Fix] issue with checkout of relative file path for non root user; pr #223

v1.6 | Mar 17 2017:
[New] added curated set of YARA webshell & malware signatures for use with ClamAV >= 0.99b
[New] added cleaner rule 'VisitorTracker.Mob'
[New] added cleaner rule 'js.inject.fakejquery02'
[New] added support for 'froxlor' to cron.daily execution
[New] added support for 'vestacp' to cron.daily execution
[New] added support for 'ispconfig3' to cron.daily execution
[New] added support for 'DTC' to cron.daily execution
[New] added '$confpath', '$varlibpath' and '$libpath' for FHS separation
[New] moved compatibility (legacy) variables out of internals.conf into compat.conf
[New] added support to pull configuration variables for cron executions from 'sysconfig/maldet'
[New] added Debian derivatives sysconfig and initd compatibility for function sourcing and subsys locking
[New] added LSB tags to init script
[New] added capability of moving public scan path with $userbasedir variable
[New] manpage added and setup default with install.sh execution
[New] added support for clamd running as an unprivileged user through clamdscan w/ --fdpass options
[New] added --wget-proxy CLI option for http(s) proxy support
[New] added clam(d)scan_extraopts variables to internals.conf for appending extra CLI options on clam(d)scan;
 these values can also be defined in sysconfig or cron/exec based config files and on CLI
[New] sysconfig support through '/etc/sysconfig/maldet' or '/etc/default/maldet', system dependant, to
 allow easier configuration overrides; all conf.maldet and internals.conf variables supported
[Change] file stat calls replaced with function file_stat
[Change] stat calls are now (Free|Net)BSD compatible through file_stat function
[Change] report listing, '-e|--report list', now displays scan run time
[Change] scan reports and cli outputs once again display simplified path definitions instead of expanded paths
[Change] unified all clamav selection logic for data paths, running clamd processes, clam(d)scan CLI options etc...
 into a single function, clamselector(); this will make clam behavior more predictable across all functions
[Change] added subdomains path for ISPConfig to cron.daily
[Change] corrected variable naming semantics for import_*_(md5|hex)_url parameters
[Change] monitor mode now identifies inotifywait processes based on a string pattern unique to maldet
 to avoid conflicts with any other inotifywait processes
[Change] added wget_proxy variable for us in sysconfig and conf.maldet options
[Change] YARA-LMD curated signature set will now be included with signature updates
[Change] differentiate signature hits for YARA with '{YARA}' signame prefix
[Change] inotify_docroot now accepts comma or white spaced list of paths under user root to monitor
[Change] removed absolute path usage from 'pidof'
[Change] drop unneeded usage of shebang from sourced configuration files
[Change] modified shebang usage with 'env' prefix for portability
[Change] temporary path usage now consistently using $tmpdir value
[Change] scan paths must now be absolute paths
[Change] modified init script stop function for Debian derivatives
[Change] improved history tracking with proper date stamps, more verbose quarantine history logging and storing
 into more explicitly named files '$sessdir/hits.hist' and '$sessdir/quarantine.hist'
[Change] added scan_days value to cron.daily allowing customization of the date range scanned by daily cron
[Change] replaced remaining absolute calls to sigdirs with '$sigdir'
[Change] added Debian derivatives support for MONITOR_MODE checks
[Change] updated cron.daily to provide for a custom execution file and modified custom config file into
 'cron/conf.maldet.cron' and 'cron/custom.cron'
[Change] install.sh cased variable on find execution
[Change] symlink hookscan.sh to modsec.sh for pre-v1.5 compat
[Change] added '^/tmp/clamav-.*' to ignored paths where ownership matches clamd process
[Change] preserve custom cron configuration files on upgrade
[Change] hookscan.sh was calling LMD using legacy, deprecated, '--config-option' options
[Change] normalize installation path variable between LMD proper and installation scripts
[Change] reduced redundant path definitions
[Change] added test for main.cvd and main.cld in determining clamav signature paths
[Change] README changes to reflect new cron customization setup
[Change] added attempting passive ftp when active fails for malware checkout uploads
[Change] .ca.def configuration template renamed importconf and now copied over during installation to
 'internals/importconf'
[Change] new versions of 'chown' don't support use of . (dot) to separate user and group
[Change] find option regextype is now dropped on FreeBSD for compatibility
[Change] scan.tpl reporting template handles column spacing on filenames with spaces better
[Change] CLI usage semantics of --include-regex and --exclude-regex now consistently passing to 'find' command
[Change] moved all internal field separator line break modifications to lbreakifs()
[Change] quarantine .info file is now field separated with colon symbol (:)
[Change] quarantine .info file value ordering has been modified
 # owner:group:mode:size(b):md5:atime(epoch):mtime(epoch):ctime(epoch):file(path)
[Change] record_hits() now writes file mode and file times (a|m|c) into hits history file
[Change] 'eval' is now used as a prefix on the 'find' command to better handle the complex set of options passed to 'find'
 and avoid globbing, splitting and other bash'esque semantic issues
[Change] modified mkpubpaths cronjob to execute every 5 minutes instead of 10
[Change] public mode scanning errors are now more verbose
[Change] updated README to reflect required modsec >=2.9 variable 'SecTmpSaveUploadedFiles'
 for upload scanning
[Change] hookscan.sh (modsec.sh) now checks for variable override file at conf.maldet.hookscan
[Change] added use of sed flag -E for FreeBSD compatibility with GNU sed usage
[Change] clamscan will now respect scan_max_filesize value instead of hardcoded 5M
[Change] default scan_max_filesize increased from 768k to 2048k
[Change] clamscan max-scansize for archive depth set as scan_max_filesize*2
[Fix] improved special character argument escaping for -a|-r options that could have caused arbitrary command
 executions in environments where LMD was allowed to be called by non-root users and/or set-uid/gid wrappers
[Fix] FreeBSD calls to 'md5 -q' were being incorrectly escaped causing file names to never pass and return valid
 md5 hash string; corrected by preprending 'eval' to the md5 command callouts.
[Fix] corrected typo with import_* variables causing configuration imports to fail
[Fix] suppress eout() output for certain import_*() and get_remote_file() calls; this was causing
 false-positive hits for modsec integration
[Fix] install.sh may not have preserved certain variables on upgrade
[Fix] clamdscan was running as a non-root user, would generate lstat errors for all file find results
 leading to potential false positive hit/quarantine
[Fix] the permissions of the $tmpdir path can cause clamd when running as a non-root user to fail on
 startup due as a result of lstat errors on the custom user signature files stored under $tmpdir
[Fix] clamd.conf configurations containing Follow(File|Directory)Symlinks set to false results in
 the rfxn.*/lmd.user.* links causing clamd startup failures
[Fix] suppress error output to cli for customer user signature files when they do not exist
[Fix] uninstall.sh now cleans up signature files from clamav data paths
[Fix] corrected invalid matching against clamdscan binary when clamd was running as non-root user
[Fix] inotifywait on Ubuntu12 doesn't support the '-o' and '-d' option; modified to send stdout to logfile
 for better compatibility
[Fix] conditionally test for vz container and disable use of ionice which is not support in vz containers
[Fix] '-k|--kill-monitor' would under certain circumstances leave zombie processes
[Fix] monitor_cycle() could lead to memory depletion due to infinite loop cycle calls
[Fix] uninstall.sh was not shutting off monitor mode on uninstall
[Fix] legacy variable suppress_cleanhit references updated to email_ignore_clean
[Fix] email alerting broke during an iterative update due to order of precedence change of how configuration
 files were loaded and compatibility (legacy) variables being set before main conf.maldet was loaded;
 caused by FHS refactoring
[Fix] installation upgrade configuration importer was not properly executing after FHS refactoring during an
 iterative update
[Fix] issue #167 certain variables not being preserved on importconf execution, updated 'compat.conf'
[Fix] custom signature runtime files could grow exponentially in monitor mode
[Fix] make '--mkpubpaths' option cross-platform compatible (debian, rh, bsd)
[Fix] replaced usage of 'awk' on file name sensitive variables with 'cut' and/or better scoped field separator for awk
[Fix] double quote wrapped file name variables properly on restore*() functions
[Fix] quarantine .info files were not properly recording source file atime,mtime,ctime values manual quarantine calls
[Fix] user supplied paths to CLI are now better handled if they contain special characters
[Fix] multiple user supplied paths to CLI would generate an error if the first path contained a space and
 subsequent paths did not
[Fix] commit c8a1279 introduced bug where clamav could be fed zero sized signature files resulting in fatal exit
[Fix] public mode scanning will now properly error if mkpubpaths paths do not exist
[Fix] hookscan.sh (modsec.sh) will now default to not using clamav if clamd is not running
[Fix] though functional, public mode scanning would result in permission errors on console due to pathing issues with
 history tracking files
[Fix] clam(d)scan was not respecting values in 'ignore_sigs' file, this has been corrected for both CLI and monitor mode
[Fix] addition of prefixing eval to find command required certain values to be escaped differently for proper function
 of '-r|--recent'
[Fix] util-linux 2.23 supports 'column' command with '-o' but earlier versions do not, resulting in scan reports
 generating empty hit lists
[Fix] importconf was setting invalid vars for custom signature imports; correct variables are import_custsigs_md5_url
 and import_custsigs_hex_url
[Fix] multiplying maldet monitor processes due to 'ps' command expansion under parent bash process on CentOS6
[Fix] added default installation path to ignore_inotify to prevent monitor looping when '/' is scoped into
 monitoring mode; results in notify log filling disk space
[Fix] importconf was not importing the value for import_config_url

v1.5 | Sep 19 2015:
[New] added -f|--file-list CLI option to allow user supplied run-time file list for scanning
[New] added -i|--include-regex CLI option for run-time path/file inclusion based on posix-egrep regular expressions
[New] added -x|--exclude-regex CLI option for run-time path/file exclusion based on posix-egrep regular expressions
[New] added support for custom md5/hex signatures with preservation across signature and version updates, files located at:
 sigs/custom.md5.dat
 sigs/custom.hex.dat
[New] custom signatures perform run-time conversion into clamscan compatible format on systems that use clamscan engine
[New] new md5 signature format (md5v2) now includes file size that an md5 hash was derived from in format of:
 hash:filesize:signame
[New] added support for custom cleaner rules to be executed on clean events, file name format of
 "clean/custom.signame"; rules are preserved across signature and version updates
[New] added support for clam(d) engine when running in inotify monitoring mode
[New] added URL import feature for global configuration overrides using import_config_url variable in conf.maldet
[New] added URL import feature for user custom signatures using import_custsigs_md5_url & import_custsigs_hex_url variables in conf.maldet
[New] added set of defined exit codes for errored exits(1), successful runs with hits(2), successful runs with no hits(0)
[New] added uninstall.sh script to maldetect installation path
[New] added md5 hash verification of signature and version update downloads
[New] added scan_cpunice option to control CPU priority value of all scan operations such as find, clamscan etc.. (default 19)
[New] added scan_ionice option to control IO priority value of all scan operations such as find, clamscan etc.. (default 6)
[New] added autoupdate_signatures/autoupdate_version options to control daily cron based signature/version updates
[New] added autoupdate_version_hashed option to control validating hash of maldet executable against upstream version
[New] added support for virtualmin to cron.daily scans
[New] added support for ispmanager to cron.daily scans
[New] added support/detection of clamdscan to leverage memory preloaded signatures and multi-threaded scanning
[New] added scan_find_timeout option which controls the maximum execution time, in seconds, for the find command to generate a file list
[New] added scan_ignore_root option to exclude root owned files from scans
[New] added scan_ignore_user and scan_ignore_group options which allow for the exclusion of specified user and group names from scans
[New] added scan_export_filelist option allowing for daily scan of recent added/modified files to be exported to a static path
[New] added sourcing of of conf.maldet.cron into the cron.daily task which allows for cron specific configurations
[New] added inotify_reloadtime which controls the time at which inotify watcher will reload LMD configuration data
[New] added support for comma space (,) path list on CLI
[New] added reload option for monitor mode to invoke forced configuration reload (-m|--monitor reload)
[New] added maldet init script for monitor mode with $default_monitor_mode conf.maldet variable
[New] added usage of /etc/sysconfig/maldet for configuration of monitor mode init/systemd options, overrides conf.maldet
[New] added support for 'cpulimit' usage, when installed, through scan_cpulimit and inotify_cpulimit configuration variables
[Change] increased randomness of quarantine temporary file names
[Change] added atime,mtime,ctime since epoch values into quarantine info files
[Change] monitor mode now supports all existing ignore options as well as enforcing minimum/maximum file sizes
[Change] monitor mode now supports hot configuration reloads by touching reload_monitor under installation path (e.g: touch /usr/local/maldetect/monitor_reload)
[Change] modsec.sh has been renamed to hookscan.sh and more generic hook based scanning conventions set
[Change] hookscan.sh will now autodetect if clamdscan is running and perform scans through clamd when appropriate
[Change] hookscan.sh will now provide more verbose output on malware hit events
[Change] hookscan.sh now explicitly disables scanning of temporary paths, ensuring only requested file/paths are scanned
[Change] install.sh now gracefully handles upgrades when monitoring mode is enabled by restarting monitor mode
[Change] improved handling of single file scans which should now behave as expected
[Change] explicitly removed the inclusion of tmpdir paths during single file scans
[Change] automagically remove empty lines from ignore files
[Change] reordered configuration file, expanded on variable descriptions, overall attempt to simplify/streamline conf.maldet
[Change] installer symlinks LMD signatures into known/existing ClamAV paths to ensure signatures are loaded into memory by clamd
[Change] installer issues SIGUSR2 to any running clamd processes to force reload of signature databases
[Change] cron.daily signature updates issue SIGUSR2 to any running clamd processes to force reload of signature databases
[Change] cron.daily signature/version updates sleep random interval 1-999 secs before contacting upstream rfxn.com servers to reduce cdn load
[Change] modified clamscan database path checks to support cPanel >=11.40 RPM clamAV connector RPM's
[Change] modified location of statistical data files from tmpdir to sessdir making tmpdir a stateless path that can be purged at anytime
[Change] when clamscan engine is enabled scan_max_filesize value is now set dynamically based on the largest known file in the md5v2 signature set
[Change] modified e-mail based alerts to source from an e-mail template file at .email.template
[Change] clamscan execution command logged to logs/clamscan_log to make debugging clamscan errors easier
[Change] clamscan stderr/stdout output now pipes to logs/clamscan_log and if clamscan returns an error code (2), flag with an appropriate
 error message to check the clamscan_log file for more details
[Change] ambiguous variables renamed for better consistency and more logical naming conventions, documented in CHANGELOG.VARIABLES
[Change] modified sessionid values to derive from YYMMDD instead of MMDDYY and adjusted human readable report START/END date to include year value
[Change] modified view_report output to sort output on unix time of scan start times
[Change] signature updates now download as a single file tgz to reduce bandwidth usage and request load on upstream cdn
[Change] modified signature update function for additional error checking and better handling of zero sized signature downloads
[Change] modified version update function for additional error checking and better handling of zero sized file downloads
[Change] modified '-e|--report list' output include total files scanned, hits and cleaned results, reversed output order and
 consistent column spacing (column -t)
[Change] moved tlog executable out of inotify/ path, changed inotify_log path to logs/, removed inotify directory
[Change] created logs/ path, moved event_log path to logs/
[Change] modified previous wget timeout values of 3s timeout & 3 retries to 5s timeout & 3 retries
[Change] wget timeout and retry attempts are now configurable through internals.conf wget_timeout & wget_retries variables
[Change] removed file type check on native LMD stage2 hex scanner which was part of legacy code and no longer needed
[Change] removed verbose progressive scan output for native LMD scanner as performance penalty was unreasonable
[Change] replaced usage of tmpwatch with find in cron.daily for temporary path pruning
[Change] removed internals.conf from version check hashing for installation version updates (-d|--update-ver)
[Change] cron.daily now tests for directadmin and scans appropriate user domain paths
[Change] directory checkout uploads limited to maximum of 50 files
[Change] added tmpdir_paths option to explicitly scan known temporary (world-write) paths on all scan types
[Change] updated example ModSecurity rule in README file for compatibility with ModSec 2.7 which now requires
 every rule, even hooks, to have a rule ID
[Change] -r|--recent scan now uses mtime and ctime, instead of just mtime, to find recently changed/modified files
[Change] LMD v1.4.2+ will now use the new md5 v2 signature format and make direct requests on signature
 updates to the appropriate upstream file (md5v2.dat); old format, md5 v1, preserved in signature
 releases for compatibility of pre-1.4.2 releases
[Change] modified hexfifo.pl & hexstring.pl to accept user supplied value for path to hex signature file
[Change] install.sh now deletes LMD backup installation copies older than 30days
[Change] references to www.rfxn.com for remote signature and version updates now query cdn.rfxn.com
[Change] cleaner rules are now executable scripts in which infected files are passed as an argument ($1)
 allowing for a diverse set of cleaner rule options apart from the previous sed only setup
[Change] converted current cleaner rules to new executable scripts format
[Change] checkout uploads now store malware in the filename format of (hostid is an anonymous md5 identifier):
 $hostid.$RANDOM.$filename.[ascii|bin]
[Change] inotifywait from inotify-tools is no longer packaged with LMD, it should be downloaded in binary or
 source form from:
 https://github.com/rvoicilas/inotify-tools/wiki/
 binary versions are also available from dag repo at:
 http://pkgs.repoforge.org/inotify-tools/
[Change] internals.conf will now attempt to detect the path to inotifywait from $PATH
[Change] inotify max_user_watches was static set to 128, now configurable with inotify_user_watches
[Change] inotify values for max_user_instances|watches will first be checked and only modified if the existing
 values are lower than what maldet requires
[Change] modified error output for missing inotifywait to display URL to inotify-tools github page
[Change] modified default scan_hexdepth value to 65k as a result of improved scan efficiency in native scanner engine
[Change] added backwards compatibility for all pre-v1.5 configuration options however they should be considered deprecated and will be removed in the future
[Change] expanded on EICAR test signature support for native LMD scanner engine to better facilitate testing of functional installed signature set
[Change] added scan/find elapsed execution time values to scan report and cli output
[Change] relocated internal files into $inspath/internals/
[Change] created generic clean_exit() function to handle file cleanups on all fatal exist and replaced many random rm -f calls with it
[Change] moved all pre/post actions into a prerun() and postrun() functions
[Change] moved statistical logging to record_hits() function
[Change] quarantine() function borrows stat file data from record_hits to reduce calls to stat
[Change] more extensible cleaner rules with additional input arguments:
 $1 file path, $2 signame, $3 owner.group, $4 file_chmod, $5 file_size, $6 file_md5
[Change] added additional fields file_size and file_md5 to quarantine info file
[Change] added caching support for import_config_url with import_config_expire to control expiry interval
[Change] stricter handling of variable definitions which contain dynamic variable values
[Change] modified daily cron recent range from 2 to 1 as mtime/ctime values are n*24h, as such value of 1 is equal to two days
[Change] modified daily cron to use comma spaced path lists instead of multiple maldet executions
[Change] changed quarantine malware cleaning default value to 0
[Change] use of clamav engine output statement now more verbose
[Change] previously LMD only linked clamav signatures into clamav data paths on install, this is now done after each signature update
[Change] maldet.sh init script exites code 1 on status check when maldet monitor mode is not found running
[Change] monitor mode now invokes every 15 seconds, legacy installations will preserve 30 second cycle timing
[Change] modified shebang to use env bash for portability
[Fix] when clamdscan was running as a non-root user, would generate lstat errors for all file find results leading
 to potential false positive hits/quarantines
[Fix] the permissions of the $tmpdir path can cause clamd when running as a non-root user to fail on startup due
 as a result of lstat errors on the custom user signature files stored under $tmpdir
[Fix] clamd.conf configurations containing FollowDirectorySymlinks/FollowFileSymlinks set to false results in the
 rfxn.* and lmd.user.* links causing clamd startup failures; corrected by updating clamav_linksigs() to copy
 signatures into clamav data paths instead of linking them
[Fix] inotify monitor execution now properly passes ionice configuration value
[Fix] monitor_paths was not being preserved on version updates
[Fix] record_hit() was not being invoked outside of clamscan based events
[Fix] monitor.pid file would potentially have an incorrect pid written to it on each execution of monitor_check()
[Fix] quote syntax error in scan.etpl
[Fix] help output for -k|--kill-monitor incorrectly referred to --kill instead of --kill-monitor
[Fix] inotify_user_instances was defined in internals.conf incorrectly as inotify_user_watches
[Fix] tlog executable was not being set +x during installation
[Fix] install.sh was attempt to create default event_log while the parent directory did not yet exist
[Fix] invalid find expression was causing find to return directory paths on recent scans
[Fix] OSTYPE env checking was not properly matching on all FreeBSD versions
[Fix] renamed alert() to genalert() to avoid builtin function conflict on Ubuntu
[Fix] corrected -r|--recent scan mode trap on SIGINT (CTRL+C) not calling trap_exit() for cleanup actions
[Fix] modified native LMD scanner to better leverage bash internal field separator for handling of paths with spaces
[Fix] modified all calls to system executables to use paths derived from $PATH
[Fix] suppressed ignore signature count being displayed when calling with --modsec
[Fix] set modsec.sh to use /bin/bash as interpreter instead of /bin/sh for compatibility
[Fix] removed MAILTO & SHELL variables from crons which were causing crond 'bad minute' errors on some systems
[Fix] quoted extension values from ignore_file_ext input to provide consistent behavior
[Fix] added trailing slash '/' to all cron.daily scan (find) paths to properly handle symlinked paths
[Fix] install.sh now links LMD clamav signatures into all clamav data paths it finds instead of just the first
[Fix] clean() function was improperly exiting after first file hit clean attempt and ignoring all other hits
[Fix] set interpreter in uninstall.sh to /bin/bash instead of /bin/sh for better compatibility
[Fix] modified psa scan paths to pull in top level and sub domain content
[Fix] corrected invalid matching against clamdscan binary when clamd was not available

v1.4.2 | Feb 25th 2013:
[New] detection and alerting of libkeyutils root compromised libraries
[Change] cron.daily now tests for directadmin and scans appropriate user domain paths
[Change] removed temporary paths /var/tmp, /tmp, and /dev/shm from cron.daily which are
 now added explicitly to all scanning paths / modes

v1.4.1 | Nov 20th 2011:
[Change] rfxn.com ftp server moved and anonymous FTP checkout uploads changed
[Change] modsec.sh force sets clamav_scan=0 as native LMD scanner engine is faster on
 single / small file sets
[Fix] correct plesk if statement added to to daily scan cronjob
[New] added -U|--user to force execution under defined user, ideal for restoring user
 quarantined data or viewing user reports
 e.g: maldet --user nobody --report
 e.g: maldet --user nobody --restore 050910-1534.21135
[New] added public_scan variable to conf.maldet to control enabling of public mode
 scanning, disabled by default
[New] added cron.d/maldet_pub cronjob to populate public user paths when public mode
 scanning is enabled; does nothing when disabled
[Change] README file updated, had fallen behind on CLI usage help details
[New] added -co|--config-option for defining conf.maldet options on the CLI
[Fix] README, COPYING.GPL and CHANGELOG are now properly copied into the installation path
[Fix] version header in config import template was incorrect
[Fix] value of email_ignore_clean is now properly preserved on version upgrades
[New] added modsec.sh to allow for easy calls from mod_security2 inspectFile hook
[Change] autodetect executing uid and define public mode scanning variables
[New] added public mode scanning which redefines tmpdir, sessdir, quardir to pub/username/
 directory tree for user initiated (non-root) scans
[Change] installation permissions changed to 644/755 for public mode support
[Change] revised (gz)base64 rules to be more specific thus reducing false positives
[Fix] tlog was set to use /bin/sh which breaks usage on systems with default shells other
 than bash

v1.4.0 | Apr 17th 2011:
[Change] default editor now inherited from $EDITOR
[New] clamav signatures update through sigup(), -u|--update
[New] cleaner rules update through sigup(), -u|--update
[Change] added error checking for missing or corrupted signature files
[Fix] monitor_cycle() now properly trims inotify_log
[Fix] version dates in CHANGELOG for 1.3.8 -> current had 2010 instead of 2012
[New] added -b|--background flag to execute scans in background
[Change] cron.daily now uses the -b flag for background scanning
[Change] wget calls now use the --referer option to broadcast local LMD version
[Fix] replaced stray references of absolute install path with the install path variable
[New] stage2 (HEX) scanner now supports use of named pipe (FIFO) for passing file hex contents,
 enabled by default, provides better performance with larger depth analysis of files
[New] added hex_fifo_scan & hex_fifo_depth variables to conf.maldet for fifo hex scanning
[Change] -c|--checkout now supports directory paths
[Change] -r|--scan-recent and -a|--scan-all now supports single file scans
[Fix] replaced absolute path to nice on inotifywait exec to which located variable value
[Change] added error checking for all internally required binaries e.g: wget, find, od etc...
[New] detection of ClamAV clamscan binary and usage as default scanner engine; when detected,
 clamscan is executed on scan file lists using rfxn.com LMD clamav-compat sigs
[Change] added OSTYPE check for differentiating md5 sum binaries on linux and FreeBSD
[Change] added OSTYPE check on monitor mode to disable on FreeBSD, pending kqueue alternative
 to inotifywait
[Fix] revised od flags for FreeBSD support
[Fix] ignore_inotify now properly interprets extended posix regexp as ignore parameters
[Change] added sample ignore values into ignore_inotify along with sane defaults to
 ignore common noisy files
[New] added statistical analysis for string length to identify threats based on the longest
 uninterrupted string within files, common of obfuscated code (e.g: base64, gzip etc...)
[New] added string_length_scan & string_length variables to conf.maldet for strlength scanning
[Fix] ignore_file_ext has been readded and now correctly ignores files based on extension
[Fix] replaced absolute path to mail with which located variable value
[Fix] lmdup() now properly errors out when rfxn.com web server is offline
[New] added clamav_scan variable to conf.maldet to toggle clamscan detection
[New] Full compatibility under the following distros has been verified :)
 - FreeBSD 9.0-CURRENT
 - RHEL/CentOS 5.6
 - RHEL 6
 - Fedora Core 14
 - OpenSuse 11.4
 - Suse Linux Enterprise Server 11 SP1
 - Ubuntu Desktop/Server 10.10
 - Debian 6.0.1a
[Change] updated README file for new features & vars, sample ignore usage, revised features
 and updated cymru hash statistics
[Fix] relaxed grep for inotify sysfunctions to just inotify_ on System.map file
[New] can now pass list to -e|--report to view all available scan reports
 e.g: maldet --report list
[New] can now pass an e-mail address to -e|--report to email a specific report
 e.g: maldet --report SCANID user@domain.com
[New] added email_ignore_clean variable to suppress alerts where all hits are cleaned

v1.3.9 | Mar 16th 2011:
[Fix] ignore files are now properly imported on version updates
[Change] cron.daily now checks for version updates
[Fix] hexdepth greater than 65Kb caused an 'argument list too long' error with hexstring.pl
 which would fail-clean any malware on hex checks
[Change] default hex depth increased to 61440 as there was an increasing margin of error on
 missing threats due to them falling outside the default hexdepth; will add offset
 option to signatures in the near future
[Change] updated cymru hash statistics in README file

v1.3.8 | Jan 30th 2011:
[Fix] revised inotify tracking log file to properly rotate instead of growing indefinitely

v1.3.7 | Nov 27th 2010:
[Fix] package ownership at some point got set to uid 501 instead of root
[Fix] daily cronjob now checks ps output for inotifywait proc instead of pidof
[Fix] monitor mode users would exit prematurely if a user home path did not exist
[Fix] a file hijacking race condition existed with quarantine mode restore function
[Fix] inotify max_user_instances value was being set to a value that would cause inotifywait
 to fail

v1.3.6 | May 21st 2010:
[Fix] restore option will now handle session based restores for quarantines that
 were manually invoked with -q|--quar SCANID
[Fix] session data gets recreated if it disappears during scan

v1.3.5 | May 18th 2010:
[Fix] tlog now handles data that logged between 0bytes and first wake cycle
[Fix] monitor_check now properly handles CREATE,ISDIR events
[Change] --alert-daily|weekly alerts have been changed similar to manual alerts
[Fix] cleaner was not properly running on monitor_check calls to scan files
[Fix] quar_suspend was not properly running on monitor_check calls to quar()
[Change] monitor tracker files now pass through trim_log to avoid oversizing
[Fix] monitor_check now properly handles path names with spaces
[Fix] monitor_check was throwing nx file/directory error for monitor.pid
[Fix] older bash versions were having trouble with the [[ =~ ]] regexp search
[Change] set all script files from shebang/bin/sh to shebang/bin/bash
[Change] --alert-daily|weekly will now only send alerts if hits were found
[New] -d|--update-ver now compares file hashes to determine update status
[Fix] suspend events were not properly being added to monitor alerts
[Change] all alerts have had spacing changes to make them more readable
[Fix] signature names now properly list for daily|weekly alerts hit list
[Fix] monitor_check will now recursive monitor newly created directories
[New] monitor daily|weekly alerts now save as a pseudo scan report with SCANID
[Fix] monitor reports now generate properly when quar_hits=0

v1.3.4 | May 16th 2010:
[Fix] cleaner function was not properly executing under certain conditions
[Change] additional error checking/output added to the cleaner function
[Change] default status output of scans changed for better performance
[New] added ignore_inotify for ignoring paths from the monitor service
[Change] updated ignore section of README
[Fix] backreference errors kicking from scan_stage1 function
[New] -d|--update-ver option added to update installed version from rfxn.com
[Change] updated short and long usage output for update-ver usage
[Fix] -k|--kill-monitor now properly kills only the inotifywait/monitor pid's
[Fix] monitor_cycle function now correctly stores its pid in the pidfile
[Fix] files with multiple events in the same waking cycle are only scanned once
[Change] install.sh now symlinks maldet executable to /usr/local/sbin/lmd

v1.3.3 | May 15th 2010:
[Fix] quarantined files were not properly dropping owner
[New] signature based, rule driven, cleaner component added
[New] base64.inject cleaner rule
[New] gzbase64.inject cleaner rule
[New] -n|--clean SCANID option added to batch clean scan all files from a scan
[Fix] made default install file/path permissions more strict (750/640)
[New] install.sh now preserves conf.maldet settings
[New] install.sh now links backups of old installation to INSTALL_PATH.last
[Fix] install.sh now properly imports session data from previous install
[New] -s|--restore can now take a SCANID to batch restore all files from a scan
[Change] improved the layout of conf.maldet; more scan options and commenting
[New] added quar_susp_minuid option for suspend user minimum user id
[Fix] inotify monitor now properly acts on MODIFY,MOVE_TO,MOVE_FROM states
[Change] inotify monitor now can take a list of paths or file for path input
[Change] inotify monitor now has no default use, must specify USER|FILE|PATHS
[Change] revised short and long usage output for new options/usage changes
[Change] inotify monitor now spawns only one process for all monitored paths
[Change] inotify monitor sets max_user_instances to processors*2
[Change] inotify monitor sets max_user_watches to inotify_base_watches*users
[Change] migrated all inotify options from internals.conf to conf.maldet
[New] added inotify_base_watches to conf.maldet for max file watches multiplier
[New] added inotify_nice to conf.maldet for run-time prio of inotifywait
[New] added inotify_webdir to conf.maldet for html/web root only monitoring
[Change] extensive format change to README
[Change] rewrote inotify section of README to reflect the many changes
[New] added cleaner section to README
[Change] -q|--quarantine now calls cleaner if quar_clean=1
[Change] -n|--clean can now do in place cleaning without quarantine
[Fix] cleaner function was not properly executing under certain conditions

v1.3.2 | May 13th 2010:
[New] added ignore files: ignore_paths , ignore_sigs
[Change] ignore_sigs is processed as a pre-scan component before all scans
[Change] revised README file to include details on new ignore options
[Change] signature counts now displayed pre-scan and post-update
[Change] install.sh now runs --update after installation
[Fix] -p|--purge now properly clears session state data
[New] added [ SIGNATURE UPDATES ] section to README file
[Fix] some functions were referencing full paths instead of the variable equivs

v1.3.1 | May 12th 2010:
[Fix] typo in report command eout()
[Fix] cron.daily tmpwatch on invalid path
[Change] redirect stdout to /dev/null on tmpwatch calls in cron.daily
[Change] better commented cron.daily actions
[Change] cron.daily scans will now hit /home*/*/public_html on non-ensim systems
[Change] inotify monitor now properly handles any user homedir paths
[Fix] sigup will now download full signature set when no sigs are found local
[Fix] rewrote 17 signatures that would never match due to hexdepth restrictions
[Fix] removed some HEX signatures derived from ClamAV that would never hit
[Change] files must now be >32bytes to be included in search results
[Change] search results default to a max directory depth of 15
[New] added vars for minfilesize and maxdepth scan options
[Change] updated inotifywait to v1.3.6, statically linked binary
[Info] signature RSS and XML data sources added, see:
http://www.rfxn.com/signature-updates-rss-feed/
[Info] LMD now has a homepage on rfxn.com:
http://www.rfxn.com/projects/linux-malware-detect/
[New] adopted new versioning scheme
 [MAJOR].[MINOR].[REV]
 1 3 1

v1.3 | May 11th 2010:
- First public release

v1.1 - v1.2 | Mar. 2010 - May 2010:
- Internal releases

v0.5 - v1.0 | Nov. 2009 - Feb. 2010:
- Closed beta

v0.4< | Oct. 2009:
- Internal releases
