-TDICT_DBM
-TDICT_DEBUG
-TDICT_ENV
+-TDICT_FAIL
-TDICT_HT
-TDICT_LDAP
-TDICT_MC
-TMASTER_STATUS
-TMASTER_STR_WATCH
-TMATCH_LIST
+-TMATCH_OPS
-TMBLOCK
-TMBOX
-TMILTER
Incompatibility: the Postfix SMTP server now always checks
the smtpd_sender_login_maps table, even without having
"smtpd_sasl_auth_enable = yes" in main.cf.
+
+20111219
+
+ Cleanup: the match_list-based primitives now provide an
+ option to return an error result instead of terminating the
+ process with a fatal error. Files: util/match_ops.[hc],
+ util/match_list.c, global/addr_list_match.c, domain_list.c,
+ string_list.c, namadr_list.c.
+
+ Cleanup: a "fail:" database type that reliably fails all
+ requests. The lookup table name specifies the internal error
+ result code. having this table facilitates a systematic
+ review of all Postfix table lookup error handling.
+
+ Cleanup: trivial-rewrite now "catches" errors with implicit
+ database lookups in virtual_alias_domains, relay_domains,
+ virtual_mailbox_domains, just like it already caught explicit
+ database lookup errors. This means there are fewer occasions
+ where trivial-rewrite clients will appear to hang. File:
+ trivial-rewrite/resolve.c.
+
+ Cleanup: a broken relay_domains table would cause many
+ Postfix processes to terminate with fatal error. Postfix
+ now logs a warning instead. File: global/flush_clnt.c.
+
+ Cleanup: the Postfix SMTP server now "catches" some of the
+ errors with implicit database lookups in mynetworks and TLS
+ client certificate tables, and reports "server configuration
+ error" instead of terminating with a fatal error. This is
+ work in progress. Files: smtpd/smtpd.c, smtpd/smtpd_check.c.
e\ben\bnv\bvi\bir\bro\bon\bn
The UNIX process environment array. The lookup key is the variable
name. The lookup table name in "environ:table" is ignored.
+ f\bfa\bai\bil\bl (read-write)
+ A table that reliably fails all requests. The lookup table name
+ provides the internal error result code. This table exists to simplify
+ Postfix error tests.
h\bha\bas\bsh\bh
An indexed file type based on hashing. This is available only on
systems with support for Berkeley DB databases. Database files are
If you upgrade from Postfix 2.7 or earlier, read RELEASE_NOTES-2.8
before proceeding.
-Incompatible changes with snapshot 201112XX
+Incompatible changes with snapshot 20111218
===========================================
To support external SASL authentication, the Postfix SMTP server
now always checks the smtpd_sender_login_maps table, even without
having "smtpd_sasl_auth_enable = yes" in main.cf.
-Major changes with snapshot 201112XX
+Major changes with snapshot 20111218
====================================
Support for external SASL authentication via the XCLIENT command.
limits on attribute string length in IPC protocols. 10-20KB
seems OK. We could start with limits enabled only in proxymap.
+ move flush_init() etc. from defer service clients to the
+ bounce daemon?
+
Either make all void dict_* operations return an error code,
or require that they reset dict_errno on entry, either exit
with a fatal error or set dict_errno on error.
variable name. The lookup table name in "environ:table" is ignored.
</dd>
+<dt> <b>fail</b> (read-write) </dt>
+
+<dd> A table that reliably fails all requests. The lookup table
+name provides the internal error result code. This table exists to
+simplify Postfix error tests. </dd>
+
<dt> <b>hash</b> </dt>
<dd> An indexed file type based on hashing. This is available only
implemented for testing, someone may find
this useful someday.
+ <b>fail</b> A table that reliably fails all requests.
+ The lookup table name provides the internal
+ error result code. This table exists to sim-
+ plify Postfix error tests.
+
<b>hash</b> An indexed file type based on hashing. This
- is available on systems with support for
+ is available on systems with support for
Berkeley DB databases.
<b>internal</b>
tent are lost when a process terminates.
<b>ldap</b> (read-only)
- Perform lookups using the LDAP protocol.
+ Perform lookups using the LDAP protocol.
This is described in <a href="ldap_table.5.html"><b>ldap_table</b>(5)</a>.
<b>memcache</b> (read-write)
This is described in <a href="memcache_table.5.html"><b>memcache_table</b>(5)</a>.
<b>mysql</b> (read-only)
- Perform lookups using the MYSQL protocol.
+ Perform lookups using the MYSQL protocol.
This is described in <a href="mysql_table.5.html"><b>mysql_table</b>(5)</a>.
<b>pcre</b> (read-only)
A lookup table based on Perl Compatible Reg-
- ular Expressions. The file format is
+ ular Expressions. The file format is
described in <a href="pcre_table.5.html"><b>pcre_table</b>(5)</a>.
<b>pgsql</b> (read-only)
- Perform lookups using the PostgreSQL proto-
+ Perform lookups using the PostgreSQL proto-
col. This is described in <a href="pgsql_table.5.html"><b>pgsql_table</b>(5)</a>.
<b>proxy</b> (read-only)
- A lookup table that is implemented via the
- Postfix <a href="proxymap.8.html"><b>proxymap</b>(8)</a> service. The table name
+ A lookup table that is implemented via the
+ Postfix <a href="proxymap.8.html"><b>proxymap</b>(8)</a> service. The table name
syntax is <i>type</i><b>:</b><i>name</i>.
<b>regexp</b> (read-only)
A lookup table based on regular expressions.
- The file format is described in <a href="regexp_table.5.html"><b>regexp_ta-</b></a>
+ The file format is described in <a href="regexp_table.5.html"><b>regexp_ta-</b></a>
<a href="regexp_table.5.html"><b>ble</b>(5)</a>.
<b>sdbm</b> An indexed file type based on hashing. This
- is available on systems with support for
+ is available on systems with support for
SDBM databases.
<b>sqlite</b> (read-only)
- Perform lookups from SQLite database files.
+ Perform lookups from SQLite database files.
This is described in <a href="sqlite_table.5.html"><b>sqlite_table</b>(5)</a>.
<b>static</b> (read-only)
- A table that always returns its name as
- lookup result. For example, <b><a href="DATABASE_README.html#types">static</a>:foobar</b>
- always returns the string <b>foobar</b> as lookup
+ A table that always returns its name as
+ lookup result. For example, <b><a href="DATABASE_README.html#types">static</a>:foobar</b>
+ always returns the string <b>foobar</b> as lookup
result.
<b>tcp</b> (read-only)
Perform lookups using a simple request-reply
- protocol that is described in <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>.
+ protocol that is described in <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>.
<b>texthash</b> (read-only)
- Produces similar results as hash: files,
+ Produces similar results as hash: files,
except that you don't need to run the
- <a href="postmap.1.html"><b>postmap</b>(1)</a> command before you can use the
- file, and that it does not detect changes
+ <a href="postmap.1.html"><b>postmap</b>(1)</a> command before you can use the
+ file, and that it does not detect changes
after the file is read.
<b>unix</b> (read-only)
- A limited way to query the UNIX authentica-
+ A limited way to query the UNIX authentica-
tion database. The following tables are
implemented:
<b>unix:passwd.byname</b>
- The table is the UNIX password data-
- base. The key is a login name. The
- result is a password file entry in
+ The table is the UNIX password data-
+ base. The key is a login name. The
+ result is a password file entry in
<b>passwd</b>(5) format.
<b>unix:group.byname</b>
The table is the UNIX group database.
- The key is a group name. The result
- is a group file entry in <b>group</b>(5)
+ The key is a group name. The result
+ is a group file entry in <b>group</b>(5)
format.
- Other table types may exist depending on how Post-
+ Other table types may exist depending on how Post-
fix was built.
- <b>-M</b> Show <a href="master.5.html"><b>master.cf</b></a> file contents instead of <a href="postconf.5.html"><b>main.cf</b></a>
- file contents. Specify <b>-Mf</b> to fold long lines for
+ <b>-M</b> Show <a href="master.5.html"><b>master.cf</b></a> file contents instead of <a href="postconf.5.html"><b>main.cf</b></a>
+ file contents. Specify <b>-Mf</b> to fold long lines for
human readability.
If <i>service ...</i> is specified, only the matching ser-
- vices will be output. For example, "<b>postconf -Mf</b>
- <b>inet</b>" will output all services that listen on the
+ vices will be output. For example, "<b>postconf -Mf</b>
+ <b>inet</b>" will output all services that listen on the
network.
- Specify zero or more arguments, each with a <i>ser-</i>
- <i>vice-type</i> name (<b>inet</b>, <b>unix</b>, <b>fifo</b>, or <b>pass</b>) or with
- a <i>service-name.service-type</i> pair, where <i>service-</i>
+ Specify zero or more arguments, each with a <i>ser-</i>
+ <i>vice-type</i> name (<b>inet</b>, <b>unix</b>, <b>fifo</b>, or <b>pass</b>) or with
+ a <i>service-name.service-type</i> pair, where <i>service-</i>
<i>name</i> is the first field of a <a href="master.5.html">master.cf</a> entry.
- This feature is available with Postfix 2.9 and
+ This feature is available with Postfix 2.9 and
later.
- <b>-n</b> Print <a href="postconf.5.html"><b>main.cf</b></a> parameter settings that are explic-
- itly specified in <a href="postconf.5.html"><b>main.cf</b></a>. Specify <b>-nf</b> to fold
- long lines for human readability (Postfix 2.9 and
+ <b>-n</b> Print <a href="postconf.5.html"><b>main.cf</b></a> parameter settings that are explic-
+ itly specified in <a href="postconf.5.html"><b>main.cf</b></a>. Specify <b>-nf</b> to fold
+ long lines for human readability (Postfix 2.9 and
later).
<b>-t</b> [<i>template</i><b>_</b><i>file</i>]
- Display the templates for text that appears at the
- beginning of delivery status notification (DSN)
+ Display the templates for text that appears at the
+ beginning of delivery status notification (DSN)
messages, without expanding $<b>name</b> expressions.
- To override the built-in templates, specify a tem-
- plate file name at the end of the <a href="postconf.1.html"><b>postconf</b>(1)</a> com-
- mand line, or specify a file name in <a href="postconf.5.html"><b>main.cf</b></a> with
+ To override the built-in templates, specify a tem-
+ plate file name at the end of the <a href="postconf.1.html"><b>postconf</b>(1)</a> com-
+ mand line, or specify a file name in <a href="postconf.5.html"><b>main.cf</b></a> with
the <b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a></b> parameter.
To force selection of the built-in templates, spec-
- ify an empty template file name on the <a href="postconf.1.html"><b>postconf</b>(1)</a>
+ ify an empty template file name on the <a href="postconf.1.html"><b>postconf</b>(1)</a>
command line (in shell language: "").
- This feature is available with Postfix 2.3 and
+ This feature is available with Postfix 2.3 and
later.
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
+ tiple <b>-v</b> options make the software increasingly
verbose.
- <b>-#</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and comment
+ <b>-#</b> Edit the <a href="postconf.5.html"><b>main.cf</b></a> configuration file, and comment
out the parameters given on the <a href="postconf.1.html"><b>postconf</b>(1)</a> command
- line, so that those parameters revert to their
- default values. The file is copied to a temporary
- file then renamed into place. Specify a list of
+ line, so that those parameters revert to their
+ default values. The file is copied to a temporary
+ file then renamed into place. Specify a list of
parameter names, not <i>name</i>=<i>value</i> pairs. There is no
- <a href="postconf.1.html"><b>postconf</b>(1)</a> command to perform the reverse opera-
+ <a href="postconf.1.html"><b>postconf</b>(1)</a> command to perform the reverse opera-
tion.
- This feature is available with Postfix 2.6 and
+ This feature is available with Postfix 2.6 and
later.
<b>DIAGNOSTICS</b>
Directory with Postfix configuration files.
<b>CONFIGURATION PARAMETERS</b>
- The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
+ The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
to this program.
- The text below provides only a parameter summary. See
+ The text below provides only a parameter summary. See
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a> (empty)</b>
- Pathname of a configuration file with bounce mes-
+ Pathname of a configuration file with bounce mes-
sage templates.
<b>FILES</b>
<a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
<b>TARPIT CONTROLS</b>
<b><a href="postconf.5.html#qmqpd_error_delay">qmqpd_error_delay</a> (1s)</b>
- How long the QMQP server will pause before sending
- a negative reply to the client.
+ How long the Postfix QMQP server will pause before
+ sending a negative reply to the remote QMQP client.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
- How much time a Postfix daemon process may take to
- handle a request before it is terminated by a
+ How much time a Postfix daemon process may take to
+ handle a request before it is terminated by a
built-in watchdog timer.
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
over an internal communication channel.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
- The maximum amount of time that an idle Postfix
- daemon process waits for an incoming connection
+ The maximum amount of time that an idle Postfix
+ daemon process waits for an incoming connection
before terminating voluntarily.
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
- The maximal number of incoming connections that a
- Postfix daemon process will service before termi-
+ The maximal number of incoming connections that a
+ Postfix daemon process will service before termi-
nating voluntarily.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon
+ The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#qmqpd_authorized_clients">qmqpd_authorized_clients</a> (empty)</b>
- What clients are allowed to connect to the QMQP
- server port.
+ What remote QMQP clients are allowed to connect to
+ the Postfix QMQP server port.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b><a href="postconf.5.html#verp_delimiter_filter">verp_delimiter_filter</a> (-=+)</b>
- The characters Postfix accepts as VERP delimiter
- characters on the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command line
+ The characters Postfix accepts as VERP delimiter
+ characters on the Postfix <a href="sendmail.1.html"><b>sendmail</b>(1)</a> command line
and in SMTP commands.
Available in Postfix version 2.5 and later:
<b><a href="postconf.5.html#qmqpd_client_port_logging">qmqpd_client_port_logging</a> (no)</b>
- Enable logging of the remote QMQP client port in
+ Enable logging of the remote QMQP client port in
addition to the hostname and IP address.
<b>SEE ALSO</b>
<a href="QMQP_README.html">QMQP_README</a>, Postfix ezmlm-idx howto.
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>HISTORY</b>
The UNIX process environment array. The lookup key is the variable
name. Originally implemented for testing, someone may find this
useful someday.
+.IP \fBfail\fR
+A table that reliably fails all requests. The lookup table
+name provides the internal error result code. This table
+exists to simplify Postfix error tests.
.IP \fBhash\fR
An indexed file type based on hashing.
This is available on systems with support for Berkeley DB
.ad
.fi
.IP "\fBqmqpd_error_delay (1s)\fR"
-How long the QMQP server will pause before sending a negative reply
-to the client.
+How long the Postfix QMQP server will pause before sending a negative
+reply to the remote QMQP client.
.SH "MISCELLANEOUS CONTROLS"
.na
.nf
.IP "\fBprocess_name (read-only)\fR"
The process name of a Postfix command or daemon process.
.IP "\fBqmqpd_authorized_clients (empty)\fR"
-What clients are allowed to connect to the QMQP server port.
+What remote QMQP clients are allowed to connect to the Postfix QMQP
+server port.
.IP "\fBqueue_directory (see 'postconf -d' output)\fR"
The location of the Postfix top-level queue directory.
.IP "\fBsyslog_facility (mail)\fR"
variable name. The lookup table name in "environ:table" is ignored.
</dd>
+<dt> <b>fail</b> (read-write) </dt>
+
+<dd> A table that reliably fails all requests. The lookup table
+name provides the internal error result code. This table exists to
+simplify Postfix error tests. </dd>
+
<dt> <b>hash</b> </dt>
<dd> An indexed file type based on hashing. This is available only
-2001:240:587:0:2d0:b7ff:fe88:2ca7 =?= 168.100.189.2
+2604:8d00:189::2 =?= 168.100.189.2
tested by function: no
tested by macro: no
168.100.189.2 =?= 168.100.189.2
tested by function: yes
tested by macro: yes
-2001:240:587:0:2d0:b7ff:fe88:2ca7 =?= 168.100.189.3
+2604:8d00:189::2 =?= 168.100.189.3
tested by function: no
tested by macro: no
168.100.189.2 =?= 168.100.189.3
tested by function: no
tested by macro: no
-2001:240:587:0:2d0:b7ff:fe88:2ca7 =?= 2001:240:587:0:2d0:b7ff:fe88:2ca7
-tested by function: yes
-tested by macro: yes
+2604:8d00:189::2 =?= 2001:240:587:0:2d0:b7ff:fe88:2ca7
+tested by function: no
+tested by macro: no
168.100.189.2 =?= 2001:240:587:0:2d0:b7ff:fe88:2ca7
tested by function: no
tested by macro: no
-2001:240:587:0:2d0:b7ff:fe88:2ca7 =?= 2001:240:587:0:2d0:b7ff:febe:ca9f
+2604:8d00:189::2 =?= 2001:240:587:0:2d0:b7ff:febe:ca9f
tested by function: no
tested by macro: no
168.100.189.2 =?= 2001:240:587:0:2d0:b7ff:febe:ca9f
spike.porcupine.org -> 168.100.189.2
-spike.porcupine.org -> 2001:240:587:0:2d0:b7ff:fe88:2ca7
+spike.porcupine.org -> 2604:8d00:189::2
spike.porcupine.org 25 -> 168.100.189.2 25
-spike.porcupine.org 25 -> 2001:240:587:0:2d0:b7ff:fe88:2ca7 25
+spike.porcupine.org 25 -> 2604:8d00:189::2 25
-spike.porcupine.org -> 2001:240:587:0:2d0:b7ff:fe88:2ca7
+spike.porcupine.org -> 2604:8d00:189::2
spike.porcupine.org -> 168.100.189.2
static int flush_policy_ok(const char *site)
{
- return (domain_list_match(flush_domains, site));
+ return (domain_list_match(flush_domains, site) > 0);
}
/* flush_add_service - append queue ID to per-site fast flush logfile */
static void pre_jail_init(char *unused_name, char **unused_argv)
{
- flush_domains = domain_list_init(match_parent_style(VAR_FFLUSH_DOMAINS),
+ flush_domains = domain_list_init(MATCH_FLAG_RETURN
+ | match_parent_style(VAR_FFLUSH_DOMAINS),
var_fflush_domains);
}
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
+ mail_version_test server_acl_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 mail_version.ref mail_version.tmp
rm -f mail_version.tmp
+server_acl_test: server_acl server_acl.in server_acl.ref
+ ./server_acl <server_acl.in >server_acl.tmp 2>&1
+ diff server_acl.ref server_acl.tmp
+ rm -f server_acl.tmp
+
# Requires: Postfix running, root privileges
rewrite_clnt_test: rewrite_clnt rewrite_clnt.in rewrite_clnt.ref
/* The matching process is case insensitive.
/*
/* addr_match_list_init() performs initializations. The first
-/* argument is MATCH_FLAG_NONE for future extension.
+/* 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.
+/* .PP
+/* Specify MATCH_FLAG_NONE to request none of the above.
/* The second argument is a list of patterns, or the absolute
/* pathname of a file with patterns.
/*
ADDR_MATCH_LIST *list;
char *addr;
int ch;
+ int rc;
msg_vstream_init(argv[0], VSTREAM_ERR);
}
if (argc != optind + 2)
usage(argv[0]);
- list = addr_match_list_init(MATCH_FLAG_PARENT, argv[optind]);
+ list = addr_match_list_init(MATCH_FLAG_PARENT | MATCH_FLAG_RETURN, argv[optind]);
addr = argv[optind + 1];
if (strcmp(addr, "-") == 0) {
VSTRING *buf = vstring_alloc(100);
- while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF)
+ while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) {
+ rc = addr_match_list_match(list, vstring_str(buf));
vstream_printf("%s: %s\n", vstring_str(buf),
- addr_match_list_match(list, vstring_str(buf)) ?
- "YES" : "NO");
+ rc > 0 ? "YES" : rc == 0 ? "NO" : "ERROR");
+ }
vstring_free(buf);
} else {
+ rc = addr_match_list_match(list, addr);
vstream_printf("%s: %s\n", addr,
- addr_match_list_match(list, addr) ?
- "YES" : "NO");
+ rc > 0 ? "YES" : rc == 0 ? "NO" : "ERROR");
}
vstream_fflush(VSTREAM_OUT);
addr_match_list_free(list);
* Utility library.
*/
#include <match_list.h>
-#include <match_ops.h>
/*
* External interface.
*/
if (*var_debug_peer_list)
debug_peer_list =
- namadr_list_init(match_parent_style(VAR_DEBUG_PEER_LIST),
+ namadr_list_init(MATCH_FLAG_RETURN
+ | match_parent_style(VAR_DEBUG_PEER_LIST),
var_debug_peer_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);
if ((fp = auto_clnt_access(dict_mc->clnt)) == 0) {
if (errno == ECONNREFUSED)
break;
+ } else if (memcache_printf(fp, "set %s %d %d %ld",
+ STR(dict_mc->key_buf), dict_mc->mc_flags, ttl, data_len) < 0
+ || memcache_fwrite(fp, value, strlen(value)) < 0
+ || memcache_get(fp, dict_mc->clnt_buf,
+ dict_mc->max_line) < 0) {
+ if (count > 0)
+ msg_warn(errno ? "database %s:%s: I/O error: %m" :
+ "database %s:%s: I/O error",
+ DICT_TYPE_MEMCACHE, dict_mc->dict.name);
+ } else if (strcmp(STR(dict_mc->clnt_buf), "STORED") != 0) {
+ if (count > 0)
+ msg_warn("database %s:%s: update failed: %.30s",
+ DICT_TYPE_MEMCACHE, dict_mc->dict.name,
+ STR(dict_mc->clnt_buf));
} else {
- if (memcache_printf(fp, "set %s %d %d %ld",
- STR(dict_mc->key_buf), dict_mc->mc_flags,
- ttl, data_len) < 0
- || memcache_fwrite(fp, value, strlen(value)) < 0
- || memcache_get(fp, dict_mc->clnt_buf,
- dict_mc->max_line) < 0) {
- if (count > 0)
- msg_warn(errno ? "database %s:%s: I/O error: %m" :
- "database %s:%s: I/O error",
- DICT_TYPE_MEMCACHE, dict_mc->dict.name);
- } else if (strcmp(STR(dict_mc->clnt_buf), "STORED") != 0) {
- if (count > 0)
- msg_warn("database %s:%s: update failed: %.30s",
- DICT_TYPE_MEMCACHE, dict_mc->dict.name,
- STR(dict_mc->clnt_buf));
- } else {
- /* Victory! */
- dict_mc->mc_errno = 0;
- break;
- }
+ /* Victory! */
+ dict_mc->mc_errno = 0;
+ break;
}
auto_clnt_recover(dict_mc->clnt);
}
if ((fp = auto_clnt_access(dict_mc->clnt)) == 0) {
if (errno == ECONNREFUSED)
break;
- } else {
- if (memcache_printf(fp, "get %s", STR(dict_mc->key_buf)) < 0
+ } else if (memcache_printf(fp, "get %s", STR(dict_mc->key_buf)) < 0
|| memcache_get(fp, dict_mc->clnt_buf, dict_mc->max_line) < 0) {
- if (count > 0)
- msg_warn(errno ? "database %s:%s: I/O error: %m" :
- "database %s:%s: I/O error",
- DICT_TYPE_MEMCACHE, dict_mc->dict.name);
- } else if (strcmp(STR(dict_mc->clnt_buf), "END") == 0) {
- /* Not found. */
- dict_mc->mc_errno = 0;
- break;
- } else if (sscanf(STR(dict_mc->clnt_buf),
- "VALUE %*s %*s %ld", &todo) != 1
- || todo < 0 || todo > dict_mc->max_data) {
- if (count > 0)
- msg_warn("%s: unexpected memcache server reply: %.30s",
- dict_mc->dict.name, STR(dict_mc->clnt_buf));
- } else if (memcache_fread(fp, dict_mc->res_buf, todo) < 0) {
- if (count > 0)
- msg_warn("%s: EOF receiving memcache server reply",
- dict_mc->dict.name);
- } else {
- /* Victory! */
- retval = STR(dict_mc->res_buf);
- dict_mc->mc_errno = 0;
- if (memcache_get(fp, dict_mc->clnt_buf, dict_mc->max_line) < 0
- || strcmp(STR(dict_mc->clnt_buf), "END") != 0)
- auto_clnt_recover(dict_mc->clnt);
- break;
- }
+ if (count > 0)
+ msg_warn(errno ? "database %s:%s: I/O error: %m" :
+ "database %s:%s: I/O error",
+ DICT_TYPE_MEMCACHE, dict_mc->dict.name);
+ } else if (strcmp(STR(dict_mc->clnt_buf), "END") == 0) {
+ /* Not found. */
+ dict_mc->mc_errno = 0;
+ break;
+ } else if (sscanf(STR(dict_mc->clnt_buf),
+ "VALUE %*s %*s %ld", &todo) != 1
+ || todo < 0 || todo > dict_mc->max_data) {
+ if (count > 0)
+ msg_warn("%s: unexpected memcache server reply: %.30s",
+ dict_mc->dict.name, STR(dict_mc->clnt_buf));
+ } else if (memcache_fread(fp, dict_mc->res_buf, todo) < 0) {
+ if (count > 0)
+ msg_warn("%s: EOF receiving memcache server reply",
+ dict_mc->dict.name);
+ } else {
+ /* Victory! */
+ retval = STR(dict_mc->res_buf);
+ dict_mc->mc_errno = 0;
+ if (memcache_get(fp, dict_mc->clnt_buf, dict_mc->max_line) < 0
+ || strcmp(STR(dict_mc->clnt_buf), "END") != 0)
+ auto_clnt_recover(dict_mc->clnt);
+ break;
}
auto_clnt_recover(dict_mc->clnt);
}
if ((fp = auto_clnt_access(dict_mc->clnt)) == 0) {
if (errno == ECONNREFUSED)
break;
+ } else if (memcache_printf(fp, "delete %s", STR(dict_mc->key_buf)) < 0
+ || memcache_get(fp, dict_mc->clnt_buf, dict_mc->max_line) < 0) {
+ if (count > 0)
+ msg_warn(errno ? "database %s:%s: I/O error: %m" :
+ "database %s:%s: I/O error",
+ DICT_TYPE_MEMCACHE, dict_mc->dict.name);
+ } else if (strcmp(STR(dict_mc->clnt_buf), "DELETED") == 0) {
+ /* Victory! */
+ dict_mc->mc_errno = 0;
+ retval = 0;
+ break;
+ } else if (strcmp(STR(dict_mc->clnt_buf), "NOT_FOUND") == 0) {
+ /* Not found! */
+ dict_mc->mc_errno = 0;
+ retval = 1;
+ break;
} else {
- if (memcache_printf(fp, "delete %s", STR(dict_mc->key_buf)) < 0
- || memcache_get(fp, dict_mc->clnt_buf,
- dict_mc->max_line) < 0) {
- if (count > 0)
- msg_warn(errno ? "database %s:%s: I/O error: %m" :
- "database %s:%s: I/O error",
- DICT_TYPE_MEMCACHE, dict_mc->dict.name);
- } else if (strcmp(STR(dict_mc->clnt_buf), "DELETED") == 0) {
- /* Victory! */
- dict_mc->mc_errno = 0;
- retval = 0;
- break;
- } else if (strcmp(STR(dict_mc->clnt_buf), "NOT_FOUND") == 0) {
- /* Not found! */
- dict_mc->mc_errno = 0;
- retval = 1;
- break;
- } else {
- if (count > 0)
- msg_warn("database %s:%s: delete failed: %.30s",
- DICT_TYPE_MEMCACHE, dict_mc->dict.name,
- STR(dict_mc->clnt_buf));
- }
+ if (count > 0)
+ msg_warn("database %s:%s: delete failed: %.30s",
+ DICT_TYPE_MEMCACHE, dict_mc->dict.name,
+ STR(dict_mc->clnt_buf));
}
auto_clnt_recover(dict_mc->clnt);
}
/*
/* domain_list_init() performs initializations. The first argument
/* is the bit-wise OR of zero or more of the following:
-/* .RS
/* .IP MATCH_FLAG_PARENT
/* 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.
-/* .RE
+/* .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.
+/* .PP
/* Specify MATCH_FLAG_NONE to request none of the above.
/* The second argument is a list of domain patterns, or the name of
/* a file containing domain patterns.
DOMAIN_LIST *list;
char *host;
int ch;
+ int rc;
msg_vstream_init(argv[0], VSTREAM_ERR);
}
if (argc != optind + 2)
usage(argv[0]);
- list = domain_list_init(MATCH_FLAG_PARENT, argv[optind]);
+ list = domain_list_init(MATCH_FLAG_PARENT | MATCH_FLAG_RETURN, argv[optind]);
host = argv[optind + 1];
- vstream_printf("%s: %s\n", host, domain_list_match(list, host) ?
- "YES" : "NO");
+ rc = domain_list_match(list, host);
+ vstream_printf("%s: %s\n", host,
+ rc > 0 ? "YES" : rc == 0 ? "NO" : "ERROR");
vstream_fflush(VSTREAM_OUT);
domain_list_free(list);
return (0);
* Utility library.
*/
#include <match_list.h>
-#include <match_ops.h>
/*
* External interface.
void flush_init(void)
{
- flush_domains = domain_list_init(match_parent_style(VAR_FFLUSH_DOMAINS),
+ flush_domains = domain_list_init(MATCH_FLAG_RETURN
+ | match_parent_style(VAR_FFLUSH_DOMAINS),
var_fflush_domains);
}
{
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 (domain_list_match(flush_domains, site) == 0)
+ if ((rc = domain_list_match(flush_domains, site)) == 0)
status = FLUSH_STAT_DENY;
- else
+ else if (rc > 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
+ status = FLUSH_STAT_FAIL;
if (msg_verbose)
msg_info("%s: site %s status %d", myname, site, status);
{
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 (domain_list_match(flush_domains, site) == 0)
+ if ((rc = domain_list_match(flush_domains, site)) == 0)
status = FLUSH_STAT_DENY;
- else
+ else if (rc > 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
+ status = FLUSH_STAT_FAIL;
if (msg_verbose)
msg_info("%s: site %s id %s status %d", myname, site, queue_id,
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20111218"
+#define MAIL_RELEASE_DATE "20111219"
#define MAIL_VERSION_NUMBER "2.9"
#ifdef SNAPSHOT
/* namadr_list_init() performs initializations. The first
/* argument is the bit-wise OR of zero or more of the
/* following:
-/* .RS
/* .IP MATCH_FLAG_PARENT
/* 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.
-/* .RE
+/* .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.
+/* .PP
/* Specify MATCH_FLAG_NONE to request none of the above.
/* The second argument is a list of patterns, or the absolute
/* pathname of a file with patterns.
char *host;
char *addr;
int ch;
+ int rc;
msg_vstream_init(argv[0], VSTREAM_ERR);
}
if (argc != optind + 3)
usage(argv[0]);
- list = namadr_list_init(MATCH_FLAG_PARENT, argv[optind]);
+ 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,
- namadr_list_match(list, host, addr) ?
- "YES" : "NO");
+ rc > 0 ? "YES" : rc == 0 ? "NO" : "ERROR");
vstream_fflush(VSTREAM_OUT);
namadr_list_free(list);
return (0);
* Utility library.
*/
#include <match_list.h>
-#include <match_ops.h>
/*
* External interface.
./namadr_list 168.100.189.0/28 dummy 168.100.189.2
+./namadr_list '!168.100.189.2 168.100.189.0/28' dummy 168.100.189.2
+./namadr_list '!168.100.189.2 168.100.189.0/28' dummy 168.100.189.3
./namadr_list 168.100.189.0/28 dummy 168.100.189.16
./namadr_list 168.100.189.0/98 dummy 168.100.189.16
./namadr_list 168.100.589.0/28 dummy 168.100.189.16
env foo=x ./namadr_list !environ:junk bar 168.100.189.3
env foo=x ./namadr_list !!environ:junk foo 168.100.189.3
env foo=x ./namadr_list !!environ:junk bar 168.100.189.3
+./namadr_list fail:1 bar 168.100.189.3
+./namadr_list !fail:1 bar 168.100.189.3
dummy/168.100.189.2: YES
+dummy/168.100.189.2: NO
+dummy/168.100.189.3: YES
dummy/168.100.189.16: NO
-./namadr_list: fatal: bad net/mask pattern: "168.100.189.0/98"
-./namadr_list: fatal: bad net/mask pattern: "168.100.589.0/28"
+./namadr_list: warning: bad net/mask pattern: "168.100.189.0/98"
+dummy/168.100.189.16: ERROR
+./namadr_list: warning: bad net/mask pattern: "168.100.589.0/28"
+dummy/168.100.189.16: ERROR
dummy/168.100.989.16: NO
./namadr_list: fatal: unsupported dictionary type: 2001
dummy/2001:240:5c7:0:2d0:b7ff:fe88:2ca7: YES
dummy/2001:240:5c7:0:2d0:b7ff:fe88:2ca8: NO
-./namadr_list: fatal: non-null host address bits in "2001:240:5c7:0:2d0:b7ff:fe88:2ca7/64", perhaps you should use "2001:240:5c7::/64" instead
+./namadr_list: warning: non-null host address bits in "2001:240:5c7:0:2d0:b7ff:fe88:2ca7/64", perhaps you should use "2001:240:5c7::/64" instead
+dummy/2001:240:5c7:0:2d0:b7ff:fe88:2ca8: ERROR
dummy/2001:240:5c7:0:2d0:b7ff:fe88:2ca8: YES
dummy/2001:24:5c7:0:2d0:b7ff:fe88:2ca8: NO
dummy/2001:24:5c7:0:2d0:b7ff:fe88:2ca8: YES
bar/168.100.189.3: NO
baz/168.100.189.3: YES
x.x.x/127.0.0.1: NO
-./namadr_list: fatal: bad net/mask pattern: "be/be"
+./namadr_list: warning: bad net/mask pattern: "be/be"
+x.x.x/127.0.0.1: ERROR
x.x.x/127.0.0.1: NO
-./namadr_list: fatal: bad address pattern: "be:be"
+./namadr_list: warning: bad address pattern: "be:be"
+x.x.x/::1: ERROR
foo/168.100.189.3: YES
bar/168.100.189.3: NO
foo/168.100.189.3: NO
bar/168.100.189.3: NO
foo/168.100.189.3: YES
bar/168.100.189.3: NO
+./namadr_list: warning: fail:1(0,lock|fold_fix): table lookup problem
+bar/168.100.189.3: ERROR
+./namadr_list: warning: fail:1(0,lock|fold_fix): table lookup problem
+bar/168.100.189.3: ERROR
{
if (server_acl_mynetworks)
addr_match_list_free(server_acl_mynetworks);
- server_acl_mynetworks = addr_match_list_init(match_parent_style(origin),
+ server_acl_mynetworks =
+ addr_match_list_init(MATCH_FLAG_RETURN | match_parent_style(origin),
mynetworks);
}
int ret;
ARGV fake_argv;
const char *fake_args[2];
+ 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)) {
- if (addr_match_list_match(server_acl_mynetworks, client_addr))
+ rc = addr_match_list_match(server_acl_mynetworks, client_addr);
+ if (rc > 0)
return (SERVER_ACL_ACT_PERMIT);
+ if (rc < 0) {
+ msg_warn("%s: %s: mynetworks lookup error -- ignoring the "
+ "remainder of this access list", origin, acl);
+ return (SERVER_ACL_ACT_ERROR);
+ }
} else if (strchr(acl, ':') != 0) {
if ((dict = dict_handle(acl)) == 0)
msg_panic("%s: unexpected dictionary: %s", myname, acl);
if (ret != SERVER_ACL_ACT_DUNNO)
return (ret);
} else if (dict_errno != 0) {
- msg_warn("%s: table lookup error -- ignoring the remainder "
- "of this access list", acl);
+ msg_warn("%s: %s: table lookup error -- ignoring the remainder "
+ "of this access list", origin, acl);
return (SERVER_ACL_ACT_ERROR);
}
} else if (STREQ(acl, SERVER_ACL_NAME_DUNNO)) {
--- /dev/null
+mynetworks=168.100.189.0/27
+server_acl=permit_mynetworks,reject
+address=168.100.189.2
+mynetworks=!168.100.189.2,168.100.189.0/27
+address=168.100.189.2
+address=168.100.189.3
+mynetworks=fail:1
+address=168.100.189.4
+server_acl=fail:1,reject
+address=168.100.189.2
--- /dev/null
+> mynetworks=168.100.189.0/27
+> server_acl=permit_mynetworks,reject
+> address=168.100.189.2
+168.100.189.2: permit
+> mynetworks=!168.100.189.2,168.100.189.0/27
+> address=168.100.189.2
+168.100.189.2: reject
+> address=168.100.189.3
+168.100.189.3: permit
+> mynetworks=fail:1
+> address=168.100.189.4
+unknown: warning: fail:1(0,lock|fold_fix): table lookup problem
+unknown: warning: server_acl: permit_mynetworks: mynetworks lookup error -- ignoring the remainder of this access list
+168.100.189.4: error
+> server_acl=fail:1,reject
+> address=168.100.189.2
+unknown: warning: server_acl: fail:1: table lookup error -- ignoring the remainder of this access list
+168.100.189.2: error
/* In order to reverse the result, precede a pattern with an
/* exclamation point (!).
/*
-/* string_list_init() performs initializations. The flags argument
-/* is ignored; pattern_list specifies a list of string patterns.
+/* 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.
+/* .PP
+/* Specify MATCH_FLAG_NONE to request none of the above.
+/* The second argument specifies a list of string patterns.
/*
/* string_list_match() matches the specified string against the
/* compiled pattern list.
STRING_LIST *list;
char *string;
int ch;
+ int rc;
msg_vstream_init(argv[0], VSTREAM_ERR);
}
if (argc != optind + 2)
usage(argv[0]);
- list = string_list_init(MATCH_FLAG_NONE, argv[optind]);
+ list = string_list_init(MATCH_FLAG_NONE | MATCH_FLAG_RETURN, argv[optind]);
string = argv[optind + 1];
- vstream_printf("%s: %s\n", string, string_list_match(list, string) ?
- "YES" : "NO");
+ rc = string_list_match(list, string);
+ vstream_printf("%s: %s\n", string,
+ rc > 0 ? "YES" : rc == 0 ? "NO" : "ERROR");
vstream_fflush(VSTREAM_OUT);
string_list_free(list);
return (0);
* Utility library.
*/
#include <match_list.h>
-#include <match_ops.h>
/*
* External interface.
/* The UNIX process environment array. The lookup key is the variable
/* name. Originally implemented for testing, someone may find this
/* useful someday.
+/* .IP \fBfail\fR
+/* A table that reliably fails all requests. The lookup table
+/* name provides the internal error result code. This table
+/* exists to simplify Postfix error tests.
/* .IP \fBhash\fR
/* An indexed file type based on hashing.
/* This is available on systems with support for Berkeley DB
/* .ad
/* .fi
/* .IP "\fBqmqpd_error_delay (1s)\fR"
-/* How long the QMQP server will pause before sending a negative reply
-/* to the client.
+/* How long the Postfix QMQP server will pause before sending a negative
+/* reply to the remote QMQP client.
/* MISCELLANEOUS CONTROLS
/* .ad
/* .fi
/* .IP "\fBprocess_name (read-only)\fR"
/* The process name of a Postfix command or daemon process.
/* .IP "\fBqmqpd_authorized_clients (empty)\fR"
-/* What clients are allowed to connect to the QMQP server port.
+/* What remote QMQP clients are allowed to connect to the Postfix QMQP
+/* server port.
/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
/* The location of the Postfix top-level queue directory.
/* .IP "\fBsyslog_facility (mail)\fR"
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.
*/
- if (namadr_list_match(qmqpd_clients, state->name, state->addr) == 0) {
+ rc = namadr_list_match(qmqpd_clients, state->name, state->addr);
+ if (rc > 0) {
+ qmqpd_receive(state);
+ } else if (rc == 0) {
qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD,
"Error: %s is not authorized to use this service",
state->namaddr);
- } else
- qmqpd_receive(state);
+ } else {
+ qmqpd_reply(state, DONT_LOG, QMQPD_STAT_RETRY,
+ "Error: server configuration error");
+ }
break;
}
{
debug_peer_init();
qmqpd_clients =
- namadr_list_init(match_parent_style(VAR_QMQPD_CLIENTS),
+ namadr_list_init(MATCH_FLAG_RETURN
+ | match_parent_style(VAR_QMQPD_CLIENTS),
var_qmqpd_clients);
}
* feature.
*/
if (state->proxy_mail) {
- smtpd_check_rewrite(state);
if (smtpd_proxy_create(state, smtpd_proxy_opts, var_smtpd_proxy_filt,
var_smtpd_proxy_tmout, var_smtpd_proxy_ehlo,
state->proxy_mail) != 0) {
else if (SMTPD_STAND_ALONE(state) == 0) {
int cleanup_flags;
- smtpd_check_rewrite(state);
cleanup_flags = input_transp_cleanup(CLEANUP_FLAG_MASK_EXTERNAL,
smtpd_input_transp_mask)
| CLEANUP_FLAG_SMTP_REPLY;
return (-1);
}
}
+ err = smtpd_check_rewrite(state);
+ if (err != 0) {
+ /* XXX Reset access map side effects. */
+ mail_reset(state);
+ smtpd_chat_reply(state, "%s", err);
+ return (-1);
+ }
/*
* Check the queue file space, if applicable. The optional before-filter
/*
* Results of restrictions.
*/
+#define SMTPD_CHECK_ERROR (-1) /* server error */
#define SMTPD_CHECK_DUNNO 0 /* indifferent */
#define SMTPD_CHECK_OK 1 /* explicitly permit */
#define SMTPD_CHECK_REJECT 2 /* explicitly reject */
/* smtpd_check_rewrite - choose address qualification context */
-void smtpd_check_rewrite(SMTPD_STATE *state)
+char *smtpd_check_rewrite(SMTPD_STATE *state)
{
const char *myname = "smtpd_check_rewrite";
int status;
if ((dict = dict_handle(*cpp)) == 0)
msg_panic("%s: dictionary not found: %s", myname, *cpp);
dict_errno = 0;
- /* for now, dict errors are fatal */
if (dict_get(dict, state->addr) != 0)
status = SMTPD_CHECK_OK;
- else if (dict_errno != 0)
- msg_fatal("%s: table lookup error", *cpp);
+ else if (dict_errno != 0) {
+ msg_warn("%s: %s: lookup error", VAR_LOC_RWR_CLIENTS, *cpp);
+ status = SMTPD_CHECK_ERROR;
+ }
} else if (strcasecmp(name, PERMIT_SASL_AUTH) == 0) {
#ifdef USE_SASL_AUTH
if (smtpd_sasl_is_active(state))
#endif
} else if (strcasecmp(name, PERMIT_TLS_ALL_CLIENTCERTS) == 0) {
status = permit_tls_clientcerts(state, 1);
- /* for now, dict errors are fatal */
#ifdef USE_TLS
if (dict_errno != 0)
- msg_fatal("%s: table lookup error", var_smtpd_relay_ccerts);
+ status = SMTPD_CHECK_ERROR;
#endif
} else if (strcasecmp(name, PERMIT_TLS_CLIENTCERTS) == 0) {
status = permit_tls_clientcerts(state, 0);
- /* for now, dict errors are fatal */
#ifdef USE_TLS
if (dict_errno != 0)
- msg_fatal("%s: table lookup error", var_smtpd_relay_ccerts);
+ status = SMTPD_CHECK_ERROR;
#endif
} else {
msg_warn("parameter %s: invalid request: %s",
VAR_LOC_RWR_CLIENTS, name);
continue;
}
+ if (status < 0) {
+ state->error_mask |= MAIL_ERROR_RESOURCE;
+ return ("451 4.3.5 Server configuration error");
+ }
if (status == SMTPD_CHECK_OK) {
state->rewrite_context = MAIL_ATTR_RWR_LOCAL;
- return;
+ return (0);
}
}
state->rewrite_context = MAIL_ATTR_RWR_REMOTE;
+ return (0);
}
/* smtpd_check_client - validate client name or address */
return (ifnot);
}
+/* smtpd_sasl_state_init - the real deal */
+
+void smtpd_sasl_state_init(SMTPD_STATE *state)
+{
+ state->sasl_username = 0;
+ state->sasl_method = 0;
+ state->sasl_sender = 0;
+}
+
#endif
/* verify_clnt_query - stub */
*/
extern void smtpd_check_init(void);
extern int smtpd_check_addr(const char *);
-extern void smtpd_check_rewrite(SMTPD_STATE *);
+extern char *smtpd_check_rewrite(SMTPD_STATE *);
extern char *smtpd_check_client(SMTPD_STATE *);
extern char *smtpd_check_helo(SMTPD_STATE *, char *);
extern char *smtpd_check_mail(SMTPD_STATE *, char *);
const char *relay;
const char *xport;
const char *sender_key;
+ int rc;
*flags = 0;
vstring_strcpy(channel, "CHANNEL NOT UPDATED");
* Virtual alias domain.
*/
if (virt_alias_doms
- && string_list_match(virt_alias_doms, rcpt_domain)) {
+ && (rc = string_list_match(virt_alias_doms, rcpt_domain)) > 0) {
if (var_helpful_warnings) {
if (virt_mailbox_doms
- && string_list_match(virt_mailbox_doms, rcpt_domain))
+ && string_list_match(virt_mailbox_doms, rcpt_domain) > 0)
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))
+ && domain_list_match(relay_domains, rcpt_domain) > 0)
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) {
+ } else if (dict_errno != 0 || rc < 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
- && string_list_match(virt_mailbox_doms, rcpt_domain)) {
+ && (rc = string_list_match(virt_mailbox_doms, rcpt_domain)) > 0) {
if (var_helpful_warnings) {
if (relay_domains
- && domain_list_match(relay_domains, rcpt_domain))
+ && domain_list_match(relay_domains, rcpt_domain) > 0)
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) {
+ } else if (dict_errno != 0 || rc < 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
- && domain_list_match(relay_domains, rcpt_domain)) {
+ && (rc = domain_list_match(relay_domains, rcpt_domain)) > 0) {
vstring_strcpy(channel, RES_PARAM_VALUE(rp->relay_transport));
blame = rp->relay_transport_name;
*flags |= RESOLVE_CLASS_RELAY;
- } else if (dict_errno != 0) {
+ } else if (dict_errno != 0 || rc < 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))
+ && string_list_match(virt_alias_doms, rcpt_domain) > 0)
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))
+ && string_list_match(virt_mailbox_doms, rcpt_domain) > 0)
msg_warn("do not list domain %s in BOTH %s and %s",
rcpt_domain, VAR_MYDEST, VAR_VIRT_MAILBOX_DOMS);
}
if (*var_virt_alias_doms)
virt_alias_doms =
- string_list_init(MATCH_FLAG_NONE, var_virt_alias_doms);
+ string_list_init(MATCH_FLAG_RETURN, var_virt_alias_doms);
if (*var_virt_mailbox_doms)
virt_mailbox_doms =
- string_list_init(MATCH_FLAG_NONE, var_virt_mailbox_doms);
+ string_list_init(MATCH_FLAG_RETURN, var_virt_mailbox_doms);
if (*var_relay_domains)
relay_domains =
- domain_list_init(match_parent_style(VAR_RELAY_DOMAINS),
+ domain_list_init(MATCH_FLAG_RETURN
+ | match_parent_style(VAR_RELAY_DOMAINS),
var_relay_domains);
if (*var_relocated_maps)
allascii.c load_file.c killme_after.c vstream_tweak.c \
unix_pass_listen.c unix_pass_trigger.c edit_file.c inet_windowsize.c \
unix_pass_fd_fix.c dict_cache.c valid_utf_8.c dict_thash.c \
- ip_match.c nbbio.c stream_pass_connect.c base32_code.c dict_test.c
+ ip_match.c nbbio.c stream_pass_connect.c base32_code.c dict_test.c \
+ dict_fail.c
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
allascii.o load_file.o killme_after.o vstream_tweak.o \
unix_pass_listen.o unix_pass_trigger.o edit_file.o inet_windowsize.o \
unix_pass_fd_fix.o dict_cache.o valid_utf_8.o dict_thash.o \
- ip_match.o nbbio.o stream_pass_connect.o base32_code.o dict_test.o
+ ip_match.o nbbio.o stream_pass_connect.o base32_code.o dict_test.o \
+ dict_fail.o
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
stringops.h sys_defs.h timed_connect.h timed_wait.h trigger.h \
username.h valid_hostname.h vbuf.h vbuf_print.h vstream.h vstring.h \
vstring_vstream.h watchdog.h format_tv.h load_file.h killme_after.h \
- edit_file.h dict_cache.h dict_thash.h \
- ip_match.h nbbio.h base32_code.h
+ edit_file.h dict_cache.h dict_thash.h ip_match.h nbbio.h base32_code.h \
+ dict_fail.h
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
stream_test.c dup2_pass_on_exec.c
DEFS = -I. -D$(SYSTYPE)
dict_env.o: vbuf.h
dict_env.o: vstream.h
dict_env.o: vstring.h
+dict_fail.o: argv.h
+dict_fail.o: dict.h
+dict_fail.o: dict_fail.c
+dict_fail.o: dict_fail.h
+dict_fail.o: msg.h
+dict_fail.o: mymalloc.h
+dict_fail.o: sys_defs.h
+dict_fail.o: vbuf.h
+dict_fail.o: vstream.h
+dict_fail.o: vstring.h
dict_ht.o: argv.h
dict_ht.o: dict.h
dict_ht.o: dict_ht.c
dict_open.o: dict_db.h
dict_open.o: dict_dbm.h
dict_open.o: dict_env.h
+dict_open.o: dict_fail.h
dict_open.o: dict_ht.h
dict_open.o: dict_ni.h
dict_open.o: dict_nis.h
--- /dev/null
+/*++
+/* NAME
+/* dict_fail 3
+/* SUMMARY
+/* dictionary manager interface to 'always fail' table
+/* SYNOPSIS
+/* #include <dict_fail.h>
+/*
+/* DICT *dict_fail_open(name, name, dict_flags)
+/* const char *name;
+/* int dummy;
+/* int dict_flags;
+/* DESCRIPTION
+/* dict_fail_open() implements a dummy dictionary that fails
+/* all operations. The name specifies the dict_errno value.
+/* SEE ALSO
+/* dict(3) generic dictionary manager
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdlib.h>
+
+/* Utility library. */
+
+#include <mymalloc.h>
+#include <msg.h>
+#include <dict.h>
+#include <dict_fail.h>
+
+/* Application-specific. */
+
+typedef struct {
+ DICT dict; /* generic members */
+ int dict_errno; /* fixed error result */
+} DICT_FAIL;
+
+/* dict_fail_sequence - fail lookup */
+
+static int dict_fail_sequence(DICT *dict, int unused_func,
+ const char **key, const char **value)
+{
+ DICT_FAIL *dp = (DICT_FAIL *) dict;
+
+ dict_errno = dp->dict_errno;
+ return (1);
+}
+
+/* dict_fail_update - fail lookup */
+
+static void dict_fail_update(DICT *dict, const char *unused_name,
+ const char *unused_value)
+{
+ DICT_FAIL *dp = (DICT_FAIL *) dict;
+
+ dict_errno = dp->dict_errno;
+}
+
+/* dict_fail_lookup - fail lookup */
+
+static const char *dict_fail_lookup(DICT *dict, const char *unused_name)
+{
+ DICT_FAIL *dp = (DICT_FAIL *) dict;
+
+ dict_errno = dp->dict_errno;
+ return (0);
+}
+
+/* dict_fail_delete - fail delete */
+
+static int dict_fail_delete(DICT *dict, const char *unused_name)
+{
+ DICT_FAIL *dp = (DICT_FAIL *) dict;
+
+ dict_errno = dp->dict_errno;
+ return (-1);
+}
+
+/* dict_fail_close - close fail dictionary */
+
+static void dict_fail_close(DICT *dict)
+{
+ dict_free(dict);
+}
+
+/* dict_fail_open - make association with fail variable */
+
+DICT *dict_fail_open(const char *name, int open_flags, int dict_flags)
+{
+ DICT_FAIL *dp;
+
+ dp = (DICT_FAIL *) dict_alloc(DICT_TYPE_FAIL, name, sizeof(*dp));
+ dp->dict.lookup = dict_fail_lookup;
+ if (open_flags & O_RDWR) {
+ dp->dict.update = dict_fail_update;
+ dp->dict.delete = dict_fail_delete;
+ }
+ dp->dict.sequence = dict_fail_sequence;
+ dp->dict.close = dict_fail_close;
+ dp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
+ dp->dict_errno = atoi(name);
+ dp->dict.owner.status = DICT_OWNER_TRUSTED;
+ return (DICT_DEBUG (&dp->dict));
+}
--- /dev/null
+#ifndef _DICT_FAIL_H_INCLUDED_
+#define _DICT_FAIL_H_INCLUDED_
+
+/*++
+/* NAME
+/* dict_fail 3h
+/* SUMMARY
+/* dictionary manager interface to 'always fail' table
+/* SYNOPSIS
+/* #include <dict_fail.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <dict.h>
+
+ /*
+ * External interface.
+ */
+#define DICT_TYPE_FAIL "fail"
+
+extern DICT *dict_fail_open(const char *, int, int);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* jeffm
+/* ghostgun.com
+/*--*/
+
+#endif
#include <dict_cidr.h>
#include <dict_ht.h>
#include <dict_thash.h>
+#include <dict_fail.h>
#include <stringops.h>
#include <split_at.h>
#include <htable.h>
DICT_TYPE_STATIC, dict_static_open,
DICT_TYPE_CIDR, dict_cidr_open,
DICT_TYPE_THASH, dict_thash_open,
+ DICT_TYPE_FAIL, dict_fail_open,
0,
};
-./dict_open: warning: regexp map dict_regexp.map, line 1: ignoring extra text after IF
+./dict_open: warning: regexp map dict_regexp.map, line 1: ignoring extra text after IF statement: "fodder"
+./dict_open: warning: regexp map dict_regexp.map, line 1: do not prepend whitespace to statements between IF and ENDIF
./dict_open: warning: regexp map dict_regexp.map, line 5: ignoring extra text after ENDIF
./dict_open: warning: regexp map dict_regexp.map, line 9: using empty replacement string
./dict_open: warning: regexp map dict_regexp.map, line 10: out of range replacement index "5": skipping this rule
/* SYNOPSIS
/* #include <dict_static.h>
/*
-/* DICT *dict_static_open(name, dummy, dict_flags)
+/* DICT *dict_static_open(name, name, dict_flags)
/* const char *name;
/* int dummy;
/* int dict_flags;
/* dict_static_open() implements a dummy dictionary that returns
/* as lookup result the dictionary name, regardless of the lookup
/* key value.
-/*
-/* The \fIdummy\fR argument is ignored.
/* SEE ALSO
/* dict(3) generic dictionary manager
/* LICENSE
int ch;
int dict_flags = DICT_FLAG_LOCK | DICT_FLAG_DUP_REPLACE;
int n;
+ int rc;
signal(SIGPIPE, SIG_IGN);
if (strcmp(cmd, "verbose") == 0 && !key) {
msg_verbose++;
} else if (strcmp(cmd, "del") == 0 && key && !value) {
- if (dict_del(dict, key))
+ if ((rc = dict_del(dict, key)) > 0)
vstream_printf("%s: not found\n", key);
+ else if (rc < 0)
+ vstream_printf("%s: error\n", key);
else
vstream_printf("%s: deleted\n", key);
} else if (strcmp(cmd, "get") == 0 && key && !value) {
if ((value = dict_get(dict, key)) == 0) {
- vstream_printf("%s: %s\n", key,
- dict_errno == DICT_ERR_RETRY ?
- "soft error" : "not found");
+ vstream_printf("%s: %s\n", key, dict_errno ?
+ "error" : "not found");
} else {
vstream_printf("%s=%s\n", key, value);
}
dict_errno = 0;
dict_put(dict, key, value);
if (dict_errno)
- vstream_printf("%s: soft error\n", key);
+ vstream_printf("%s: error\n", key);
else
vstream_printf("%s=%s\n", key, value);
} else if (strcmp(cmd, "first") == 0 && !key && !value) {
if (dict_seq(dict, DICT_SEQ_FUN_FIRST, &key, &value) == 0)
vstream_printf("%s=%s\n", key, value);
else
- vstream_printf("%s\n",
- dict_errno == DICT_ERR_RETRY ?
- "soft error" : "not found");
+ vstream_printf("%s\n", dict_errno ?
+ "error" : "not found");
} else if (strcmp(cmd, "next") == 0 && !key && !value) {
if (dict_seq(dict, DICT_SEQ_FUN_NEXT, &key, &value) == 0)
vstream_printf("%s=%s\n", key, value);
else
- vstream_printf("%s\n",
- dict_errno == DICT_ERR_RETRY ?
- "soft error" : "not found");
+ vstream_printf("%s\n", dict_errno ?
+ "error" : "not found");
} else if (strcmp(cmd, "flags") == 0 && !key && !value) {
vstream_printf("dict flags %s\n",
dict_flags_str(dict->flags));
/* The hostname pattern foo.com matches any name within 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 a negative result (MATCH_ERR_TEMP or MATCH_ERR_FAIL)
+/* 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
while ((start = mystrtok(&bp, delim)) != 0) {
if (*start == '#') {
msg_warn("%s: comment at end of line is not supported: %s %s",
- myname, start, bp);
+ myname, start, bp);
break;
}
for (match = init_match, item = start; *item == '!'; item++)
/* match_list_match - match strings against pattern list */
-int match_list_match(MATCH_LIST * list,...)
+int match_list_match(MATCH_LIST *list,...)
{
const char *myname = "match_list_match";
char **cpp;
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 (list->match_func[i] (list->flags, list->match_args[i], pat))
+ if ((rc = list->match_func[i] (list->flags,
+ list->match_args[i], pat)) > 0)
return (match);
+ else if (rc < 0)
+ return (rc);
}
if (msg_verbose)
for (i = 0; i < list->match_count; i++)
/* match_list_free - release storage */
-void match_list_free(MATCH_LIST * list)
+void match_list_free(MATCH_LIST *list)
{
argv_free(list->patterns);
myfree((char *) list->match_func);
/* DESCRIPTION
/* .nf
+ /*
+ * Utility library.
+ */
+#include <match_ops.h>
+
/*
* External interface.
*/
/* 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
+/* Return MATCH_ERR_TEMP or MATCH_ERR_PERM, instead of raising
+/* a fatal run-time error.
/* .RE
/* Specify MATCH_FLAG_NONE to request none of the above.
/*
#define MATCH_DICTIONARY(pattern) \
((pattern)[0] != '[' && strchr((pattern), ':') != 0)
+/* match_error - return or raise fatal error */
+
+static int match_error(int flags, int err_val, 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.
+ */
+ va_start(ap, fmt);
+ vstring_vsprintf(buf, fmt, ap);
+ va_end(ap);
+ if (flags & MATCH_FLAG_RETURN) {
+ msg_warn("%s", vstring_str(buf));
+ } else {
+ msg_fatal("%s", vstring_str(buf));
+ }
+ vstring_free(buf);
+ return (err_val);
+}
+
/* match_string - match a string literal */
-int match_string(int unused_flags, const char *string, const char *pattern)
+int match_string(int flags, const char *string, const char *pattern)
{
const char *myname = "match_string";
int match;
if (match != 0)
return (1);
if (dict_errno != 0)
- msg_fatal("%s: table lookup problem", pattern);
+ return (match_error(flags, MATCH_ERR_TEMP,
+ "%s: table lookup problem", pattern));
return (0);
}
if (match != 0)
break;
if (dict_errno != 0)
- msg_fatal("%s: table lookup problem", pattern);
+ return (match_error(flags, MATCH_ERR_TEMP,
+ "%s: table lookup problem", pattern));
}
if ((next = strchr(entry + 1, '.')) == 0)
break;
/* match_hostaddr - match host by address */
-int match_hostaddr(int unused_flags, const char *addr, const char *pattern)
+int match_hostaddr(int flags, const char *addr, const char *pattern)
{
const char *myname = "match_hostaddr";
char *saved_patt;
if (dict_lookup(pattern, addr) != 0)
return (1);
if (dict_errno != 0)
- msg_fatal("%s: table lookup problem", pattern);
+ return (match_error(flags, MATCH_ERR_TEMP,
+ "%s: table lookup problem", pattern));
return (0);
}
* everything into to binary form, and to do the comparison there.
*/
saved_patt = mystrdup(pattern);
- if ((err = cidr_match_parse(&match_info, saved_patt, (VSTRING *) 0)) != 0)
- msg_fatal("%s", vstring_str(err));
+ 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)));
return (cidr_match_execute(&match_info, addr) != 0);
}
#define MATCH_FLAG_NONE 0
#define MATCH_FLAG_PARENT (1<<0)
-#define MATCH_FLAG_ALL (MATCH_FLAG_PARENT)
+#define MATCH_FLAG_RETURN (1<<1)
+#define MATCH_FLAG_ALL (MATCH_FLAG_PARENT | MATCH_FLAG_RETURN)
+
+#define MATCH_ERR_TEMP (-1) /* temporary error, e.g., database */
+#define MATCH_ERR_PERM (-2) /* permanent error, e.g., syntax */
extern int match_string(int, const char *, const char *);
extern int match_hostname(int, const char *, const char *);
./myaddrinfo: === hostname belly.porcupine.org ===
-./myaddrinfo: belly.porcupine.org -> family=28 sock=1 proto=6 2001:240:587:0:250:56ff:fe10:bd03
-./myaddrinfo: 2001:240:587:0:250:56ff:fe10:bd03 -> belly.porcupine.org
+./myaddrinfo: belly.porcupine.org -> family=28 sock=1 proto=6 2604:8d00:189::6
+./myaddrinfo: 2604:8d00:189::6 -> belly.porcupine.org
./myaddrinfo: belly.porcupine.org -> family=2 sock=1 proto=6 168.100.189.6
./myaddrinfo: 168.100.189.6 -> belly.porcupine.org
./myaddrinfo: === host address 168.100.189.2 ===