mirror of
https://github.com/chillout2k/ldap-acl-milter.git
synced 2025-12-11 02:30:17 +00:00
ENV[MILTER_MAX_RCPT]: limits number of envelope recipients
This commit is contained in:
parent
539b65e6f8
commit
a516ded2c8
@ -10,7 +10,6 @@ import logging
|
||||
import string
|
||||
import random
|
||||
import re
|
||||
from timeit import default_timer as timer
|
||||
import email.utils
|
||||
import authres
|
||||
|
||||
@ -29,7 +28,6 @@ g_re_domain = re.compile(r'^\S*@(\S+)$')
|
||||
# http://emailregex.com/ -> Python
|
||||
g_re_email = re.compile(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)")
|
||||
g_milter_mode = 'test'
|
||||
g_milter_default_policy = 'reject'
|
||||
g_milter_schema = False
|
||||
g_milter_schema_wildcard_domain = False # works only if g_milter_schema == True
|
||||
g_milter_expect_auth = False
|
||||
@ -37,6 +35,8 @@ g_milter_whitelisted_rcpts = {}
|
||||
g_milter_dkim_enabled = False
|
||||
g_milter_trusted_authservid = None
|
||||
g_re_srs = re.compile(r"^SRS0=.+=.+=(\S+)=(\S+)\@.+$")
|
||||
g_milter_max_rcpt_enabled = False
|
||||
g_milter_max_rcpt = 1
|
||||
|
||||
class LamException(Exception):
|
||||
def __init__(self, message="General exception message"):
|
||||
@ -152,9 +152,6 @@ class LdapAclMilter(Milter.Base):
|
||||
from_addr = kwargs['from_addr']
|
||||
rcpt_addr = kwargs['rcpt_addr']
|
||||
from_source = kwargs['from_source']
|
||||
self.log_info("check_policy: from={0} rcpt={1} from_source={2}".format(
|
||||
from_addr, rcpt_addr, from_source
|
||||
))
|
||||
m = g_re_domain.match(from_addr)
|
||||
if m == None:
|
||||
self.log_info("Could not determine domain of from={0}".format(
|
||||
@ -243,19 +240,23 @@ class LdapAclMilter(Milter.Base):
|
||||
if len(g_ldap_conn.entries) == 0:
|
||||
# Policy not found in LDAP
|
||||
if g_milter_expect_auth == True:
|
||||
self.log_info("policy mismatch from={0} rcpt={1} auth_method={2}".format(
|
||||
from_addr, rcpt_addr, auth_method
|
||||
))
|
||||
self.log_info(
|
||||
"policy mismatch: from={0} from_src={1} rcpt={2} auth_method={3}".format(
|
||||
from_addr, from_source, rcpt_addr, auth_method
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.log_info("policy mismatch from={0} rcpt={1}".format(
|
||||
from_addr, rcpt_addr
|
||||
))
|
||||
self.log_info(
|
||||
"policy mismatch: from={0} from_src={1} rcpt={2}".format(
|
||||
from_addr, from_source, rcpt_addr
|
||||
)
|
||||
)
|
||||
raise LamHardException("policy mismatch!")
|
||||
elif len(g_ldap_conn.entries) == 1:
|
||||
# Policy found in LDAP, but which one?
|
||||
entry = g_ldap_conn.entries[0]
|
||||
self.log_info("policy match: {}".format(
|
||||
entry.policyID.value
|
||||
self.log_info("policy match: '{0}' from_src={1}".format(
|
||||
entry.policyID.value, from_source
|
||||
))
|
||||
elif len(g_ldap_conn.entries) > 1:
|
||||
# Something went wrong!? There shouldn´t be more than one entries!
|
||||
@ -276,10 +277,15 @@ class LdapAclMilter(Milter.Base):
|
||||
self.log_debug("LDAP query: {}".format(query))
|
||||
g_ldap_conn.search(g_ldap_base, query)
|
||||
if len(g_ldap_conn.entries) == 0:
|
||||
self.log_info("policy mismatch from={0} rcpt={1}".format(
|
||||
from_addr, rcpt_addr
|
||||
))
|
||||
self.log_info(
|
||||
"policy mismatch from={0} from_src={1} rcpt={2}".format(
|
||||
from_addr, from_source, rcpt_addr
|
||||
)
|
||||
)
|
||||
raise LamHardException("policy mismatch")
|
||||
self.log_info("policy match: '{0}' from_src={1}".format(
|
||||
entry.policyID.value, from_source
|
||||
))
|
||||
except LDAPException as e:
|
||||
self.log_error("LDAP exception: {}".format(str(e)))
|
||||
raise LamSoftException("LDAP exception: " + str(e)) from e;
|
||||
@ -435,6 +441,12 @@ class LdapAclMilter(Milter.Base):
|
||||
|
||||
def eom(self):
|
||||
self.proto_stage = 'EOM'
|
||||
if g_milter_max_rcpt_enabled:
|
||||
if len(self.env_rcpts) > int(g_milter_max_rcpt):
|
||||
if g_milter_mode == 'reject':
|
||||
return self.milter_action(action='reject', reason='Too many recipients!')
|
||||
else:
|
||||
self.do_log("TEST-Mode: Too many recipients!")
|
||||
if g_milter_dkim_enabled:
|
||||
self.log_info("5321.from={0} 5322.from={1} 5322.from_domain={2} 5321.rcpt={3}".format(
|
||||
self.env_from, self.hdr_from, self.hdr_from_domain, self.env_rcpts
|
||||
@ -519,13 +531,6 @@ if __name__ == "__main__":
|
||||
if 'MILTER_MODE' in os.environ:
|
||||
if re.match(r'^test|reject$',os.environ['MILTER_MODE'], re.IGNORECASE):
|
||||
g_milter_mode = os.environ['MILTER_MODE'].lower()
|
||||
if 'MILTER_DEFAULT_POLICY' in os.environ:
|
||||
if re.match(r'^reject|permit$',os.environ['MILTER_DEFAULT_POLICY'], re.IGNORECASE):
|
||||
g_milter_default_policy = str(os.environ['MILTER_DEFAULT_POLICY']).lower()
|
||||
else:
|
||||
logging.warning("MILTER_DEFAULT_POLICY invalid value: {}"
|
||||
.format(os.environ['MILTER_DEFAULT_POLICY'])
|
||||
)
|
||||
if 'MILTER_NAME' in os.environ:
|
||||
g_milter_name = os.environ['MILTER_NAME']
|
||||
if 'MILTER_SCHEMA' in os.environ:
|
||||
@ -589,6 +594,14 @@ if __name__ == "__main__":
|
||||
logging.error("ENV[MILTER_TRUSTED_AUTHSERVID] is mandatory!")
|
||||
sys.exit(1)
|
||||
logging.info("ENV[MILTER_DKIM_ENABLED]: {0}".format(g_milter_dkim_enabled))
|
||||
if 'MILTER_MAX_RCPT_ENABLED' in os.environ:
|
||||
g_milter_max_rcpt_enabled = True
|
||||
if 'MILTER_MAX_RCPT' in os.environ:
|
||||
if os.environ['MILTER_MAX_RCPT'].isnumeric():
|
||||
g_milter_max_rcpt = os.environ['MILTER_MAX_RCPT']
|
||||
else:
|
||||
print("ENV[MILTER_MAX_RCPT] must be numeric!")
|
||||
sys.exit(1)
|
||||
try:
|
||||
set_config_parameter("RESTARTABLE_SLEEPTIME", 2)
|
||||
set_config_parameter("RESTARTABLE_TRIES", 2)
|
||||
|
||||
56
tests/miltertest-ip-fail.lua
Normal file
56
tests/miltertest-ip-fail.lua
Normal file
@ -0,0 +1,56 @@
|
||||
-- https://mopano.github.io/sendmail-filter-api/constant-values.html#com.sendmail.milter.MilterConstants
|
||||
-- http://www.opendkim.org/miltertest.8.html
|
||||
|
||||
-- socket must be defined as miltertest global variable (-D)
|
||||
conn = mt.connect(socket)
|
||||
if conn == nil then
|
||||
error "mt.connect() failed"
|
||||
end
|
||||
if mt.conninfo(conn, "blubb-ip.host", "127.6.6.6") ~= nil then
|
||||
error "mt.conninfo() failed"
|
||||
end
|
||||
|
||||
mt.set_timeout(60)
|
||||
|
||||
-- 5321.FROM
|
||||
if mt.mailfrom(conn, "tester-ip-fail@test.blah") ~= nil then
|
||||
error "mt.mailfrom() failed"
|
||||
end
|
||||
if mt.getreply(conn) == SMFIR_CONTINUE then
|
||||
mt.echo("FROM-continue")
|
||||
elseif mt.getreply(conn) == SMFIR_REPLYCODE then
|
||||
error("FROM-reject")
|
||||
end
|
||||
|
||||
-- 5321.RCPT+MACROS
|
||||
mt.macro(conn, SMFIC_RCPT, "i", "4CgSNs5Q9sz7SllQ")
|
||||
if mt.rcptto(conn, "<rcpt-ip-fail@test.blubb>") ~= nil then
|
||||
error "mt.rcptto() failed"
|
||||
end
|
||||
if mt.getreply(conn) == SMFIR_CONTINUE then
|
||||
mt.echo("RCPT-continue")
|
||||
elseif mt.getreply(conn) == SMFIR_REPLYCODE then
|
||||
mt.echo("RCPT-reject")
|
||||
end
|
||||
|
||||
-- 5322.HEADERS
|
||||
if mt.header(conn, "fRoM", '"Blah Blubb" <tester-ip-fail@test.blah>') ~= nil then
|
||||
error "mt.header(From) failed"
|
||||
end
|
||||
if mt.header(conn, "Authentication-REsuLTS", "my-auth-serv-id;\n dkim=fail header.d=test.blah header.s=selector1-test-blah header.b=mumble") ~= nil then
|
||||
error "mt.header(Authentication-Results) failed"
|
||||
end
|
||||
|
||||
-- EOM
|
||||
if mt.eom(conn) ~= nil then
|
||||
error "mt.eom() failed"
|
||||
end
|
||||
mt.echo("EOM: " .. mt.getreply(conn))
|
||||
if mt.getreply(conn) == SMFIR_CONTINUE then
|
||||
mt.echo("EOM-continue")
|
||||
elseif mt.getreply(conn) == SMFIR_REPLYCODE then
|
||||
mt.echo("EOM-reject")
|
||||
end
|
||||
|
||||
-- DISCONNECT
|
||||
mt.disconnect(conn)
|
||||
Loading…
Reference in New Issue
Block a user