GhostManSec
Server: Apache
System: Linux s323.xrea.com 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User: moonarc (17751)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: //var/qmail/bin/rcptcheck-overlimit.sh
#!/bin/bash
# rcptcheck-overlimit v0.3
# Digitalmind 2017-08-23
# This script limits the number of emails sent by relayclients (authusers or ip with RELAYCLIENT in tcprules)
# You must define the variable RCPTCHECK=/var/qmail/bin/rcptcheck-overlimit.sh AND RCPTCHECKRELAYCLIENT="1"
# This script will be called for every accepted rcptto.
# If RELAYCLIENT is not defined the script terminates with the exit code 112 (ignore/accept).
# Messages sent to domains in rcpthosts will NOT be accounted for.
# For every accepted rcptto with RELAYCLIENT defined, a char 'X' will be appended to a file in the directory $OVERLIMITDIR;
# this file name will be the authuser, if defined, or  the client ip address.
# The script will look for an entry corresponding to the client (authuser or ip) in $LIMITSCONTROLFILE and use the number found
# as the maximum number of allowed outgoing emails.
# If the OVERLIMITDIR is not writable by the user running qmail-smtpd or the LIMITSCONTROLFILE cannot be read, the script terminates with 112 (ignore/accept).
# In case of overlimit, an exit code 113 (reject/overlimit) will be returned to qmail-smtpd and the connection will be dropped with a 421.
# $LIMITSCONTROLFILEFILE can contain comments, '0' means unlimited, the entry starting with ':' will be considered the default limit.
# If the default entry can't be found, the default will be set to unlimited.
# In case more lines match the client name, only the last will be used.
# A cronjob must be created to periodically cleanup files in $OVERLIMITDIR: to use daily limits, schedule the job once a day.
#
# Cronjob example: 
#   # find /var/qmail/overlimit/ -type f -exec rm -f "{}" \;
#
# $LIMITSCONTROLFILE example:
# -----
#:1000
#1.2.3.4:3000
#test@example.com:0
# -----
# Known bugs:
# - the line 'info@example.com:1000' also matches the client name 'testinfo@example.com'.

EXITIGNORE=112
EXITOVERLIMIT=113

LIMITSCONTROLFILE=/var/qmail/control/relaylimits
OVERLIMITDIR=/var/qmail/overlimit
DEBUGLOG=/var/log/overlimit/debug.log

if [ -z "${RELAYCLIENT+x}" ]; then exit $EXITIGNORE; fi
if [ ! -r "$LIMITSCONTROLFILE" ]; then exit $EXITIGNORE; fi
if [ ! -w "$OVERLIMITDIR" ]; then exit $EXITIGNORE; fi

# Read config file removing comments, blank lines, spaces and tabs
PREFILTER="sed -e 's/#.*$//g' -e '/^$/d' -e 's/[ \t]*//g' $LIMITSCONTROLFILE"

# SMTPAUTHUSER should be already validated, but just to be safe leave only alphanum, -.', '_', '-' and '@'
FILTEREDSMTPAUTHUSER=$(echo "$SMTPAUTHUSER" | tr -cd '[:alnum:].\-_@')

if [ -n "${RCPTHOSTS}" ]; then
  logger -t qmail-overlimit -p mail.info "RELAYCLIENT and RCPTHOSTS: mailfrom=$SENDER rcptto=$RECIPIENT authuser=${FILTEREDAUTHUSER} remoteip=${TCPREMOTEIP}"
  exit $EXITIGNORE
fi

if [ -n "${FILTEREDSMTPAUTHUSER}" ]; then
  value=$(eval ${PREFILTER} | grep -Fi "$FILTEREDSMTPAUTHUSER:" | tail -1); limit="${value##*:}" # specific authuser
  ##if [ -z "${limit}" ]; then value=$(eval ${PREFILTER} | grep -Fi "${FILTEREDSMTPAUTHUSER##*@}:" | tail -1); limit="${value##*:}"; fi # domain part
  client="${FILTEREDSMTPAUTHUSER}"
else
  value=$(eval ${PREFILTER} | grep -Fi "$TCPREMOTEIP:" | tail -1); limit="${value##*:}" # specific ip address
  client="${TCPREMOTEIP}"
fi
if [ -z "${limit}" ]; then value=$(eval ${PREFILTER} | grep "^:" | tail -1); limit="${value##*:}"; fi  # default ':value'
if [ -z "${limit}" ]; then limit=0; fi # if nothing else

currentnum=$(stat -c%s $OVERLIMITDIR/$client 2>/dev/null)
if [ -z "$currentnum" ]; then currentnum=1; fi

logger -t qmail-overlimit -p mail.info "client=$client limit=$limit current=$currentnum"

if [ "$currentnum" -gt "$limit" ] && [ "$limit" -ne "0" ]; then
  logger -t qmail-overlimit -p mail.info "REJECTED $client "
  exit $EXITOVERLIMIT
else
  echo -n "X" >> "$OVERLIMITDIR/$client" 2>/dev/null
fi
exit $EXITIGNORE