mirror of
https://github.com/chillout2k/ldap-acl-milter.git
synced 2025-12-12 19:00:19 +00:00
refactoring; more logging
This commit is contained in:
parent
c93916cf19
commit
f06be7b0c3
99
app/lam.py
99
app/lam.py
@ -5,7 +5,7 @@ import random
|
|||||||
import re
|
import re
|
||||||
import email.utils
|
import email.utils
|
||||||
import authres
|
import authres
|
||||||
from lam_globals import g_config, g_policy_backend
|
from lam_backends import g_config_backend, g_policy_backend
|
||||||
from lam_rex import g_rex_domain, g_rex_srs
|
from lam_rex import g_rex_domain, g_rex_srs
|
||||||
from lam_logger import log_debug, log_info, log_warning, log_error
|
from lam_logger import log_debug, log_info, log_warning, log_error
|
||||||
from lam_exceptions import LamSoftException, LamHardException
|
from lam_exceptions import LamSoftException, LamHardException
|
||||||
@ -57,7 +57,7 @@ class LdapAclMilter(Milter.Base):
|
|||||||
self.passed_dkim_results = []
|
self.passed_dkim_results = []
|
||||||
self.log_debug("reset(): {}".format(self.__dict__))
|
self.log_debug("reset(): {}".format(self.__dict__))
|
||||||
# https://stackoverflow.com/a/2257449
|
# https://stackoverflow.com/a/2257449
|
||||||
self.mconn_id = g_config.milter_name + ': ' + ''.join(
|
self.mconn_id = g_config_backend.milter_name + ': ' + ''.join(
|
||||||
random.choice(string.ascii_lowercase + string.digits) for _ in range(8)
|
random.choice(string.ascii_lowercase + string.digits) for _ in range(8)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -69,12 +69,12 @@ class LdapAclMilter(Milter.Base):
|
|||||||
smtp_code = None
|
smtp_code = None
|
||||||
smtp_ecode = None
|
smtp_ecode = None
|
||||||
if kwargs['action'] == 'reject':
|
if kwargs['action'] == 'reject':
|
||||||
message = g_config.milter_reject_message
|
message = g_config_backend.milter_reject_message
|
||||||
smtp_code = '550'
|
smtp_code = '550'
|
||||||
smtp_ecode = '5.7.1'
|
smtp_ecode = '5.7.1'
|
||||||
smfir = Milter.REJECT
|
smfir = Milter.REJECT
|
||||||
elif kwargs['action'] == 'tmpfail':
|
elif kwargs['action'] == 'tmpfail':
|
||||||
message = g_config.milter_tmpfail_message
|
message = g_config_backend.milter_tmpfail_message
|
||||||
smtp_code = '450'
|
smtp_code = '450'
|
||||||
smtp_ecode = '4.7.1'
|
smtp_ecode = '4.7.1'
|
||||||
smfir = Milter.TEMPFAIL
|
smfir = Milter.TEMPFAIL
|
||||||
@ -93,8 +93,8 @@ class LdapAclMilter(Milter.Base):
|
|||||||
if 'reason' in kwargs:
|
if 'reason' in kwargs:
|
||||||
message = "{0} - reason: {1}".format(message, kwargs['reason'])
|
message = "{0} - reason: {1}".format(message, kwargs['reason'])
|
||||||
if kwargs['action'] == 'reject' or kwargs['action'] == 'tmpfail':
|
if kwargs['action'] == 'reject' or kwargs['action'] == 'tmpfail':
|
||||||
self.log_info("milter_action={0} message={1}".format(
|
self.log_info("{0} - milter_action={1} message={2}".format(
|
||||||
kwargs['action'], message
|
self.mconn_id, kwargs['action'], message
|
||||||
))
|
))
|
||||||
self.setreply(smtp_code, smtp_ecode, message)
|
self.setreply(smtp_code, smtp_ecode, message)
|
||||||
return smfir
|
return smfir
|
||||||
@ -119,7 +119,7 @@ class LdapAclMilter(Milter.Base):
|
|||||||
def envfrom(self, mailfrom, *str):
|
def envfrom(self, mailfrom, *str):
|
||||||
self.reset()
|
self.reset()
|
||||||
self.proto_stage = 'FROM'
|
self.proto_stage = 'FROM'
|
||||||
if g_config.milter_expect_auth:
|
if g_config_backend.milter_expect_auth:
|
||||||
try:
|
try:
|
||||||
# this may fail, if no x509 client certificate was used.
|
# this may fail, if no x509 client certificate was used.
|
||||||
# postfix only passes this macro to milters if the TLS connection
|
# postfix only passes this macro to milters if the TLS connection
|
||||||
@ -181,24 +181,28 @@ class LdapAclMilter(Milter.Base):
|
|||||||
to = to.replace(">","")
|
to = to.replace(">","")
|
||||||
to = to.lower()
|
to = to.lower()
|
||||||
self.log_debug("5321.rcpt={}".format(to))
|
self.log_debug("5321.rcpt={}".format(to))
|
||||||
if to in g_config.milter_whitelisted_rcpts:
|
if to in g_config_backend.milter_whitelisted_rcpts:
|
||||||
return self.milter_action(action = 'continue')
|
return self.milter_action(action = 'continue')
|
||||||
if g_config.milter_dkim_enabled:
|
if g_config_backend.milter_dkim_enabled:
|
||||||
# Collect all envelope-recipients for later
|
# Collect all envelope-recipients for later
|
||||||
# investigation (EOM). Do not perform any
|
# investigation (EOM). Do not perform any
|
||||||
# policy action at this protocol phase.
|
# policy action at this protocol phase.
|
||||||
self.env_rcpts.append(to)
|
self.env_rcpts.append(to)
|
||||||
else:
|
else:
|
||||||
|
# DKIM disabled. Policy enforcement takes place here.
|
||||||
try:
|
try:
|
||||||
ret = g_policy_backend.check_policy(
|
g_policy_backend.check_policy(
|
||||||
from_addr=self.env_from, rcpt_addr=to, from_source='5321.from', lam_session=self
|
from_addr = self.env_from,
|
||||||
|
rcpt_addr = to,
|
||||||
|
from_source = 'envelope',
|
||||||
|
lam_session = self
|
||||||
)
|
)
|
||||||
self.log_info(ret)
|
self.env_rcpts.append(to)
|
||||||
except LamSoftException as e:
|
except LamSoftException as e:
|
||||||
if g_config.milter_mode == 'reject':
|
if g_config_backend.milter_mode == 'reject':
|
||||||
return self.milter_action(action = 'tmpfail')
|
return self.milter_action(action = 'tmpfail')
|
||||||
except LamHardException as e:
|
except LamHardException as e:
|
||||||
if g_config.milter_mode == 'reject':
|
if g_config_backend.milter_mode == 'reject':
|
||||||
return self.milter_action(
|
return self.milter_action(
|
||||||
action = 'reject',
|
action = 'reject',
|
||||||
reason = e.message
|
reason = e.message
|
||||||
@ -210,7 +214,7 @@ class LdapAclMilter(Milter.Base):
|
|||||||
def header(self, hname, hval):
|
def header(self, hname, hval):
|
||||||
self.proto_stage = 'HDR'
|
self.proto_stage = 'HDR'
|
||||||
self.queue_id = self.getsymval('i')
|
self.queue_id = self.getsymval('i')
|
||||||
if g_config.milter_dkim_enabled == True:
|
if g_config_backend.milter_dkim_enabled == True:
|
||||||
# Parse RFC-5322-From header
|
# Parse RFC-5322-From header
|
||||||
if(hname.lower() == "From".lower()):
|
if(hname.lower() == "From".lower()):
|
||||||
hdr_5322_from = email.utils.parseaddr(hval)
|
hdr_5322_from = email.utils.parseaddr(hval)
|
||||||
@ -232,7 +236,7 @@ class LdapAclMilter(Milter.Base):
|
|||||||
ar = authres.AuthenticationResultsHeader.parse(
|
ar = authres.AuthenticationResultsHeader.parse(
|
||||||
"{0}: {1}".format(hname, hval)
|
"{0}: {1}".format(hname, hval)
|
||||||
)
|
)
|
||||||
if ar.authserv_id.lower() == g_config.milter_trusted_authservid.lower():
|
if ar.authserv_id.lower() == g_config_backend.milter_trusted_authservid.lower():
|
||||||
for ar_result in ar.results:
|
for ar_result in ar.results:
|
||||||
if ar_result.method.lower() == 'dkim':
|
if ar_result.method.lower() == 'dkim':
|
||||||
if ar_result.result.lower() == 'pass':
|
if ar_result.result.lower() == 'pass':
|
||||||
@ -249,13 +253,13 @@ class LdapAclMilter(Milter.Base):
|
|||||||
|
|
||||||
def eom(self):
|
def eom(self):
|
||||||
self.proto_stage = 'EOM'
|
self.proto_stage = 'EOM'
|
||||||
if g_config.milter_max_rcpt_enabled:
|
if g_config_backend.milter_max_rcpt_enabled:
|
||||||
if len(self.env_rcpts) > int(g_config.milter_max_rcpt):
|
if len(self.env_rcpts) > int(g_config_backend.milter_max_rcpt):
|
||||||
if g_config.milter_mode == 'reject':
|
if g_config_backend.milter_mode == 'reject':
|
||||||
return self.milter_action(action='reject', reason='Too many recipients!')
|
return self.milter_action(action='reject', reason='Too many recipients!')
|
||||||
else:
|
else:
|
||||||
self.do_log("TEST-Mode: Too many recipients!")
|
self.do_log("TEST-Mode: Too many recipients!")
|
||||||
if g_config.milter_dkim_enabled:
|
if g_config_backend.milter_dkim_enabled:
|
||||||
self.log_info("5321.from={0} 5322.from={1} 5322.from_domain={2} 5321.rcpt={3}".format(
|
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
|
self.env_from, self.hdr_from, self.hdr_from_domain, self.env_rcpts
|
||||||
))
|
))
|
||||||
@ -272,42 +276,55 @@ class LdapAclMilter(Milter.Base):
|
|||||||
for rcpt in self.env_rcpts:
|
for rcpt in self.env_rcpts:
|
||||||
try:
|
try:
|
||||||
# Check 5321.from against policy
|
# Check 5321.from against policy
|
||||||
ret = g_policy_backend.check_policy(
|
g_policy_backend.check_policy(
|
||||||
from_addr=self.env_from, rcpt_addr=rcpt, from_source='5321.from', lam_session=self
|
from_addr=self.env_from,
|
||||||
|
rcpt_addr=rcpt,
|
||||||
|
from_source='envelope',
|
||||||
|
lam_session=self
|
||||||
|
)
|
||||||
|
self.log_info(
|
||||||
|
"action=pass 5321.from={0} 5321.rcpt={1}".format(self.env_from, rcpt)
|
||||||
)
|
)
|
||||||
self.log_info(ret)
|
|
||||||
except LamSoftException as e:
|
except LamSoftException as e:
|
||||||
self.log_info(str(e))
|
self.log_info(e.message)
|
||||||
if g_config.milter_mode == 'reject':
|
if g_config_backend.milter_mode == 'reject':
|
||||||
return self.milter_action(action = 'tmpfail')
|
return self.milter_action(action = 'tmpfail')
|
||||||
else:
|
else:
|
||||||
self.log_info("TEST-Mode - tmpfail")
|
self.log_info("TEST-Mode - tmpfail")
|
||||||
except LamHardException as e:
|
except LamHardException as e:
|
||||||
|
self.log_info(e.message)
|
||||||
if self.dkim_aligned:
|
if self.dkim_aligned:
|
||||||
try:
|
try:
|
||||||
# Check 5322.from against policy
|
# Check 5322.from against policy
|
||||||
ret = g_policy_backend.check_policy(
|
g_policy_backend.check_policy(
|
||||||
from_addr=self.hdr_from, rcpt_addr=rcpt, from_source='5322.from', lam_session=self
|
from_addr=self.hdr_from,
|
||||||
|
rcpt_addr=rcpt,
|
||||||
|
from_source='from-header',
|
||||||
|
lam_session=self
|
||||||
|
)
|
||||||
|
self.log_info(
|
||||||
|
"action=pass 5322.from={0} 5321.rcpt={1}".format(self.hdr_from, rcpt)
|
||||||
)
|
)
|
||||||
self.log_info(ret)
|
|
||||||
self.log_info("5322.from={} authorized by DKIM signature".format(
|
|
||||||
self.hdr_from
|
|
||||||
))
|
|
||||||
except LamHardException as e:
|
except LamHardException as e:
|
||||||
reject_message = True
|
reject_message = True
|
||||||
else:
|
else:
|
||||||
reject_message = True
|
reject_message = True
|
||||||
|
if reject_message:
|
||||||
|
if g_config_backend.milter_mode == 'reject':
|
||||||
|
return self.milter_action(
|
||||||
|
action = 'reject',
|
||||||
|
reason = 'policy mismatch! Message rejected for all recipients!'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.log_info(
|
||||||
|
"TEST-Mode: policy mismatch! Message would be rejected for all recipients!"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# * DKIM check disabled
|
||||||
|
# Iterate through all accepted envelope recipients and log
|
||||||
|
for rcpt in self.env_rcpts:
|
||||||
|
self.log_info("action=pass 5321.from={0} 5321.rcpt={1}".format(self.env_from, rcpt))
|
||||||
|
|
||||||
if reject_message:
|
|
||||||
if g_config.milter_mode == 'reject':
|
|
||||||
return self.milter_action(
|
|
||||||
action = 'reject',
|
|
||||||
reason = 'policy mismatch! Message rejected for all recipients!'
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.log_info(
|
|
||||||
"TEST-Mode: policy mismatch! Message would be rejected for all recipients!"
|
|
||||||
)
|
|
||||||
return self.milter_action(action = 'continue')
|
return self.milter_action(action = 'continue')
|
||||||
|
|
||||||
def abort(self):
|
def abort(self):
|
||||||
|
|||||||
30
app/lam_backends.py
Normal file
30
app/lam_backends.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import traceback
|
||||||
|
from lam_exceptions import (
|
||||||
|
LamInitException, LamPolicyBackendException, LamConfigBackendException
|
||||||
|
)
|
||||||
|
from lam_logger import init_logger
|
||||||
|
from lam_config_backend import LamConfigBackend
|
||||||
|
from lam_policy_backend import LamPolicyBackend
|
||||||
|
|
||||||
|
init_logger()
|
||||||
|
|
||||||
|
g_config_backend = None
|
||||||
|
try:
|
||||||
|
if g_config_backend is None:
|
||||||
|
g_config_backend = LamConfigBackend()
|
||||||
|
except LamConfigBackendException as e:
|
||||||
|
raise LamInitException(e.message) from e
|
||||||
|
except Exception as e:
|
||||||
|
raise LamInitException(traceback.format_exc()) from e
|
||||||
|
|
||||||
|
# Instantiate the LDAP policy backend and
|
||||||
|
# establish a permanent connection with the LDAP server
|
||||||
|
# which will be reused on any milter connection
|
||||||
|
g_policy_backend = None
|
||||||
|
try:
|
||||||
|
if g_policy_backend is None:
|
||||||
|
g_policy_backend = LamPolicyBackend(g_config_backend)
|
||||||
|
except LamPolicyBackendException as e:
|
||||||
|
raise LamInitException(e.message) from e
|
||||||
|
except Exception as e:
|
||||||
|
raise LamInitException(traceback.format_exc()) from e
|
||||||
@ -1,23 +1,25 @@
|
|||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
from lam_logger import log_info
|
from lam_logger import log_info
|
||||||
from lam_exceptions import LamConfigException
|
from lam_exceptions import LamConfigBackendException
|
||||||
from lam_rex import g_rex_email
|
from lam_rex import g_rex_email
|
||||||
|
|
||||||
class LamConfig():
|
class LamConfigBackend():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.milter_mode = 'test'
|
|
||||||
self.milter_name = 'ldap-acl-milter'
|
self.milter_name = 'ldap-acl-milter'
|
||||||
|
self.milter_mode = 'test'
|
||||||
self.milter_socket = '/socket/{}'.format(self.milter_name)
|
self.milter_socket = '/socket/{}'.format(self.milter_name)
|
||||||
|
self.milter_timeout = 60
|
||||||
self.milter_reject_message = 'Security policy violation!'
|
self.milter_reject_message = 'Security policy violation!'
|
||||||
self.milter_tmpfail_message = 'Service temporarily not available! Please try again later.'
|
self.milter_tmpfail_message = 'Service temporarily not available! Please try again later.'
|
||||||
self.ldap_server = 'ldap://127.0.0.1:389'
|
self.ldap_server = 'ldap://127.0.0.1:389'
|
||||||
|
self.ldap_server_connect_timeout = 3
|
||||||
self.ldap_binddn = 'cn=ldap-reader,ou=binds,dc=example,dc=org'
|
self.ldap_binddn = 'cn=ldap-reader,ou=binds,dc=example,dc=org'
|
||||||
self.ldap_bindpw = 'TopSecret;-)'
|
self.ldap_bindpw = 'TopSecret;-)'
|
||||||
self.ldap_base = 'ou=lam,ou=services,dc=example,dc=org'
|
self.ldap_base = 'ou=lam,ou=services,dc=example,dc=org'
|
||||||
self.ldap_query = '(&(mail=%rcpt%)(allowedEnvelopeSender=%from%))'
|
self.ldap_query = '(&(mail=%rcpt%)(allowedEnvelopeSender=%from%))'
|
||||||
self.milter_schema = False
|
self.milter_schema = False
|
||||||
self.milter_schema_wildcard_domain = False # works only if milter_schema == True
|
self.milter_schema_wildcard_domain = False
|
||||||
self.milter_expect_auth = False
|
self.milter_expect_auth = False
|
||||||
self.milter_whitelisted_rcpts = {}
|
self.milter_whitelisted_rcpts = {}
|
||||||
self.milter_dkim_enabled = False
|
self.milter_dkim_enabled = False
|
||||||
@ -25,75 +27,127 @@ class LamConfig():
|
|||||||
self.milter_max_rcpt_enabled = False
|
self.milter_max_rcpt_enabled = False
|
||||||
self.milter_max_rcpt = 1
|
self.milter_max_rcpt = 1
|
||||||
|
|
||||||
|
if 'MILTER_NAME' in os.environ:
|
||||||
|
self.milter_name = os.environ['MILTER_NAME']
|
||||||
|
|
||||||
if 'MILTER_MODE' in os.environ:
|
if 'MILTER_MODE' in os.environ:
|
||||||
if re.match(r'^test|reject$',os.environ['MILTER_MODE'], re.IGNORECASE):
|
if re.match(r'^test|reject$',os.environ['MILTER_MODE'], re.IGNORECASE):
|
||||||
self.milter_mode = os.environ['MILTER_MODE'].lower()
|
self.milter_mode = os.environ['MILTER_MODE'].lower()
|
||||||
if 'MILTER_NAME' in os.environ:
|
log_info("ENV[MILTER_MODE]: {}". format(self.milter_mode))
|
||||||
self.milter_name = os.environ['MILTER_NAME']
|
|
||||||
|
if 'MILTER_SOCKET' in os.environ:
|
||||||
|
self.milter_socket = os.environ['MILTER_SOCKET']
|
||||||
|
log_info("ENV[MILTER_SOCKET]: {}".format(self.milter_socket))
|
||||||
|
|
||||||
|
if 'MILTER_TIMEOUT' in os.environ:
|
||||||
|
if os.environ['MILTER_TIMEOUT'].isnumeric():
|
||||||
|
self.milter_timeout = int(os.environ['MILTER_TIMEOUT'])
|
||||||
|
else:
|
||||||
|
raise LamConfigBackendException("ENV[MILTER_TIMEOUT] must be numeric!")
|
||||||
|
log_info("ENV[MILTER_TIMEOUT]: {}".format(self.milter_timeout))
|
||||||
|
|
||||||
if 'MILTER_SCHEMA' in os.environ:
|
if 'MILTER_SCHEMA' in os.environ:
|
||||||
if re.match(r'^true$', os.environ['MILTER_SCHEMA'], re.IGNORECASE):
|
if re.match(r'^true$', os.environ['MILTER_SCHEMA'], re.IGNORECASE):
|
||||||
self.milter_schema = True
|
self.milter_schema = True
|
||||||
if 'MILTER_SCHEMA_WILDCARD_DOMAIN' in os.environ:
|
if 'MILTER_SCHEMA_WILDCARD_DOMAIN' in os.environ:
|
||||||
if re.match(r'^true$', os.environ['MILTER_SCHEMA_WILDCARD_DOMAIN'], re.IGNORECASE):
|
if re.match(r'^true$', os.environ['MILTER_SCHEMA_WILDCARD_DOMAIN'], re.IGNORECASE):
|
||||||
self.milter_schema_wildcard_domain = True
|
self.milter_schema_wildcard_domain = True
|
||||||
|
log_info("ENV[MILTER_SCHEMA]: {}".format(self.milter_schema))
|
||||||
|
log_info(
|
||||||
|
"ENV[MILTER_SCHEMA_WILDCARD_DOMAIN]: {}".format(
|
||||||
|
self.milter_schema_wildcard_domain
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if 'LDAP_SERVER' not in os.environ:
|
if 'LDAP_SERVER' not in os.environ:
|
||||||
raise LamConfigException("Missing ENV[LDAP_SERVER], e.g. {}".format(self.ldap_server))
|
raise LamConfigBackendException(
|
||||||
|
"Missing ENV[LDAP_SERVER], e.g. {}".format(self.ldap_server)
|
||||||
|
)
|
||||||
self.ldap_server = os.environ['LDAP_SERVER']
|
self.ldap_server = os.environ['LDAP_SERVER']
|
||||||
|
log_info("ENV[LDAP_SERVER]: {}".format(self.ldap_server))
|
||||||
|
|
||||||
|
if 'LDAP_SERVER_CONNECT_TIMEOUT' in os.environ:
|
||||||
|
if not os.environ['LDAP_SERVER_CONNECT_TIMEOUT'].isnumeric():
|
||||||
|
raise LamConfigBackendException(
|
||||||
|
"ENV[LDAP_SERVER_CONNECT_TIMEOUT] must be numeric!"
|
||||||
|
)
|
||||||
|
self.ldap_server_connect_timeout = int(os.environ['LDAP_SERVER_CONNECT_TIMEOUT'])
|
||||||
|
log_info("ENV[LDAP_SERVER_CONNECT_TIMEOUT]: {}".format(
|
||||||
|
self.ldap_server_connect_timeout
|
||||||
|
))
|
||||||
|
|
||||||
if 'LDAP_BINDDN' in os.environ:
|
if 'LDAP_BINDDN' in os.environ:
|
||||||
self.ldap_binddn = os.environ['LDAP_BINDDN']
|
self.ldap_binddn = os.environ['LDAP_BINDDN']
|
||||||
if 'LDAP_BINDPW' in os.environ:
|
if 'LDAP_BINDPW' in os.environ:
|
||||||
self.ldap_bindpw = os.environ['LDAP_BINDPW']
|
self.ldap_bindpw = os.environ['LDAP_BINDPW']
|
||||||
|
|
||||||
if 'LDAP_BASE' not in os.environ:
|
if 'LDAP_BASE' not in os.environ:
|
||||||
raise LamConfigException(
|
raise LamConfigBackendException(
|
||||||
"Missing ENV[LDAP_BASE], e.g. {}".format(self.ldap_base)
|
"Missing ENV[LDAP_BASE], e.g. {}".format(self.ldap_base)
|
||||||
)
|
)
|
||||||
self.ldap_base = os.environ['LDAP_BASE']
|
self.ldap_base = os.environ['LDAP_BASE']
|
||||||
|
log_info("ENV[LDAP_BASE]: {}".format(self.ldap_base))
|
||||||
|
|
||||||
if 'LDAP_QUERY' not in os.environ:
|
if 'LDAP_QUERY' not in os.environ:
|
||||||
if self.milter_schema == False:
|
if self.milter_schema == False:
|
||||||
raise LamConfigException(
|
raise LamConfigBackendException(
|
||||||
"ENV[MILTER_SCHEMA] is disabled and ENV[LDAP_QUERY] is not set instead!"
|
"ENV[MILTER_SCHEMA] is disabled and ENV[LDAP_QUERY] is not set instead!"
|
||||||
)
|
)
|
||||||
if 'LDAP_QUERY' in os.environ:
|
else:
|
||||||
self.ldap_query = os.environ['LDAP_QUERY']
|
self.ldap_query = os.environ['LDAP_QUERY']
|
||||||
if 'MILTER_SOCKET' in os.environ:
|
log_info("ENV[LDAP_QUERY]: {}".format(self.ldap_query))
|
||||||
self.milter_socket = os.environ['MILTER_SOCKET']
|
|
||||||
if 'MILTER_REJECT_MESSAGE' in os.environ:
|
if 'MILTER_REJECT_MESSAGE' in os.environ:
|
||||||
self.milter_reject_message = os.environ['MILTER_REJECT_MESSAGE']
|
self.milter_reject_message = os.environ['MILTER_REJECT_MESSAGE']
|
||||||
|
log_info("ENV[MILTER_REJECT_MESSAGE]: {}".format(self.milter_reject_message))
|
||||||
|
|
||||||
if 'MILTER_TMPFAIL_MESSAGE' in os.environ:
|
if 'MILTER_TMPFAIL_MESSAGE' in os.environ:
|
||||||
self.milter_tmpfail_message = os.environ['MILTER_TMPFAIL_MESSAGE']
|
self.milter_tmpfail_message = os.environ['MILTER_TMPFAIL_MESSAGE']
|
||||||
|
log_info("ENV[MILTER_TMPFAIL_MESSAGE]: {}".format(self.milter_tmpfail_message))
|
||||||
|
|
||||||
if 'MILTER_EXPECT_AUTH' in os.environ:
|
if 'MILTER_EXPECT_AUTH' in os.environ:
|
||||||
if re.match(r'^true$', os.environ['MILTER_EXPECT_AUTH'], re.IGNORECASE):
|
if re.match(r'^true$', os.environ['MILTER_EXPECT_AUTH'], re.IGNORECASE):
|
||||||
self.milter_expect_auth = True
|
self.milter_expect_auth = True
|
||||||
|
log_info("ENV[MILTER_EXPECT_AUTH]: {}".format(self.milter_expect_auth))
|
||||||
|
|
||||||
if 'MILTER_WHITELISTED_RCPTS' in os.environ:
|
if 'MILTER_WHITELISTED_RCPTS' in os.environ:
|
||||||
# A blank separated list is expected
|
# A blank separated list is expected
|
||||||
whitelisted_rcpts_str = os.environ['MILTER_WHITELISTED_RCPTS']
|
whitelisted_rcpts_str = os.environ['MILTER_WHITELISTED_RCPTS']
|
||||||
for whitelisted_rcpt in re.split(',|\s', whitelisted_rcpts_str):
|
for whitelisted_rcpt in re.split(',|\s', whitelisted_rcpts_str):
|
||||||
if g_rex_email.match(whitelisted_rcpt) == None:
|
if g_rex_email.match(whitelisted_rcpt) == None:
|
||||||
raise LamConfigException(
|
raise LamConfigBackendException(
|
||||||
"ENV[MILTER_WHITELISTED_RCPTS]: invalid email address: {}"
|
"ENV[MILTER_WHITELISTED_RCPTS]: invalid email address: {}"
|
||||||
.format(whitelisted_rcpt)
|
.format(whitelisted_rcpt)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
log_info("ENV[MILTER_WHITELISTED_RCPTS]: {}".format(
|
|
||||||
whitelisted_rcpt
|
|
||||||
))
|
|
||||||
self.milter_whitelisted_rcpts[whitelisted_rcpt] = {}
|
self.milter_whitelisted_rcpts[whitelisted_rcpt] = {}
|
||||||
|
log_info(
|
||||||
|
"ENV[MILTER_WHITELISTED_RCPTS]: {}".format(
|
||||||
|
self.milter_whitelisted_rcpts
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if 'MILTER_DKIM_ENABLED' in os.environ:
|
if 'MILTER_DKIM_ENABLED' in os.environ:
|
||||||
self.milter_dkim_enabled = True
|
self.milter_dkim_enabled = True
|
||||||
if 'MILTER_TRUSTED_AUTHSERVID' in os.environ:
|
if 'MILTER_TRUSTED_AUTHSERVID' in os.environ:
|
||||||
self.milter_trusted_authservid = os.environ['MILTER_TRUSTED_AUTHSERVID'].lower()
|
self.milter_trusted_authservid = os.environ['MILTER_TRUSTED_AUTHSERVID'].lower()
|
||||||
log_info("ENV[MILTER_TRUSTED_AUTHSERVID]: {0}".format(
|
log_info(
|
||||||
self.milter_trusted_authservid
|
"ENV[MILTER_TRUSTED_AUTHSERVID]: {}".format(
|
||||||
))
|
self.milter_trusted_authservid
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise LamConfigException("ENV[MILTER_TRUSTED_AUTHSERVID] is mandatory!")
|
raise LamConfigBackendException("ENV[MILTER_TRUSTED_AUTHSERVID] is mandatory!")
|
||||||
log_info("ENV[MILTER_DKIM_ENABLED]: {0}".format(self.milter_dkim_enabled))
|
log_info("ENV[MILTER_DKIM_ENABLED]: {}".format(self.milter_dkim_enabled))
|
||||||
|
|
||||||
if 'MILTER_MAX_RCPT_ENABLED' in os.environ:
|
if 'MILTER_MAX_RCPT_ENABLED' in os.environ:
|
||||||
self.milter_max_rcpt_enabled = True
|
self.milter_max_rcpt_enabled = True
|
||||||
if 'MILTER_MAX_RCPT' in os.environ:
|
if 'MILTER_MAX_RCPT' in os.environ:
|
||||||
if os.environ['MILTER_MAX_RCPT'].isnumeric():
|
if os.environ['MILTER_MAX_RCPT'].isnumeric():
|
||||||
self.milter_max_rcpt = os.environ['MILTER_MAX_RCPT']
|
self.milter_max_rcpt = int(os.environ['MILTER_MAX_RCPT'])
|
||||||
|
log_info("ENV[MILTER_MAX_RCPT]: {}".format(self.milter_max_rcpt))
|
||||||
else:
|
else:
|
||||||
raise LamConfigException("ENV[MILTER_MAX_RCPT] must be numeric!")
|
raise LamConfigBackendException("ENV[MILTER_MAX_RCPT] must be numeric!")
|
||||||
|
log_info("ENV[MILTER_MAX_RCPT_ENABLED]: {}".format(self.milter_max_rcpt_enabled))
|
||||||
|
|
||||||
|
|
||||||
@ -16,5 +16,5 @@ class LamHardException(LamException):
|
|||||||
class LamPolicyBackendException(LamException):
|
class LamPolicyBackendException(LamException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class LamConfigException(LamException):
|
class LamConfigBackendException(LamException):
|
||||||
pass
|
pass
|
||||||
@ -1,26 +0,0 @@
|
|||||||
import sys
|
|
||||||
from lam_exceptions import (
|
|
||||||
LamInitException, LamPolicyBackendException, LamConfigException
|
|
||||||
)
|
|
||||||
from lam_config import LamConfig
|
|
||||||
from lam_logger import init_logger
|
|
||||||
from lam_policy_backend import LamPolicyBackend
|
|
||||||
|
|
||||||
init_logger()
|
|
||||||
|
|
||||||
g_config = None
|
|
||||||
try:
|
|
||||||
if g_config is None:
|
|
||||||
g_config = LamConfig()
|
|
||||||
except LamConfigException as e:
|
|
||||||
raise LamInitException(e.message) from e
|
|
||||||
|
|
||||||
# Instantiate the LDAP policy backend and
|
|
||||||
# establish a permanent connection with the LDAP server
|
|
||||||
# which will be reused on any milter connection
|
|
||||||
g_policy_backend = None
|
|
||||||
try:
|
|
||||||
if g_policy_backend is None:
|
|
||||||
g_policy_backend = LamPolicyBackend(g_config)
|
|
||||||
except LamPolicyBackendException as e:
|
|
||||||
raise LamInitException(e.message) from e
|
|
||||||
@ -17,8 +17,8 @@ class LamPolicyBackend():
|
|||||||
set_config_parameter("RESTARTABLE_SLEEPTIME", 2)
|
set_config_parameter("RESTARTABLE_SLEEPTIME", 2)
|
||||||
set_config_parameter("RESTARTABLE_TRIES", 2)
|
set_config_parameter("RESTARTABLE_TRIES", 2)
|
||||||
server = Server(
|
server = Server(
|
||||||
self.config.ldap_server,
|
host = self.config.ldap_server,
|
||||||
connect_timeout = 3,
|
connect_timeout = self.config.ldap_server_connect_timeout,
|
||||||
get_info = NONE
|
get_info = NONE
|
||||||
)
|
)
|
||||||
self.ldap_conn = Connection(server,
|
self.ldap_conn = Connection(server,
|
||||||
@ -34,19 +34,19 @@ class LamPolicyBackend():
|
|||||||
"Connection to LDAP-server failed: {}".format(str(e))
|
"Connection to LDAP-server failed: {}".format(str(e))
|
||||||
) from e
|
) from e
|
||||||
|
|
||||||
def check_policy(self, **kwargs) -> str:
|
def check_policy(self, **kwargs):
|
||||||
from_addr = kwargs['from_addr']
|
from_addr = kwargs['from_addr']
|
||||||
rcpt_addr = kwargs['rcpt_addr']
|
rcpt_addr = kwargs['rcpt_addr']
|
||||||
from_source = kwargs['from_source']
|
from_source = kwargs['from_source']
|
||||||
lam_session = kwargs['lam_session']
|
lam_session = kwargs['lam_session']
|
||||||
|
mcid = "{}/Policy".format(lam_session.mconn_id)
|
||||||
m = g_rex_domain.match(from_addr)
|
m = g_rex_domain.match(from_addr)
|
||||||
if m == None:
|
if m == None:
|
||||||
log_info("Could not determine domain of from={0}".format(
|
raise LamHardException(
|
||||||
from_addr
|
"Could not determine domain of from={0}".format(from_addr)
|
||||||
))
|
)
|
||||||
raise LamSoftException()
|
|
||||||
from_domain = m.group(1)
|
from_domain = m.group(1)
|
||||||
log_debug("from_domain={}".format(from_domain))
|
log_debug("{0} from_domain={1}".format(mcid, from_domain))
|
||||||
m = g_rex_domain.match(rcpt_addr)
|
m = g_rex_domain.match(rcpt_addr)
|
||||||
if m == None:
|
if m == None:
|
||||||
raise LamHardException(
|
raise LamHardException(
|
||||||
@ -55,7 +55,7 @@ class LamPolicyBackend():
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
rcpt_domain = m.group(1)
|
rcpt_domain = m.group(1)
|
||||||
log_debug("rcpt_domain={}".format(rcpt_domain))
|
log_debug("{0} rcpt_domain={1}".format(mcid, rcpt_domain))
|
||||||
try:
|
try:
|
||||||
if self.config.milter_schema == True:
|
if self.config.milter_schema == True:
|
||||||
# LDAP-ACL-Milter schema
|
# LDAP-ACL-Milter schema
|
||||||
@ -77,7 +77,7 @@ class LamPolicyBackend():
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
auth_method = auth_method.replace('%X509_AUTH%','')
|
auth_method = auth_method.replace('%X509_AUTH%','')
|
||||||
log_debug("auth_method: {}".format(auth_method))
|
log_debug("{0} auth_method: {1}".format(mcid, auth_method))
|
||||||
if self.config.milter_schema_wildcard_domain == True:
|
if self.config.milter_schema_wildcard_domain == True:
|
||||||
# The asterisk (*) character is in term of local part
|
# The asterisk (*) character is in term of local part
|
||||||
# RFC5322 compliant and expected as a wildcard literal in this code.
|
# RFC5322 compliant and expected as a wildcard literal in this code.
|
||||||
@ -126,26 +126,28 @@ class LamPolicyBackend():
|
|||||||
)
|
)
|
||||||
if len(self.ldap_conn.entries) == 0:
|
if len(self.ldap_conn.entries) == 0:
|
||||||
# Policy not found in LDAP
|
# Policy not found in LDAP
|
||||||
ex = "policy mismatch: from={0} from_src={1} rcpt={2}".format(
|
raise LamHardException(
|
||||||
from_addr, from_source, rcpt_addr
|
"mismatch: from_src={0} from={1} rcpt={2}".format(
|
||||||
)
|
from_source, from_addr, rcpt_addr
|
||||||
if self.config.milter_expect_auth == True:
|
|
||||||
ex = "policy mismatch: from={0} from_src={1} rcpt={2} auth_method={3}".format(
|
|
||||||
from_addr, from_source, rcpt_addr, auth_method
|
|
||||||
)
|
)
|
||||||
raise LamHardException(ex)
|
)
|
||||||
elif len(self.ldap_conn.entries) == 1:
|
elif len(self.ldap_conn.entries) == 1:
|
||||||
|
if from_source == 'from-header':
|
||||||
|
log_info("{0} 5322.from={1} authorized by DKIM signature".format(
|
||||||
|
mcid, from_addr
|
||||||
|
))
|
||||||
# Policy found in LDAP, but which one?
|
# Policy found in LDAP, but which one?
|
||||||
entry = self.ldap_conn.entries[0]
|
entry = self.ldap_conn.entries[0]
|
||||||
return "policy match: '{0}' from_src={1}".format(
|
log_info("{0} match: '{1}' from_src={2}".format(
|
||||||
entry.policyID.value, from_source
|
mcid, entry.policyID.value, from_source
|
||||||
)
|
))
|
||||||
elif len(self.ldap_conn.entries) > 1:
|
elif len(self.ldap_conn.entries) > 1:
|
||||||
# Something went wrong!? There shouldn´t be more than one entries!
|
# Something went wrong!? There shouldn´t be more than one entries!
|
||||||
log_error("More than one policies found! from={0} rcpt={1} auth_method={2}".format(
|
raise LamHardException(
|
||||||
from_addr, rcpt_addr, auth_method
|
"More than one policies found! from={0} rcpt={1} auth_method={2}".format(
|
||||||
))
|
from_addr, rcpt_addr, auth_method
|
||||||
raise LamHardException("More than one policies found!")
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# Custom LDAP schema
|
# Custom LDAP schema
|
||||||
# 'build' a LDAP query per recipient
|
# 'build' a LDAP query per recipient
|
||||||
@ -156,18 +158,14 @@ class LamPolicyBackend():
|
|||||||
query = query.replace("%sasl_user%", lam_session.sasl_user)
|
query = query.replace("%sasl_user%", lam_session.sasl_user)
|
||||||
query = query.replace("%from_domain%", from_domain)
|
query = query.replace("%from_domain%", from_domain)
|
||||||
query = query.replace("%rcpt_domain%", rcpt_domain)
|
query = query.replace("%rcpt_domain%", rcpt_domain)
|
||||||
log_debug("LDAP query: {}".format(query))
|
log_debug("{0} LDAP query: {1}".format(mcid, query))
|
||||||
self.ldap_conn.search(self.config.ldap_base, query)
|
self.ldap_conn.search(self.config.ldap_base, query)
|
||||||
if len(self.ldap_conn.entries) == 0:
|
if len(self.ldap_conn.entries) == 0:
|
||||||
log_info(
|
raise LamHardException(
|
||||||
"policy mismatch from={0} from_src={1} rcpt={2}".format(
|
"mismatch from_src={0} from={1} rcpt={2}".format(
|
||||||
from_addr, from_source, rcpt_addr
|
from_source, from_addr, rcpt_addr
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
raise LamHardException("policy mismatch")
|
log_info("{0} match from_src={1}".format(mcid, from_source))
|
||||||
return "policy match: '{0}' from_src={1}".format(
|
|
||||||
entry.policyID.value, from_source
|
|
||||||
)
|
|
||||||
except LDAPException as e:
|
except LDAPException as e:
|
||||||
log_error("LDAP exception: {}".format(str(e)))
|
|
||||||
raise LamSoftException("LDAP exception: " + str(e)) from e
|
raise LamSoftException("LDAP exception: " + str(e)) from e
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import traceback
|
|||||||
from lam_exceptions import LamInitException
|
from lam_exceptions import LamInitException
|
||||||
from lam_logger import log_info, log_error
|
from lam_logger import log_info, log_error
|
||||||
try:
|
try:
|
||||||
import lam_globals
|
import lam_backends
|
||||||
except LamInitException as e:
|
except LamInitException as e:
|
||||||
log_error("Init exception: {}".format(e.message))
|
log_error("Init exception: {}".format(e.message))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -12,24 +12,22 @@ from lam import LdapAclMilter
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
timeout = 600
|
timeout = lam_backends.g_config_backend.milter_timeout
|
||||||
# Register to have the Milter factory create instances of your class:
|
# Register to have the Milter factory create instances of your class:
|
||||||
Milter.factory = LdapAclMilter
|
Milter.factory = LdapAclMilter
|
||||||
# Tell the MTA which features we use
|
# Tell the MTA which features we use
|
||||||
flags = Milter.ADDHDRS
|
flags = Milter.ADDHDRS
|
||||||
Milter.set_flags(flags)
|
Milter.set_flags(flags)
|
||||||
log_info("Starting {0}@socket: {1} in mode {2}".format(
|
log_info("Starting {}".format(
|
||||||
lam_globals.g_config.milter_name,
|
lam_backends.g_config_backend.milter_name
|
||||||
lam_globals.g_config.milter_socket,
|
|
||||||
lam_globals.g_config.milter_mode
|
|
||||||
))
|
))
|
||||||
Milter.runmilter(
|
Milter.runmilter(
|
||||||
lam_globals.g_config.milter_name,
|
lam_backends.g_config_backend.milter_name,
|
||||||
lam_globals.g_config.milter_socket,
|
lam_backends.g_config_backend.milter_socket,
|
||||||
timeout,
|
timeout,
|
||||||
True
|
True
|
||||||
)
|
)
|
||||||
log_info("Shutdown {}".format(lam_globals.g_config.milter_name))
|
log_info("Shutdown {}".format(lam_backends.g_config_backend.milter_name))
|
||||||
except:
|
except:
|
||||||
log_error("MAIN-EXCEPTION: {}".format(traceback.format_exc()))
|
log_error("MAIN-EXCEPTION: {}".format(traceback.format_exc()))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
@ -16,18 +16,12 @@ mt.set_timeout(60)
|
|||||||
if mt.mailfrom(conn, "tester-ip@test.blah") ~= nil then
|
if mt.mailfrom(conn, "tester-ip@test.blah") ~= nil then
|
||||||
error "mt.mailfrom() failed"
|
error "mt.mailfrom() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.mailfrom() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5321.RCPT+MACROS
|
-- 5321.RCPT+MACROS
|
||||||
mt.macro(conn, SMFIC_RCPT, "i", "4CgSNs5Q9sz7SllQ")
|
mt.macro(conn, SMFIC_RCPT, "i", "4CgSNs5Q9sz7SllQ")
|
||||||
if mt.rcptto(conn, "<rcpt-ip@test.blubb>") ~= nil then
|
if mt.rcptto(conn, "<rcpt-ip@test.blubb>") ~= nil then
|
||||||
error "mt.rcptto() failed"
|
error "mt.rcptto() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.rcptto() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5322.HEADERS
|
-- 5322.HEADERS
|
||||||
if mt.header(conn, "fRoM", '"Blah Blubb" <tester-ip@test.blah>') ~= nil then
|
if mt.header(conn, "fRoM", '"Blah Blubb" <tester-ip@test.blah>') ~= nil then
|
||||||
@ -54,18 +48,12 @@ end
|
|||||||
if mt.mailfrom(conn, "tester-ip2@test.blah") ~= nil then
|
if mt.mailfrom(conn, "tester-ip2@test.blah") ~= nil then
|
||||||
error "mt.mailfrom() failed"
|
error "mt.mailfrom() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.mailfrom() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5321.RCPT+MACROS
|
-- 5321.RCPT+MACROS
|
||||||
mt.macro(conn, SMFIC_RCPT, "i", "conn-reused-QID")
|
mt.macro(conn, SMFIC_RCPT, "i", "conn-reused-QID")
|
||||||
if mt.rcptto(conn, "<rcpt-ip2@test.blubb>") ~= nil then
|
if mt.rcptto(conn, "<rcpt-ip2@test.blubb>") ~= nil then
|
||||||
error "mt.rcptto() failed"
|
error "mt.rcptto() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.rcptto() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5322.HEADERS
|
-- 5322.HEADERS
|
||||||
if mt.header(conn, "fRoM", '"Blah Blubb" <tester-ip2@test.blah>') ~= nil then
|
if mt.header(conn, "fRoM", '"Blah Blubb" <tester-ip2@test.blah>') ~= nil then
|
||||||
|
|||||||
@ -16,9 +16,6 @@ mt.set_timeout(60)
|
|||||||
if mt.mailfrom(conn, "tester-ipx@test.blah") ~= nil then
|
if mt.mailfrom(conn, "tester-ipx@test.blah") ~= nil then
|
||||||
error "mt.mailfrom() failed"
|
error "mt.mailfrom() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.mailfrom() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- FIRST 5321.RCPT
|
-- FIRST 5321.RCPT
|
||||||
if mt.rcptto(conn, "<rcpt-ip@test.blubb>") ~= nil then
|
if mt.rcptto(conn, "<rcpt-ip@test.blubb>") ~= nil then
|
||||||
|
|||||||
@ -16,19 +16,12 @@ mt.set_timeout(60)
|
|||||||
if mt.mailfrom(conn, "tester-noauth@test.blah") ~= nil then
|
if mt.mailfrom(conn, "tester-noauth@test.blah") ~= nil then
|
||||||
error "mt.mailfrom() failed"
|
error "mt.mailfrom() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.mailfrom() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5321.RCPT+MACROS
|
-- 5321.RCPT+MACROS
|
||||||
mt.macro(conn, SMFIC_RCPT, "i", "4CgSNs5Q9sz7SllQ")
|
mt.macro(conn, SMFIC_RCPT, "i", "4CgSNs5Q9sz7SllQ")
|
||||||
if mt.rcptto(conn, "<rcpt-noauth@test.blubb>") ~= nil then
|
if mt.rcptto(conn, "<rcpt-noauth@test.blubb>") ~= nil then
|
||||||
-- if mt.rcptto(conn, "<rcpt-noauth@>") ~= nil then
|
|
||||||
error "mt.rcptto() failed"
|
error "mt.rcptto() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.rcptto() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5322.HEADERS
|
-- 5322.HEADERS
|
||||||
if mt.header(conn, "fRoM", '"Blah Blubb" <tester-noauth@test.blah>') ~= nil then
|
if mt.header(conn, "fRoM", '"Blah Blubb" <tester-noauth@test.blah>') ~= nil then
|
||||||
|
|||||||
0
tests/miltertest-null_sender.lua
Normal file
0
tests/miltertest-null_sender.lua
Normal file
@ -17,18 +17,12 @@ mt.macro(conn, SMFIC_MAIL, "{auth_authen}", "blubb-user-wild")
|
|||||||
if mt.mailfrom(conn, "tester-invalid@test.blah") ~= nil then
|
if mt.mailfrom(conn, "tester-invalid@test.blah") ~= nil then
|
||||||
error "mt.mailfrom() failed"
|
error "mt.mailfrom() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.mailfrom() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5321.RCPT+MACROS
|
-- 5321.RCPT+MACROS
|
||||||
mt.macro(conn, SMFIC_RCPT, "i", "test-wildcard-qid")
|
mt.macro(conn, SMFIC_RCPT, "i", "test-wildcard-qid")
|
||||||
if mt.rcptto(conn, "<anybody-xyz@out.there>") ~= nil then
|
if mt.rcptto(conn, "<anybody-xyz@out.there>") ~= nil then
|
||||||
error "mt.rcptto() failed"
|
error "mt.rcptto() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.rcptto() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5322.HEADERS
|
-- 5322.HEADERS
|
||||||
if mt.header(conn, "fRoM", '"Blah Blubb" <tester@test.blah>') ~= nil then
|
if mt.header(conn, "fRoM", '"Blah Blubb" <tester@test.blah>') ~= nil then
|
||||||
|
|||||||
@ -17,18 +17,12 @@ mt.macro(conn, SMFIC_MAIL, "{auth_authen}", "blubb-user1")
|
|||||||
if mt.mailfrom(conn, "tester@test.blah") ~= nil then
|
if mt.mailfrom(conn, "tester@test.blah") ~= nil then
|
||||||
error "mt.mailfrom() failed"
|
error "mt.mailfrom() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.mailfrom() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5321.RCPT+MACROS
|
-- 5321.RCPT+MACROS
|
||||||
mt.macro(conn, SMFIC_RCPT, "i", "4CgSNs5Q9sz7SllQ")
|
mt.macro(conn, SMFIC_RCPT, "i", "4CgSNs5Q9sz7SllQ")
|
||||||
if mt.rcptto(conn, "<rcpt@test.blubb>") ~= nil then
|
if mt.rcptto(conn, "<rcpt@test.blubb>") ~= nil then
|
||||||
error "mt.rcptto() failed"
|
error "mt.rcptto() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.rcptto() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5322.HEADERS
|
-- 5322.HEADERS
|
||||||
if mt.header(conn, "fRoM", '"Blah Blubb" <tester@test.blah>') ~= nil then
|
if mt.header(conn, "fRoM", '"Blah Blubb" <tester@test.blah>') ~= nil then
|
||||||
|
|||||||
0
tests/miltertest-whitelisted_sender.lua
Normal file
0
tests/miltertest-whitelisted_sender.lua
Normal file
@ -18,18 +18,12 @@ mt.macro(conn, SMFIC_MAIL, "{cert_issuer}", "x509-issuer", "{cert_subject}", "x5
|
|||||||
if mt.mailfrom(conn, "tester-x509@test.blah") ~= nil then
|
if mt.mailfrom(conn, "tester-x509@test.blah") ~= nil then
|
||||||
error "mt.mailfrom() failed"
|
error "mt.mailfrom() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.mailfrom() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5321.RCPT+MACROS
|
-- 5321.RCPT+MACROS
|
||||||
mt.macro(conn, SMFIC_RCPT, "i", "4CgSNs5Q9sz7SllQ")
|
mt.macro(conn, SMFIC_RCPT, "i", "4CgSNs5Q9sz7SllQ")
|
||||||
if mt.rcptto(conn, "<rcpt-x509@test.blubb>") ~= nil then
|
if mt.rcptto(conn, "<rcpt-x509@test.blubb>") ~= nil then
|
||||||
error "mt.rcptto() failed"
|
error "mt.rcptto() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.rcptto() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5322.HEADERS
|
-- 5322.HEADERS
|
||||||
if mt.header(conn, "fRoM", '"Blah Blubb" <tester@test.blah>') ~= nil then
|
if mt.header(conn, "fRoM", '"Blah Blubb" <tester@test.blah>') ~= nil then
|
||||||
|
|||||||
@ -17,18 +17,12 @@ mt.macro(conn, SMFIC_MAIL, "{cert_issuer}", "x509-issuer", "{cert_subject}", "x5
|
|||||||
if mt.mailfrom(conn, "tester-x509-invalid@test.blah") ~= nil then
|
if mt.mailfrom(conn, "tester-x509-invalid@test.blah") ~= nil then
|
||||||
error "mt.mailfrom() failed"
|
error "mt.mailfrom() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.mailfrom() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5321.RCPT+MACROS
|
-- 5321.RCPT+MACROS
|
||||||
mt.macro(conn, SMFIC_RCPT, "i", "4CgSNs5Q9sz7SllQ")
|
mt.macro(conn, SMFIC_RCPT, "i", "4CgSNs5Q9sz7SllQ")
|
||||||
if mt.rcptto(conn, "<rcpt-x509@test.blubb>") ~= nil then
|
if mt.rcptto(conn, "<rcpt-x509@test.blubb>") ~= nil then
|
||||||
error "mt.rcptto() failed"
|
error "mt.rcptto() failed"
|
||||||
end
|
end
|
||||||
if mt.getreply(conn) ~= SMFIR_CONTINUE then
|
|
||||||
error "mt.rcptto() unexpected reply"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- 5322.HEADERS
|
-- 5322.HEADERS
|
||||||
if mt.header(conn, "fRoM", '"Blah Blubb" <tester-x509@test.blah>') ~= nil then
|
if mt.header(conn, "fRoM", '"Blah Blubb" <tester-x509@test.blah>') ~= nil then
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user