errors with opening a database. Files: smtpd/smtpd.c,
smtpd/smtpd_checks.c, smtpd/smtpd_error.in, smtpd/smtpd_error.ref.
- Cleanup: memory leak testing of error handling. Files:
- util/name_mask.c, util/cidr_mask.c.
+ Cleanup: memory leak testing of error handling. File:
+ util/name_mask.c.
+
+20111222
+
+ Cleanup: memory leak testing of error handling. File:
+ util/name_mask.c.
+
+ Cleanup: simplified the match_list error reporting, thereby
+ reducing the footprint of the changes to "catch" errors
+ with implicit database lookups in mynetworks, and other
+ lists. Files: util/match_ops.[hc], util/match_list.c,
+ global/addr_list_match.c, domain_list.c, string_list.c,
+ namadr_list.c, trivial-rewrite/resolve.c, smtpd/smtpd.c,
+ smtpd/smtpd_check.c, global/flush_clnt.c, flush/flush.c.
SMTP servers need to decide whether an SMTP client is authorized to send mail
to remote destinations, or only to destinations that the server itself is
-responsible for. Usually, SMTP servers allow mail to remote destinations when
+responsible for. Usually, SMTP servers accept mail to remote destinations when
the client's IP address is in the "same network" as the server's IP address.
SMTP clients outside the SMTP server's network need a different way to get
<p> SMTP servers need to decide whether an SMTP client is authorized
to send mail to remote destinations, or only to destinations that
-the server itself is responsible for. Usually, SMTP servers allow
+the server itself is responsible for. Usually, SMTP servers accept
mail to remote destinations when the client's IP address is in the
"same network" as the server's IP address. </p>
<p> SMTP servers need to decide whether an SMTP client is authorized
to send mail to remote destinations, or only to destinations that
-the server itself is responsible for. Usually, SMTP servers allow
+the server itself is responsible for. Usually, SMTP servers accept
mail to remote destinations when the client's IP address is in the
"same network" as the server's IP address. </p>
static int flush_policy_ok(const char *site)
{
- return (domain_list_match(flush_domains, site) > 0);
+ return (domain_list_match(flush_domains, site));
}
/* flush_add_service - append queue ID to per-site fast flush logfile */
tests: tok822_test mime_tests strip_addr_test tok822_limit_test \
xtext_test scache_multi_test ehlo_mask_test \
namadr_list_test mail_conf_time_test header_body_checks_tests \
- mail_version_test server_acl_test
+ mail_version_test server_acl_test resolve_local_test maps_test
mime_tests: mime_test mime_nest mime_8bit mime_dom mime_trunc mime_cvt \
mime_cvt2 mime_cvt3 mime_garb1 mime_garb2 mime_garb3 mime_garb4
diff server_acl.ref server_acl.tmp
rm -f server_acl.tmp
+resolve_local_test: resolve_local resolve_local.in resolve_local.ref
+ sh resolve_local.in >resolve_local.tmp 2>&1
+ diff resolve_local.ref resolve_local.tmp
+ rm -f resolve_local.tmp
+
+maps_test: maps maps.in maps.ref
+ sh maps.in >maps.tmp 2>&1
+ diff maps.ref maps.tmp
+ rm -f maps.tmp
+
# Requires: Postfix running, root privileges
rewrite_clnt_test: rewrite_clnt rewrite_clnt.in rewrite_clnt.ref
abounce.o: mail_proto.h
abounce.o: msg_stats.h
abounce.o: recipient_list.h
+addr_match_list.o: ../../include/argv.h
+addr_match_list.o: ../../include/dict.h
addr_match_list.o: ../../include/match_list.h
addr_match_list.o: ../../include/match_ops.h
addr_match_list.o: ../../include/sys_defs.h
+addr_match_list.o: ../../include/vbuf.h
+addr_match_list.o: ../../include/vstream.h
+addr_match_list.o: ../../include/vstring.h
addr_match_list.o: addr_match_list.c
addr_match_list.o: addr_match_list.h
anvil_clnt.o: ../../include/attr.h
db_common.o: db_common.c
db_common.o: db_common.h
db_common.o: string_list.h
+debug_peer.o: ../../include/argv.h
+debug_peer.o: ../../include/dict.h
debug_peer.o: ../../include/match_list.h
debug_peer.o: ../../include/match_ops.h
debug_peer.o: ../../include/msg.h
debug_peer.o: ../../include/sys_defs.h
+debug_peer.o: ../../include/vbuf.h
+debug_peer.o: ../../include/vstream.h
+debug_peer.o: ../../include/vstring.h
debug_peer.o: debug_peer.c
debug_peer.o: debug_peer.h
debug_peer.o: mail_params.h
dict_sqlite.o: dict_sqlite.c
dict_sqlite.o: dict_sqlite.h
dict_sqlite.o: string_list.h
+domain_list.cdebug_peer.o: domain_list.cdebug_peer.c
+domain_list.o: ../../include/argv.h
+domain_list.o: ../../include/dict.h
domain_list.o: ../../include/match_list.h
domain_list.o: ../../include/match_ops.h
domain_list.o: ../../include/sys_defs.h
+domain_list.o: ../../include/vbuf.h
+domain_list.o: ../../include/vstream.h
+domain_list.o: ../../include/vstring.h
domain_list.o: domain_list.c
domain_list.o: domain_list.h
dot_lockfile.o: ../../include/iostuff.h
file_id.o: file_id.h
file_id.o: mail_queue.h
file_id.o: safe_ultostr.h
+flush_clnt.o: ../../include/argv.h
flush_clnt.o: ../../include/attr.h
+flush_clnt.o: ../../include/dict.h
flush_clnt.o: ../../include/iostuff.h
flush_clnt.o: ../../include/match_list.h
flush_clnt.o: ../../include/match_ops.h
flush_clnt.o: ../../include/sys_defs.h
flush_clnt.o: ../../include/vbuf.h
flush_clnt.o: ../../include/vstream.h
+flush_clnt.o: ../../include/vstring.h
flush_clnt.o: domain_list.h
flush_clnt.o: flush_clnt.c
flush_clnt.o: flush_clnt.h
mark_corrupt.o: mark_corrupt.h
mark_corrupt.o: msg_stats.h
mark_corrupt.o: recipient_list.h
+match_parent_style.o: ../../include/argv.h
+match_parent_style.o: ../../include/dict.h
match_parent_style.o: ../../include/match_list.h
match_parent_style.o: ../../include/match_ops.h
match_parent_style.o: ../../include/sys_defs.h
+match_parent_style.o: ../../include/vbuf.h
+match_parent_style.o: ../../include/vstream.h
+match_parent_style.o: ../../include/vstring.h
match_parent_style.o: mail_params.h
match_parent_style.o: match_parent_style.c
match_parent_style.o: match_parent_style.h
mime_state.o: mime_state.c
mime_state.o: mime_state.h
mime_state.o: rec_type.h
-mkmap_cdb.o: ../../include/argv.h
-mkmap_cdb.o: ../../include/dict.h
-mkmap_cdb.o: ../../include/dict_cdb.h
-mkmap_cdb.o: ../../include/mymalloc.h
mkmap_cdb.o: ../../include/sys_defs.h
-mkmap_cdb.o: ../../include/vbuf.h
-mkmap_cdb.o: ../../include/vstream.h
-mkmap_cdb.o: ../../include/vstring.h
-mkmap_cdb.o: mkmap.h
mkmap_cdb.o: mkmap_cdb.c
mkmap_db.o: ../../include/argv.h
mkmap_db.o: ../../include/dict.h
mypwd.o: ../../include/sys_defs.h
mypwd.o: mypwd.c
mypwd.o: mypwd.h
+namadr_list.o: ../../include/argv.h
+namadr_list.o: ../../include/dict.h
namadr_list.o: ../../include/match_list.h
namadr_list.o: ../../include/match_ops.h
namadr_list.o: ../../include/sys_defs.h
+namadr_list.o: ../../include/vbuf.h
+namadr_list.o: ../../include/vstream.h
+namadr_list.o: ../../include/vstring.h
namadr_list.o: namadr_list.c
namadr_list.o: namadr_list.h
off_cvt.o: ../../include/msg.h
resolve_clnt.o: mail_proto.h
resolve_clnt.o: resolve_clnt.c
resolve_clnt.o: resolve_clnt.h
+resolve_local.o: ../../include/argv.h
+resolve_local.o: ../../include/dict.h
resolve_local.o: ../../include/inet_addr_list.h
resolve_local.o: ../../include/match_list.h
resolve_local.o: ../../include/match_ops.h
resolve_local.o: ../../include/mymalloc.h
resolve_local.o: ../../include/sys_defs.h
resolve_local.o: ../../include/valid_hostname.h
+resolve_local.o: ../../include/vbuf.h
+resolve_local.o: ../../include/vstream.h
+resolve_local.o: ../../include/vstring.h
resolve_local.o: mail_params.h
resolve_local.o: own_inet_addr.h
resolve_local.o: resolve_local.c
sent.o: sent.h
sent.o: trace.h
sent.o: verify.h
+server_acl.o: ../../include/argv.h
+server_acl.o: ../../include/dict.h
server_acl.o: ../../include/match_list.h
server_acl.o: ../../include/match_ops.h
server_acl.o: ../../include/msg.h
server_acl.o: ../../include/stringops.h
server_acl.o: ../../include/sys_defs.h
server_acl.o: ../../include/vbuf.h
+server_acl.o: ../../include/vstream.h
server_acl.o: ../../include/vstring.h
server_acl.o: addr_match_list.h
server_acl.o: mail_params.h
server_acl.o: match_parent_style.h
server_acl.o: server_acl.c
+server_acl.o: server_acl.h
smtp_reply_footer.o: ../../include/mac_expand.h
smtp_reply_footer.o: ../../include/mac_parse.h
smtp_reply_footer.o: ../../include/msg.h
stream2rec.o: rec_type.h
stream2rec.o: record.h
stream2rec.o: stream2rec.c
+string_list.o: ../../include/argv.h
+string_list.o: ../../include/dict.h
string_list.o: ../../include/match_list.h
string_list.o: ../../include/match_ops.h
string_list.o: ../../include/sys_defs.h
+string_list.o: ../../include/vbuf.h
+string_list.o: ../../include/vstream.h
+string_list.o: ../../include/vstring.h
string_list.o: string_list.c
string_list.o: string_list.h
strip_addr.o: ../../include/mymalloc.h
/* addr_match_list_init() performs initializations. The first
/* argument is the bit-wise OR of zero or more of the following:
/* .IP MATCH_FLAG_RETURN
-/* Request that addr_match_list_match() returns a negative result
-/* (MATCH_ERR_TEMP or MATCH_ERR_PERM), instead of raising a fatal
-/* error.
+/* Request that addr_match_list_match() returns zero with
+/* dict_errno != 0, instead of raising a fatal error.
/* .PP
/* Specify MATCH_FLAG_NONE to request none of the above.
/* The second argument is a list of patterns, or the absolute
ADDR_MATCH_LIST *list;
char *addr;
int ch;
- int rc;
msg_vstream_init(argv[0], VSTREAM_ERR);
if (strcmp(addr, "-") == 0) {
VSTRING *buf = vstring_alloc(100);
- while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) {
- rc = addr_match_list_match(list, vstring_str(buf));
+ while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF)
vstream_printf("%s: %s\n", vstring_str(buf),
- rc > 0 ? "YES" : rc == 0 ? "NO" : "ERROR");
- }
+ addr_match_list_match(list, vstring_str(buf)) ?
+ "YES" : dict_errno == 0 ? "NO" : "ERROR");
vstring_free(buf);
} else {
- rc = addr_match_list_match(list, addr);
vstream_printf("%s: %s\n", addr,
- rc > 0 ? "YES" : rc == 0 ? "NO" : "ERROR");
+ addr_match_list_match(list, addr) > 0 ?
+ "YES" : dict_errno == 0 ? "NO" : "ERROR");
}
vstream_fflush(VSTREAM_OUT);
addr_match_list_free(list);
*/
if (debug_peer_list != 0
&& saved_level == UNUSED_SAVED_LEVEL
- && namadr_list_match(debug_peer_list, name, addr) > 0) {
+ && namadr_list_match(debug_peer_list, name, addr) != 0) {
saved_level = msg_verbose;
msg_verbose += var_debug_peer_level;
return (1);
/* domain_list_init() performs initializations. The first argument
/* is the bit-wise OR of zero or more of the following:
/* .IP MATCH_FLAG_PARENT
-/* The hostname pattern foo.com matches itself and any name below
+/* The hostname pattern foo.com matches itself and any name below
/* the domain foo.com. If this flag is cleared, foo.com matches itself
/* only, and .foo.com matches any name below the domain foo.com.
/* .IP MATCH_FLAG_RETURN
-/* Request that domain_list_match() returns a negative result
-/* (MATCH_ERR_TEMP or MATCH_ERR_PERM), instead of raising a
-/* fatal error.
+/* Request that domain_list_match() returns zero with
+/* dict_errno != 0, instead of raising a fatal error.
/* .PP
/* Specify MATCH_FLAG_NONE to request none of the above.
/* The second argument is a list of domain patterns, or the name of
DOMAIN_LIST *list;
char *host;
int ch;
- int rc;
msg_vstream_init(argv[0], VSTREAM_ERR);
usage(argv[0]);
list = domain_list_init(MATCH_FLAG_PARENT | MATCH_FLAG_RETURN, argv[optind]);
host = argv[optind + 1];
- rc = domain_list_match(list, host);
- vstream_printf("%s: %s\n", host,
- rc > 0 ? "YES" : rc == 0 ? "NO" : "ERROR");
+ vstream_printf("%s: %s\n", host, domain_list_match(list, host) ?
+ "YES" : dict_errno == 0 ? "NO" : "ERROR");
vstream_fflush(VSTREAM_OUT);
domain_list_free(list);
return (0);
{
const char *myname = "flush_send_site";
int status;
- int rc;
if (msg_verbose)
msg_info("%s: site %s", myname, site);
*/
if (flush_domains == 0)
msg_panic("missing flush client initialization");
- if ((rc = domain_list_match(flush_domains, site)) == 0)
- status = FLUSH_STAT_DENY;
- else if (rc > 0)
+ if (domain_list_match(flush_domains, site) != 0)
status = mail_command_client(MAIL_CLASS_PUBLIC, var_flush_service,
ATTR_TYPE_STR, MAIL_ATTR_REQ, FLUSH_REQ_SEND_SITE,
ATTR_TYPE_STR, MAIL_ATTR_SITE, site,
ATTR_TYPE_END);
+ else if (dict_errno == 0)
+ status = FLUSH_STAT_DENY;
else
status = FLUSH_STAT_FAIL;
{
const char *myname = "flush_add";
int status;
- int rc;
if (msg_verbose)
msg_info("%s: site %s id %s", myname, site, queue_id);
*/
if (flush_domains == 0)
msg_panic("missing flush client initialization");
- if ((rc = domain_list_match(flush_domains, site)) == 0)
- status = FLUSH_STAT_DENY;
- else if (rc > 0)
+ if (domain_list_match(flush_domains, site) != 0)
status = mail_command_client(MAIL_CLASS_PUBLIC, var_flush_service,
ATTR_TYPE_STR, MAIL_ATTR_REQ, FLUSH_REQ_ADD,
ATTR_TYPE_STR, MAIL_ATTR_SITE, site,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
ATTR_TYPE_END);
+ else if (dict_errno == 0)
+ status = FLUSH_STAT_DENY;
else
status = FLUSH_STAT_FAIL;
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20111221"
+#define MAIL_RELEASE_DATE "20111222"
#define MAIL_VERSION_NUMBER "2.9"
#ifdef SNAPSHOT
const char *expansion;
DICT *dict;
+ /*
+ * In case of return without map lookup (empty name or no maps).
+ */
+ dict_errno = 0;
+
/*
* Temp. workaround, for buggy callers that pass zero-length keys when
* given partial addresses.
maps = maps_create("whatever", argv[1], DICT_FLAG_LOCK);
while (vstring_fgets_nonl(buf, VSTREAM_IN)) {
+ dict_errno = 99;
+ vstream_printf("\"%s\": ", vstring_str(buf));
if ((result = maps_find(maps, vstring_str(buf), 0)) != 0) {
vstream_printf("%s\n", result);
} else if (dict_errno != 0) {
- msg_fatal("lookup error: %m");
+ vstream_printf("lookup error\n");
} else {
vstream_printf("not found\n");
}
--- /dev/null
+./maps fail:1maps <<EOF
+
+foobar
+EOF
--- /dev/null
+unknown: dict_open: fail:1maps
+unknown: dict_register: fail:1maps(0,lock) 1
+"": not found
+unknown: maps_find: whatever: foobar: search aborted
+"foobar": lookup error
+unknown: maps_free: fail:1maps(0,lock)
+unknown: dict_unregister: fail:1maps(0,lock) 1
/* the domain foo.com. If this flag is cleared, foo.com matches itself
/* only, and .foo.com matches any name below the domain foo.com.
/* .IP MATCH_FLAG_RETURN
-/* Request that namadr_list_match() returns a negative result
-/* (MATCH_ERR_TEMP or MATCH_ERR_PERM), instead of raising a
-/* fatal error.
+/* Request that namadr_list_match() returns zero with
+/* dict_errno != 0, instead of raising a fatal error.
/* .PP
/* Specify MATCH_FLAG_NONE to request none of the above.
/* The second argument is a list of patterns, or the absolute
char *host;
char *addr;
int ch;
- int rc;
msg_vstream_init(argv[0], VSTREAM_ERR);
list = namadr_list_init(MATCH_FLAG_PARENT | MATCH_FLAG_RETURN, argv[optind]);
host = argv[optind + 1];
addr = argv[optind + 2];
- rc = namadr_list_match(list, host, addr);
vstream_printf("%s/%s: %s\n", host, addr,
- rc > 0 ? "YES" : rc == 0 ? "NO" : "ERROR");
+ namadr_list_match(list, host, addr) ?
+ "YES" : dict_errno == 0 ? "NO" : "ERROR");
vstream_fflush(VSTREAM_OUT);
namadr_list_free(list);
return (0);
/* against the domains, files or tables listed in $mydestination,
/* or by a match of an [address-literal] against of the network
/* addresses listed in $inet_interfaces or in $proxy_interfaces.
+/* The result is non-zero if the domain matches the list of local
+/* domains and IP addresses, 0 when it does not match or in case
+/* of error (in the latter case dict_errno is non-zero).
/*
/* resolve_local_init() performs initialization. If this routine is
/* not called explicitly ahead of time, it will be called on the fly.
void resolve_local_init(void)
{
+ /* Allow on-the-fly update to make testing easier. */
if (resolve_local_list)
- msg_panic("resolve_local_init: duplicate initialization");
- resolve_local_list = string_list_init(MATCH_FLAG_NONE, var_mydest);
+ string_list_free(resolve_local_list);
+ resolve_local_list = string_list_init(MATCH_FLAG_RETURN, var_mydest);
}
/* resolve_local - match domain against list of local destinations */
if (resolve_local_list == 0)
resolve_local_init();
+ /*
+ * In case of return without table lookup (empty address, malformed
+ * address, empty destination list)
+ */
+ dict_errno = 0;
+
/*
* Strip one trailing dot but not dot-dot.
*
*/
if (string_list_match(resolve_local_list, saved_addr))
RETURN(1);
+ if (dict_errno != 0)
+ RETURN(0);
/*
* Compare the destination against the list of interface addresses that
int main(int argc, char **argv)
{
- if (argc != 2)
- msg_fatal("usage: %s domain", argv[0]);
+ if (argc != 3)
+ msg_fatal("usage: %s mydestination domain", argv[0]);
mail_conf_read();
- vstream_printf("%s\n", resolve_local(argv[1]) ? "yes" : "no");
+ myfree(var_mydest);
+ var_mydest = mystrdup(argv[1]);
+ dict_errno = 99;
+ vstream_printf("mydestination=%s destination=%s %s\n",
+ argv[1], argv[2], resolve_local(argv[2]) ? "YES" :
+ dict_errno == 0 ? "NO" : "ERROR");
vstream_fflush(VSTREAM_OUT);
return (0);
}
/* DESCRIPTION
/* .nf
+ /*
+ * Utility library.
+ */
+#include <dict.h>
+
/*
* External interface.
*/
--- /dev/null
+./resolve_local example.com example.com
+./resolve_local example.net example.com
+./resolve_local fail:1_resolve_local example.com
+./resolve_local fail:1_resolve_local example.com..
+./resolve_local fail:1_resolve_local ''
--- /dev/null
+mydestination=example.com destination=example.com YES
+mydestination=example.net destination=example.com NO
+unknown: warning: fail:1_resolve_local(0,lock|fold_fix): table lookup problem
+mydestination=fail:1_resolve_local destination=example.com ERROR
+mydestination=fail:1_resolve_local destination=example.com.. NO
+mydestination=fail:1_resolve_local destination= NO
{
if (server_acl_mynetworks)
addr_match_list_free(server_acl_mynetworks);
- server_acl_mynetworks =
+ server_acl_mynetworks =
addr_match_list_init(MATCH_FLAG_RETURN | match_parent_style(origin),
- mynetworks);
+ mynetworks);
}
/* server_acl_parse - parse access list */
} else {
if (dict_handle(acl) == 0)
dict_register(acl, dict_open(acl, O_RDONLY, DICT_FLAG_LOCK
- | DICT_FLAG_FOLD_FIX));
+ | DICT_FLAG_FOLD_FIX));
}
}
argv_add(intern_acl, acl, (char *) 0);
const char *acl;
const char *dict_val;
int ret;
- int rc;
for (cpp = intern_acl->argv; (acl = *cpp) != 0; cpp++) {
if (msg_verbose)
} else if (STREQ(acl, SERVER_ACL_NAME_PERMIT)) {
return (SERVER_ACL_ACT_PERMIT);
} else if (STREQ(acl, SERVER_ACL_NAME_WL_MYNETWORKS)) {
- rc = addr_match_list_match(server_acl_mynetworks, client_addr);
- if (rc > 0)
+ if (addr_match_list_match(server_acl_mynetworks, client_addr))
return (SERVER_ACL_ACT_PERMIT);
- if (rc < 0) {
+ if (dict_errno != 0) {
msg_warn("%s: %s: mynetworks lookup error -- ignoring the "
"remainder of this access list", origin, acl);
return (SERVER_ACL_ACT_ERROR);
/* string_list_init() performs initializations. The first argument
/* is a bit-wise OR of zero or more of following:
/* .IP MATCH_FLAG_RETURN
-/* Request that string_list_match() returns a negative result
-/* (MATCH_ERR_TEMP or MATCH_ERR_PERM), instead of raising a fatal
-/* error.
+/* Request that string_list_match() returns zero with
+/* dict_errno != 0, instead of raising a fatal error.
/* .PP
/* Specify MATCH_FLAG_NONE to request none of the above.
/* The second argument specifies a list of string patterns.
STRING_LIST *list;
char *string;
int ch;
- int rc;
msg_vstream_init(argv[0], VSTREAM_ERR);
usage(argv[0]);
list = string_list_init(MATCH_FLAG_NONE | MATCH_FLAG_RETURN, argv[optind]);
string = argv[optind + 1];
- rc = string_list_match(list, string);
- vstream_printf("%s: %s\n", string,
- rc > 0 ? "YES" : rc == 0 ? "NO" : "ERROR");
+ vstream_printf("%s: %s\n", string, string_list_match(list, string) ?
+ "YES" : dict_errno == 0 ? "NO" : "ERROR");
vstream_fflush(VSTREAM_OUT);
string_list_free(list);
return (0);
static void qmqpd_proto(QMQPD_STATE *state)
{
int status;
- int rc;
netstring_setup(state->client, var_qmqpd_timeout);
/*
* See if we want to talk to this client at all.
*/
- rc = namadr_list_match(qmqpd_clients, state->name, state->addr);
- if (rc > 0) {
+ if (namadr_list_match(qmqpd_clients, state->name, state->addr) != 0) {
qmqpd_receive(state);
- } else if (rc == 0) {
+ } else if (dict_errno == 0) {
qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD,
"Error: %s is not authorized to use this service",
state->namaddr);
smtpd_check.o: ../../include/record.h
smtpd_check.o: ../../include/resolve_clnt.h
smtpd_check.o: ../../include/resolve_local.h
-smtpd_check.o: ../../include/rewrite_clnt.h
smtpd_check.o: ../../include/sock_addr.h
smtpd_check.o: ../../include/split_at.h
smtpd_check.o: ../../include/string_list.h
static int permit_mynetworks(SMTPD_STATE *state)
{
const char *myname = "permit_mynetworks";
- int rc;
if (msg_verbose)
msg_info("%s: %s %s", myname, state->name, state->addr);
- if ((rc = namadr_list_match(mynetworks, state->name, state->addr)) > 0)
+ if (namadr_list_match(mynetworks, state->name, state->addr))
return (SMTPD_CHECK_OK);
- else if (rc == 0)
+ else if (dict_errno == 0)
return (SMTPD_CHECK_DUNNO);
else
return (SMTPD_CHECK_ERROR);
DNS_RR *rr;
DNS_RR *addr_list;
int dns_status;
- int rc;
if (msg_verbose)
msg_info("%s: host %s", myname, host);
if (msg_verbose)
msg_info("%s: checking: %s", myname, hostaddr.buf);
- rc = namadr_list_match(perm_mx_networks, host, hostaddr.buf);
- if (rc == 0) {
+ if (!namadr_list_match(perm_mx_networks, host, hostaddr.buf)) {
+ if (dict_errno == 0) {
- /*
- * Reject: at least one IP address is not listed in
- * permit_mx_backup_networks.
- */
- if (msg_verbose)
- msg_info("%s: address %s for %s does not match %s",
- myname, hostaddr.buf, host, VAR_PERM_MX_NETWORKS);
+ /*
+ * Reject: at least one IP address is not listed in
+ * permit_mx_backup_networks.
+ */
+ if (msg_verbose)
+ msg_info("%s: address %s for %s does not match %s",
+ myname, hostaddr.buf, host, VAR_PERM_MX_NETWORKS);
+ } else {
+ msg_warn("%s: %s lookup error for address %s for %s",
+ myname, VAR_PERM_MX_NETWORKS, hostaddr.buf, host);
+ DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
+ 450, "4.4.4",
+ "<%s>: %s rejected: Unable to verify host %s as mail exchanger",
+ reply_name, reply_class, host);
+ }
dns_rr_free(addr_list);
return (NOPE);
- } else if (rc < 0) {
- msg_warn("%s: %s lookup error for address %s for %s",
- myname, VAR_PERM_MX_NETWORKS, hostaddr.buf, host);
- DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
- 450, "4.4.4",
- "<%s>: %s rejected: Unable to verify host %s as mail exchanger",
- reply_name, reply_class, host);
- return (NOPE);
}
}
dns_rr_free(addr_list);
msg_info("%s: resolve hostname: %s", myname, (char *) mx->data);
if (resolve_local((char *) mx->data))
return (YUP);
+ /* if no match or error, match interface addresses instead. */
}
/*
reply->flags = RESOLVE_CLASS_LOCAL;
vstring_strcpy(reply->transport, MAIL_SERVICE_LOCAL);
vstring_strcpy(reply->nexthop, domain);
+ } else if (dict_errno) {
+ reply->flags = RESOLVE_FLAG_FAIL;
} else if (string_list_match(virt_alias_doms, domain)) {
reply->flags = RESOLVE_CLASS_ALIAS;
vstring_strcpy(reply->transport, MAIL_SERVICE_ERROR);
vstring_strcpy(reply->nexthop, "user unknown");
+ } else if (dict_errno) {
+ reply->flags = RESOLVE_FLAG_FAIL;
} else if (string_list_match(virt_mailbox_doms, domain)) {
reply->flags = RESOLVE_CLASS_VIRTUAL;
vstring_strcpy(reply->transport, MAIL_SERVICE_VIRTUAL);
vstring_strcpy(reply->nexthop, domain);
+ } else if (dict_errno) {
+ reply->flags = RESOLVE_FLAG_FAIL;
} else if (domain_list_match(relay_domains, domain)) {
reply->flags = RESOLVE_CLASS_RELAY;
vstring_strcpy(reply->transport, MAIL_SERVICE_RELAY);
vstring_strcpy(reply->nexthop, domain);
+ } else if (dict_errno) {
+ reply->flags = RESOLVE_FLAG_FAIL;
} else {
reply->flags = RESOLVE_CLASS_DEFAULT;
vstring_strcpy(reply->transport, MAIL_SERVICE_SMTP);
ptr = string_list_init(MATCH_FLAG_NONE, val); }
case 2:
+ if (strcasecmp(args->argv[0], VAR_MYDEST) == 0) {
+ UPDATE_STRING(var_mydest, args->argv[1]);
+ resolve_local_init();
+ resp = 0;
+ break;
+ }
if (strcasecmp(args->argv[0], VAR_VIRT_ALIAS_MAPS) == 0) {
UPDATE_STRING(var_virt_alias_maps, args->argv[1]);
UPDATE_MAPS(virt_alias_maps, VAR_VIRT_ALIAS_MAPS,
# Expect: REJECT (temporary lookup failure)
#
rewrite
+#
+# Test resolve_local()
+#
+mydestination example.com
+recipient_restrictions reject_unauth_destination
+rcpt user@example.com
+mydestination fail:1_mydestination
+rcpt user@example.com
+#
+# Test virtual alias lookup.
+#
+mydestination example.com
+virtual_alias_maps fail:1_virtual
+rcpt user@example.com
./smtpd_check: warning: local_header_rewrite_clients: fail:1_rewrite: lookup error
./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 Temporary lookup error; from=<> proto=SMTP helo=<foobar>
451 4.3.0 Temporary lookup error
+>>> #
+>>> # Test resolve_local()
+>>> #
+>>> mydestination example.com
+OK
+>>> recipient_restrictions reject_unauth_destination
+OK
+>>> rcpt user@example.com
+OK
+>>> mydestination fail:1_mydestination
+OK
+>>> rcpt user@example.com
+./smtpd_check: warning: fail:1_mydestination(0,lock|fold_fix): table lookup problem
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 <user@example.com>: Temporary lookup failure; from=<> to=<user@example.com> proto=SMTP helo=<foobar>
+451 4.3.0 <user@example.com>: Temporary lookup failure
+>>> #
+>>> # Test virtual alias lookup.
+>>> #
+>>> mydestination example.com
+OK
+>>> virtual_alias_maps fail:1_virtual
+OK
+>>> rcpt user@example.com
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 <user@example.com>: Temporary lookup failure; from=<> to=<user@example.com> proto=SMTP helo=<foobar>
+451 4.3.0 <user@example.com>: Temporary lookup failure
const char *relay;
const char *xport;
const char *sender_key;
- int rc;
*flags = 0;
vstring_strcpy(channel, "CHANNEL NOT UPDATED");
#define RESOLVE_LOCAL(domain) \
resolve_local(STR(tok822_internalize(addr_buf, domain, TOK822_STR_DEFL)))
- dict_errno = 0;
-
for (loop_count = 0, loop_max = addr_len + 100; /* void */ ; loop_count++) {
- /*
- * Grr. resolve_local() table lookups may fail. It may be OK for
- * local file lookup code to abort upon failure, but with
- * network-based tables it is preferable to return an error
- * indication to the requestor.
- */
- if (dict_errno) {
- *flags |= RESOLVE_FLAG_FAIL;
- FREE_MEMORY_AND_RETURN;
- }
-
/*
* XXX Should never happen, but if this happens with some
* pathological address, then that is not sufficient reason to
/*
* Strip (and save) @domain if local.
+ *
+ * Grr. resolve_local() table lookups may fail. It may be OK for local
+ * file lookup code to abort upon failure, but with network-based
+ * tables it is preferable to return an error indication to the
+ * requestor.
*/
if ((domain = tok822_rfind_type(tree->tail, '@')) != 0) {
- if (domain->next && RESOLVE_LOCAL(domain->next) == 0)
+ if (domain->next && RESOLVE_LOCAL(domain->next) == 0) {
+ if (dict_errno != 0) {
+ *flags |= RESOLVE_FLAG_FAIL;
+ FREE_MEMORY_AND_RETURN;
+ }
break;
+ }
tok822_sub_keep_before(tree, domain);
if (saved_domain)
tok822_free_tree(saved_domain);
rcpt_domain = strrchr(STR(nextrcpt), '@') + 1;
if (resolve_local(rcpt_domain)) /* XXX */
domain = 0;
+ else if (dict_errno != 0)
+ *flags |= RESOLVE_FLAG_FAIL;
} else {
*flags |= RESOLVE_FLAG_ERROR;
}
* Virtual alias domain.
*/
if (virt_alias_doms
- && (rc = string_list_match(virt_alias_doms, rcpt_domain)) > 0) {
+ && string_list_match(virt_alias_doms, rcpt_domain)) {
if (var_helpful_warnings) {
if (virt_mailbox_doms
- && string_list_match(virt_mailbox_doms, rcpt_domain) > 0)
+ && string_list_match(virt_mailbox_doms, rcpt_domain))
msg_warn("do not list domain %s in BOTH %s and %s",
rcpt_domain, VAR_VIRT_ALIAS_DOMS,
VAR_VIRT_MAILBOX_DOMS);
if (relay_domains
- && domain_list_match(relay_domains, rcpt_domain) > 0)
+ && domain_list_match(relay_domains, rcpt_domain))
msg_warn("do not list domain %s in BOTH %s and %s",
rcpt_domain, VAR_VIRT_ALIAS_DOMS,
VAR_RELAY_DOMAINS);
var_show_unk_rcpt_table ?
" in virtual alias table" : "");
*flags |= RESOLVE_CLASS_ALIAS;
- } else if (dict_errno != 0 || rc < 0) {
+ } else if (dict_errno != 0) {
msg_warn("%s lookup failure", VAR_VIRT_ALIAS_DOMS);
*flags |= RESOLVE_FLAG_FAIL;
FREE_MEMORY_AND_RETURN;
* Virtual mailbox domain.
*/
else if (virt_mailbox_doms
- && (rc = string_list_match(virt_mailbox_doms, rcpt_domain)) > 0) {
+ && string_list_match(virt_mailbox_doms, rcpt_domain)) {
if (var_helpful_warnings) {
if (relay_domains
- && domain_list_match(relay_domains, rcpt_domain) > 0)
+ && domain_list_match(relay_domains, rcpt_domain))
msg_warn("do not list domain %s in BOTH %s and %s",
rcpt_domain, VAR_VIRT_MAILBOX_DOMS,
VAR_RELAY_DOMAINS);
vstring_strcpy(nexthop, rcpt_domain);
blame = rp->virt_transport_name;
*flags |= RESOLVE_CLASS_VIRTUAL;
- } else if (dict_errno != 0 || rc < 0) {
+ } else if (dict_errno != 0) {
msg_warn("%s lookup failure", VAR_VIRT_MAILBOX_DOMS);
*flags |= RESOLVE_FLAG_FAIL;
FREE_MEMORY_AND_RETURN;
* Off-host relay destination.
*/
if (relay_domains
- && (rc = domain_list_match(relay_domains, rcpt_domain)) > 0) {
+ && domain_list_match(relay_domains, rcpt_domain)) {
vstring_strcpy(channel, RES_PARAM_VALUE(rp->relay_transport));
blame = rp->relay_transport_name;
*flags |= RESOLVE_CLASS_RELAY;
- } else if (dict_errno != 0 || rc < 0) {
+ } else if (dict_errno != 0) {
msg_warn("%s lookup failure", VAR_RELAY_DOMAINS);
*flags |= RESOLVE_FLAG_FAIL;
FREE_MEMORY_AND_RETURN;
else {
if (var_helpful_warnings) {
if (virt_alias_doms
- && string_list_match(virt_alias_doms, rcpt_domain) > 0)
+ && string_list_match(virt_alias_doms, rcpt_domain))
msg_warn("do not list domain %s in BOTH %s and %s",
rcpt_domain, VAR_MYDEST, VAR_VIRT_ALIAS_DOMS);
if (virt_mailbox_doms
- && string_list_match(virt_mailbox_doms, rcpt_domain) > 0)
+ && string_list_match(virt_mailbox_doms, rcpt_domain))
msg_warn("do not list domain %s in BOTH %s and %s",
rcpt_domain, VAR_MYDEST, VAR_VIRT_MAILBOX_DOMS);
}
if (*var_relay_domains)
relay_domains =
- domain_list_init(MATCH_FLAG_RETURN
+ domain_list_init(MATCH_FLAG_RETURN
| match_parent_style(VAR_RELAY_DOMAINS),
var_relay_domains);
MAI_HOSTADDR_STR hostaddr;
unsigned char *np;
unsigned char *mp;
- static VSTRING *buf;
-
-#define WHY_OR_BUF (why ? why : buf ? (why = buf) : \
- (why = buf = vstring_alloc(20)))
/*
* Strip [] from [addr/len] or [addr]/len, destroying the pattern. CIDR
if (*pattern == '[') {
pattern++;
if ((mask_search = split_at(pattern, ']')) == 0) {
- vstring_sprintf(WHY_OR_BUF,
+ vstring_sprintf(why ? why : (why = vstring_alloc(20)),
"missing ']' character after \"[%s\"", pattern);
return (why);
} else if (*mask_search != '/') {
if (*mask_search != 0) {
- vstring_sprintf(WHY_OR_BUF, "garbage after \"[%s]\"", pattern);
+ vstring_sprintf(why ? why : (why = vstring_alloc(20)),
+ "garbage after \"[%s]\"", pattern);
return (why);
}
mask_search = pattern;
if (!alldig(mask)
|| (ip->mask_shift = atoi(mask)) > ip->addr_bit_count
|| inet_pton(ip->addr_family, pattern, ip->net_bytes) != 1) {
- vstring_sprintf(WHY_OR_BUF,
+ vstring_sprintf(why ? why : (why = vstring_alloc(20)),
"bad net/mask pattern: \"%s/%s\"", pattern, mask);
return (why);
}
if (inet_ntop(ip->addr_family, ip->net_bytes, hostaddr.buf,
sizeof(hostaddr.buf)) == 0)
msg_fatal("inet_ntop: %m");
- vstring_sprintf(WHY_OR_BUF,
+ vstring_sprintf(why ? why : (why = vstring_alloc(20)),
"non-null host address bits in \"%s/%s\", "
"perhaps you should use \"%s/%d\" instead",
pattern, mask, hostaddr.buf, ip->mask_shift);
ip->addr_bit_count = CIDR_MATCH_ADDR_BIT_COUNT(ip->addr_family);
ip->addr_byte_count = CIDR_MATCH_ADDR_BYTE_COUNT(ip->addr_family);
if (inet_pton(ip->addr_family, pattern, ip->net_bytes) != 1) {
- vstring_sprintf(WHY_OR_BUF, "bad address pattern: \"%s\"", pattern);
+ vstring_sprintf(why ? why : (why = vstring_alloc(20)),
+ "bad address pattern: \"%s\"", pattern);
return (why);
}
ip->mask_shift = ip->addr_bit_count;
#define DICT_ERR_NONE 0 /* no error */
#define DICT_ERR_RETRY 1 /* soft error */
+#define DICT_ERR_CONFIG 2 /* configuration error */
/*
* Sequence function types.
/* foo.com. If this flag is cleared, foo.com matches itself
/* only, and .foo.com matches any name below the domain foo.com.
/* .IP MATCH_FLAG_RETURN
-/* Return a negative result (MATCH_ERR_TEMP or MATCH_ERR_FAIL)
-/* instead of raising a fatal run-time error.
+/* Request that match_list_match() returns zero (with dict_errno
+/* set) instead of raising a fatal run-time error.
/* .RE
/* Specify MATCH_FLAG_NONE to request none of the above.
/* The pattern_list argument specifies a list of patterns. The third
int match;
int i;
va_list ap;
- int rc;
/*
* Iterate over all patterns in the list, stop at the first match.
for (match = 1; *pat == '!'; pat++)
match = !match;
for (i = 0; i < list->match_count; i++)
- if ((rc = list->match_func[i] (list->flags,
- list->match_args[i], pat)) > 0)
+ if (list->match_func[i] (list->flags, list->match_args[i], pat))
return (match);
- else if (rc < 0)
- return (rc);
+ else if (dict_errno != 0)
+ return (0);
}
if (msg_verbose)
for (i = 0; i < list->match_count; i++)
/* the domain foo.com. If this flag is cleared, foo.com matches itself
/* only, and .foo.com matches any name below the domain foo.com.
/* .IP MATCH_FLAG_RETURN
-/* Return MATCH_ERR_TEMP or MATCH_ERR_PERM, instead of raising
+/* Return "not found" and set dict_errno, instead of raising
/* a fatal run-time error.
/* .RE
/* Specify MATCH_FLAG_NONE to request none of the above.
/* match_error - return or raise fatal error */
-static int match_error(int flags, int err_val, const char *fmt,...)
+static int match_error(int flags, const char *fmt,...)
{
VSTRING *buf = vstring_alloc(100);
va_list ap;
- /*
- * In case arguments get swapped after some code change.
- */
- if (err_val >= 0)
- msg_panic("match_error: bad error value: %d", err_val);
-
/*
* Report, and maybe return.
*/
msg_fatal("%s", vstring_str(buf));
}
vstring_free(buf);
- return (err_val);
+ return (0);
}
/* match_string - match a string literal */
if (match != 0)
return (1);
if (dict_errno != 0)
- return (match_error(flags, MATCH_ERR_TEMP,
- "%s: table lookup problem", pattern));
+ return (match_error(flags, "%s: table lookup problem", pattern));
return (0);
}
if (match != 0)
break;
if (dict_errno != 0)
- return (match_error(flags, MATCH_ERR_TEMP,
- "%s: table lookup problem", pattern));
+ return (match_error(flags, "%s: table lookup problem",
+pattern));
}
if ((next = strchr(entry + 1, '.')) == 0)
break;
char *saved_patt;
CIDR_MATCH match_info;
VSTRING *err;
+ int rc;
if (msg_verbose)
msg_info("%s: %s ~? %s", myname, addr, pattern);
if (dict_lookup(pattern, addr) != 0)
return (1);
if (dict_errno != 0)
- return (match_error(flags, MATCH_ERR_TEMP,
- "%s: table lookup problem", pattern));
+ return (match_error(flags, "%s: table lookup problem", pattern));
return (0);
}
saved_patt = mystrdup(pattern);
err = cidr_match_parse(&match_info, saved_patt, (VSTRING *) 0);
myfree(saved_patt);
- if (err != 0)
- return (match_error(flags, MATCH_ERR_PERM, "%s", vstring_str(err)));
+ if (err != 0) {
+ rc = match_error(flags, "%s", vstring_str(err));
+ vstring_free(err);
+ dict_errno = DICT_ERR_CONFIG;
+ return (rc);
+ }
return (cidr_match_execute(&match_info, addr) != 0);
}
/* .nf
/*
- * External interface.
+ * Utility library.
*/
+#include <dict.h>
/*
- * This is what the caller specifies.
+ * External interface.
*/
#define MATCH_FLAG_NONE 0
#define MATCH_FLAG_PARENT (1<<0)
#define MATCH_FLAG_RETURN (1<<1)
-
- /*
- * This is for internal use.
- */
#define MATCH_FLAG_ALL (MATCH_FLAG_PARENT | MATCH_FLAG_RETURN)
- /*
- * Some errors cannot be signaled as (result == 0, dict_errno > 0).
- * Therefore we signal all errors as (result < 0).
- */
-#define MATCH_ERR_TEMP (-1) /* e.g., database is down */
-#define MATCH_ERR_PERM (-2) /* e.g., net/mask syntax */
-
extern int match_string(int, const char *, const char *);
extern int match_hostname(int, const char *, const char *);
extern int match_hostaddr(int, const char *, const char *);
} else if (flags & NAME_MASK_RETURN) {
msg_warn("unknown %s value \"%s\" in \"%s\"",
context, name, names);
- result = 0;
- break;
+ myfree(saved_names);
+ return (0);
} else if (flags & NAME_MASK_WARN) {
msg_warn("unknown %s value \"%s\" in \"%s\"",
context, name, names);
} else if (flags & NAME_MASK_RETURN) {
msg_warn("unknown %s value \"%s\" in \"%s\"",
context, name, names);
+ myfree(saved_names);
return (0);
} else if (flags & NAME_MASK_WARN) {
msg_warn("unknown %s value \"%s\" in \"%s\"",