2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-23 10:28:06 +00:00

snapshot-19990909

This commit is contained in:
Wietse Venema 1999-09-09 00:00:00 -05:00
parent 981562b004
commit f90b3d19a4
47 changed files with 663 additions and 346 deletions

1
postfix/.indent.pro vendored
View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -3039,3 +3039,40 @@ Apologies for any names omitted.
and for upgrading Postfix. It replaces files instead of and for upgrading Postfix. It replaces files instead of
overwriting them, and leaves existing configuration and overwriting them, and leaves existing configuration and
queue files intact. queue files intact.
19990907
Bugfix: reject_non_fqdn_sender used the wrong test to see
if a sender address was given and could dump core. This
must have been broken ever since the UCE tests were moved
to the RCPT TO stage in 19990510.
Bugfix: check_sender_access was recognized as a valid
restriction name only if a sender had been specified.
19990908
Portability: Unixware has <sysexits.h> only after sendmail
is installed. Changed postlock.c to use global/sys_exists.h.
19990909
Performance: added one-entry cache to the address rewriting
client and to the address resolving client. This is because
UCE restrictions tend to produce the same query repeatedly.
Feature: the UCE restrictions are now fully recursive so
you can have per-client/helo/sender/recipient restrictions.
Instead of OK, REJECT or [45]xx, you can specify a sequence
of restrictions on the right-hand side of an SMTPD access
table. This means you can no longer use canonical/virtual/alias
maps as SMTPD access tables. But the loss is compensated for.
Feature: restriction classes, essentially a short-hand for
restriction lists. These short hands are useful mostly on
the right-hand side of SMTPD access tables.
Feature: "permit_address_map maptype:mapname" permits a
recipient address when it matches the specified table.
Lookups are done just as with canonical/virtual maps. With
this, you can also use passwd/aliases as SMTPD access maps.

View File

@ -174,7 +174,7 @@ rm -f junk
# Install files. Be careful to not copy over running programs. # Install files. Be careful to not copy over running programs.
for file in `ls libexec` for file in `ls libexec | grep '^[a-z]'`
do do
compare_or_replace a+x,go-w libexec/$file $daemon_directory/$file || exit 1 compare_or_replace a+x,go-w libexec/$file $daemon_directory/$file || exit 1
done done

View File

@ -1,3 +1,51 @@
Incompatible changes with snapshot 19990909
===========================================
- You can not longer use virtual, canonical or aliases tables as
SMTPD access control tables. Use the permit_address_map feature
instead. The loss is compensated for.
Major changes with snapshot 19990909
====================================
- Per-client/helo/sender/recipient UCE restrictions: you can now
specify arbitrary restrictions on the right-hand side of SMTPD
access tables. The only anomaly in this scheme is that header
checks are the same for every message.
- Restriction classes allow you to conveniently group restrictions
under one name. This is great for per-client/helo/sender/recipient
UCE restrictions. For example in main.cf:
smtpd_restriction_classes = restrictive, permissive
restrictive = reject_unknown_sender reject_unknown_client ...
permissive = permit
Then use "restrictive" or "restrictive" on the right-hand side of
your per-client/helo/sender/recipient SMTPD access tables.
- Reject mail for non-existent local accounts. You can now use
passwd/canonical/virtual/aliases tables for SMTPD access control.
For example, specify in main.cf:
relay_domains = $mydestination other domains...
smtpd_recipient_restrictions =
reject_unauth_destination
permit_address_map unix:passwd.byname
permit_address_map hash:/etc/canonical
permit_address_map hash:/etc/postfix/virtual
permit_address_map hash:/etc/aliases
reject
That should stop a lot of the mail to non-existent recipients. It
won't stop mail to broken aliases or to users with broken .forward
files, though.
Unfortunately, permit_address_map does not combine well with
check_relay_domains, because that restriction ALWAYS permits mail
for local destinations. Instead of check_relay_domains, use some
combination of permit_mynetworks and reject_unauth_destination.
Incompatible changes with postfix-19990906 Incompatible changes with postfix-19990906
========================================== ==========================================
@ -7,7 +55,7 @@ files while delivering to files specified in aliases/forward/include
files. This is a no-op when the recipient lacks directory write files. This is a no-op when the recipient lacks directory write
permission. permission.
- The LDAP client code no longer looks up name containing "*" - The LDAP client code no longer looks up a name containing "*"
because it could be abused. See the LDAP_README file for how to because it could be abused. See the LDAP_README file for how to
restore previous behavior. restore previous behavior.

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -203,6 +203,8 @@ smtpd_sender_restrictions =
# reject_non_fqdn_hostname: reject HELO hostname that is not in FQDN form # reject_non_fqdn_hostname: reject HELO hostname that is not in FQDN form
# reject_non_fqdn_sender: reject sender address that is not in FQDN form # reject_non_fqdn_sender: reject sender address that is not in FQDN form
# reject_non_fqdn_recipient: reject recipient address that is not in FQDN form # reject_non_fqdn_recipient: reject recipient address that is not in FQDN form
# permit_address_map maptype:mapname: permit if the recipient address matches
# the table. Matching is as with virtual/canonical tables.
# reject: reject the request. Place this at the end of a restriction. # reject: reject the request. Place this at the end of a restriction.
# permit: permit the request. Place this at the end of a restriction. # permit: permit the request. Place this at the end of a restriction.
# #

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -718,6 +718,10 @@ extern char *var_rcpt_checks;
#define DEF_ETRN_CHECKS "" #define DEF_ETRN_CHECKS ""
extern char *var_etrn_checks; extern char *var_etrn_checks;
#define VAR_REST_CLASSES "smtpd_restriction_classes"
#define DEF_REST_CLASSES ""
extern char *var_rest_classes;
/* /*
* Names of specific restrictions, and the corresponding configuration * Names of specific restrictions, and the corresponding configuration
* parameters that control the status codes sent in response to rejected * parameters that control the status codes sent in response to rejected
@ -795,6 +799,8 @@ extern int var_smtpd_delay_reject;
#define REJECT_UNAUTH_PIPE "reject_unauth_pipelining" #define REJECT_UNAUTH_PIPE "reject_unauth_pipelining"
#define PERMIT_ADDR_MAP "permit_address_map"
/* /*
* Other. * Other.
*/ */

View File

@ -15,7 +15,7 @@
* Version of this program. * Version of this program.
*/ */
#define VAR_MAIL_VERSION "mail_version" #define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "Postfix-19990906" #define DEF_MAIL_VERSION "Snapshot-19990909"
extern char *var_mail_version; extern char *var_mail_version;
/* LICENSE /* LICENSE

View File

@ -80,6 +80,9 @@
*/ */
extern CLNT_STREAM *rewrite_clnt_stream; extern CLNT_STREAM *rewrite_clnt_stream;
static VSTRING *last_addr;
static RESOLVE_REPLY last_reply;
/* resolve_clnt_init - initialize reply */ /* resolve_clnt_init - initialize reply */
void resolve_clnt_init(RESOLVE_REPLY *reply) void resolve_clnt_init(RESOLVE_REPLY *reply)
@ -96,6 +99,14 @@ void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
char *myname = "resolve_clnt_query"; char *myname = "resolve_clnt_query";
VSTREAM *stream; VSTREAM *stream;
/*
* One-entry cache.
*/
if (last_addr == 0) {
last_addr = vstring_alloc(100);
resolve_clnt_init(&last_reply);
}
/* /*
* Sanity check. The result must not clobber the input because we may * Sanity check. The result must not clobber the input because we may
* have to retransmit the request. * have to retransmit the request.
@ -105,6 +116,20 @@ void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
if (addr == STR(reply->recipient)) if (addr == STR(reply->recipient))
msg_panic("%s: result clobbers input", myname); msg_panic("%s: result clobbers input", myname);
/*
* Peek at the cache.
*/
if (strcmp(addr, STR(last_addr)) == 0) {
vstring_strcpy(reply->transport, STR(last_reply.transport));
vstring_strcpy(reply->nexthop, STR(last_reply.nexthop));
vstring_strcpy(reply->recipient, STR(last_reply.recipient));
if (msg_verbose)
msg_info("%s: cached: `%s' -> t=`%s' h=`%s' r=`%s'",
myname, addr, STR(reply->transport),
STR(reply->nexthop), STR(reply->recipient));
return;
}
/* /*
* Keep trying until we get a complete response. The resolve service is * Keep trying until we get a complete response. The resolve service is
* CPU bound; making the client asynchronous would just complicate the * CPU bound; making the client asynchronous would just complicate the
@ -139,6 +164,14 @@ void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
sleep(10); /* XXX make configurable */ sleep(10); /* XXX make configurable */
clnt_stream_recover(rewrite_clnt_stream); clnt_stream_recover(rewrite_clnt_stream);
} }
/*
* Update the cache.
*/
vstring_strcpy(last_addr, addr);
vstring_strcpy(last_reply.transport, STR(reply->transport));
vstring_strcpy(last_reply.nexthop, STR(reply->nexthop));
vstring_strcpy(last_reply.recipient, STR(reply->recipient));
} }
/* resolve_clnt_free - destroy reply */ /* resolve_clnt_free - destroy reply */

View File

@ -71,6 +71,9 @@
*/ */
CLNT_STREAM *rewrite_clnt_stream = 0; CLNT_STREAM *rewrite_clnt_stream = 0;
VSTRING *last_addr;
VSTRING *last_result;
/* rewrite_clnt - rewrite address to (transport, next hop, recipient) */ /* rewrite_clnt - rewrite address to (transport, next hop, recipient) */
VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result) VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
@ -78,6 +81,14 @@ VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
char *myname = "rewrite_clnt"; char *myname = "rewrite_clnt";
VSTREAM *stream; VSTREAM *stream;
/*
* One-entry cache.
*/
if (last_addr == 0) {
last_addr = vstring_alloc(100);
last_result = vstring_alloc(100);
}
/* /*
* Sanity check. An address must be in externalized form. The result must * Sanity check. An address must be in externalized form. The result must
* not clobber the input, because we may have to retransmit the query. * not clobber the input, because we may have to retransmit the query.
@ -89,6 +100,17 @@ VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
if (addr == STR(result)) if (addr == STR(result))
msg_panic("rewrite_clnt: result clobbers input"); msg_panic("rewrite_clnt: result clobbers input");
/*
* Peek at the cache.
*/
if (strcmp(addr, STR(last_addr)) == 0) {
vstring_strcpy(result, STR(last_result));
if (msg_verbose)
msg_info("rewrite_clnt: cached: %s: %s -> %s",
rule, addr, vstring_str(result));
return (result);
}
/* /*
* Keep trying until we get a complete response. The rewrite service is * Keep trying until we get a complete response. The rewrite service is
* CPU bound and making the client asynchronous would just complicate the * CPU bound and making the client asynchronous would just complicate the
@ -111,16 +133,19 @@ VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
if (msg_verbose) if (msg_verbose)
msg_info("rewrite_clnt: %s: %s -> %s", msg_info("rewrite_clnt: %s: %s -> %s",
rule, addr, vstring_str(result)); rule, addr, vstring_str(result));
#if 0 break;
if (addr[0] != 0 && STR(result)[0] == 0)
msg_warn("%s: null result for: <%s>", myname, addr);
else
#endif
return (result);
} }
sleep(10); /* XXX make configurable */ sleep(10); /* XXX make configurable */
clnt_stream_recover(rewrite_clnt_stream); clnt_stream_recover(rewrite_clnt_stream);
} }
/*
* Update the cache.
*/
vstring_strcpy(last_addr, addr);
vstring_strcpy(last_result, STR(result));
return (result);
} }
/* rewrite_clnt_internal - rewrite from/to internal form */ /* rewrite_clnt_internal - rewrite from/to internal form */

View File

@ -203,46 +203,52 @@ SMTPD(8) SMTPD(8)
SMTPD(8) SMTPD(8) SMTPD(8) SMTPD(8)
<b>restriction</b><i>_</i><b>classes</b>
Declares the name of zero or more parameters that
contain a list of UCE restrictions. The names of
these parameters can then be used instead of the
restriction lists that they represent.
<b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b> <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b>
List of DNS domains that publish the addresses of List of DNS domains that publish the addresses of
blacklisted hosts. blacklisted hosts.
<b>relay</b><i>_</i><b>domains</b> <b>relay</b><i>_</i><b>domains</b>
Restrict what domains or networks this mail system Restrict what domains or networks this mail system
will relay mail from or to. will relay mail from or to.
<b>UCE</b> <b>control</b> <b>responses</b> <b>UCE</b> <b>control</b> <b>responses</b>
<b>access</b><i>_</i><b>map</b><i>_</i><b>reject</b><i>_</i><b>code</b> <b>access</b><i>_</i><b>map</b><i>_</i><b>reject</b><i>_</i><b>code</b>
Server response when a client violates an access Server response when a client violates an access
database restriction. database restriction.
<b>invalid</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b> <b>invalid</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b>
Server response when a client violates the Server response when a client violates the
<b>reject</b><i>_</i><b>invalid</b><i>_</i><b>hostname</b> restriction. <b>reject</b><i>_</i><b>invalid</b><i>_</i><b>hostname</b> restriction.
<b>maps</b><i>_</i><b>rbl</b><i>_</i><b>reject</b><i>_</i><b>code</b> <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>reject</b><i>_</i><b>code</b>
Server response when a client violates the Server response when a client violates the
<b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b> restriction. <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b> restriction.
<b>reject</b><i>_</i><b>code</b> <b>reject</b><i>_</i><b>code</b>
Response code when the client matches a <b>reject</b> Response code when the client matches a <b>reject</b>
restriction. restriction.
<b>relay</b><i>_</i><b>domains</b><i>_</i><b>reject</b><i>_</i><b>code</b> <b>relay</b><i>_</i><b>domains</b><i>_</i><b>reject</b><i>_</i><b>code</b>
Server response when a client attempts to violate Server response when a client attempts to violate
the mail relay policy. the mail relay policy.
<b>unknown</b><i>_</i><b>address</b><i>_</i><b>reject</b><i>_</i><b>code</b> <b>unknown</b><i>_</i><b>address</b><i>_</i><b>reject</b><i>_</i><b>code</b>
Server response when a client violates the Server response when a client violates the
<b>reject</b><i>_</i><b>unknown</b><i>_</i><b>address</b> restriction. <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>address</b> restriction.
<b>unknown</b><i>_</i><b>client</b><i>_</i><b>reject</b><i>_</i><b>code</b> <b>unknown</b><i>_</i><b>client</b><i>_</i><b>reject</b><i>_</i><b>code</b>
Server response when a client without address to Server response when a client without address to
name mapping violates the <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>clients</b> name mapping violates the <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>clients</b>
restriction. restriction.
<b>unknown</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b> <b>unknown</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b>
Server response when a client violates the Server response when a client violates the
<b>reject</b><i>_</i><b>unknown</b><i>_</i><b>hostname</b> restriction. <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>hostname</b> restriction.
<b>SEE</b> <b>ALSO</b> <b>SEE</b> <b>ALSO</b>
@ -250,13 +256,7 @@ SMTPD(8) SMTPD(8)
<a href="master.8.html">master(8)</a> process manager <a href="master.8.html">master(8)</a> process manager
syslogd(8) system logging syslogd(8) system logging
<b>LICENSE</b>
The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
Wietse Venema
IBM T.J. Watson Research
@ -269,6 +269,13 @@ SMTPD(8) SMTPD(8)
SMTPD(8) SMTPD(8) SMTPD(8) SMTPD(8)
<b>LICENSE</b>
The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
Wietse Venema
IBM T.J. Watson Research
P.O. Box 704 P.O. Box 704
Yorktown Heights, NY 10598, USA Yorktown Heights, NY 10598, USA
@ -311,13 +318,6 @@ SMTPD(8) SMTPD(8)

View File

@ -191,9 +191,10 @@ href="access.5.html">access database</a> for the client name, parent
domains, client address, or networks obtained by stripping least domains, client address, or networks obtained by stripping least
significant octets. Reject the request if the result is <b>REJECT</b> significant octets. Reject the request if the result is <b>REJECT</b>
or "[<b>45</b>]<i>XX text</i>". Permit the request if the result or "[<b>45</b>]<i>XX text</i>". Permit the request if the result
is anything else. The <b>access_map_reject_code</b> parameter is <b>OK</b> or <b>RELAY</b>. Otherwise, treat the result as another
specifies the response code for <b>REJECT</b> results (default: list of UCE restrictions. The <b>access_map_reject_code</b>
<b>554</b>). parameter specifies the response code for <b>REJECT</b> results
(default: <b>554</b>).
<p> <p>
@ -338,7 +339,8 @@ response code to rejected requests (default: <b>504</b>).
href="access.5.html">access database</a> for the <b>HELO</b> hostname href="access.5.html">access database</a> for the <b>HELO</b> hostname
or parent domains in the specified table. Reject the request if or parent domains in the specified table. Reject the request if
the result is <b>REJECT</b> or "[<b>45</b>]<i>XX text</i>". Permit the result is <b>REJECT</b> or "[<b>45</b>]<i>XX text</i>". Permit
the request when the result is anything else. The the request when the result is <b>OK</b> or <b>RELAY</b>. Otherwise,
treat the result as another list of UCE restrictions. The
<b>access_map_reject_code </b> parameter specifies the response <b>access_map_reject_code </b> parameter specifies the response
code for <b>REJECT</b> results (default: <b>554</b>). code for <b>REJECT</b> results (default: <b>554</b>).
@ -429,9 +431,10 @@ is always <b>450</b> in case of a temporary DNS error.
href="access.5.html">access database</a> for the sender mail address, href="access.5.html">access database</a> for the sender mail address,
parent domain, or <i>localpart</i>@. Reject the request if the parent domain, or <i>localpart</i>@. Reject the request if the
result is <b>REJECT</b> or "[<b>45</b>]<i>XX text</i>". Permit the result is <b>REJECT</b> or "[<b>45</b>]<i>XX text</i>". Permit the
request if the result is anything else. The <b>access_map_reject_code request if the result is <b>OK</b> or <b>RELAY</b>. Otherwise,
</b> parameter specifies the result code for rejected requests treat the result as another list of UCE restrictions. The
(default: <b>554</b>). <b>access_map_reject_code </b> parameter specifies the result code
for rejected requests (default: <b>554</b>).
<p> <p>
@ -568,9 +571,10 @@ $inet_interfaces</a>.
href="access.5.html">access database</a> for the resolved destination href="access.5.html">access database</a> for the resolved destination
address, parent domain, or <i>localpart</i>@. Reject the request address, parent domain, or <i>localpart</i>@. Reject the request
if the result is <b>REJECT</b> or "[<b>45</b>]<i>XX text</i>". if the result is <b>REJECT</b> or "[<b>45</b>]<i>XX text</i>".
Permit the request if the result is anything else. The Permit the request if the result is <b>OK</b> or <b>RELAY</b>.
<b>access_map_reject_code </b> parameter specifies the result code Otherwise, treat the result as another list of UCE restrictions.
for rejected requests (default: <b>554</b>). The <b>access_map_reject_code </b> parameter specifies the result
code for rejected requests (default: <b>554</b>).
<p> <p>
@ -593,6 +597,16 @@ response code to rejected requests (default: <b>504</b>).
<p> <p>
<dt> <b>permit_address_map</b> <i>maptype</i>:<i>mapname</i> <dd>
Permit the request when the recipient address matches the named
table. Table lookup is done as with the <a
href="virtual.5.html">virtual</a> and <a
href="canonical.5.html">canonical</a> tables. This also produces
useful results with the <a href="aliases.5.html">aliases</a> and
<b>unix:passwd.byname</b> maps.
<p>
<dt> <b><a href="#reject_unknown_sender_domain">reject_unknown_sender_domain</a></b> <dt> <b><a href="#reject_unknown_sender_domain">reject_unknown_sender_domain</a></b>
<dt> <b><a href="#reject_non_fqdn_sender">reject_non_fqdn_sender</a></b> <dt> <b><a href="#reject_non_fqdn_sender">reject_non_fqdn_sender</a></b>
@ -691,9 +705,10 @@ address.
href="access.5.html">access database</a> for the domain specified href="access.5.html">access database</a> for the domain specified
in the ETRN command, or its parent domains. Reject the request if in the ETRN command, or its parent domains. Reject the request if
the result is <b>REJECT</b> or "[<b>45</b>]<i>XX text</i>". Permit the result is <b>REJECT</b> or "[<b>45</b>]<i>XX text</i>". Permit
the request if the result is anything else. The <b>access_map_reject_code the request if the result is <b>OK</b> or <b>RELAY</b>. Otherwise,
</b> parameter specifies the result code for rejected requests treat the result as another list of UCE restrictions. The
(default: <b>554</b>). <b>access_map_reject_code </b> parameter specifies the result code
for rejected requests (default: <b>554</b>).
<p> <p>

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -147,6 +147,10 @@ Restrict what recipient addresses are allowed in \fBRCPT TO\fR commands.
.IP \fBsmtpd_etrn_restrictions\fR .IP \fBsmtpd_etrn_restrictions\fR
Restrict what domain names can be used in \fBETRN\fR commands, Restrict what domain names can be used in \fBETRN\fR commands,
and what clients may issue \fBETRN\fR commands. and what clients may issue \fBETRN\fR commands.
.IP \fBrestriction_classes\fR
Declares the name of zero or more parameters that contain a
list of UCE restrictions. The names of these parameters can
then be used instead of the restriction lists that they represent.
.IP \fBmaps_rbl_domains\fR .IP \fBmaps_rbl_domains\fR
List of DNS domains that publish the addresses of blacklisted List of DNS domains that publish the addresses of blacklisted
hosts. hosts.

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -86,7 +86,6 @@
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <sysexits.h>
/* Utility library. */ /* Utility library. */
@ -102,6 +101,7 @@
#include <dot_lockfile.h> #include <dot_lockfile.h>
#include <deliver_flock.h> #include <deliver_flock.h>
#include <mail_conf.h> #include <mail_conf.h>
#include <sys_exits.h>
/* Application-specific. */ /* Application-specific. */

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -131,6 +131,10 @@
/* .IP \fBsmtpd_etrn_restrictions\fR /* .IP \fBsmtpd_etrn_restrictions\fR
/* Restrict what domain names can be used in \fBETRN\fR commands, /* Restrict what domain names can be used in \fBETRN\fR commands,
/* and what clients may issue \fBETRN\fR commands. /* and what clients may issue \fBETRN\fR commands.
/* .IP \fBrestriction_classes\fR
/* Declares the name of zero or more parameters that contain a
/* list of UCE restrictions. The names of these parameters can
/* then be used instead of the restriction lists that they represent.
/* .IP \fBmaps_rbl_domains\fR /* .IP \fBmaps_rbl_domains\fR
/* List of DNS domains that publish the addresses of blacklisted /* List of DNS domains that publish the addresses of blacklisted
/* hosts. /* hosts.
@ -278,6 +282,7 @@ int var_non_fqdn_code;
char *var_always_bcc; char *var_always_bcc;
char *var_error_rcpt; char *var_error_rcpt;
int var_smtpd_delay_reject; int var_smtpd_delay_reject;
char *var_rest_classes;
/* /*
* Global state, for stand-alone mode queue file cleanup. When this is * Global state, for stand-alone mode queue file cleanup. When this is
@ -1178,6 +1183,7 @@ int main(int argc, char **argv)
VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains, 0, 0, VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains, 0, 0,
VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0, VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0,
VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0, VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes, 0, 0,
0, 0,
}; };

View File

@ -47,6 +47,7 @@ typedef struct SMTPD_STATE {
char *reason; char *reason;
char *sender; char *sender;
char *recipient; char *recipient;
char *etrn_name;
char *protocol; char *protocol;
char *where; char *where;
} SMTPD_STATE; } SMTPD_STATE;

View File

@ -135,6 +135,13 @@
/* Allow the request when the local mail system is mail exchanger /* Allow the request when the local mail system is mail exchanger
/* for the recipient domain (this includes the case where the local /* for the recipient domain (this includes the case where the local
/* system is the final destination). /* system is the final destination).
/* .IP permit_address_map maptype:mapname
/* Permit the request when the recipient address matches the named
/* table. Lookups are done in the same way as with virtual and
/* canonical maps.
/* .IP restriction_classes
/* Defines a list of parameter names, each parameter being a list
/* of restrictions that can be used anywhere a restriction is legal.
/* .PP /* .PP
/* smtpd_check_client() validates the client host name or address. /* smtpd_check_client() validates the client host name or address.
/* Relevant configuration parameters: /* Relevant configuration parameters:
@ -246,6 +253,7 @@
#include <argv.h> #include <argv.h>
#include <mymalloc.h> #include <mymalloc.h>
#include <dict.h> #include <dict.h>
#include <htable.h>
/* DNS library. */ /* DNS library. */
@ -261,6 +269,9 @@
#include <mail_error.h> #include <mail_error.h>
#include <resolve_local.h> #include <resolve_local.h>
#include <own_inet_addr.h> #include <own_inet_addr.h>
#include <mail_conf.h>
#include <maps.h>
#include <mail_addr_find.h>
/* Application-specific. */ /* Application-specific. */
@ -302,6 +313,15 @@ static ARGV *mail_restrctions;
static ARGV *rcpt_restrctions; static ARGV *rcpt_restrctions;
static ARGV *etrn_restrctions; static ARGV *etrn_restrctions;
static HTABLE *smtpd_rest_classes;
static HTABLE *smtpd_addr_maps;
/*
* The routine that recursively applies restrictions.
*/
static int generic_checks(SMTPD_STATE *, ARGV *, char *, char *, char *);
/* /*
* Reject context. * Reject context.
*/ */
@ -318,7 +338,7 @@ static ARGV *etrn_restrctions;
/* smtpd_check_parse - pre-parse restrictions */ /* smtpd_check_parse - pre-parse restrictions */
static ARGV *smtpd_check_parse(char *checks) static ARGV *smtpd_check_parse(const char *checks)
{ {
char *saved_checks = mystrdup(checks); char *saved_checks = mystrdup(checks);
ARGV *argv = argv_alloc(1); ARGV *argv = argv_alloc(1);
@ -348,6 +368,10 @@ static ARGV *smtpd_check_parse(char *checks)
void smtpd_check_init(void) void smtpd_check_init(void)
{ {
char *saved_classes;
const char *name;
const char *value;
char *cp;
/* /*
* Pre-open access control lists before going to jail. * Pre-open access control lists before going to jail.
@ -372,6 +396,35 @@ void smtpd_check_init(void)
mail_restrctions = smtpd_check_parse(var_mail_checks); mail_restrctions = smtpd_check_parse(var_mail_checks);
rcpt_restrctions = smtpd_check_parse(var_rcpt_checks); rcpt_restrctions = smtpd_check_parse(var_rcpt_checks);
etrn_restrctions = smtpd_check_parse(var_etrn_checks); etrn_restrctions = smtpd_check_parse(var_etrn_checks);
/*
* Parse the pre-defined restriction classes.
*/
smtpd_rest_classes = htable_create(1);
if (*var_rest_classes) {
cp = saved_classes = mystrdup(var_rest_classes);
while ((name = mystrtok(&cp, " \t\r\n,")) != 0) {
if ((value = mail_conf_lookup_eval(name)) == 0 || *value == 0)
msg_fatal("restriction class `%s' needs a definition", name);
htable_enter(smtpd_rest_classes, name,
(char *) smtpd_check_parse(value));
}
myfree(saved_classes);
}
/*
* This is the place to specify definitions for complex restrictions
* such as check_relay_domains in terms of more elementary restrictions.
*/
#if 0
htable_enter("check_relay_domains",
smtpd_check_parse("permit_mydomain reject_unauth_destination"));
#endif
/*
* Other one-off initializations.
*/
smtpd_addr_maps = htable_create(1);
} }
/* smtpd_check_reject - do the boring things that must be done */ /* smtpd_check_reject - do the boring things that must be done */
@ -946,14 +999,61 @@ static int reject_unknown_address(SMTPD_STATE *state, char *addr,
return (reject_unknown_mailhost(state, domain, reply_name, reply_class)); return (reject_unknown_mailhost(state, domain, reply_name, reply_class));
} }
/* permit_addr_map - permit if address matches rewriting table */
static int permit_addr_map(SMTPD_STATE *state, char *table,
char *reply_name, char *reply_class)
{
char *myname = "permit_addr_map";
char *domain;
MAPS *map;
if (msg_verbose)
msg_info("%s: %s %s", myname, table, reply_name);
/*
* Resolve the address.
*/
canon_addr_internal(query, reply_name);
resolve_clnt_query(STR(query), &reply);
/*
* Skip non-DNS forms. Skip non-local numerical forms.
*/
if ((domain = strrchr(STR(reply.recipient), '@')) == 0)
return (SMTPD_CHECK_DUNNO);
domain += 1;
if (domain[0] == '#' || domain[0] == '[')
if (STR(reply.nexthop)[0] != 0)
return (SMTPD_CHECK_DUNNO);
/*
* Look up the name in the specified table, using the usual magic of
* canonical and virtual maps.
*/
if ((map = (MAPS *) htable_find(smtpd_addr_maps, table)) == 0) {
map = maps_create("addr_map", table, DICT_FLAG_LOCK);
htable_enter(smtpd_addr_maps, table, (char *) map);
}
#define TOSS_THE_EXTENSION ((char **) 0)
if (mail_addr_find(map, STR(reply.recipient), TOSS_THE_EXTENSION) != 0)
return (SMTPD_CHECK_OK);
return (SMTPD_CHECK_DUNNO);
}
/* check_table_result - translate table lookup result into pass/reject */ /* check_table_result - translate table lookup result into pass/reject */
static int check_table_result(SMTPD_STATE *state, char *table, static int check_table_result(SMTPD_STATE *state, char *table,
const char *value, const char *datum, const char *value, const char *datum,
char *reply_name, char *reply_class) char *reply_name, char *reply_class,
char *def_acl)
{ {
char *myname = "check_table_result"; char *myname = "check_table_result";
int code; int code;
ARGV *restrictions;
int status;
if (msg_verbose) if (msg_verbose)
msg_info("%s: %s %s %s", myname, table, value, datum); msg_info("%s: %s %s %s", myname, table, value, datum);
@ -986,15 +1086,25 @@ static int check_table_result(SMTPD_STATE *state, char *table,
} }
/* /*
* OK or RELAY or whatever means YES. * OK or RELAY means YES.
*/ */
return (SMTPD_CHECK_OK); if (strcasecmp(value, "OK") == 0 || strcasecmp(value, "RELAY") == 0)
return (SMTPD_CHECK_OK);
/*
* XXX Don't use passwd files or address rewriting maps as access tables.
*/
restrictions = argv_split(value, " \t\r\n,");
status = generic_checks(state, restrictions, reply_name,
reply_class, def_acl);
argv_free(restrictions);
return (status);
} }
/* check_access - table lookup without substring magic */ /* check_access - table lookup without substring magic */
static int check_access(SMTPD_STATE *state, char *table, char *name, int flags, static int check_access(SMTPD_STATE *state, char *table, char *name, int flags,
char *reply_name, char *reply_class) char *reply_name, char *reply_class, char *def_acl)
{ {
char *myname = "check_access"; char *myname = "check_access";
char *low_name = lowercase(mystrdup(name)); char *low_name = lowercase(mystrdup(name));
@ -1013,7 +1123,8 @@ static int check_access(SMTPD_STATE *state, char *table, char *name, int flags,
if (flags == 0 || (flags & dict->flags) != 0) { if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, low_name)) != 0) if ((value = dict_get(dict, low_name)) != 0)
CHK_ACCESS_RETURN(check_table_result(state, table, value, name, CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
reply_name, reply_class)); reply_name, reply_class,
def_acl));
if (dict_errno != 0) if (dict_errno != 0)
msg_fatal("%s: table lookup problem", table); msg_fatal("%s: table lookup problem", table);
} }
@ -1024,7 +1135,8 @@ static int check_access(SMTPD_STATE *state, char *table, char *name, int flags,
static int check_domain_access(SMTPD_STATE *state, char *table, static int check_domain_access(SMTPD_STATE *state, char *table,
char *domain, int flags, char *domain, int flags,
char *reply_name, char *reply_class) char *reply_name, char *reply_class,
char *def_acl)
{ {
char *myname = "check_domain_access"; char *myname = "check_domain_access";
char *low_domain = lowercase(mystrdup(domain)); char *low_domain = lowercase(mystrdup(domain));
@ -1047,7 +1159,8 @@ static int check_domain_access(SMTPD_STATE *state, char *table,
if (flags == 0 || (flags & dict->flags) != 0) { if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, name)) != 0) if ((value = dict_get(dict, name)) != 0)
CHK_DOMAIN_RETURN(check_table_result(state, table, value, CHK_DOMAIN_RETURN(check_table_result(state, table, value,
domain, reply_name, reply_class)); domain, reply_name, reply_class,
def_acl));
if (dict_errno != 0) if (dict_errno != 0)
msg_fatal("%s: table lookup problem", table); msg_fatal("%s: table lookup problem", table);
} }
@ -1060,7 +1173,8 @@ static int check_domain_access(SMTPD_STATE *state, char *table,
static int check_addr_access(SMTPD_STATE *state, char *table, static int check_addr_access(SMTPD_STATE *state, char *table,
char *address, int flags, char *address, int flags,
char *reply_name, char *reply_class) char *reply_name, char *reply_class,
char *def_acl)
{ {
char *myname = "check_addr_access"; char *myname = "check_addr_access";
char *addr; char *addr;
@ -1081,7 +1195,8 @@ static int check_addr_access(SMTPD_STATE *state, char *table,
if (flags == 0 || (flags & dict->flags) != 0) { if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, addr)) != 0) if ((value = dict_get(dict, addr)) != 0)
return (check_table_result(state, table, value, address, return (check_table_result(state, table, value, address,
reply_name, reply_class)); reply_name, reply_class,
def_acl));
if (dict_errno != 0) if (dict_errno != 0)
msg_fatal("%s: table lookup problem", table); msg_fatal("%s: table lookup problem", table);
} }
@ -1095,7 +1210,8 @@ static int check_addr_access(SMTPD_STATE *state, char *table,
static int check_namadr_access(SMTPD_STATE *state, char *table, static int check_namadr_access(SMTPD_STATE *state, char *table,
char *name, char *addr, int flags, char *name, char *addr, int flags,
char *reply_name, char *reply_class) char *reply_name, char *reply_class,
char *def_acl)
{ {
char *myname = "check_namadr_access"; char *myname = "check_namadr_access";
int status; int status;
@ -1108,14 +1224,16 @@ static int check_namadr_access(SMTPD_STATE *state, char *table,
* wildcard may pre-empt a more specific address table entry. * wildcard may pre-empt a more specific address table entry.
*/ */
if ((status = check_domain_access(state, table, name, flags, if ((status = check_domain_access(state, table, name, flags,
reply_name, reply_class)) != 0) reply_name, reply_class,
def_acl)) != 0)
return (status); return (status);
/* /*
* Look up the network address, or parent networks thereof. * Look up the network address, or parent networks thereof.
*/ */
if ((status = check_addr_access(state, table, addr, flags, if ((status = check_addr_access(state, table, addr, flags,
reply_name, reply_class)) != 0) reply_name, reply_class,
def_acl)) != 0)
return (status); return (status);
/* /*
@ -1127,7 +1245,8 @@ static int check_namadr_access(SMTPD_STATE *state, char *table,
/* check_mail_access - OK/FAIL based on mail address lookup */ /* check_mail_access - OK/FAIL based on mail address lookup */
static int check_mail_access(SMTPD_STATE *state, char *table, char *addr, static int check_mail_access(SMTPD_STATE *state, char *table, char *addr,
char *reply_name, char *reply_class) char *reply_name, char *reply_class,
char *def_acl)
{ {
char *myname = "check_mail_access"; char *myname = "check_mail_access";
char *ratsign; char *ratsign;
@ -1156,14 +1275,14 @@ static int check_mail_access(SMTPD_STATE *state, char *table, char *addr,
* Look up the full address. * Look up the full address.
*/ */
if ((status = check_access(state, table, STR(reply.recipient), FULL, if ((status = check_access(state, table, STR(reply.recipient), FULL,
reply_name, reply_class)) != 0) reply_name, reply_class, def_acl)) != 0)
return (status); return (status);
/* /*
* Look up the domain name, or parent domains thereof. * Look up the domain name, or parent domains thereof.
*/ */
if ((status = check_domain_access(state, table, ratsign + 1, PARTIAL, if ((status = check_domain_access(state, table, ratsign + 1, PARTIAL,
reply_name, reply_class)) != 0) reply_name, reply_class, def_acl)) != 0)
return (status); return (status);
/* /*
@ -1172,7 +1291,7 @@ static int check_mail_access(SMTPD_STATE *state, char *table, char *addr,
local_at = mystrndup(STR(reply.recipient), local_at = mystrndup(STR(reply.recipient),
ratsign - STR(reply.recipient) + 1); ratsign - STR(reply.recipient) + 1);
status = check_access(state, table, local_at, PARTIAL, status = check_access(state, table, local_at, PARTIAL,
reply_name, reply_class); reply_name, reply_class, def_acl);
myfree(local_at); myfree(local_at);
if (status != 0) if (status != 0)
return (status); return (status);
@ -1267,170 +1386,226 @@ static int is_map_command(char *name, char *command, char ***argp)
/* generic_checks - generic restrictions */ /* generic_checks - generic restrictions */
static int generic_checks(SMTPD_STATE *state, char *name, static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
char ***cpp, int *status, char *reply_name, char *reply_class, char *def_acl)
char *reply_name, char *reply_class)
{ {
char *myname = "generic_checks";
char **cpp;
char *name;
int status;
ARGV *list;
/* status = setjmp(smtpd_check_buf);
* Generic restrictions. if (status != 0)
*/ return (0);
if (strcasecmp(name, PERMIT_ALL) == 0) {
*status = SMTPD_CHECK_OK; if (msg_verbose)
if ((*cpp)[1] != 0) msg_info("%s: START", myname);
msg_warn("restriction `%s' after `%s' is ignored",
(*cpp)[1], PERMIT_ALL); for (cpp = restrictions->argv; (name = *cpp) != 0; cpp++) {
return (1);
} if (msg_verbose)
if (strcasecmp(name, REJECT_ALL) == 0) { msg_info("%s: name=%s", myname, name);
*status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: %s rejected: Access denied", /*
* Spoof the is_map_command() routine, so that we do not have to make
* special cases for the implicit short-hand access map notation.
*/
if (strchr(name, ':') != 0) {
name = def_acl;
cpp -= 1;
}
/*
* Generic restrictions.
*/
if (strcasecmp(name, PERMIT_ALL) == 0) {
status = SMTPD_CHECK_OK;
if (cpp[1] != 0)
msg_warn("restriction `%s' after `%s' is ignored",
cpp[1], PERMIT_ALL);
} else if (strcasecmp(name, REJECT_ALL) == 0) {
status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: %s rejected: Access denied",
var_reject_code, reply_name, reply_class); var_reject_code, reply_name, reply_class);
if ((*cpp)[1] != 0) if (cpp[1] != 0)
msg_warn("restriction `%s' after `%s' is ignored", msg_warn("restriction `%s' after `%s' is ignored",
(*cpp)[1], REJECT_ALL); cpp[1], REJECT_ALL);
return (1); } else if (strcasecmp(name, REJECT_UNAUTH_PIPE) == 0) {
} status = reject_unauth_pipelining(state);
if (strcasecmp(name, REJECT_UNAUTH_PIPE) == 0) {
*status = reject_unauth_pipelining(state);
return (1);
}
/*
* Client name/address restrictions.
*/
if (strcasecmp(name, REJECT_UNKNOWN_CLIENT) == 0) {
*status = reject_unknown_client(state);
return (1);
}
if (strcasecmp(name, PERMIT_MYNETWORKS) == 0) {
*status = permit_mynetworks(state);
return (1);
}
if (is_map_command(name, CHECK_CLIENT_ACL, cpp)) {
*status = check_namadr_access(state, **cpp, state->name, state->addr,
FULL, state->namaddr, SMTPD_NAME_CLIENT);
return (1);
}
if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
*status = reject_maps_rbl(state);
return (1);
}
/*
* HELO/EHLO parameter restrictions.
*/
if (is_map_command(name, CHECK_HELO_ACL, cpp) && state->helo_name) {
if (state->helo_name)
*status = check_domain_access(state, **cpp, state->helo_name, FULL,
state->helo_name, SMTPD_NAME_HELO);
return (1);
}
if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) {
if (state->helo_name) {
if (*state->helo_name != '[')
*status = reject_invalid_hostname(state, state->helo_name,
state->helo_name, SMTPD_NAME_HELO);
else
*status = reject_invalid_hostaddr(state, state->helo_name,
state->helo_name, SMTPD_NAME_HELO);
} }
return (1);
} /*
if (strcasecmp(name, REJECT_UNKNOWN_HOSTNAME) == 0) { * Client name/address restrictions.
if (state->helo_name) { */
if (*state->helo_name != '[') else if (strcasecmp(name, REJECT_UNKNOWN_CLIENT) == 0) {
*status = reject_unknown_hostname(state, state->helo_name, status = reject_unknown_client(state);
state->helo_name, SMTPD_NAME_HELO); } else if (strcasecmp(name, PERMIT_MYNETWORKS) == 0) {
else status = permit_mynetworks(state);
*status = reject_invalid_hostaddr(state, state->helo_name, } else if (is_map_command(name, CHECK_CLIENT_ACL, &cpp)) {
state->helo_name, SMTPD_NAME_HELO); status = check_namadr_access(state, *cpp, state->name, state->addr,
FULL, state->namaddr,
SMTPD_NAME_CLIENT, def_acl);
} else if (strcasecmp(name, REJECT_MAPS_RBL) == 0) {
status = reject_maps_rbl(state);
} }
return (1);
} /*
if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) { * HELO/EHLO parameter restrictions.
if (state->helo_name) { */
if (state->helo_name[strspn(state->helo_name, "0123456789.")] == 0 else if (is_map_command(name, CHECK_HELO_ACL, &cpp)) {
&& (*status = reject_invalid_hostaddr(state, state->helo_name, if (state->helo_name)
status = check_domain_access(state, *cpp, state->helo_name,
FULL, state->helo_name,
SMTPD_NAME_HELO, def_acl);
} else if (strcasecmp(name, REJECT_INVALID_HOSTNAME) == 0) {
if (state->helo_name) {
if (*state->helo_name != '[')
status = reject_invalid_hostname(state, state->helo_name,
state->helo_name, SMTPD_NAME_HELO);
else
status = reject_invalid_hostaddr(state, state->helo_name,
state->helo_name, SMTPD_NAME_HELO);
}
} else if (strcasecmp(name, REJECT_UNKNOWN_HOSTNAME) == 0) {
if (state->helo_name) {
if (*state->helo_name != '[')
status = reject_unknown_hostname(state, state->helo_name,
state->helo_name, SMTPD_NAME_HELO);
else
status = reject_invalid_hostaddr(state, state->helo_name,
state->helo_name, SMTPD_NAME_HELO);
}
} else if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) {
if (state->helo_name) {
if (state->helo_name[strspn(state->helo_name, "0123456789.")] == 0
&& (status = reject_invalid_hostaddr(state, state->helo_name,
state->helo_name, SMTPD_NAME_HELO)) == 0) state->helo_name, SMTPD_NAME_HELO)) == 0)
*status = SMTPD_CHECK_OK; status = SMTPD_CHECK_OK;
} }
return (1); } else if (strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) {
} if (state->helo_name) {
if (strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) { if (*state->helo_name != '[')
if (state->helo_name) { status = reject_non_fqdn_hostname(state, state->helo_name,
if (*state->helo_name != '[')
*status = reject_non_fqdn_hostname(state, state->helo_name,
state->helo_name, SMTPD_NAME_HELO); state->helo_name, SMTPD_NAME_HELO);
else else
*status = reject_invalid_hostaddr(state, state->helo_name, status = reject_invalid_hostaddr(state, state->helo_name,
state->helo_name, SMTPD_NAME_HELO); state->helo_name, SMTPD_NAME_HELO);
}
} }
return (1);
}
/* /*
* Sender mail address restrictions. * Sender mail address restrictions.
*/ */
if (is_map_command(name, CHECK_SENDER_ACL, cpp) && state->sender) { else if (is_map_command(name, CHECK_SENDER_ACL, &cpp)) {
if (state->sender) if (state->sender)
*status = check_mail_access(state, **cpp, state->sender, status = check_mail_access(state, *cpp, state->sender,
state->sender, SMTPD_NAME_SENDER); state->sender,
return (1); SMTPD_NAME_SENDER, def_acl);
} } else if (strcasecmp(name, REJECT_UNKNOWN_ADDRESS) == 0) {
if (strcasecmp(name, REJECT_UNKNOWN_ADDRESS) == 0) { if (state->sender)
if (state->sender) status = reject_unknown_address(state, state->sender,
*status = reject_unknown_address(state, state->sender,
state->sender, SMTPD_NAME_SENDER); state->sender, SMTPD_NAME_SENDER);
return (1); } else if (strcasecmp(name, REJECT_UNKNOWN_SENDDOM) == 0) {
} if (state->sender)
if (strcasecmp(name, REJECT_UNKNOWN_SENDDOM) == 0) { status = reject_unknown_address(state, state->sender,
if (state->sender)
*status = reject_unknown_address(state, state->sender,
state->sender, SMTPD_NAME_SENDER); state->sender, SMTPD_NAME_SENDER);
return (1); } else if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) {
} if (state->sender && *state->sender)
if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) { status = reject_non_fqdn_address(state, state->sender,
if (*state->sender)
*status = reject_non_fqdn_address(state, state->sender,
state->sender, SMTPD_NAME_SENDER); state->sender, SMTPD_NAME_SENDER);
return (1); }
/*
* Recipient mail address restrictions.
*/
else if (is_map_command(name, CHECK_RECIP_ACL, &cpp)) {
if (state->recipient)
status = check_mail_access(state, *cpp, state->recipient,
state->recipient,
SMTPD_NAME_RECIPIENT, def_acl);
} else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) {
if (state->recipient)
status = permit_mx_backup(state, state->recipient);
} else if (strcasecmp(name, REJECT_UNAUTH_DEST) == 0) {
if (state->recipient)
status = reject_unauth_destination(state, state->recipient);
} else if (strcasecmp(name, CHECK_RELAY_DOMAINS) == 0) {
if (state->recipient)
status = check_relay_domains(state, state->recipient,
state->recipient, SMTPD_NAME_RECIPIENT);
if (cpp[1] != 0)
msg_warn("restriction `%s' after `%s' is ignored",
cpp[1], CHECK_RELAY_DOMAINS);
} else if (strcasecmp(name, REJECT_UNKNOWN_RCPTDOM) == 0) {
if (state->recipient)
status = reject_unknown_address(state, state->recipient,
state->recipient, SMTPD_NAME_RECIPIENT);
} else if (strcasecmp(name, REJECT_NON_FQDN_RCPT) == 0) {
if (state->recipient)
status = reject_non_fqdn_address(state, state->recipient,
state->recipient, SMTPD_NAME_RECIPIENT);
} else if (is_map_command(name, PERMIT_ADDR_MAP, &cpp)) {
if (state->recipient)
status = permit_addr_map(state, *cpp,
state->recipient, SMTPD_NAME_RECIPIENT);
}
/*
* ETRN domain name restrictions.
*/
else if (is_map_command(name, CHECK_ETRN_ACL, &cpp)) {
if (state->etrn_name)
status = check_domain_access(state, *cpp, state->etrn_name,
FULL, state->etrn_name,
SMTPD_NAME_ETRN, def_acl);
}
/*
* User-defined restriction class.
*/
else if ((list = (ARGV *) htable_find(smtpd_rest_classes, name)) != 0) {
status = generic_checks(state, list, reply_name,
reply_class, def_acl);
}
/*
* Error: undefined restriction name.
*/
else {
msg_warn("unknown smtpd restriction: \"%s\"", name);
break;
}
if (msg_verbose)
msg_info("%s: name=%s status=%d", myname, name, status);
if (status != 0)
break;
} }
return (0); if (msg_verbose && name == 0)
msg_info("%s: END", myname);
return (status);
} }
/* smtpd_check_client - validate client name or address */ /* smtpd_check_client - validate client name or address */
char *smtpd_check_client(SMTPD_STATE *state) char *smtpd_check_client(SMTPD_STATE *state)
{ {
char **cpp;
char *name;
int status; int status;
/* /*
* Initialize. * Initialize.
*/ */
if (state->name == 0 && state->addr == 0) if (state->name == 0 || state->addr == 0)
return (0);
status = setjmp(smtpd_check_buf);
if (status != 0)
return (0); return (0);
/* /*
* Apply restrictions in the order as specified. * Apply restrictions in the order as specified.
*/ */
for (cpp = client_restrctions->argv; (name = *cpp) != 0; cpp++) { status = generic_checks(state, client_restrctions, state->namaddr,
if (strchr(name, ':') != 0) { SMTPD_NAME_CLIENT, CHECK_CLIENT_ACL);
status = check_namadr_access(state, name, state->name, state->addr,
FULL, state->namaddr, SMTPD_NAME_CLIENT);
} else if (generic_checks(state, name, &cpp, &status,
state->namaddr, SMTPD_NAME_CLIENT) == 0) {
msg_warn("unknown %s check: \"%s\"", VAR_CLIENT_CHECKS, name);
break;
}
if (status != 0)
break;
}
return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0); return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
} }
@ -1438,90 +1613,84 @@ char *smtpd_check_client(SMTPD_STATE *state)
char *smtpd_check_helo(SMTPD_STATE *state, char *helohost) char *smtpd_check_helo(SMTPD_STATE *state, char *helohost)
{ {
char **cpp;
char *name;
int status; int status;
char *saved_helo = state->helo_name; char *saved_helo;
/* /*
* Initialize. * Initialize.
*/ */
if (helohost == 0) if (helohost == 0)
return (0); return (0);
status = setjmp(smtpd_check_buf);
if (status != 0)
return (0);
/* /*
* Apply restrictions in the order as specified. Minor kluge so that we * Minor kluge so that we can delegate work to the generic routine and so
* can delegate work to the generic routine. * that we can syslog the recipient with the reject messages.
*/ */
state->helo_name = mystrdup(helohost); #define SMTPD_CHECK_PUSH(backup, current, new) { \
for (cpp = helo_restrctions->argv; (name = *cpp) != 0; cpp++) { backup = current; \
if (strchr(name, ':') != 0) { current = mystrdup(new); \
status = check_domain_access(state, name, helohost, FULL,
helohost, SMTPD_NAME_HELO);
} else if (generic_checks(state, name, &cpp, &status,
helohost, SMTPD_NAME_HELO) == 0) {
msg_warn("unknown %s check: \"%s\"", VAR_HELO_CHECKS, name);
break;
}
if (status != 0)
break;
} }
myfree(state->helo_name);
state->helo_name = saved_helo; #define SMTPD_CHECK_POP(current, backup) { \
return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0); myfree(current); \
current = backup; \
}
SMTPD_CHECK_PUSH(saved_helo, state->helo_name, helohost);
#define SMTPD_CHECK_HELO_RETURN(x) { \
SMTPD_CHECK_POP(state->helo_name, saved_helo); \
return (x); \
}
/*
* Apply restrictions in the order as specified.
*/
status = generic_checks(state, helo_restrctions, state->helo_name,
SMTPD_NAME_HELO, CHECK_HELO_ACL);
SMTPD_CHECK_HELO_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
} }
/* smtpd_check_mail - validate sender address */ /* smtpd_check_mail - validate sender address, driver */
char *smtpd_check_mail(SMTPD_STATE *state, char *sender) char *smtpd_check_mail(SMTPD_STATE *state, char *sender)
{ {
char **cpp;
char *name;
int status; int status;
char *saved_sender = state->sender; char *saved_sender;
/* /*
* Initialize. * Initialize.
*/ */
if (sender == 0) if (sender == 0)
return (0); return (0);
status = setjmp(smtpd_check_buf);
if (status != 0)
return (0);
/* /*
* Apply restrictions in the order as specified. Minor kluge so that we * Minor kluge so that we can delegate work to the generic routine and so
* can delegate work to the generic routine. * that we can syslog the recipient with the reject messages.
*/ */
state->sender = mystrdup(sender); SMTPD_CHECK_PUSH(saved_sender, state->sender, sender);
for (cpp = mail_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) { #define SMTPD_CHECK_MAIL_RETURN(x) { \
status = check_mail_access(state, name, sender, SMTPD_CHECK_POP(state->sender, saved_sender); \
sender, SMTPD_NAME_SENDER); return (x); \
} else if (generic_checks(state, name, &cpp, &status,
sender, SMTPD_NAME_SENDER) == 0) {
msg_warn("unknown %s check: \"%s\"", VAR_MAIL_CHECKS, name);
return (0);
}
if (status != 0)
break;
} }
myfree(state->sender);
state->sender = saved_sender; /*
return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0); * Apply restrictions in the order as specified.
*/
status = generic_checks(state, mail_restrctions, sender,
SMTPD_NAME_SENDER, CHECK_SENDER_ACL);
SMTPD_CHECK_MAIL_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
} }
/* smtpd_check_rcpt - validate recipient address */ /* smtpd_check_rcpt - validate recipient address, driver */
char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient) char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
{ {
char **cpp;
char *name;
int status; int status;
char *saved_recipient = state->recipient; char *saved_recipient;
char *err; char *err;
/* /*
@ -1534,11 +1703,10 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
* Minor kluge so that we can delegate work to the generic routine and so * Minor kluge so that we can delegate work to the generic routine and so
* that we can syslog the recipient with the reject messages. * that we can syslog the recipient with the reject messages.
*/ */
state->recipient = mystrdup(recipient); SMTPD_CHECK_PUSH(saved_recipient, state->recipient, recipient);
#define SMTPD_CHECK_RCPT_RETURN(x) { \ #define SMTPD_CHECK_RCPT_RETURN(x) { \
myfree(state->recipient); \ SMTPD_CHECK_POP(state->recipient, saved_recipient); \
state->recipient = saved_recipient; \
return (x); \ return (x); \
} }
@ -1551,47 +1719,12 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
|| (err = smtpd_check_mail(state, state->sender)) != 0) || (err = smtpd_check_mail(state, state->sender)) != 0)
SMTPD_CHECK_RCPT_RETURN(err); SMTPD_CHECK_RCPT_RETURN(err);
/*
* More initialization.
*/
status = setjmp(smtpd_check_buf);
if (status != 0)
SMTPD_CHECK_RCPT_RETURN(0);
/* /*
* Apply restrictions in the order as specified. * Apply restrictions in the order as specified.
*/ */
for (cpp = rcpt_restrctions->argv; (name = *cpp) != 0; cpp++) { status = generic_checks(state, rcpt_restrctions,
if (strchr(name, ':') != 0) { recipient, SMTPD_NAME_RECIPIENT, CHECK_RECIP_ACL);
status = check_mail_access(state, name, recipient,
recipient, SMTPD_NAME_RECIPIENT);
} else if (is_map_command(name, CHECK_RECIP_ACL, &cpp)) {
status = check_mail_access(state, *cpp, recipient,
recipient, SMTPD_NAME_RECIPIENT);
} else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) {
status = permit_mx_backup(state, recipient);
} else if (strcasecmp(name, REJECT_UNAUTH_DEST) == 0) {
status = reject_unauth_destination(state, recipient);
} else if (strcasecmp(name, CHECK_RELAY_DOMAINS) == 0) {
status = check_relay_domains(state, recipient,
recipient, SMTPD_NAME_RECIPIENT);
if (cpp[1] != 0)
msg_warn("restriction `%s' after `%s' is ignored",
cpp[1], CHECK_RELAY_DOMAINS);
} else if (strcasecmp(name, REJECT_UNKNOWN_RCPTDOM) == 0) {
status = reject_unknown_address(state, recipient,
recipient, SMTPD_NAME_RECIPIENT);
} else if (strcasecmp(name, REJECT_NON_FQDN_RCPT) == 0) {
status = reject_non_fqdn_address(state, recipient,
recipient, SMTPD_NAME_RECIPIENT);
} else if (generic_checks(state, name, &cpp, &status,
recipient, SMTPD_NAME_RECIPIENT) == 0) {
msg_warn("unknown %s check: \"%s\"", VAR_RCPT_CHECKS, name);
break;
}
if (status != 0)
break;
}
SMTPD_CHECK_RCPT_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0); SMTPD_CHECK_RCPT_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
} }
@ -1599,47 +1732,42 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
char *smtpd_check_etrn(SMTPD_STATE *state, char *domain) char *smtpd_check_etrn(SMTPD_STATE *state, char *domain)
{ {
char **cpp;
char *name;
int status; int status;
char *saved_etrn_name;
char *err; char *err;
/*
* Initialize.
*/
if (domain == 0)
return (0);
/*
* Minor kluge so that we can delegate work to the generic routine and so
* that we can syslog the recipient with the reject messages.
*/
SMTPD_CHECK_PUSH(saved_etrn_name, state->etrn_name, domain);
#define SMTPD_CHECK_ETRN_RETURN(x) { \
SMTPD_CHECK_POP(state->etrn_name, saved_etrn_name); \
return (x); \
}
/* /*
* Apply delayed restrictions. * Apply delayed restrictions.
*/ */
if (var_smtpd_delay_reject) if (var_smtpd_delay_reject)
if ((err = smtpd_check_client(state)) != 0 if ((err = smtpd_check_client(state)) != 0
|| (err = smtpd_check_helo(state, state->helo_name)) != 0) || (err = smtpd_check_helo(state, state->helo_name)) != 0)
return (err); SMTPD_CHECK_ETRN_RETURN(err);
/*
* Initialize.
*/
if (domain == 0)
return (0);
status = setjmp(smtpd_check_buf);
if (status != 0)
return (0);
/* /*
* Apply restrictions in the order as specified. * Apply restrictions in the order as specified.
*/ */
for (cpp = etrn_restrctions->argv; (name = *cpp) != 0; cpp++) { status = generic_checks(state, etrn_restrctions, domain,
if (strchr(name, ':') != 0) { SMTPD_NAME_ETRN, CHECK_ETRN_ACL);
status = check_domain_access(state, name, domain, FULL,
domain, SMTPD_NAME_ETRN); SMTPD_CHECK_ETRN_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
} else if (is_map_command(name, CHECK_ETRN_ACL, &cpp)) {
status = check_domain_access(state, *cpp, domain, FULL,
domain, SMTPD_NAME_ETRN);
} else if (generic_checks(state, name, &cpp, &status,
domain, SMTPD_NAME_ETRN) == 0) {
msg_warn("unknown %s check: \"%s\"", VAR_RCPT_CHECKS, name);
break;
}
if (status != 0)
break;
}
return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
} }
/* smtpd_check_size - check optional SIZE parameter value */ /* smtpd_check_size - check optional SIZE parameter value */
@ -1661,6 +1789,7 @@ char *smtpd_check_size(SMTPD_STATE *state, off_t size)
return (STR(error_text)); return (STR(error_text));
} }
fsspace(".", &fsbuf); fsspace(".", &fsbuf);
if (msg_verbose) if (msg_verbose)
msg_info("%s: blocks %lu avail %lu min_free %lu size %lu", msg_info("%s: blocks %lu avail %lu min_free %lu size %lu",
myname, myname,
@ -1713,6 +1842,7 @@ char *var_notify_classes = "";
char *var_maps_rbl_domains; char *var_maps_rbl_domains;
char *var_mydest; char *var_mydest;
char *var_inet_interfaces; char *var_inet_interfaces;
char *var_rest_classes;
typedef struct { typedef struct {
char *name; char *name;
@ -1724,6 +1854,7 @@ static STRING_TABLE string_table[] = {
VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains, VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains,
VAR_MYDEST, DEF_MYDEST, &var_mydest, VAR_MYDEST, DEF_MYDEST, &var_mydest,
VAR_INET_INTERFACES, DEF_INET_INTERFACES, &var_inet_interfaces, VAR_INET_INTERFACES, DEF_INET_INTERFACES, &var_inet_interfaces,
VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes,
0, 0,
}; };
@ -1822,9 +1953,9 @@ static int int_update(char **argv)
typedef struct { typedef struct {
char *name; char *name;
ARGV **target; ARGV **target;
} REST_TABLE; } SMTPD_REST_TABLE;
static REST_TABLE rest_table[] = { static SMTPD_REST_TABLE smtpd_rest_table[] = {
"client_restrictions", &client_restrctions, "client_restrictions", &client_restrctions,
"helo_restrictions", &helo_restrctions, "helo_restrictions", &helo_restrctions,
"sender_restrictions", &mail_restrctions, "sender_restrictions", &mail_restrctions,
@ -1833,13 +1964,13 @@ static REST_TABLE rest_table[] = {
0, 0,
}; };
/* rest_update - update restriction */ /* smtpd_rest_update - update restriction */
static int rest_update(char **argv) static int smtpd_rest_update(char **argv)
{ {
REST_TABLE *rp; SMTPD_REST_TABLE *rp;
for (rp = rest_table; rp->name; rp++) { for (rp = smtpd_rest_table; rp->name; rp++) {
if (strcasecmp(rp->name, argv[0]) == 0) { if (strcasecmp(rp->name, argv[0]) == 0) {
argv_free(rp->target[0]); argv_free(rp->target[0]);
rp->target[0] = smtpd_check_parse(argv[1]); rp->target[0] = smtpd_check_parse(argv[1]);
@ -1980,7 +2111,7 @@ main(int argc, char **argv)
} }
if (int_update(args->argv) if (int_update(args->argv)
|| string_update(args->argv) || string_update(args->argv)
|| rest_update(args->argv)) { || smtpd_rest_update(args->argv)) {
resp = 0; resp = 0;
break; break;
} }

View File

@ -150,7 +150,6 @@ rcpt foo
# #
# Numerical HELO checks # Numerical HELO checks
# #
msg_verbose 1
helo_restrictions permit_naked_ip_address,reject_non_fqdn_hostname helo_restrictions permit_naked_ip_address,reject_non_fqdn_hostname
helo [1.2.3.4] helo [1.2.3.4]
helo [321.255.255.255] helo [321.255.255.255]

View File

@ -307,93 +307,73 @@ OK
>>> # >>> #
>>> # Numerical HELO checks >>> # Numerical HELO checks
>>> # >>> #
>>> msg_verbose 1
OK
>>> helo_restrictions permit_naked_ip_address,reject_non_fqdn_hostname >>> helo_restrictions permit_naked_ip_address,reject_non_fqdn_hostname
OK OK
>>> helo [1.2.3.4] >>> helo [1.2.3.4]
./smtpd_check: reject_invalid_hostaddr: [1.2.3.4]
OK OK
>>> helo [321.255.255.255] >>> helo [321.255.255.255]
./smtpd_check: reject_invalid_hostaddr: [321.255.255.255]
./smtpd_check: warning: valid_hostaddr: invalid octet value: 321.255.255.255 ./smtpd_check: warning: valid_hostaddr: invalid octet value: 321.255.255.255
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[321.255.255.255]>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[321.255.255.255]>: Helo command rejected: invalid ip address; from=<foo>
501 <[321.255.255.255]>: Helo command rejected: invalid ip address 501 <[321.255.255.255]>: Helo command rejected: invalid ip address
>>> helo [0.255.255.255] >>> helo [0.255.255.255]
./smtpd_check: reject_invalid_hostaddr: [0.255.255.255]
./smtpd_check: warning: valid_hostaddr: bad initial octet value: 0.255.255.255 ./smtpd_check: warning: valid_hostaddr: bad initial octet value: 0.255.255.255
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[0.255.255.255]>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[0.255.255.255]>: Helo command rejected: invalid ip address; from=<foo>
501 <[0.255.255.255]>: Helo command rejected: invalid ip address 501 <[0.255.255.255]>: Helo command rejected: invalid ip address
>>> helo [1.2.3.321] >>> helo [1.2.3.321]
./smtpd_check: reject_invalid_hostaddr: [1.2.3.321]
./smtpd_check: warning: valid_hostaddr: invalid octet value: 1.2.3.321 ./smtpd_check: warning: valid_hostaddr: invalid octet value: 1.2.3.321
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.321]>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.321]>: Helo command rejected: invalid ip address; from=<foo>
501 <[1.2.3.321]>: Helo command rejected: invalid ip address 501 <[1.2.3.321]>: Helo command rejected: invalid ip address
>>> helo [1.2.3] >>> helo [1.2.3]
./smtpd_check: reject_invalid_hostaddr: [1.2.3]
./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3 ./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3]>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3]>: Helo command rejected: invalid ip address; from=<foo>
501 <[1.2.3]>: Helo command rejected: invalid ip address 501 <[1.2.3]>: Helo command rejected: invalid ip address
>>> helo [1.2.3.4.5] >>> helo [1.2.3.4.5]
./smtpd_check: reject_invalid_hostaddr: [1.2.3.4.5]
./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5 ./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5]>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5]>: Helo command rejected: invalid ip address; from=<foo>
501 <[1.2.3.4.5]>: Helo command rejected: invalid ip address 501 <[1.2.3.4.5]>: Helo command rejected: invalid ip address
>>> helo [1..2.3.4] >>> helo [1..2.3.4]
./smtpd_check: reject_invalid_hostaddr: [1..2.3.4]
./smtpd_check: warning: valid_hostaddr: misplaced dot: 1..2.3.4 ./smtpd_check: warning: valid_hostaddr: misplaced dot: 1..2.3.4
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1..2.3.4]>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1..2.3.4]>: Helo command rejected: invalid ip address; from=<foo>
501 <[1..2.3.4]>: Helo command rejected: invalid ip address 501 <[1..2.3.4]>: Helo command rejected: invalid ip address
>>> helo [.1.2.3.4] >>> helo [.1.2.3.4]
./smtpd_check: reject_invalid_hostaddr: [.1.2.3.4]
./smtpd_check: warning: valid_hostaddr: misplaced dot: .1.2.3.4 ./smtpd_check: warning: valid_hostaddr: misplaced dot: .1.2.3.4
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[.1.2.3.4]>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[.1.2.3.4]>: Helo command rejected: invalid ip address; from=<foo>
501 <[.1.2.3.4]>: Helo command rejected: invalid ip address 501 <[.1.2.3.4]>: Helo command rejected: invalid ip address
>>> helo [1.2.3.4.5.] >>> helo [1.2.3.4.5.]
./smtpd_check: reject_invalid_hostaddr: [1.2.3.4.5.]
./smtpd_check: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5. ./smtpd_check: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5.
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5.]>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5.]>: Helo command rejected: invalid ip address; from=<foo>
501 <[1.2.3.4.5.]>: Helo command rejected: invalid ip address 501 <[1.2.3.4.5.]>: Helo command rejected: invalid ip address
>>> helo 1.2.3.4 >>> helo 1.2.3.4
./smtpd_check: reject_invalid_hostaddr: 1.2.3.4
OK OK
>>> helo 321.255.255.255 >>> helo 321.255.255.255
./smtpd_check: reject_invalid_hostaddr: 321.255.255.255
./smtpd_check: warning: valid_hostaddr: invalid octet value: 321.255.255.255 ./smtpd_check: warning: valid_hostaddr: invalid octet value: 321.255.255.255
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <321.255.255.255>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <321.255.255.255>: Helo command rejected: invalid ip address; from=<foo>
501 <321.255.255.255>: Helo command rejected: invalid ip address 501 <321.255.255.255>: Helo command rejected: invalid ip address
>>> helo 0.255.255.255 >>> helo 0.255.255.255
./smtpd_check: reject_invalid_hostaddr: 0.255.255.255
./smtpd_check: warning: valid_hostaddr: bad initial octet value: 0.255.255.255 ./smtpd_check: warning: valid_hostaddr: bad initial octet value: 0.255.255.255
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <0.255.255.255>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <0.255.255.255>: Helo command rejected: invalid ip address; from=<foo>
501 <0.255.255.255>: Helo command rejected: invalid ip address 501 <0.255.255.255>: Helo command rejected: invalid ip address
>>> helo 1.2.3.321 >>> helo 1.2.3.321
./smtpd_check: reject_invalid_hostaddr: 1.2.3.321
./smtpd_check: warning: valid_hostaddr: invalid octet value: 1.2.3.321 ./smtpd_check: warning: valid_hostaddr: invalid octet value: 1.2.3.321
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.321>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.321>: Helo command rejected: invalid ip address; from=<foo>
501 <1.2.3.321>: Helo command rejected: invalid ip address 501 <1.2.3.321>: Helo command rejected: invalid ip address
>>> helo 1.2.3 >>> helo 1.2.3
./smtpd_check: reject_invalid_hostaddr: 1.2.3
./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3 ./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3>: Helo command rejected: invalid ip address; from=<foo>
501 <1.2.3>: Helo command rejected: invalid ip address 501 <1.2.3>: Helo command rejected: invalid ip address
>>> helo 1.2.3.4.5 >>> helo 1.2.3.4.5
./smtpd_check: reject_invalid_hostaddr: 1.2.3.4.5
./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5 ./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5>: Helo command rejected: invalid ip address; from=<foo>
501 <1.2.3.4.5>: Helo command rejected: invalid ip address 501 <1.2.3.4.5>: Helo command rejected: invalid ip address
>>> helo 1..2.3.4 >>> helo 1..2.3.4
./smtpd_check: reject_invalid_hostaddr: 1..2.3.4
./smtpd_check: warning: valid_hostaddr: misplaced dot: 1..2.3.4 ./smtpd_check: warning: valid_hostaddr: misplaced dot: 1..2.3.4
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1..2.3.4>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1..2.3.4>: Helo command rejected: invalid ip address; from=<foo>
501 <1..2.3.4>: Helo command rejected: invalid ip address 501 <1..2.3.4>: Helo command rejected: invalid ip address
>>> helo .1.2.3.4 >>> helo .1.2.3.4
./smtpd_check: reject_invalid_hostaddr: .1.2.3.4
./smtpd_check: warning: valid_hostaddr: misplaced dot: .1.2.3.4 ./smtpd_check: warning: valid_hostaddr: misplaced dot: .1.2.3.4
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <.1.2.3.4>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <.1.2.3.4>: Helo command rejected: invalid ip address; from=<foo>
501 <.1.2.3.4>: Helo command rejected: invalid ip address 501 <.1.2.3.4>: Helo command rejected: invalid ip address
>>> helo 1.2.3.4.5. >>> helo 1.2.3.4.5.
./smtpd_check: reject_invalid_hostaddr: 1.2.3.4.5.
./smtpd_check: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5. ./smtpd_check: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5.
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5.>: Helo command rejected: invalid ip address; from=<foo> ./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5.>: Helo command rejected: invalid ip address; from=<foo>
501 <1.2.3.4.5.>: Helo command rejected: invalid ip address 501 <1.2.3.4.5.>: Helo command rejected: invalid ip address

View File

@ -95,6 +95,7 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream,
state->reason = 0; state->reason = 0;
state->sender = 0; state->sender = 0;
state->recipient = 0; state->recipient = 0;
state->etrn_name = 0;
state->protocol = "SMTP"; state->protocol = "SMTP";
state->where = SMTPD_AFTER_CONNECT; state->where = SMTPD_AFTER_CONNECT;

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER -TSINGLE_SERVER
-TSINK_COMMAND -TSINK_COMMAND
-TSINK_STATE -TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE -TSMTPD_STATE
-TSMTPD_TOKEN -TSMTPD_TOKEN
-TSMTP_ADDR -TSMTP_ADDR