MMCT TEAM
Server IP : 45.113.226.95  /  Your IP : 216.73.216.239
Web Server : LiteSpeed
System : Linux bharat.hostitbro.com 5.14.0-611.13.1.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 11 04:57:59 EST 2025 x86_64
User : digita21 ( 1701)
PHP Version : 8.3.30
Disable Function : mail
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF
Directory (0555) :  /lib/

[  Home  ][  C0mmand  ][  Upload File  ]

Current File : //lib/ie-common
#!/usr/bin/bash

# dprint level message
#	print a message to stderr if requested debug level
#	is greater than DEBUG_LEVEL global variable
dprint()
{
	_level=$1
	shift

	case "$DEBUG_LEVEL" in
	[0-9])
		if [ "0$_level" -le "0$DEBUG_LEVEL" ] ; then
			echo 1>&2 "$0: $*"
		fi
		;;
	*)
		err 1 "DEBUG_LEVEL variable contains garbage"
		;;
	esac
}

# warn message
#	print warning message to stderr
warn()
{
	echo 1>&2 "$0: WARNING: $*"
}

# err return_code message
#	print error message to stderr and terminate execution
err()
{
	_code=$1
	shift

	echo 1>&2 "$0: ERROR: $*"

	_dsn_file="/usr/share/imunifyemail/imunifyemail.dsn"

	if [	-n "$REPORT_ERROR" -a "$REPORT_ERROR" = "yes" \
		-a -x /usr/bin/sentry-cli \
		-a -r "$_dsn_file" ]
	then
		/usr/bin/env SENTRY_DSN=$(head -1 "$_dsn_file") \
		    /usr/bin/sentry-cli send-event \
			-e "source:ie-config" \
			-e "errorcode:$_code" \
			-r "2.2.8" \
			-m "$0: ERROR: $*" > /dev/null

		if [ $? -eq 0 ] ; then
			dprint 1 "(the error message reported)"
		fi
	fi

	backup_cleanup "$BACKUP"

	exit $_code
}

# getpwuid_dir id
#	securely get user home directory by the given id
getpwuid_dir()
{
	_id=$1
	awk -F: -v id="$_id" '(id == $3) {print $6}' /etc/passwd
}

# auth_root
#	check if the user is authenticated to use this script
auth_root()
{
	if [ $(id -u) -ne 0 ] ; then
		err 2 "must be root to run this command"
	fi
}

# fqfn path
#	check and resolve path to fully qualified file name
fqfn()
{
	if [ -e "$1" ]; then
		echo "$(cd $(dirname "$1") && pwd)/$(basename "$1")"
	else
		warn "$1 not found"
		echo ""
	fi
}

# backup_file archive files...
#	pack given files into archive for backup
#	please note, it's okay to have some files missed
backup_file()
{
	_archive=$1
	shift

	if [ -z "$_archive" ] ; then
		warn "no backup archive name given"
		return
	fi

	# create empty $_archive so the subsequent tar -u can succeed
	if [ ! -f "$_archive" ] ; then
		umask 077
		touch "$_archive" || \
			err 3 "$_archive: can't open archive for writing"
	fi

	for _arg in $*; do
		_file=$(fqfn "$_arg" | sed 's:^/::')

		# backup only once!
		if [ -s "$_archive" ] && \
		   tar -tf "$_archive" | grep -q "^$_file$" ; then
			continue
		fi

		if [ -n "$_file" -a -r "/$_file" ] ; then
			dprint 2 "  backing up /$_file"
			if ! tar -uf "$_archive" -C/ "$_file" ; then
				err 3 "$_file can't be backed up"
			fi
		fi
	done
}

# backup_cleanup archive
#	remove unused backup archive or notify user
backup_cleanup()
{
	_archive="$1"

	if [ -n "$_archive" ] ; then
		if [ -s "$_archive" ] ; then
			dprint 1 "backup file is at $_archive"
		else
			dprint 3 "remove unused backup file"
			if [ -f "$_archive" ] ; then
				rm "$_archive"
			fi
		fi
	fi
}

old_backup_cleanup()
{
  backup_files=($(ls -1 "$HOME" | grep imunifyemail-backup | sort))
  two_weeks_ago_ts=$(date +%s --date='-2 weeks')

  for i in "${backup_files[@]}";do
    ts=$(echo "$i" | cut -d - -f 3)
    if [ "$ts" -lt "$two_weeks_ago_ts" ]; then
      rm "$HOME/$i"
    fi
  done
}

#### CONSTANTS ####
QUARANTINE_ENV_FILE="/etc/imunifyemail/quarantine.env"
DEC_NODE_ENV_FILE="/etc/imunifyemail/dec-node.env"

RSPAMD_OVERRIDE_D_FOLDER="/etc/rspamd/override.d"
RSPMAD_OVERRIDED_WORKER_CONTROLLER_INC="/etc/rspamd/override.d/worker-controller.inc"
RSPAMD_OVERRIDED_IE_SPAMFILTER_CONF="/etc/rspamd/override.d/ie-spamfilter.conf"

INCOMING_FILTER_CONF_FILE="/etc/ie_incoming_conf.json"

# cfg_qtoken token
#	install new security token for the Quarantine
cfg_qtoken()
{
  _name="cfg_qtoken"

  _token="$1"

  dprint 1 "$_name: set node token $1"

  # In the case if there's no token given, generate a random string.
  # To obtain at least 512 bits key from a-zA-Z0-9 sequence it's
  # required at least ceil(512/log2(26+26+10)) symbols.
  if [ -z "$_token" ] ; then
    dprint 2 "$_name: generating new security token"
    _token=$(tr -cd a-zA-Z0-9 < /dev/urandom | head -c 86)
  fi

  if ! echo "$_token" | grep -qE '^[a-zA-Z0-9]+$' ; then
    err 1 "$_name: token must be of alphanumeric characters only"
  fi

  override_section_of_rspamd_imunifyemail_conf quarantine api_token "\"$_token\""
  override_quarantine_env SERVER_RSPAMDTOKEN "$_token"
}

# cfg_nport port
#	set DEC node server address port
cfg_nport()
{
  _name="cfg_nport"

  _port="$1"

  if [ -z "$_port" ] ; then
    dprint 2 "$_name: empty port, skip"
    return 0
  fi

  if ! echo "$_port" | grep -qE '^[0-9]+$' ; then
    err 1 "$_name: $_port: invalid port number"
  fi

  override_section_of_rspamd_imunifyemail_conf sampler api_url "http://localhost:$_port/v1/message"
  override_dec_node_env SERVER_ADDRESS ":${_port}"
}

# cfg_ntoken token
#	install new security token for the DEC
cfg_ntoken()
{
  _name="cfg_ntoken"

  _token="$1"

  dprint 1 "$_name: set node token $1"

  # In the case if there's no token given, generate a random string.
  # To obtain at least 512 bits key from a-zA-Z0-9 sequence it's
  # required at least ceil(512/log2(26+26+10)) symbols.
  if [ -z "$_token" ] ; then
    dprint 2 "$_name: generating new security token"
    _token=$(tr -cd a-zA-Z0-9 < /dev/urandom | head -c 86)
  fi

  if ! echo "$_token" | grep -qE '^[a-zA-Z0-9]+$' ; then
    err 1 "$_name: token must be of alphanumeric characters only"
  fi

  override_section_of_rspamd_imunifyemail_conf sampler api_token "\"$_token\""
  override_dec_node_env SERVER_TOKEN "$_token"
  override_quarantine_env DECNODE_TOKEN "$_token"
}

# cfg_nsr [rate]
#	set sampling rate for the node
cfg_nsr()
{
  _name="cfg_nsr"
  _rate="$1"

  if [ -z "$_rate" ] ; then
    dprint 2 "$_name: empty rate value, skip"
    return 0
  fi

  if ! echo "$_rate" | grep -qE '^([0-9]|[1-9][0-9]|100)$' ; then
    err 1 "$_name: rate value must be in range of [0..100]"
  fi

  override_section_of_rspamd_imunifyemail_conf sampler sampling_freq "$_rate"

  /bin/systemctl restart rspamd.service
}

# print_version ["packages"]
#	print package version number
print_version()
{
	_packages=$1

	_pkgtool=$(which rpm 2>&1)
	if [ $? -eq 0 ] ; then
		if [ -n "$_packages" -a "$_packages" = "packages" ] ; then
			rpm -qa --queryformat "%{NAME}:%{VERSION}:%{RELEASE}\n" \
				"imunifyemail*" | grep -v "debuginfo" | sort
		else
			rpm -qa --queryformat "%{VERSION}-%{RELEASE}\n" \
				imunifyemail | sed 's/-\([0-9][0-9]*\).*/-\1/'
		fi
		return 0
	fi

	_pkgtool=$(which dpkg 2>&1)
	if [ $? -eq 0 ] ; then
		if [ -n "$_packages" -a "$_packages" = "packages" ] ; then
			dpkg-query -W -f='${binary:Package}:${Version}:${Whatever}\n' | grep '^imunifyemail' | sed 's/:$//'
		else
			dpkg -s "imunifyemail" \
				| sed -n 's/^Version: \([0-9][0-9.-]*\).*/\1/p'
		fi
    return 0
	fi

	err 6 "print_version: no known package tool found"
}

add_user_in_group()
{
  _group=$1
  _user=$2
  _auig_name="add_user_in_group(user=$_user, group=$_group)"

  if groups "$_user" | grep -w "$_group"; then
    dprint 1 "$_auig_name: user already in the group, skip"
  else
    dprint 1 "$_auig_name: adding user to the group"
    usermod -a -G "$_group" "$_user"
  fi
}

override_quarantine_env()
{
  _create_file_and_set_perms "$QUARANTINE_ENV_FILE" _imunifyemail _imunify
  _override_conf_file "$QUARANTINE_ENV_FILE" "$1" "$2"
}

override_dec_node_env()
{
  _create_file_and_set_perms "$DEC_NODE_ENV_FILE" _imunifyemail _imunify
  _override_conf_file "$DEC_NODE_ENV_FILE" "$1" "$2"
}

override_section_of_rspamd_imunifyemail_conf()
{
  _section=$1
  _key=$2
  _value=$3

  case "$_section" in
    sampler|quarantine|cpanel)
      _file_name="$RSPAMD_OVERRIDE_D_FOLDER/$_section.conf"
      _create_file_and_set_perms "$_file_name" root _rspamd
      _override_conf_file "$_file_name" "$_key" "$_value"
      ;;
    *)
      err 1 "override_section_of_rspamd_imunifyemail_conf(section=$_section, key=$_key): unknown section"
      ;;
  esac
}

override_ie_spamfilter_conf()
{
  _create_file_and_set_perms "$RSPAMD_OVERRIDED_IE_SPAMFILTER_CONF" root mail
  _override_conf_file "$RSPAMD_OVERRIDED_IE_SPAMFILTER_CONF" "$1" "$2"
}

_override_conf_file()
{
  _conf_file=$1
  _key=$2
  _value=$3
  _ocf_name="_override_conf_file(conf_file=$_conf_file, key=$_key)"

  dprint 2 "$_ocf_name"

  # validate parameters
  if [ -z "$_key" ] || [ -z "$_value" ] || [ -z "$_conf_file" ]; then
    err 100 "$_ocf_name: wrong parameters"
  fi

  # append or edit env_file file
  if grep -q "${_key}" "$_conf_file" 2>/dev/null; then
    sed -i 's/'"$_key"'=.*/'"$_key"'='"$_value"'/g' "$_conf_file" || err 250 "$_ocf_name: unexpected error (sed)"
  else
    echo "$_key=$_value" >> "$_conf_file"
  fi
}

_create_file_and_set_perms()
{
  _file_name=$1
  _user=$2
  _group=$3
  _permissions=$4

  # set default permissions if it doesn't provided
  if [ -z "$_permissions" ]; then
    _permissions="640"
  fi

  _cfsp_name="_create_file_and_set_perms(file_name=$_file_name, user=$_user, group=$_group, permissions=$_permissions)"

  if ! test -f "$_file_name"; then
    dprint 2 "$_cfsp_name: creating file"
    touch "$_file_name"
  fi

  _sf_stat=$(stat --format '%a:%U:%G' "$_file_name")
  if [ "$_sf_stat" != "$_permissions:$_user:$_group" ] ; then
    dprint 1 "$_cfsp_name: set permissions"
    chown "$_user":"$_group" "$_file_name"
    chmod $_permissions "$_file_name"
  fi
}

_add_line_to_file() {
  local file="$1"
  local value="$2"
  local case_sensitive="${3:-false}"
  local cdb="$4"
  local lock_file="${file}.lock"
  local temp_file="${file}.tmp"
  local _ocf_name="_add_line_to_file(conf_file=$file, value=$value, cdb=$cdb)"

  dprint 2 "$_ocf_name"

  # validate parameters
  if [ -z "$value" ] || [ -z "$file" ]; then
    err 100 "$_ocf_name: wrong parameters"
  fi
  # Create the file if it doesn't exist
  if [ ! -f "$file" ]; then
      touch "$file"
  fi

  # Use flock to ensure only one process can modify the file at a time
  (
    flock -e 200  # Acquire an exclusive lock

    if [ "$case_sensitive" = true ]; then
        grep_cmd="grep -q"
    else
        grep_cmd="grep -qi"
    fi
    # Check if the line already exists (case-insensitive)
    if ! eval "$grep_cmd" "^${value}$" "$file"; then
      # Write the current content to a temporary file and append the new line
      if cat "$file" > "$temp_file" && echo "$value" >> "$temp_file"; then
        # Move the temp file to the original file atomically
        if mv "$temp_file" "$file"; then
          if [ ! -z "$cdb" ]; then
            if ! cdb -c -m "$cdb" "$file"; then
              err 1 "Failed to create cdb file"
            fi
          fi
          echo "The config added successfully to $file"
        else
          rm -f "$temp_file"  # Clean up the temp file if the move fails
          err 1 "Failed to replace the original file."
        fi
      else
        err 1 "Failed to write to the temporary file."
      fi
    fi

  ) 200>"$lock_file"  # Lock file descriptor 200 using the lock file
  # Remove the lock file after the operation
  rm -f "$lock_file"
}
_remove_line_from_file() {
  local file="$1"
  local value="$2"
  local case_sensitive="${3:-false}"
  local cdb="$4"
  local temp_file="${file}.tmp"
  local lock_file="${file}.lock"
  local _ocf_name="_remove_line_from_file(conf_file=$file, value=$value)"

  dprint 2 "$_ocf_name"

  # validate parameters
  if [ -z "$value" ] || [ -z "$file" ]; then
    err 100 "$_ocf_name: wrong parameters"
  fi
  if [ -f "$file" ]; then
    # Use flock to ensure only one process can modify the file at a time
    (
      flock -e 200  # Acquire an exclusive lock
      # Escape any / characters in the value
      local escaped=$(echo "$value" | sed 's/\//\\\//g')
	  # Set sed command based on case sensitivity
      if [ "$case_sensitive" = true ]; then
          sed_cmd="sed '/^${escaped}$/d'"
      else
          sed_cmd="sed '/^${escaped}$/I d'"
      fi
      # Use sed to delete the matching line in a case-insensitive way
      if eval "${sed_cmd}" "$file" > "$temp_file"; then
        # Move the temp file to the original file atomically
        if mv "$temp_file" "$file"; then
          if [ ! -z "$cdb" ]; then
            if ! cdb -c -m "$cdb" "$file"; then
              err 1 "Failed to create cdb file"
            fi
          fi
          echo "The config removed successfully from $file"
        else
          rm -f "$temp_file"  # Clean up the temp file if the move fails
          err 1 "Failed to replace the original file."
        fi
      else
        err 1 "Failed to write to the temporary file."
      fi

    ) 200>"$lock_file"  # Lock file descriptor 200 using the lock file
    # Remove the lock file after the operation
    rm -f "$lock_file"
  fi
}

_incoming_filtration_state()
{
  if [ ! -f "$INCOMING_FILTER_CONF_FILE" ]; then
    echo "disabled"
  elif grep -q '"enabled"' $INCOMING_FILTER_CONF_FILE; then
    echo "enabled"
  else
    echo "disabled"
  fi
}

_toggle_incoming_filtration()
{
  in_state=$1
  _tif_name="_toggle_incoming_filtration(state=$in_state)"

  case $in_state in
  enabled|disabled|enabled_stat)
    if [ -f "$INCOMING_FILTER_CONF_FILE" ]; then
      if ! grep -q '"state"' $INCOMING_FILTER_CONF_FILE; then
        err 250  "malformed $INCOMING_FILTER_CONF_FILE file"
      fi

      sed -i 's/\("state":\s*"\)[^"]*"/\1'"$in_state"'"/' "$INCOMING_FILTER_CONF_FILE" || \
      err 250 "$_tif_name: unexpected error (sed)"

    else
      _create_file_and_set_perms $INCOMING_FILTER_CONF_FILE _imunifyemail mail 640
      echo "{ \"state\": \"${in_state}\" }" > "$INCOMING_FILTER_CONF_FILE"
    fi

    dprint 2 "restarting ie-quarantine service"
		# should we also catch errors from the folowing?
		/bin/systemctl restart ie-quarantine.service
    ;;
  *)
    err "$_tif_name: unsupported state value"
  esac

  dprint 1 "$_tif_name: incoming email filtering has been changed to $in_state."
}

MMCT - 2023