2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 21:55:20 +00:00

postfix-2.0.16-20030917

This commit is contained in:
Wietse Venema
2003-09-17 00:00:00 -05:00
committed by Viktor Dukhovni
parent b7fe5bb669
commit 116a98032d
15 changed files with 547 additions and 17 deletions

1
postfix/.indent.pro vendored
View File

@@ -77,6 +77,7 @@
-TINTV
-TINT_TABLE
-TJMP_BUF_WRAPPER
-TLDAP_CONN
-TLMTP_ATTR
-TLMTP_RESP
-TLMTP_SESSION

View File

@@ -8558,6 +8558,38 @@ Apologies for any names omitted.
Cleanup: postcat is now null-byte transparent. File:
postcat/postcat.c.
20030916
Feature: ``check_{sender,recipient}_mx_access maptype:mapname''
applies the named Postfix access table to the MX host name
and IP addresses for the sender or recipient address. If
no MX record is found, the A record is used instead. File:
smtpd/smtpd_check.c.
Experimental feature: ``check_{sender,recipient}_ns_access
maptype:mapname'' applies the named Postfix access table
to the DNS server hostname and IP addresses for the sender
or recipient address. If no NS record is found, the parent
domain is used instead. File: smtpd/smtpd_check.c.
20030917
Feature: ``check_helo_{ns,mx}_access maptype:mapname'',
same semantics as sender and recipient.
Multiple LDAP lookup tables in the one Postfix process now
share one LDAP connection. Code by Victor Duchovni, Morgan
Stanley. File: util/dict_ldap.c.
Performance: with prefix_domain specified for an LDAP lookup
table, lookups of @domain are skipped. Code by Victor
Duchovni, Morgan Stanley. File: util/dict_ldap.c.
Safety: check_mumble_{mx,ns}_access refuses to be used for
whitelisting. The Postfix SMTP server will reject the
request with "451 server configuration error" and will log
a warning explaining why. File: smtpd/smtpd_check.c.
Open problems:
High: when virtual aliasing is turned off after content

View File

@@ -423,6 +423,12 @@ NOTES AND THINGS TO THINK ABOUT
they won't be a bottleneck, but it's a good idea to know how to tune
your directory service.
- Multiple LDAP maps share the same LDAP connection if they differ
only in their query related parameters: base, scope, query_filter, and
so on. To take advantage of this avoid spurious differences in the
definitions of LDAP maps: host selection order, version, bind, tls
parameters, ... should be the same for multiple maps whenever possible.
FEEDBACK
========
@@ -450,9 +456,10 @@ Samuel Tardieu: Noticed that searches could include wildcards, prompting
Sami Haahtinen: Referral chasing and v3 support.
Victor Duchovni: ldap_bind() timeout. With fixes from LaMont Jones:
OpenLDAP cache deprecation. Limits on recursion, expansion
and query results size.
and query results size. LDAP connection sharing for maps
differing only in the query parameters.
Liviu Daia: Support for SSL/STARTTLS. Support for storing map definitions in
external files (ldap:/path/ldap.cf) need to securely store
external files (ldap:/path/ldap.cf) needed to securely store
passwords for plain auth.
And of course Wietse.

View File

@@ -22,14 +22,42 @@ snapshot release). Patches change the patchlevel and the release
date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release.
Incompatible changes with Postfix snapshot 2.0.13-20030914
Major changes with Postfix snapshot 2.0.16-20030917
===================================================
New check_{helo,sender,recipient}_{ns,mx}_access maptype:mapname
restriction that applies the specified access table to the NS or
MX hosts of the host/domain given in HELO, EHLO, MAIL FROM or RCPT
TO commands.
This can be used to block mail from so-called spammer havens, or
from sender addresses that resolve to Verisign's wild-card mail
responder, currently at IP address 64.94.110.11.
/etc/postfix/main.cf:
smtpd_mumble_restrictions =
...
reject_unknown_sender_domain
check_sender_mx_access hash:/etc/postfix/mx_access
...
/etc/postfix/mx_access:
spammer.haven.tld reject spammer mx host
64.94.110.11 reject verisign wild-card domain
Note: OK actions are not allowed for security reasons. Instead of
OK, use DUNNO in order to exclude specific hosts from blacklists.
If an OK result is found for an NS or MX host, Postfix rejects the
SMTP command with "451 Server configuration error".
Incompatible changes with Postfix snapshot 2.0.16-20030915
==========================================================
In header/body_checks actions, the OK action is being phased out,
and the DUNNO action is being phased in. Both actions still work
and do the same thing, but hopefully DUNNO causes less confusion.
Major changes with Postfix snapshot 2.0.13-20030914
Major changes with Postfix snapshot 2.0.16-20030915
===================================================
LDAP parameters can now be defined in external files. Specify the

View File

@@ -358,6 +358,11 @@ smtpd_helo_required = no
# check_helo_access maptype:mapname
# look up HELO hostname or parent domains.
# see access(5) for possible lookup results.
# check_helo_mx_access maptype:mapname
# check_helo_ns_access maptype:mapname
# look up the helo hostname MX hosts (or name servers) and apply the
# specified access table to those hosts.
# Note: the OK result is not allowed here for security reasons.
# check_policy_service transport:endpoint: delegate the decision to
# an external policy server. See SMTPD_POLICY_README for details.
# reject_rhsbl_helo domain.tld: reject if the helo argument is listed
@@ -396,6 +401,11 @@ smtpd_helo_restrictions =
# check_sender_access maptype:mapname
# look up sender address, parent domain, or localpart@.
# see access(5) for possible lookup results.
# check_sender_mx_access maptype:mapname
# check_sender_ns_access maptype:mapname
# look up sender address MX hosts (or name servers) and apply the
# specified access table to those hosts.
# Note: the OK result is not allowed here for security reasons.
# reject_sender_login_mismatch: reject if $smtpd_sender_login_maps specifies
# a MAIL FROM address owner, but the client is not (SASL) logged in as
# that MAIL FROM address owner; or if the client is (SASL) logged in, but
@@ -467,6 +477,11 @@ smtpd_sender_restrictions =
# check_recipient_access maptype:mapname
# look up recipient address, parent domain, or localpart@.
# see access(5) for possible lookup results.
# check_recipient_mx_access maptype:mapname
# check_recipient_ns_access maptype:mapname
# look up the recipient address MX hosts (or name servers) and apply the
# specified access table to those hosts.
# Note: the OK result is not allowed here for security reasons.
# reject_non_fqdn_recipient: reject recipient address that is not in FQDN form
# check_policy_service transport:endpoint: delegate the decision to
# an external policy server. See SMTPD_POLICY_README for details.

View File

@@ -599,6 +599,22 @@ or parent domains.
<p>
<a name="check_helo_ns_access">
<dt> <b>check_helo_ns_access</b> <i>maptype</i>:<i>mapname</i>
<a name="check_helo_mx_access">
<dt> <b>check_helo_mx_access</b> <i>maptype</i>:<i>mapname</i>
<dd> Apply the specified <a href="access.5.html">access database</a>
to the DNS (or MX) servers for the host or domain name given with
the HELO (or EHLO) command.
<dd> Note: an OK result is not allowed for safety reasons.
<p>
<a name="reject_rhsbl_helo">
<dt> <b>reject_rhsbl_helo</b> <i>domain.tld=127.0.0.2</i>
@@ -783,6 +799,22 @@ sender domain and parent domain, or <i>localpart</i>@.
<p>
<a name="check_sender_ns_access">
<dt> <b>check_sender_ns_access</b> <i>maptype</i>:<i>mapname</i>
<a name="check_sender_mx_access">
<dt> <b>check_sender_mx_access</b> <i>maptype</i>:<i>mapname</i>
<dd> Apply the specified <a href="access.5.html">access database</a>
to the DNS (or MX) servers for the host or domain name given with
the MAIL FROM command.
<dd> Note: an OK result is not allowed for safety reasons.
<p>
<a name="reject_non_fqdn_sender">
<dt> <b>reject_non_fqdn_sender</b> <dd> Reject the request when
@@ -995,6 +1027,22 @@ address, recipient domain or parent domain, or <i>localpart</i>@.
<p>
<a name="check_recipient_ns_access">
<dt> <b>check_recipient_ns_access</b> <i>maptype</i>:<i>mapname</i>
<a name="check_recipient_mx_access">
<dt> <b>check_recipient_mx_access</b> <i>maptype</i>:<i>mapname</i>
<dd> Apply the specified <a href="access.5.html">access database</a>
to the DNS servers (or MX hosts) for the host or domain name given
with the RCPT TO command.
<dd> Note: an OK result is not allowed for safety reasons.
<p>
<a name="check_recipient_maps">
<dt> <b>check_recipient_maps</b> <dd> Reject the request

View File

@@ -509,6 +509,7 @@ int dns_lookup(const char *name, unsigned type, unsigned flags,
vstring_sprintf(why,
"Name service error for %s: invalid host or domain name",
name);
h_errno = HOST_NOT_FOUND;
return (DNS_NOTFOUND);
}
@@ -520,6 +521,7 @@ int dns_lookup(const char *name, unsigned type, unsigned flags,
vstring_sprintf(why,
"Name service error for %s: invalid host or domain name",
name);
h_errno = HOST_NOT_FOUND;
return (DNS_NOTFOUND);
}

View File

@@ -1314,6 +1314,13 @@ extern int var_access_map_code;
#define CHECK_RECIP_ACL "check_recipient_access"
#define CHECK_ETRN_ACL "check_etrn_access"
#define CHECK_HELO_MX_ACL "check_helo_mx_access"
#define CHECK_SENDER_MX_ACL "check_sender_mx_access"
#define CHECK_RECIP_MX_ACL "check_recipient_mx_access"
#define CHECK_HELO_NS_ACL "check_helo_ns_access"
#define CHECK_SENDER_NS_ACL "check_sender_ns_access"
#define CHECK_RECIP_NS_ACL "check_recipient_ns_access"
#define WARN_IF_REJECT "warn_if_reject"
#define REJECT_RBL "reject_rbl" /* LaMont compatibility */

View File

@@ -20,10 +20,10 @@
* Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release.
*/
#define MAIL_RELEASE_DATE "20030915"
#define MAIL_RELEASE_DATE "20030917"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "2.0.14-" MAIL_RELEASE_DATE
#define DEF_MAIL_VERSION "2.0.16-" MAIL_RELEASE_DATE
extern char *var_mail_version;
/*

View File

@@ -89,6 +89,18 @@
/* .IP "check_recipient_access maptype:mapname"
/* Look up the resolved recipient address in the named access table,
/* any parent domains of the recipient domain, and the localpart@.
/* .IP "check_helo_mx_access maptype:mapname"
/* .IP "check_sender_mx_access maptype:mapname"
/* .IP "check_recipient_mx_access maptype:mapname"
/* Apply the specified access table to the MX server host name and IP
/* addresses for the helo hostname, sender, or recipient, respectively.
/* If no MX record is found the A record is used instead.
/* .IP "check_helo_ns_access maptype:mapname"
/* .IP "check_sender_ns_access maptype:mapname"
/* .IP "check_recipient_ns_access maptype:mapname"
/* Apply the specified access table to the DNS server host name and IP
/* addresses for the helo hostname, sender, or recipient, respectively.
/* If no NS record is found, the parent domain is used instead.
/* .IP "check_recipient_maps"
/* Reject recipients not listed as valid local, virtual or relay
/* recipients.
@@ -482,6 +494,12 @@ static void PRINTFLIKE(3, 4) defer_if(SMTPD_DEFER *, int, const char *,...);
else \
(void) smtpd_check_reject((state), (class), (fmt), (a1), (a2), (a3)); \
} while (0)
#define DEFER_IF_PERMIT4(state, class, fmt, a1, a2, a3, a4) do { \
if ((state)->warn_if_reject == 0) \
defer_if(&(state)->defer_if_permit, (class), (fmt), (a1), (a2), (a3), (a4)); \
else \
(void) smtpd_check_reject((state), (class), (fmt), (a1), (a2), (a3), (a4)); \
} while (0)
/*
* Cached RBL lookup state.
@@ -2153,6 +2171,127 @@ static int check_namadr_access(SMTPD_STATE *state, const char *table,
return (SMTPD_CHECK_DUNNO);
}
/* check_server_access - access control by server host name or address */
static int check_server_access(SMTPD_STATE *state, const char *table,
const char *name,
int type,
const char *reply_name,
const char *reply_class,
const char *def_acl)
{
const char *myname = "check_server_access";
const char *domain;
int dns_status;
DNS_RR *server_list;
DNS_RR *server;
int found = 0;
struct in_addr addr;
struct hostent *hp;
char *addr_string;
int status;
char **cpp;
static DNS_FIXED fixed;
/*
* Sanity check.
*/
if (type != T_MX && type != T_NS)
msg_panic("%s: unexpected resource type \"%s\" in request",
myname, dns_strtype(type));
if (msg_verbose)
msg_info("%s: %s %s", myname, dns_strtype(type), name);
/*
* Skip over local-part.
*/
if ((domain = strrchr(name, '@')) != 0)
domain += 1;
else
domain = name;
/*
* If the domain does not exist then we apply no restriction. In all
* other cases, DNS lookup failure results in a "try again" status.
*
* If the domain name exists but MX lookup fails, fabricate an MX record
* that points to the domain name itself.
*
* If the domain name exists but NS lookup fails, look up the parent domain
* NS record.
*/
dns_status = dns_lookup(domain, type, 0, &server_list,
(VSTRING *) 0, (VSTRING *) 0);
if (dns_status == DNS_NOTFOUND && h_errno != HOST_NOT_FOUND) {
if (type == T_MX) {
server_list = dns_rr_create(domain, &fixed, 0,
domain, strlen(domain) + 1);
dns_status = DNS_OK;
} else if (type == T_NS && (domain = strchr(domain, '.')) != 0
&& strchr(++domain, '.') != 0) {
dns_status = dns_lookup(domain, T_NS, 0, &server_list,
(VSTRING *) 0, (VSTRING *) 0);
if (dns_status != DNS_OK)
dns_status = DNS_RETRY;
}
}
if (dns_status == DNS_NOTFOUND)
return (SMTPD_CHECK_DUNNO);
if (dns_status != DNS_OK) {
DEFER_IF_PERMIT3(state, MAIL_ERROR_POLICY,
"450 <%s>: %s rejected: unable to look up %s host",
reply_name, reply_class, dns_strtype(type));
return (SMTPD_CHECK_DUNNO);
}
/*
* No bare returns after this point or we have a memory leak.
*/
#define CHECK_SERVER_RETURN(x) { dns_rr_free(server_list); return(x); }
/*
* Check the hostnames first, then the addresses.
*/
for (server = server_list; server != 0; server = server->next) {
if ((hp = gethostbyname((char *) server->data)) == 0) {
DEFER_IF_PERMIT4(state, MAIL_ERROR_POLICY,
"450 <%s>: %s rejected: "
"Unable to look up %s host %s",
reply_name, reply_class,
dns_strtype(type), (char *) server->data);
CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO);
}
if (hp->h_addrtype != AF_INET || hp->h_length != sizeof(addr)) {
if (msg_verbose)
msg_warn("address type %d length %d for %s",
hp->h_addrtype, hp->h_length, (char *) server->data);
continue; /* XXX */
}
if (msg_verbose)
msg_info("%s: %s hostname check: %s",
myname, dns_strtype(type), (char *) server->data);
if ((status = check_domain_access(state, table, (char *) server->data,
FULL, &found, reply_name, reply_class,
def_acl)) != 0 || found)
CHECK_SERVER_RETURN(status);
if (msg_verbose)
msg_info("%s: %s host address check: %s",
myname, dns_strtype(type), (char *) server->data);
for (cpp = hp->h_addr_list; *cpp; cpp++) {
memcpy((char *) &addr, *cpp, sizeof(addr));
addr_string = mystrdup(inet_ntoa(addr));
status = check_addr_access(state, table, addr_string, FULL,
&found, reply_name, reply_class,
def_acl);
myfree(addr_string);
if (status != 0 || found)
CHECK_SERVER_RETURN(status);
}
}
CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO);
}
/* check_mail_access - OK/FAIL based on mail address lookup */
static int check_mail_access(SMTPD_STATE *state, const char *table,
@@ -2818,6 +2957,20 @@ static int is_map_command(SMTPD_STATE *state, const char *name,
}
}
/* forbid_whitelist - disallow whitelisting */
static void forbid_whitelist(SMTPD_STATE *state, const char *name,
int status, const char *target)
{
if (status == SMTPD_CHECK_OK) {
msg_warn("restriction %s returns OK for %s", name, target);
msg_warn("this is not allowed for security reasons");
msg_warn("use DUNNO instead of OK if you want to make an exception");
longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE,
"451 Server configuration error"));
}
}
/* generic_checks - generic restrictions */
static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
@@ -2979,6 +3132,20 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
state->helo_name, SMTPD_NAME_HELO)) == 0)
status = SMTPD_CHECK_OK;
}
} else if (is_map_command(state, name, CHECK_HELO_NS_ACL, &cpp)) {
if (state->helo_name) {
status = check_server_access(state, *cpp, state->helo_name,
T_NS, state->helo_name,
SMTPD_NAME_HELO, def_acl);
forbid_whitelist(state, name, status, state->helo_name);
}
} else if (is_map_command(state, name, CHECK_HELO_MX_ACL, &cpp)) {
if (state->helo_name) {
status = check_server_access(state, *cpp, state->helo_name,
T_MX, state->helo_name,
SMTPD_NAME_HELO, def_acl);
forbid_whitelist(state, name, status, state->helo_name);
}
} else if (strcasecmp(name, REJECT_NON_FQDN_HOSTNAME) == 0) {
if (state->helo_name) {
if (*state->helo_name != '[')
@@ -3032,6 +3199,20 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
} else if (strcasecmp(name, REJECT_SENDER_LOGIN_MISMATCH) == 0) {
if (state->sender && *state->sender)
status = reject_sender_login_mismatch(state, state->sender);
} else if (is_map_command(state, name, CHECK_SENDER_NS_ACL, &cpp)) {
if (state->sender && *state->sender) {
status = check_server_access(state, *cpp, state->sender,
T_NS, state->sender,
SMTPD_NAME_SENDER, def_acl);
forbid_whitelist(state, name, status, state->sender);
}
} else if (is_map_command(state, name, CHECK_SENDER_MX_ACL, &cpp)) {
if (state->sender && *state->sender) {
status = check_server_access(state, *cpp, state->sender,
T_MX, state->sender,
SMTPD_NAME_SENDER, def_acl);
forbid_whitelist(state, name, status, state->sender);
}
} else if (strcasecmp(name, REJECT_RHSBL_SENDER) == 0) {
if (cpp[1] == 0)
msg_warn("restriction %s requires domain name argument", name);
@@ -3084,6 +3265,20 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
if (state->recipient)
status = reject_non_fqdn_address(state, state->recipient,
state->recipient, SMTPD_NAME_RECIPIENT);
} else if (is_map_command(state, name, CHECK_RECIP_NS_ACL, &cpp)) {
if (state->recipient && *state->recipient) {
status = check_server_access(state, *cpp, state->recipient,
T_NS, state->recipient,
SMTPD_NAME_RECIPIENT, def_acl);
forbid_whitelist(state, name, status, state->recipient);
}
} else if (is_map_command(state, name, CHECK_RECIP_MX_ACL, &cpp)) {
if (state->recipient && *state->recipient) {
status = check_server_access(state, *cpp, state->recipient,
T_MX, state->recipient,
SMTPD_NAME_RECIPIENT, def_acl);
forbid_whitelist(state, name, status, state->recipient);
}
} else if (strcasecmp(name, REJECT_RHSBL_RECIPIENT) == 0) {
if (cpp[1] == 0)
msg_warn("restriction %s requires domain name argument", name);

View File

@@ -56,3 +56,5 @@ holdtext@hold.domain hold text
discard@hold.domain discard
discardtext@hold.domain discard text
dunnotext@dunno.domain dunno text
64.94.110.11 reject Verisign wild-card
topica.com reject

View File

@@ -60,3 +60,32 @@ recipient_restrictions reject_rhsbl_helo,abuse.rfc-ignorant.org
helo example.tld
mail sname@sdomain
rcpt rname@rdomain
#
# Check MX access
#
helo_restrictions check_helo_mx_access,hash:smtpd_check_access
helo verisign-wildcard.com
helo verisign.com
helo example.tld
sender_restrictions check_sender_mx_access,hash:smtpd_check_access
mail foo@verisign-wildcard.com
mail foo@verisign.com
recipient_restrictions check_recipient_mx_access,hash:smtpd_check_access
rcpt foo@verisign-wildcard.com
rcpt foo@verisign.com
#
# Check NS access
#
helo_restrictions check_helo_ns_access,hash:smtpd_check_access
helo email-publisher.com
helo ns1.topica.com
helo verisign-wildcard.com
helo example.tld
sender_restrictions check_sender_ns_access,hash:smtpd_check_access
mail foo@email-publisher.com
mail foo@ns1.topica.com
mail foo@verisign-wildcard.com
recipient_restrictions check_recipient_ns_access,hash:smtpd_check_access
rcpt foo@email-publisher.com
rcpt foo@ns1.topica.com
rcpt foo@verisign-wildcard.com

View File

@@ -109,3 +109,64 @@ OK
>>> rcpt rname@rdomain
./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@domain; from=<sname@sdomain> to=<rname@rdomain> proto=SMTP helo=<example.tld>
554 Service unavailable; Helo command [example.tld] blocked using abuse.rfc-ignorant.org; Not supporting abuse@domain
>>> #
>>> # Check MX access
>>> #
>>> helo_restrictions check_helo_mx_access,hash:smtpd_check_access
OK
>>> helo verisign-wildcard.com
./smtpd_check: <queue id>: reject: HELO from spike.porcupine.org[168.100.189.2]: 554 <verisign-wildcard.com>: Helo command rejected: Verisign wild-card; from=<sname@sdomain> proto=SMTP helo=<verisign-wildcard.com>
554 <verisign-wildcard.com>: Helo command rejected: Verisign wild-card
>>> helo verisign.com
OK
>>> helo example.tld
OK
>>> sender_restrictions check_sender_mx_access,hash:smtpd_check_access
OK
>>> mail foo@verisign-wildcard.com
./smtpd_check: <queue id>: reject: MAIL from spike.porcupine.org[168.100.189.2]: 554 <foo@verisign-wildcard.com>: Sender address rejected: Verisign wild-card; from=<foo@verisign-wildcard.com> proto=SMTP helo=<example.tld>
554 <foo@verisign-wildcard.com>: Sender address rejected: Verisign wild-card
>>> mail foo@verisign.com
OK
>>> recipient_restrictions check_recipient_mx_access,hash:smtpd_check_access
OK
>>> rcpt foo@verisign-wildcard.com
./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 <foo@verisign-wildcard.com>: Recipient address rejected: Verisign wild-card; from=<foo@verisign.com> to=<foo@verisign-wildcard.com> proto=SMTP helo=<example.tld>
554 <foo@verisign-wildcard.com>: Recipient address rejected: Verisign wild-card
>>> rcpt foo@verisign.com
OK
>>> #
>>> # Check NS access
>>> #
>>> helo_restrictions check_helo_ns_access,hash:smtpd_check_access
OK
>>> helo email-publisher.com
./smtpd_check: <queue id>: reject: HELO from spike.porcupine.org[168.100.189.2]: 554 <email-publisher.com>: Helo command rejected: Access denied; from=<foo@verisign.com> proto=SMTP helo=<email-publisher.com>
554 <email-publisher.com>: Helo command rejected: Access denied
>>> helo ns1.topica.com
./smtpd_check: <queue id>: reject: HELO from spike.porcupine.org[168.100.189.2]: 554 <ns1.topica.com>: Helo command rejected: Access denied; from=<foo@verisign.com> proto=SMTP helo=<ns1.topica.com>
554 <ns1.topica.com>: Helo command rejected: Access denied
>>> helo verisign-wildcard.com
OK
>>> helo example.tld
OK
>>> sender_restrictions check_sender_ns_access,hash:smtpd_check_access
OK
>>> mail foo@email-publisher.com
./smtpd_check: <queue id>: reject: MAIL from spike.porcupine.org[168.100.189.2]: 554 <foo@email-publisher.com>: Sender address rejected: Access denied; from=<foo@email-publisher.com> proto=SMTP helo=<example.tld>
554 <foo@email-publisher.com>: Sender address rejected: Access denied
>>> mail foo@ns1.topica.com
./smtpd_check: <queue id>: reject: MAIL from spike.porcupine.org[168.100.189.2]: 554 <foo@ns1.topica.com>: Sender address rejected: Access denied; from=<foo@ns1.topica.com> proto=SMTP helo=<example.tld>
554 <foo@ns1.topica.com>: Sender address rejected: Access denied
>>> mail foo@verisign-wildcard.com
OK
>>> recipient_restrictions check_recipient_ns_access,hash:smtpd_check_access
OK
>>> rcpt foo@email-publisher.com
./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 <foo@email-publisher.com>: Recipient address rejected: Access denied; from=<foo@verisign-wildcard.com> to=<foo@email-publisher.com> proto=SMTP helo=<example.tld>
554 <foo@email-publisher.com>: Recipient address rejected: Access denied
>>> rcpt foo@ns1.topica.com
./smtpd_check: <queue id>: reject: RCPT from spike.porcupine.org[168.100.189.2]: 554 <foo@ns1.topica.com>: Recipient address rejected: Access denied; from=<foo@verisign-wildcard.com> to=<foo@ns1.topica.com> proto=SMTP helo=<example.tld>
554 <foo@ns1.topica.com>: Recipient address rejected: Access denied
>>> rcpt foo@verisign-wildcard.com
OK

View File

@@ -409,9 +409,11 @@ static void resolve_addr(RES_CONTEXT *rp, char *addr,
msg_warn("do not list domain %s in BOTH %s and %s",
rcpt_domain, VAR_VIRT_ALIAS_DOMS,
VAR_RELAY_DOMAINS);
#if 0
if (strcasecmp(rcpt_domain, var_myorigin) == 0)
msg_warn("do not list $%s (%s) in %s",
VAR_MYORIGIN, var_myorigin, VAR_VIRT_ALIAS_DOMS);
#endif
}
vstring_strcpy(channel, MAIL_SERVICE_ERROR);
vstring_sprintf(nexthop, "User unknown%s",

View File

@@ -180,11 +180,17 @@
#include "dict.h"
#include "dict_ldap.h"
#include "stringops.h"
#include "binhash.h"
/* AAARGH!! */
#include "../global/mail_conf.h"
typedef struct {
LDAP *conn_ld;
int conn_refcount;
} LDAP_CONN;
/*
* Structure containing all the configuration parameters for a given
* LDAP source, plus its connection handle.
@@ -223,9 +229,14 @@ typedef struct {
char *tls_random_file;
char *tls_cipher_suite;
#endif
LDAP *ld;
BINHASH_INFO *ht; /* hash entry for LDAP connection */
LDAP *ld; /* duplicated from conn->conn_ld */
} DICT_LDAP;
#define DICT_LDAP_CONN(d) ((LDAP_CONN *)((d)->ht->value))
static BINHASH *conn_hash = 0;
typedef struct {
char *(*get_str) (const char *, const char *, const char *, int, int);
int (*get_int) (const char *, const char *, int, int, int);
@@ -641,6 +652,9 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
msg_info("%s: Successful bind to server %s as %s ",
myname, dict_ldap->server_host, dict_ldap->bind_dn);
}
/* Save connection handle in shared container */
DICT_LDAP_CONN(dict_ldap)->conn_ld = dict_ldap->ld;
if (msg_verbose)
msg_info("%s: Cached connection handle for LDAP source %s",
myname, dict_ldap->ldapsource);
@@ -648,6 +662,58 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
return (0);
}
/*
* Locate or allocate connection cache entry.
*/
static void dict_ldap_conn_find(DICT_LDAP *dict_ldap)
{
VSTRING *keybuf = vstring_alloc(10);
char *key;
int len;
int sslon = dict_ldap->start_tls || dict_ldap->ldap_ssl;
LDAP_CONN *conn;
#define ADDSTR(vp, s) vstring_memcat((vp), (s), strlen((s))+1)
#define ADDINT(vp, i) vstring_sprintf_append((vp), "%lu", (unsigned long)(i))
ADDSTR(keybuf, dict_ldap->server_host);
ADDINT(keybuf, dict_ldap->server_port);
ADDINT(keybuf, dict_ldap->bind);
ADDSTR(keybuf, dict_ldap->bind ? dict_ldap->bind_dn : "");
ADDSTR(keybuf, dict_ldap->bind ? dict_ldap->bind_pw : "");
ADDINT(keybuf, dict_ldap->dereference);
ADDINT(keybuf, dict_ldap->chase_referrals);
ADDINT(keybuf, dict_ldap->debuglevel);
ADDINT(keybuf, dict_ldap->version);
#ifdef LDAP_API_FEATURE_X_OPENLDAP
ADDINT(keybuf, dict_ldap->ldap_ssl);
ADDINT(keybuf, dict_ldap->start_tls);
ADDINT(keybuf, sslon ? dict_ldap->tls_require_cert : 0);
ADDSTR(keybuf, sslon ? dict_ldap->tls_ca_cert_file : "");
ADDSTR(keybuf, sslon ? dict_ldap->tls_ca_cert_dir : "");
ADDSTR(keybuf, sslon ? dict_ldap->tls_cert : "");
ADDSTR(keybuf, sslon ? dict_ldap->tls_key : "");
ADDSTR(keybuf, sslon ? dict_ldap->tls_random_file : "");
ADDSTR(keybuf, sslon ? dict_ldap->tls_cipher_suite : "");
#endif
key = vstring_str(keybuf);
len = VSTRING_LEN(keybuf);
if (conn_hash == 0)
conn_hash = binhash_create(0);
if ((dict_ldap->ht = binhash_locate(conn_hash, key, len)) == 0) {
conn = (LDAP_CONN *) mymalloc(sizeof(LDAP_CONN));
conn->conn_ld = 0;
conn->conn_refcount = 0;
dict_ldap->ht = binhash_enter(conn_hash, key, len, (char *) conn);
}
++DICT_LDAP_CONN(dict_ldap)->conn_refcount;
vstring_free(keybuf);
}
/*
* expand a filter (lookup or result)
*/
@@ -907,6 +973,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
VSTRING *escaped_name = 0,
*filter_buf = 0;
int rc = 0;
int sizelimit;
char *sub,
*end;
@@ -923,11 +990,8 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
if (dict_ldap->domain) {
const char *p = strrchr(name, '@');
if (p != 0)
p = p + 1;
else
p = name;
if (match_list_match(dict_ldap->domain, p) == 0) {
if (p == 0 || p == name ||
match_list_match(dict_ldap->domain, ++p) == 0) {
if (msg_verbose)
msg_info("%s: domain of %s not found in domain list", myname,
name);
@@ -942,6 +1006,13 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
result = vstring_alloc(2);
vstring_strcpy(result, "");
/*
* Because the connection may be shared and invalidated via queries for
* another map, update private copy of "ld" from shared connection
* container.
*/
dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld;
/*
* Connect to the LDAP server, if necessary.
*/
@@ -962,6 +1033,18 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
msg_info("%s: Using existing connection for LDAP source %s",
myname, dict_ldap->ldapsource);
/*
* Connection caching, means that the connection handle may have the
* wrong size limit. Re-adjust before each query. This is cheap, just
* sets a field in the ldap connection handle. We also do this in the
* connect code, because we sometimes reconnect (below) in the middle of
* a query.
*/
sizelimit = dict_ldap->size_limit ? dict_ldap->size_limit : LDAP_NO_LIMIT;
if (ldap_set_option(dict_ldap->ld, LDAP_OPT_SIZELIMIT, &sizelimit)
!= LDAP_OPT_SUCCESS)
msg_warn("%s: %s: Unable to set query result size limit to %ld.",
myname, dict_ldap->ldapsource, dict_ldap->size_limit);
/*
* Prepare the query.
@@ -1046,7 +1129,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
myname, dict_ldap->ldapsource);
ldap_unbind(dict_ldap->ld);
dict_ldap->ld = NULL;
dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
dict_ldap_connect(dict_ldap);
/*
@@ -1098,7 +1181,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
* next lookup.
*/
ldap_unbind(dict_ldap->ld);
dict_ldap->ld = NULL;
dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
/*
* And tell the caller to try again later.
@@ -1129,10 +1212,18 @@ static void dict_ldap_close(DICT *dict)
{
char *myname = "dict_ldap_close";
DICT_LDAP *dict_ldap = (DICT_LDAP *) dict;
LDAP_CONN *conn = DICT_LDAP_CONN(dict_ldap);
BINHASH_INFO *ht = dict_ldap->ht;
if (dict_ldap->ld)
ldap_unbind(dict_ldap->ld);
if (--conn->conn_refcount == 0) {
if (conn->conn_ld) {
if (msg_verbose)
msg_info("%s: Closed connection handle for LDAP source %s",
myname, dict_ldap->ldapsource);
ldap_unbind(conn->conn_ld);
}
binhash_delete(conn_hash, ht->key, ht->key_len, myfree);
}
myfree(dict_ldap->ldapsource);
myfree(dict_ldap->server_host);
myfree(dict_ldap->search_base);
@@ -1272,6 +1363,11 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
}
}
dict_ldap->server_host = mystrdup(vstring_str(url_list) + 1);
/*
* With URL scheme, clear port to normalize connection cache key
*/
dict_ldap->server_port = 0;
if (msg_verbose)
msg_info("%s: %s server_host URL is %s", myname, ldapsource,
dict_ldap->server_host);
@@ -1534,6 +1630,11 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
dict_ldap->debuglevel);
#endif
/*
* Find or allocate shared LDAP connection container.
*/
dict_ldap_conn_find(dict_ldap);
/*
* Return the new dict_ldap structure.
*/