2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-22 18:07:41 +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
-TSINK_COMMAND
-TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR

View File

@ -3039,3 +3039,40 @@ Apologies for any names omitted.
and for upgrading Postfix. It replaces files instead of
overwriting them, and leaves existing configuration and
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.
for file in `ls libexec`
for file in `ls libexec | grep '^[a-z]'`
do
compare_or_replace a+x,go-w libexec/$file $daemon_directory/$file || exit 1
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
==========================================
@ -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
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
restore previous behavior.

View File

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

View File

@ -87,6 +87,7 @@
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
-TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-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_sender: reject sender 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.
# permit: permit the request. Place this at the end of a restriction.
#

View File

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

View File

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

View File

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

View File

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

View File

@ -718,6 +718,10 @@ extern char *var_rcpt_checks;
#define DEF_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
* 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 PERMIT_ADDR_MAP "permit_address_map"
/*
* Other.
*/

View File

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

View File

@ -80,6 +80,9 @@
*/
extern CLNT_STREAM *rewrite_clnt_stream;
static VSTRING *last_addr;
static RESOLVE_REPLY last_reply;
/* resolve_clnt_init - initialize 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";
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
* have to retransmit the request.
@ -105,6 +116,20 @@ void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
if (addr == STR(reply->recipient))
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
* 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 */
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 */

View File

@ -71,6 +71,9 @@
*/
CLNT_STREAM *rewrite_clnt_stream = 0;
VSTRING *last_addr;
VSTRING *last_result;
/* rewrite_clnt - rewrite address to (transport, next hop, recipient) */
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";
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
* 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))
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
* 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)
msg_info("rewrite_clnt: %s: %s -> %s",
rule, addr, vstring_str(result));
#if 0
if (addr[0] != 0 && STR(result)[0] == 0)
msg_warn("%s: null result for: <%s>", myname, addr);
else
#endif
return (result);
break;
}
sleep(10); /* XXX make configurable */
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 */

View File

@ -203,46 +203,52 @@ 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>
List of DNS domains that publish the addresses of
List of DNS domains that publish the addresses of
blacklisted hosts.
<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.
<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>
Server response when a client violates an access
Server response when a client violates an access
database restriction.
<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>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>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.
<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.
<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>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
name mapping violates the <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>clients</b>
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>
restriction.
<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>SEE</b> <b>ALSO</b>
@ -250,13 +256,7 @@ SMTPD(8) SMTPD(8)
<a href="master.8.html">master(8)</a> process manager
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)
<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
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
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
is anything else. The <b>access_map_reject_code</b> parameter
specifies the response code for <b>REJECT</b> results (default:
<b>554</b>).
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 code for <b>REJECT</b> results
(default: <b>554</b>).
<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
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 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
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,
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
request if the result is anything else. The <b>access_map_reject_code
</b> parameter specifies the result code for rejected requests
(default: <b>554</b>).
request if 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 result code
for rejected requests (default: <b>554</b>).
<p>
@ -568,9 +571,10 @@ $inet_interfaces</a>.
href="access.5.html">access database</a> for the resolved destination
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>".
Permit the request if the result is anything else. The
<b>access_map_reject_code </b> parameter specifies the result code
for rejected requests (default: <b>554</b>).
Permit the request if 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 result
code for rejected requests (default: <b>554</b>).
<p>
@ -593,6 +597,16 @@ response code to rejected requests (default: <b>504</b>).
<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_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
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 request if the result is anything else. The <b>access_map_reject_code
</b> parameter specifies the result code for rejected requests
(default: <b>554</b>).
the request if 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 result code
for rejected requests (default: <b>554</b>).
<p>

View File

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

View File

@ -147,6 +147,10 @@ Restrict what recipient addresses are allowed in \fBRCPT TO\fR commands.
.IP \fBsmtpd_etrn_restrictions\fR
Restrict what domain names can be used in \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
List of DNS domains that publish the addresses of blacklisted
hosts.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -131,6 +131,10 @@
/* .IP \fBsmtpd_etrn_restrictions\fR
/* Restrict what domain names can be used in \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
/* List of DNS domains that publish the addresses of blacklisted
/* hosts.
@ -278,6 +282,7 @@ int var_non_fqdn_code;
char *var_always_bcc;
char *var_error_rcpt;
int var_smtpd_delay_reject;
char *var_rest_classes;
/*
* 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_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0,
VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes, 0, 0,
0,
};

View File

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

View File

@ -135,6 +135,13 @@
/* Allow the request when the local mail system is mail exchanger
/* for the recipient domain (this includes the case where the local
/* 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
/* smtpd_check_client() validates the client host name or address.
/* Relevant configuration parameters:
@ -246,6 +253,7 @@
#include <argv.h>
#include <mymalloc.h>
#include <dict.h>
#include <htable.h>
/* DNS library. */
@ -261,6 +269,9 @@
#include <mail_error.h>
#include <resolve_local.h>
#include <own_inet_addr.h>
#include <mail_conf.h>
#include <maps.h>
#include <mail_addr_find.h>
/* Application-specific. */
@ -302,6 +313,15 @@ static ARGV *mail_restrctions;
static ARGV *rcpt_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.
*/
@ -318,7 +338,7 @@ static ARGV *etrn_restrctions;
/* 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);
ARGV *argv = argv_alloc(1);
@ -348,6 +368,10 @@ static ARGV *smtpd_check_parse(char *checks)
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.
@ -372,6 +396,35 @@ void smtpd_check_init(void)
mail_restrctions = smtpd_check_parse(var_mail_checks);
rcpt_restrctions = smtpd_check_parse(var_rcpt_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 */
@ -946,14 +999,61 @@ static int reject_unknown_address(SMTPD_STATE *state, char *addr,
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 */
static int check_table_result(SMTPD_STATE *state, char *table,
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";
int code;
ARGV *restrictions;
int status;
if (msg_verbose)
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 */
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 *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 ((value = dict_get(dict, low_name)) != 0)
CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
reply_name, reply_class));
reply_name, reply_class,
def_acl));
if (dict_errno != 0)
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,
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 *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 ((value = dict_get(dict, name)) != 0)
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)
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,
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 *addr;
@ -1081,7 +1195,8 @@ static int check_addr_access(SMTPD_STATE *state, char *table,
if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, addr)) != 0)
return (check_table_result(state, table, value, address,
reply_name, reply_class));
reply_name, reply_class,
def_acl));
if (dict_errno != 0)
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,
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";
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.
*/
if ((status = check_domain_access(state, table, name, flags,
reply_name, reply_class)) != 0)
reply_name, reply_class,
def_acl)) != 0)
return (status);
/*
* Look up the network address, or parent networks thereof.
*/
if ((status = check_addr_access(state, table, addr, flags,
reply_name, reply_class)) != 0)
reply_name, reply_class,
def_acl)) != 0)
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 */
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 *ratsign;
@ -1156,14 +1275,14 @@ static int check_mail_access(SMTPD_STATE *state, char *table, char *addr,
* Look up the full address.
*/
if ((status = check_access(state, table, STR(reply.recipient), FULL,
reply_name, reply_class)) != 0)
reply_name, reply_class, def_acl)) != 0)
return (status);
/*
* Look up the domain name, or parent domains thereof.
*/
if ((status = check_domain_access(state, table, ratsign + 1, PARTIAL,
reply_name, reply_class)) != 0)
reply_name, reply_class, def_acl)) != 0)
return (status);
/*
@ -1172,7 +1291,7 @@ static int check_mail_access(SMTPD_STATE *state, char *table, char *addr,
local_at = mystrndup(STR(reply.recipient),
ratsign - STR(reply.recipient) + 1);
status = check_access(state, table, local_at, PARTIAL,
reply_name, reply_class);
reply_name, reply_class, def_acl);
myfree(local_at);
if (status != 0)
return (status);
@ -1267,170 +1386,226 @@ static int is_map_command(char *name, char *command, char ***argp)
/* generic_checks - generic restrictions */
static int generic_checks(SMTPD_STATE *state, char *name,
char ***cpp, int *status,
char *reply_name, char *reply_class)
static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
char *reply_name, char *reply_class, char *def_acl)
{
char *myname = "generic_checks";
char **cpp;
char *name;
int status;
ARGV *list;
/*
* 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);
return (1);
}
if (strcasecmp(name, REJECT_ALL) == 0) {
*status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: %s rejected: Access denied",
status = setjmp(smtpd_check_buf);
if (status != 0)
return (0);
if (msg_verbose)
msg_info("%s: START", myname);
for (cpp = restrictions->argv; (name = *cpp) != 0; cpp++) {
if (msg_verbose)
msg_info("%s: name=%s", myname, name);
/*
* 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);
if ((*cpp)[1] != 0)
msg_warn("restriction `%s' after `%s' is ignored",
(*cpp)[1], REJECT_ALL);
return (1);
}
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);
if (cpp[1] != 0)
msg_warn("restriction `%s' after `%s' is ignored",
cpp[1], REJECT_ALL);
} else if (strcasecmp(name, REJECT_UNAUTH_PIPE) == 0) {
status = reject_unauth_pipelining(state);
}
return (1);
}
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);
/*
* Client name/address restrictions.
*/
else if (strcasecmp(name, REJECT_UNKNOWN_CLIENT) == 0) {
status = reject_unknown_client(state);
} else if (strcasecmp(name, PERMIT_MYNETWORKS) == 0) {
status = permit_mynetworks(state);
} else 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, 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) {
if (state->helo_name) {
if (state->helo_name[strspn(state->helo_name, "0123456789.")] == 0
&& (*status = reject_invalid_hostaddr(state, state->helo_name,
/*
* HELO/EHLO parameter restrictions.
*/
else if (is_map_command(name, CHECK_HELO_ACL, &cpp)) {
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)
*status = SMTPD_CHECK_OK;
}
return (1);
}
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,
status = SMTPD_CHECK_OK;
}
} else 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,
state->helo_name, SMTPD_NAME_HELO);
else
*status = reject_invalid_hostaddr(state, state->helo_name,
else
status = reject_invalid_hostaddr(state, state->helo_name,
state->helo_name, SMTPD_NAME_HELO);
}
}
return (1);
}
/*
* Sender mail address restrictions.
*/
if (is_map_command(name, CHECK_SENDER_ACL, cpp) && state->sender) {
if (state->sender)
*status = check_mail_access(state, **cpp, state->sender,
state->sender, SMTPD_NAME_SENDER);
return (1);
}
if (strcasecmp(name, REJECT_UNKNOWN_ADDRESS) == 0) {
if (state->sender)
*status = reject_unknown_address(state, state->sender,
/*
* Sender mail address restrictions.
*/
else if (is_map_command(name, CHECK_SENDER_ACL, &cpp)) {
if (state->sender)
status = check_mail_access(state, *cpp, state->sender,
state->sender,
SMTPD_NAME_SENDER, def_acl);
} else if (strcasecmp(name, REJECT_UNKNOWN_ADDRESS) == 0) {
if (state->sender)
status = reject_unknown_address(state, state->sender,
state->sender, SMTPD_NAME_SENDER);
return (1);
}
if (strcasecmp(name, REJECT_UNKNOWN_SENDDOM) == 0) {
if (state->sender)
*status = reject_unknown_address(state, state->sender,
} else if (strcasecmp(name, REJECT_UNKNOWN_SENDDOM) == 0) {
if (state->sender)
status = reject_unknown_address(state, state->sender,
state->sender, SMTPD_NAME_SENDER);
return (1);
}
if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) {
if (*state->sender)
*status = reject_non_fqdn_address(state, state->sender,
} else if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) {
if (state->sender && *state->sender)
status = reject_non_fqdn_address(state, state->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 */
char *smtpd_check_client(SMTPD_STATE *state)
{
char **cpp;
char *name;
int status;
/*
* Initialize.
*/
if (state->name == 0 && state->addr == 0)
return (0);
status = setjmp(smtpd_check_buf);
if (status != 0)
if (state->name == 0 || state->addr == 0)
return (0);
/*
* Apply restrictions in the order as specified.
*/
for (cpp = client_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) {
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;
}
status = generic_checks(state, client_restrctions, state->namaddr,
SMTPD_NAME_CLIENT, CHECK_CLIENT_ACL);
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 **cpp;
char *name;
int status;
char *saved_helo = state->helo_name;
char *saved_helo;
/*
* Initialize.
*/
if (helohost == 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
* can delegate work to the generic routine.
* Minor kluge so that we can delegate work to the generic routine and so
* that we can syslog the recipient with the reject messages.
*/
state->helo_name = mystrdup(helohost);
for (cpp = helo_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) {
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;
#define SMTPD_CHECK_PUSH(backup, current, new) { \
backup = current; \
current = mystrdup(new); \
}
myfree(state->helo_name);
state->helo_name = saved_helo;
return (status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
#define SMTPD_CHECK_POP(current, backup) { \
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 **cpp;
char *name;
int status;
char *saved_sender = state->sender;
char *saved_sender;
/*
* Initialize.
*/
if (sender == 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
* can delegate work to the generic routine.
* Minor kluge so that we can delegate work to the generic routine and so
* that we can syslog the recipient with the reject messages.
*/
state->sender = mystrdup(sender);
for (cpp = mail_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) {
status = check_mail_access(state, name, sender,
sender, SMTPD_NAME_SENDER);
} 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;
SMTPD_CHECK_PUSH(saved_sender, state->sender, sender);
#define SMTPD_CHECK_MAIL_RETURN(x) { \
SMTPD_CHECK_POP(state->sender, saved_sender); \
return (x); \
}
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 **cpp;
char *name;
int status;
char *saved_recipient = state->recipient;
char *saved_recipient;
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
* 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) { \
myfree(state->recipient); \
state->recipient = saved_recipient; \
SMTPD_CHECK_POP(state->recipient, saved_recipient); \
return (x); \
}
@ -1551,47 +1719,12 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
|| (err = smtpd_check_mail(state, state->sender)) != 0)
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.
*/
for (cpp = rcpt_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) {
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;
}
status = generic_checks(state, rcpt_restrctions,
recipient, SMTPD_NAME_RECIPIENT, CHECK_RECIP_ACL);
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 **cpp;
char *name;
int status;
char *saved_etrn_name;
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.
*/
if (var_smtpd_delay_reject)
if ((err = smtpd_check_client(state)) != 0
|| (err = smtpd_check_helo(state, state->helo_name)) != 0)
return (err);
/*
* Initialize.
*/
if (domain == 0)
return (0);
status = setjmp(smtpd_check_buf);
if (status != 0)
return (0);
SMTPD_CHECK_ETRN_RETURN(err);
/*
* Apply restrictions in the order as specified.
*/
for (cpp = etrn_restrctions->argv; (name = *cpp) != 0; cpp++) {
if (strchr(name, ':') != 0) {
status = check_domain_access(state, name, domain, FULL,
domain, SMTPD_NAME_ETRN);
} 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);
status = generic_checks(state, etrn_restrctions, domain,
SMTPD_NAME_ETRN, CHECK_ETRN_ACL);
SMTPD_CHECK_ETRN_RETURN(status == SMTPD_CHECK_REJECT ? STR(error_text) : 0);
}
/* 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));
}
fsspace(".", &fsbuf);
if (msg_verbose)
msg_info("%s: blocks %lu avail %lu min_free %lu size %lu",
myname,
@ -1713,6 +1842,7 @@ char *var_notify_classes = "";
char *var_maps_rbl_domains;
char *var_mydest;
char *var_inet_interfaces;
char *var_rest_classes;
typedef struct {
char *name;
@ -1724,6 +1854,7 @@ static STRING_TABLE string_table[] = {
VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains,
VAR_MYDEST, DEF_MYDEST, &var_mydest,
VAR_INET_INTERFACES, DEF_INET_INTERFACES, &var_inet_interfaces,
VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes,
0,
};
@ -1822,9 +1953,9 @@ static int int_update(char **argv)
typedef struct {
char *name;
ARGV **target;
} REST_TABLE;
} SMTPD_REST_TABLE;
static REST_TABLE rest_table[] = {
static SMTPD_REST_TABLE smtpd_rest_table[] = {
"client_restrictions", &client_restrctions,
"helo_restrictions", &helo_restrctions,
"sender_restrictions", &mail_restrctions,
@ -1833,13 +1964,13 @@ static REST_TABLE rest_table[] = {
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) {
argv_free(rp->target[0]);
rp->target[0] = smtpd_check_parse(argv[1]);
@ -1980,7 +2111,7 @@ main(int argc, char **argv)
}
if (int_update(args->argv)
|| string_update(args->argv)
|| rest_update(args->argv)) {
|| smtpd_rest_update(args->argv)) {
resp = 0;
break;
}

View File

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

View File

@ -307,93 +307,73 @@ OK
>>> #
>>> # Numerical HELO checks
>>> #
>>> msg_verbose 1
OK
>>> helo_restrictions permit_naked_ip_address,reject_non_fqdn_hostname
OK
>>> helo [1.2.3.4]
./smtpd_check: reject_invalid_hostaddr: [1.2.3.4]
OK
>>> 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: 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
>>> 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: 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
>>> 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: 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
>>> 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: 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
>>> 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: 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
>>> 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: 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
>>> 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: 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
>>> 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: 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
>>> helo 1.2.3.4
./smtpd_check: reject_invalid_hostaddr: 1.2.3.4
OK
>>> 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: 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
>>> 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: 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
>>> 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: 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
>>> 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: 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
>>> 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: 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
>>> 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: 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
>>> 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: 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
>>> 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: 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

View File

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

View File

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

View File

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

View File

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