mirror of
https://github.com/chillout2k/ldap-acl-milter.git
synced 2025-12-12 19:00:19 +00:00
more tests; null-sender switch; take denied senders/rcpts under consideration
This commit is contained in:
parent
f06be7b0c3
commit
d6af0c648d
55
app/lam.py
55
app/lam.py
@ -45,6 +45,7 @@ class LdapAclMilter(Milter.Base):
|
|||||||
def reset(self):
|
def reset(self):
|
||||||
self.proto_stage = 'invalid'
|
self.proto_stage = 'invalid'
|
||||||
self.env_from = None
|
self.env_from = None
|
||||||
|
self.null_sender = False
|
||||||
self.sasl_user = None
|
self.sasl_user = None
|
||||||
self.x509_subject = None
|
self.x509_subject = None
|
||||||
self.x509_issuer = None
|
self.x509_issuer = None
|
||||||
@ -154,34 +155,42 @@ class LdapAclMilter(Milter.Base):
|
|||||||
self.client_addr, self.x509_subject, self.x509_issuer, self.sasl_user
|
self.client_addr, self.x509_subject, self.x509_issuer, self.sasl_user
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
mailfrom = mailfrom.replace("<","")
|
if mailfrom == '<>':
|
||||||
mailfrom = mailfrom.replace(">","")
|
self.null_sender = True
|
||||||
# BATV (https://tools.ietf.org/html/draft-levine-smtp-batv-01)
|
if g_config_backend.milter_allow_null_sender and self.null_sender:
|
||||||
# Strip out Simple Private Signature (PRVS)
|
self.log_info("Null-sender accepted - skipping policy checks")
|
||||||
mailfrom = re.sub(r"^prvs=.{10}=", '', mailfrom)
|
else:
|
||||||
# SRS (https://www.libsrs2.org/srs/srs.pdf)
|
mailfrom = mailfrom.replace("<","")
|
||||||
m_srs = g_rex_srs.match(mailfrom)
|
mailfrom = mailfrom.replace(">","")
|
||||||
if m_srs != None:
|
# BATV (https://tools.ietf.org/html/draft-levine-smtp-batv-01)
|
||||||
self.log_info("Found SRS-encoded envelope-sender: {}".format(mailfrom))
|
# Strip out Simple Private Signature (PRVS)
|
||||||
mailfrom = m_srs.group(2) + '@' + m_srs.group(1)
|
mailfrom = re.sub(r"^prvs=.{10}=", '', mailfrom)
|
||||||
self.log_info("SRS envelope-sender replaced with: {}".format(mailfrom))
|
# SRS (https://www.libsrs2.org/srs/srs.pdf)
|
||||||
self.env_from = mailfrom.lower()
|
m_srs = g_rex_srs.match(mailfrom)
|
||||||
self.log_debug("5321.from={}".format(self.env_from))
|
if m_srs != None:
|
||||||
m = g_rex_domain.match(self.env_from)
|
self.log_info("Found SRS-encoded envelope-sender: {}".format(mailfrom))
|
||||||
if m == None:
|
mailfrom = m_srs.group(2) + '@' + m_srs.group(1)
|
||||||
return self.milter_action(
|
self.log_info("SRS envelope-sender replaced with: {}".format(mailfrom))
|
||||||
action = 'reject',
|
self.env_from = mailfrom.lower()
|
||||||
reason = "Could not determine domain of 5321.from={}".format(self.env_from)
|
self.log_debug("5321.from={}".format(self.env_from))
|
||||||
)
|
m = g_rex_domain.match(self.env_from)
|
||||||
|
if m == None:
|
||||||
|
return self.milter_action(
|
||||||
|
action = 'reject',
|
||||||
|
reason = "Could not determine domain of 5321.from={}".format(self.env_from)
|
||||||
|
)
|
||||||
return self.milter_action(action = 'continue')
|
return self.milter_action(action = 'continue')
|
||||||
|
|
||||||
def envrcpt(self, to, *str):
|
def envrcpt(self, to, *str):
|
||||||
self.proto_stage = 'RCPT'
|
self.proto_stage = 'RCPT'
|
||||||
|
if g_config_backend.milter_allow_null_sender and self.null_sender:
|
||||||
|
return self.milter_action(action = 'continue')
|
||||||
to = to.replace("<","")
|
to = to.replace("<","")
|
||||||
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_backend.milter_whitelisted_rcpts:
|
if to in g_config_backend.milter_whitelisted_rcpts:
|
||||||
|
self.log_info("Welcome-listed rcpt={} - skipping policy checks".format(to))
|
||||||
return self.milter_action(action = 'continue')
|
return self.milter_action(action = 'continue')
|
||||||
if g_config_backend.milter_dkim_enabled:
|
if g_config_backend.milter_dkim_enabled:
|
||||||
# Collect all envelope-recipients for later
|
# Collect all envelope-recipients for later
|
||||||
@ -214,6 +223,8 @@ 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_backend.milter_allow_null_sender and self.null_sender:
|
||||||
|
return self.milter_action(action = 'continue')
|
||||||
if g_config_backend.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()):
|
||||||
@ -223,7 +234,7 @@ class LdapAclMilter(Milter.Base):
|
|||||||
if m is None:
|
if m is None:
|
||||||
return self.milter_action(
|
return self.milter_action(
|
||||||
action = 'reject',
|
action = 'reject',
|
||||||
reason = "Could not determine domain-part of 5322.from=" + self.hdr_from
|
reason = "Could not determine domain-part of 5322.from={}".format(self.hdr_from)
|
||||||
)
|
)
|
||||||
self.hdr_from_domain = m.group(1)
|
self.hdr_from_domain = m.group(1)
|
||||||
self.log_debug("5322.from={0}, 5322.from_domain={1}".format(
|
self.log_debug("5322.from={0}, 5322.from_domain={1}".format(
|
||||||
@ -259,6 +270,8 @@ class LdapAclMilter(Milter.Base):
|
|||||||
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_backend.milter_allow_null_sender and self.null_sender:
|
||||||
|
return self.milter_action(action = 'continue')
|
||||||
if g_config_backend.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
|
||||||
@ -274,6 +287,8 @@ class LdapAclMilter(Milter.Base):
|
|||||||
))
|
))
|
||||||
reject_message = False
|
reject_message = False
|
||||||
for rcpt in self.env_rcpts:
|
for rcpt in self.env_rcpts:
|
||||||
|
if rcpt in g_config_backend.milter_whitelisted_rcpts:
|
||||||
|
self.log_info("Welcome-listed rcpt={}".format(rcpt))
|
||||||
try:
|
try:
|
||||||
# Check 5321.from against policy
|
# Check 5321.from against policy
|
||||||
g_policy_backend.check_policy(
|
g_policy_backend.check_policy(
|
||||||
|
|||||||
@ -26,6 +26,7 @@ class LamConfigBackend():
|
|||||||
self.milter_trusted_authservid = None
|
self.milter_trusted_authservid = None
|
||||||
self.milter_max_rcpt_enabled = False
|
self.milter_max_rcpt_enabled = False
|
||||||
self.milter_max_rcpt = 1
|
self.milter_max_rcpt = 1
|
||||||
|
self.milter_allow_null_sender = False
|
||||||
|
|
||||||
if 'MILTER_NAME' in os.environ:
|
if 'MILTER_NAME' in os.environ:
|
||||||
self.milter_name = os.environ['MILTER_NAME']
|
self.milter_name = os.environ['MILTER_NAME']
|
||||||
@ -150,4 +151,7 @@ class LamConfigBackend():
|
|||||||
raise LamConfigBackendException("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))
|
log_info("ENV[MILTER_MAX_RCPT_ENABLED]: {}".format(self.milter_max_rcpt_enabled))
|
||||||
|
|
||||||
|
if 'MILTER_ALLOW_NULL_SENDER' in os.environ:
|
||||||
|
if re.match(r'^true$', os.environ['MILTER_ALLOW_NULL_SENDER'], re.IGNORECASE):
|
||||||
|
self.milter_allow_null_sender = True
|
||||||
|
log_info("ENV[MILTER_ALLOW_NULL_SENDER]: {}".format(self.milter_allow_null_sender))
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import re
|
import re
|
||||||
from lam_logger import log_info, log_debug, log_error
|
from lam_logger import log_info, log_debug
|
||||||
from lam_rex import g_rex_domain
|
from lam_rex import g_rex_domain
|
||||||
from ldap3 import (
|
from ldap3 import (
|
||||||
Server, Connection, NONE, set_config_parameter
|
Server, Connection, NONE, set_config_parameter
|
||||||
@ -8,9 +8,10 @@ from ldap3.core.exceptions import LDAPException
|
|||||||
from lam_exceptions import (
|
from lam_exceptions import (
|
||||||
LamPolicyBackendException, LamHardException, LamSoftException
|
LamPolicyBackendException, LamHardException, LamSoftException
|
||||||
)
|
)
|
||||||
|
from lam_config_backend import LamConfigBackend
|
||||||
|
|
||||||
class LamPolicyBackend():
|
class LamPolicyBackend():
|
||||||
def __init__(self, lam_config):
|
def __init__(self, lam_config: LamConfigBackend):
|
||||||
self.config = lam_config
|
self.config = lam_config
|
||||||
self.ldap_conn = None
|
self.ldap_conn = None
|
||||||
try:
|
try:
|
||||||
@ -61,18 +62,18 @@ class LamPolicyBackend():
|
|||||||
# LDAP-ACL-Milter schema
|
# LDAP-ACL-Milter schema
|
||||||
auth_method = ''
|
auth_method = ''
|
||||||
if self.config.milter_expect_auth == True:
|
if self.config.milter_expect_auth == True:
|
||||||
auth_method = "(|(allowedClientAddr="+lam_session.client_addr+")%SASL_AUTH%%X509_AUTH%)"
|
auth_method = "(|(allowedClientAddr=" + lam_session.client_addr + ")%SASL_AUTH%%X509_AUTH%)"
|
||||||
if lam_session.sasl_user:
|
if lam_session.sasl_user:
|
||||||
auth_method = auth_method.replace(
|
auth_method = auth_method.replace(
|
||||||
'%SASL_AUTH%',"(allowedSaslUser="+lam_session.sasl_user+")"
|
'%SASL_AUTH%',"(allowedSaslUser=" + lam_session.sasl_user + ")"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
auth_method = auth_method.replace('%SASL_AUTH%','')
|
auth_method = auth_method.replace('%SASL_AUTH%','')
|
||||||
if lam_session.x509_subject and lam_session.x509_issuer:
|
if lam_session.x509_subject and lam_session.x509_issuer:
|
||||||
auth_method = auth_method.replace('%X509_AUTH%',
|
auth_method = auth_method.replace('%X509_AUTH%',
|
||||||
"(&"+
|
"(&"+
|
||||||
"(allowedx509subject="+lam_session.x509_subject+")"+
|
"(allowedx509subject=" + lam_session.x509_subject + ")" +
|
||||||
"(allowedx509issuer="+lam_session.x509_issuer+")"+
|
"(allowedx509issuer=" + lam_session.x509_issuer + ")" +
|
||||||
")"
|
")"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -98,16 +99,26 @@ class LamPolicyBackend():
|
|||||||
self.ldap_conn.search(self.config.ldap_base,
|
self.ldap_conn.search(self.config.ldap_base,
|
||||||
"(&" +
|
"(&" +
|
||||||
auth_method +
|
auth_method +
|
||||||
"(|"+
|
"(|" +
|
||||||
"(allowedRcpts=" + rcpt_addr + ")"+
|
"(allowedSenders=" + from_addr + ")" +
|
||||||
"(allowedRcpts=\\2a@" + rcpt_domain + ")"+
|
"(allowedSenders=\\2a@" + from_domain + ")" +
|
||||||
"(allowedRcpts=\\2a@\\2a)"+
|
"(allowedSenders=\\2a@\\2a)" +
|
||||||
")"+
|
")" +
|
||||||
"(|"+
|
"(&" +
|
||||||
"(allowedSenders=" + from_addr + ")"+
|
"(!(deniedSenders=" + from_addr + "))" +
|
||||||
"(allowedSenders=\\2a@" + from_domain + ")"+
|
"(!(deniedSenders=\\2a@" + from_domain + "))" +
|
||||||
"(allowedSenders=\\2a@\\2a)"+
|
"(!(deniedSenders=\\2a@\\2a))" +
|
||||||
")"+
|
")" +
|
||||||
|
"(|" +
|
||||||
|
"(allowedRcpts=" + rcpt_addr + ")" +
|
||||||
|
"(allowedRcpts=\\2a@" + rcpt_domain + ")" +
|
||||||
|
"(allowedRcpts=\\2a@\\2a)" +
|
||||||
|
")" +
|
||||||
|
"(&" +
|
||||||
|
"(!(deniedRcpts=" + rcpt_addr + "))" +
|
||||||
|
"(!(deniedRcpts=\\2a@" + rcpt_domain + "))" +
|
||||||
|
"(!(deniedRcpts=\\2a@\\2a))" +
|
||||||
|
")" +
|
||||||
")",
|
")",
|
||||||
attributes=['policyID']
|
attributes=['policyID']
|
||||||
)
|
)
|
||||||
@ -119,8 +130,8 @@ class LamPolicyBackend():
|
|||||||
self.ldap_conn.search(self.config.ldap_base,
|
self.ldap_conn.search(self.config.ldap_base,
|
||||||
"(&" +
|
"(&" +
|
||||||
auth_method +
|
auth_method +
|
||||||
"(allowedRcpts=" + query_to + ")" +
|
|
||||||
"(allowedSenders=" + query_from + ")" +
|
"(allowedSenders=" + query_from + ")" +
|
||||||
|
"(allowedRcpts=" + query_to + ")" +
|
||||||
")",
|
")",
|
||||||
attributes=['policyID']
|
attributes=['policyID']
|
||||||
)
|
)
|
||||||
@ -133,8 +144,8 @@ class LamPolicyBackend():
|
|||||||
)
|
)
|
||||||
elif len(self.ldap_conn.entries) == 1:
|
elif len(self.ldap_conn.entries) == 1:
|
||||||
if from_source == 'from-header':
|
if from_source == 'from-header':
|
||||||
log_info("{0} 5322.from={1} authorized by DKIM signature".format(
|
log_info("{0} 5322.from_domain={1} authorized by DKIM signature".format(
|
||||||
mcid, from_addr
|
mcid, from_domain
|
||||||
))
|
))
|
||||||
# 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]
|
||||||
@ -150,12 +161,13 @@ class LamPolicyBackend():
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Custom LDAP schema
|
# Custom LDAP schema
|
||||||
# 'build' a LDAP query per recipient
|
# replace all placeholders in query template
|
||||||
# replace all placeholders in query templates
|
|
||||||
query = self.config.ldap_query.replace("%rcpt%", rcpt_addr)
|
query = self.config.ldap_query.replace("%rcpt%", rcpt_addr)
|
||||||
query = query.replace("%from%", from_addr)
|
query = query.replace("%from%", from_addr)
|
||||||
query = query.replace("%client_addr%", lam_session.client_addr)
|
if self.config.milter_expect_auth:
|
||||||
query = query.replace("%sasl_user%", lam_session.sasl_user)
|
query = query.replace("%client_addr%", lam_session.client_addr)
|
||||||
|
if lam_session.sasl_user is not None:
|
||||||
|
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("{0} LDAP query: {1}".format(mcid, query))
|
log_debug("{0} LDAP query: {1}".format(mcid, query))
|
||||||
|
|||||||
43
tests/null_sender.lua
Normal file
43
tests/null_sender.lua
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
-- 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.255.255.254") ~= nil then
|
||||||
|
error "mt.conninfo() failed"
|
||||||
|
end
|
||||||
|
|
||||||
|
mt.set_timeout(60)
|
||||||
|
|
||||||
|
-- 5321.FROM
|
||||||
|
if mt.mailfrom(conn, "<>") ~= nil then
|
||||||
|
error "mt.mailfrom() failed"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 5321.RCPT+MACROS
|
||||||
|
mt.macro(conn, SMFIC_RCPT, "i", "4CgSNs5Q9sz7SllQ")
|
||||||
|
if mt.rcptto(conn, "<rcpt-null@test.blubb>") ~= nil then
|
||||||
|
error "mt.rcptto() failed"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 5322.HEADERS
|
||||||
|
if mt.header(conn, "fRoM", '"MAILER DAEMON') ~= nil then
|
||||||
|
error "mt.header(From) 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)
|
||||||
47
tests/sasl-wildcard.lua
Normal file
47
tests/sasl-wildcard.lua
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
-- 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, "localhost", "::1") ~= nil then
|
||||||
|
error "mt.conninfo() failed"
|
||||||
|
end
|
||||||
|
|
||||||
|
mt.set_timeout(60)
|
||||||
|
|
||||||
|
-- 5321.FROM+MACROS
|
||||||
|
mt.macro(conn, SMFIC_MAIL, "{auth_authen}", "blubb-user-wild")
|
||||||
|
if mt.mailfrom(conn, "tester@test.blah") ~= nil then
|
||||||
|
error "mt.mailfrom() failed"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 5321.RCPT+MACROS
|
||||||
|
mt.macro(conn, SMFIC_RCPT, "i", "test-wildcard-qid")
|
||||||
|
if mt.rcptto(conn, "<anybody-xyz@out.there>") ~= nil then
|
||||||
|
error "mt.rcptto() failed"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 5322.HEADERS
|
||||||
|
if mt.header(conn, "fRoM", '"Blah Blubb" <tester@test.blah>') ~= nil then
|
||||||
|
error "mt.header(From) failed"
|
||||||
|
end
|
||||||
|
if mt.header(conn, "Authentication-RESULTS", "my-auth-serv-id;\n dkim=pass 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)
|
||||||
56
tests/welcome-listed_rcpt.lua
Normal file
56
tests/welcome-listed_rcpt.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.128.129.130") ~= nil then
|
||||||
|
error "mt.conninfo() failed"
|
||||||
|
end
|
||||||
|
|
||||||
|
mt.set_timeout(60)
|
||||||
|
|
||||||
|
-- 5321.FROM
|
||||||
|
if mt.mailfrom(conn, "some-sender@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, "<postmaster@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" <some-sender@test.blah>') ~= nil then
|
||||||
|
error "mt.header(From) failed"
|
||||||
|
end
|
||||||
|
if mt.header(conn, "Authentication-REsuLTS", "my-auth-serv-id;\n dkim=pass 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