grthtrhthjhtyjytjytkergtrhtrjytjerhrfh4:24 29/09/2026#!/usr/bin/bash # # This script exit codes # 0 means OK # 1 some error or csf is not installed # # Paths are overridable for tests only; production callers rely on the # defaults. CSF_ALLOW_FILE="${CSF_ALLOW_FILE:-/etc/csf/csf.allow}" IMUNIFY_ALLOW_CONF="${IMUNIFY_ALLOW_CONF:-/etc/csf/imunify_allow.conf}" # a reload that failed has to be retried even though the file itself no # longer changes, or one lock collision leaves the allowlist written but # never applied. Our own state directory, not /etc/csf: this is runtime # state, and /etc/csf is backed up and restored behind our back. RELOAD_PENDING="${CSF_RELOAD_PENDING_FILE:-/var/imunify360/.csf_reload_pending}" function is_csf_installed { if which csf >/dev/null 2>&1; then echo "csf is installed" return 0 else echo "csf is not installed" return 1 fi } function enable_csf { systemctl start csf systemctl start lfd csf --enable # add csf to autostart } function disable_csf { systemctl stop csf systemctl stop lfd csf --disable # remove csf from autostart } function purge_allow_entries { # $1 conf (ip;comment source), $2 target csf.allow-format file. # Entries are matched by IP and by comment: comments stay stable # across package versions while IPs rotate between builds, so # matching by comment also drops entries an older package wrote # (DEB upgrades never run "remove", only "add"). local conf=$1 target=$2 instance ip comment esc ctime mapfile -t ip_comment < "$conf" for instance in "${ip_comment[@]}" do IFS=';' read -r ip comment <<< "$instance" [ -n "$ip" ] || continue # word boundaries keep 203.0.113.1 from also purging a # customer's 203.0.113.10 line esc=$(printf '%s' "$ip" | sed 's/[][\.*^$/]/\\&/g') sed -i "/\b${esc}\b/d" "$target" # legacy "csf --add" bare lines are ours only when the # comment ends with csf's full ctime stamp (e.g. # "... # imunify360 server - Wed Mar 27 03:33:24 2024"), # so a customer row that merely reuses the comment text is # never touched if [ -n "$comment" ]; then esc=$(printf '%s' "$comment" | sed 's/[][\.*^$/]/\\&/g') ctime='[A-Za-z]\{3\} [A-Za-z]\{3\} [ 0-9][0-9]' ctime="${ctime} [0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\} [0-9]\{4\}" sed -i "/ # ${esc} - ${ctime}\$/d" "$target" fi done # our advanced filters carry the "# csf_tool: " ownership marker, so # they purge by marker alone even after their IPs rotate out; a # customer rule in the same shape but without the marker survives sed -i "/^tcp|out|d=443|d=.* # csf_tool: /d" "$target" sed -i "/^# csf_tool/d" "$target" } function edit_allow_list { FILE=$1 mapfile -t ip_comment < $FILE if [ "$2" = "remove" ] ; then purge_allow_entries "$FILE" "$CSF_ALLOW_FILE" # remove imunify360 whitelist file sed -i "/imunify360.txt/d" "$CSF_ALLOW_FILE" remove_bins_from_pignore fi if [ "$2" = "add" ] ; then add_bins_to_pignore local tmp instance ip comment has_entries=false for instance in "${ip_comment[@]}" do IFS=';' read -r ip comment <<< "$instance" if [ -n "$ip" ]; then has_entries=true break fi done # an empty or unreadable conf must not reach the rewrite below: # it would purge every marked entry, re-add nothing, and still # report success if [ "$has_entries" != "true" ]; then echo "warning: no allowlist entries in ${FILE};" \ "leaving ${CSF_ALLOW_FILE} unchanged" >&2 return 0 fi # Build the result in a temp file in the same directory, verify # it, then atomically rename it over csf.allow. A rename can't # half-write, so any earlier failure leaves the live file intact. tmp=$(mktemp "${CSF_ALLOW_FILE}.XXXXXX") || { echo "error: failed to update ${CSF_ALLOW_FILE}" >&2 return 1 } if [ -f "$CSF_ALLOW_FILE" ]; then if ! cp "$CSF_ALLOW_FILE" "$tmp"; then rm -f "$tmp" echo "error: failed to update ${CSF_ALLOW_FILE}" >&2 return 1 fi # carry over csf.allow's ownership and mode to the replacement chown --reference="$CSF_ALLOW_FILE" "$tmp" 2>/dev/null || : chmod --reference="$CSF_ALLOW_FILE" "$tmp" 2>/dev/null || : fi purge_allow_entries "$FILE" "$tmp" # a hand-edited csf.allow may have no final newline, and our marker # must not end up glued to the last entry if [ -s "$tmp" ] && [ -n "$(tail -c1 "$tmp")" ]; then printf '\n' >> "$tmp" fi # no blank line before the marker: it would accumulate one per run # and make the rendered file differ from the live one every time printf '# csf_tool:\n' >> "$tmp" for instance in "${ip_comment[@]}" do IFS=';' read -r ip comment <<< "$instance" [ -n "$ip" ] || continue echo "tcp|out|d=443|d=${ip} # csf_tool: ${comment}" >> "$tmp" done for instance in "${ip_comment[@]}" do IFS=';' read -r ip comment <<< "$instance" [ -n "$ip" ] || continue if ! grep -qF "tcp|out|d=443|d=${ip} # csf_tool: ${comment}" "$tmp" then rm -f "$tmp" echo "error: failed to build ${CSF_ALLOW_FILE}" >&2 return 1 fi done # the render is byte-stable, so an identical result means the # allowlist did not change between builds and there is nothing to # apply; reloading anyway would drop csf's policy for the length of # a full dostop/dostart on every package upgrade if [ "$(sha256sum < "$tmp")" \ = "$(sha256sum < "$CSF_ALLOW_FILE" 2>/dev/null)" ] \ && [ ! -f "$RELOAD_PENDING" ]; then rm -f "$tmp" echo "allowlist unchanged, not reloading csf" return 0 fi : > "$RELOAD_PENDING" 2>/dev/null || : if ! mv -f "$tmp" "$CSF_ALLOW_FILE"; then rm -f "$tmp" echo "error: failed to update ${CSF_ALLOW_FILE}" >&2 return 1 fi # entries go into the file directly (csf --add cannot take # advanced port filters), so csf must reload to apply them; a # reload failure is reported but must not abort package installs # on hosts whose csf config was already broken if csf -r >/dev/null 2>&1; then rm -f "$RELOAD_PENDING" else echo "warning: csf reload failed;" \ "run 'csf -r' manually to apply the allowlist" >&2 fi fi } BINS_TO_IGNORE="exe:/var/ossec/bin/ossec-monitord \ exe:/var/ossec/bin/ossec-analysisd\ exe:/var/ossec/bin/ossec-remoted" ignore_file="${CSF_PIGNORE_FILE:-/etc/csf/csf.pignore}" function remove_bins_from_pignore { for exe in $BINS_TO_IGNORE; do sed -i "\|${exe}|d" $ignore_file done } function add_bins_to_pignore { should_restart=false for exe in $BINS_TO_IGNORE; do if ! grep -q $exe $ignore_file ; then echo "$exe" >> $ignore_file should_restart=true fi done if $should_restart; then echo 'Restarting CSF to apply pignore changes' csf --restartall > /dev/null fi } if [ "$1" = "" ] ; then echo "Usage: $0 enable/disable/status/coop_install" exit 1 fi if [ "$1" = "status" ] ; then is_csf_installed exit $? fi if [ "$1" = "enable" ] then is_csf_installed >/dev/null || exit 1 enable_csf exit $? fi if [ "$1" = "disable" ] then is_csf_installed >/dev/null || exit 1 disable_csf exit $? fi if [ "$1" = "coop_install" ] then is_csf_installed >/dev/null || exit 1 edit_allow_list "$IMUNIFY_ALLOW_CONF" add exit $? fi if [ "$1" = "remove" ] then edit_allow_list "$IMUNIFY_ALLOW_CONF" remove exit $? fi