From: Wietse Venema Date: Sun, 8 Jan 2012 05:00:00 +0000 (-0500) Subject: postfix-2.9-20120108 X-Git-Tag: v2.9.0-RC1~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=54576876fd05c995424166f8ca0a59d14ee3ad25;p=thirdparty%2Fpostfix.git postfix-2.9-20120108 --- diff --git a/postfix/.indent.pro b/postfix/.indent.pro index 097a67a2c..9e679a2ca 100644 --- a/postfix/.indent.pro +++ b/postfix/.indent.pro @@ -102,6 +102,7 @@ -TDICT_STACK -TDICT_TCP -TDICT_TEXT +-TDICT_THASH -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY @@ -329,3 +330,4 @@ -Tsfsistat -Tsize_t -Tssize_t +-Ttime_t diff --git a/postfix/HISTORY b/postfix/HISTORY index 48365be99..d2ae3b1ef 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -17432,11 +17432,36 @@ Apologies for any names omitted. namadr_list.c, trivial-rewrite/resolve.c, smtpd/smtpd.c, smtpd/smtpd_check.c, global/flush_clnt.c, flush/flush.c. -20111226 +20111224 + + Cleanup: eliminated the global dict_errno variable that + made error reporting convenient but not necessarily precise. + This was a straightforward change except in the few modules + that propagate errors from one dictionary API to another: + dict_cache.c, dict_debug.c, maps.c, dict_memcache.c. Files: + src/cleanup/cleanup_map11.c, src/cleanup/cleanup_map1n.c, + src/global/addr_match_list.c, src/global/dict_ldap.c, + src/global/dict_memcache.c, src/global/dict_mysql.c, + src/global/dict_pgsql.c, src/global/dict_proxy.c, + src/global/dict_sqlite.c, src/global/domain_list.c, + src/global/flush_clnt.c, src/global/mail_addr_find.c, + src/global/mail_addr_map.c, src/global/maps.c, src/global/maps.h, + src/global/match_parent_style.h, src/global/namadr_list.c, + src/global/resolve_local.c, src/global/resolve_local.h, + src/global/server_acl.c, src/global/string_list.c, + src/local/alias.c, src/local/bounce_workaround.c, + src/local/mailbox.c, src/local/unknown.c, src/proxymap/proxymap.c, + src/qmqpd/qmqpd.c, src/smtp/smtp_map11.c, src/smtpd/smtpd_check.c, + src/trivial-rewrite/resolve.c, src/trivial-rewrite/transport.c, + src/util/dict.h, src/util/dict_alloc.c, src/util/dict_cache.c, + src/util/dict_cidr.c, src/util/dict_db.c, src/util/dict_debug.c, + src/util/dict_env.c, src/util/dict_fail.c, src/util/dict_ht.c, + src/util/dict_pcre.c, src/util/dict_regexp.c, + src/util/dict_static.c, src/util/dict_tcp.c, src/util/dict_test.c, + src/util/dict_thash.c, src/util/dict_unix.c, src/util/match_list.c, + src/util/match_list.h, src/util/match_ops.c, src/virtual/mailbox.c. - Cleanup: reset the global dict_errno flag before table - lookup, to avoid false alarms about table lookup errors. - Files: util/dict_thash.c, global/dict_sqlite.c, global.maps.c. +20111226 Bugfix (introduced 20110426): after lookup error with mailbox_transport_maps, mailbox_command_maps or @@ -17452,3 +17477,25 @@ Apologies for any names omitted. master/master_ent.c, master/master_vars.c, postscreen/postscreen.c, qmqpd/qmqpd.c, smtp/smtp_connect.c, smtpd/smtpd.c, util/inet_proto.c. + +20120107 + + Workaround: degrade gracefully when the "domain" feature + of LDAP, *SQL and memcache databases has a table lookup + problem. Files: global/db_common.c, global/dict_ldap.c, + global/dict*sql*.c, global/dict_memcache.c. + + Cleanup: fixed memcache client error handling for things + that never happen. global/dict_memcache.c. + + Future proofing: prepare postmap/postalias error logging + for future changes to database code. Files: postalias/postalias.c, + postmap/postmap.c. + +20120108 + + Cleanup: the postscreen(8) and verify(8) cache managers log + warnings at a reduced rate of one per second per cache + operation, to avoid logging large numbers of warnings about + a problem with low-value information. File: util/msg_rate_delay.c, + util/dict_cache.c. diff --git a/postfix/README_FILES/DATABASE_README b/postfix/README_FILES/DATABASE_README index 4353752c6..231e426c8 100644 --- a/postfix/README_FILES/DATABASE_README +++ b/postfix/README_FILES/DATABASE_README @@ -199,9 +199,8 @@ To find out what database types your Postfix system supports, use the "ppooss The UNIX process environment array. The lookup key is the variable name. The lookup table name in "environ:table" is ignored. ffaaiill (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. + A table that reliably fails all requests. The lookup table name is used + for logging only. This table exists to simplify Postfix error tests. hhaasshh An indexed file type based on hashing. This is available only on systems with support for Berkeley DB databases. Database files are diff --git a/postfix/WISHLIST b/postfix/WISHLIST index e12f4dc59..c201dae89 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -4,19 +4,16 @@ Wish list: Remove this file from the stable release. - limits on attribute string length in IPC protocols. 10-20KB - seems OK. We could start with limits enabled only in proxymap. + Things to do after the stable release: + + Before proxymap can be exposed to the network to share, + e.g., postscreen or verify caches, need to enforce limits + on attribute string length in IPC protocols. 10-20KB seems + OK. The VSTREAM library already supports read/write deadlines. move flush_init() etc. from defer service clients to the bounce daemon? - Is it practical to move errors from global dict_errno - to lookuphandle->dict_errno? - - 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. - multi_connect() function that takes a list of inet:host:port and/or unix:pathname specs, with an explicit "inet" prefix argument to handle applications that use host:port only. @@ -24,16 +21,14 @@ Wish list: client, dovecot client, and other. dict_memcache: treat "bad" key as cache miss, i.e. read/write - the database as if the cache did not exist. This does not - work because most Postfix maps (virtual, canonical, access, - transport, ...) also don't support spaces in keys. + the backup database as if the cache did not exist. This + does not help because most Postfix maps (virtual, canonical, + access, transport, ...) also don't support spaces in keys. postscreen: keep the cache open after "postfix reload" when it is remote (type memcache: or proxy:). This does not work because memcache can use a non-proxied file as backup). - Things to do after the stable release: - What is the feasibility of adding an mta_name (personality) attribute that is propagated via queue files and delivery agent requests? It would default to myhostname. @@ -116,12 +111,6 @@ Wish list: into doubles (converting only some leads to a documentation nightmare). - postscreen: wait for DNS completion after early HANGUP and - log DNSBL results. If the client was still waiting for the - PREGREET timer, just flag the PREGREET test as (done, not - passed). If the client was not waiting for the PREGREET - timer, just wait until DNSBL lookup (if any) completes. - Address verify cache: allow a negative cache "refresh" result to purge a "positive" cache entry in some safe manner. Currently, the negative cache "refresh" result is discarded, diff --git a/postfix/html/DATABASE_README.html b/postfix/html/DATABASE_README.html index 1beb1c898..9ce2676b5 100644 --- a/postfix/html/DATABASE_README.html +++ b/postfix/html/DATABASE_README.html @@ -295,8 +295,8 @@ variable name. The lookup table name in "environ:table" is ignored.
fail (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.
+name is used for logging only. This table exists to simplify Postfix +error tests.
hash
diff --git a/postfix/html/postalias.1.html b/postfix/html/postalias.1.html index e78cade27..10abcbe5a 100644 --- a/postfix/html/postalias.1.html +++ b/postfix/html/postalias.1.html @@ -147,29 +147,34 @@ POSTALIAS(1) POSTALIAS(1) file_name.db. This is available on systems with support for db databases. - sdbm The output consists of two files, named - file_name.pag and file_name.dir. This is - available on systems with support for sdbm + fail A table that reliably fails all requests. + The lookup table name is used for logging + only. This table exists to simplify Postfix + error tests. + + sdbm The output consists of two files, named + file_name.pag and file_name.dir. This is + available on systems with support for sdbm databases. - When no file_type is specified, the software uses - the database type specified via the default_data- + When no file_type is specified, the software uses + the database type specified via the default_data- base_type configuration parameter. The default - value for this parameter depends on the host envi- + value for this parameter depends on the host envi- ronment. file_name - The name of the alias database source file when + The name of the alias database source file when creating a database. DIAGNOSTICS - Problems are logged to the standard error stream and to - syslogd(8). No output means that no problems were - detected. Duplicate entries are skipped and are flagged + Problems are logged to the standard error stream and to + syslogd(8). No output means that no problems were + detected. Duplicate entries are skipped and are flagged with a warning. - postalias(1) terminates with zero exit status in case of - success (including successful "postalias -q" lookup) and + postalias(1) terminates with zero exit status in case of + success (including successful "postalias -q" lookup) and terminates with non-zero exit status in case of failure. ENVIRONMENT @@ -180,26 +185,26 @@ POSTALIAS(1) POSTALIAS(1) Enable verbose logging for debugging purposes. CONFIGURATION PARAMETERS - The following main.cf parameters are especially relevant + The following main.cf 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 postconf(5) for more details including examples. alias_database (see 'postconf -d' output) - The alias databases for local(8) delivery that are + The alias databases for local(8) delivery that are updated with "newaliases" or with "sendmail -bi". config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and + The default location of the Postfix main.cf and master.cf configuration files. berkeley_db_create_buffer_size (16777216) - The per-table I/O buffer size for programs that + The per-table I/O buffer size for programs that create Berkeley DB hash or btree tables. berkeley_db_read_buffer_size (131072) - The per-table I/O buffer size for programs that + The per-table I/O buffer size for programs that read Berkeley DB hash or btree tables. default_database_type (see 'postconf -d' output) @@ -210,8 +215,8 @@ POSTALIAS(1) POSTALIAS(1) The syslog facility of Postfix logging. syslog_name (see 'postconf -d' output) - 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". STANDARDS @@ -230,7 +235,7 @@ POSTALIAS(1) POSTALIAS(1) DATABASE_README, Postfix lookup table overview LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/html/postconf.1.html b/postfix/html/postconf.1.html index 63d1483e5..350cb86a8 100644 --- a/postfix/html/postconf.1.html +++ b/postfix/html/postconf.1.html @@ -182,9 +182,9 @@ POSTCONF(1) POSTCONF(1) this useful someday. fail 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. + The lookup table name is used for logging. + This table exists to simplify Postfix error + tests. hash An indexed file type based on hashing. This is available on systems with support for diff --git a/postfix/html/postmap.1.html b/postfix/html/postmap.1.html index 123536cea..c414c46bf 100644 --- a/postfix/html/postmap.1.html +++ b/postfix/html/postmap.1.html @@ -207,27 +207,32 @@ POSTMAP(1) POSTMAP(1) file_name.db. This is available on systems with support for db databases. - sdbm The output consists of two files, named - file_name.pag and file_name.dir. This is - available on systems with support for sdbm + fail A table that reliably fails all requests. + The lookup table name is used for logging + only. This table exists to simplify Postfix + error tests. + + sdbm The output consists of two files, named + file_name.pag and file_name.dir. This is + available on systems with support for sdbm databases. - When no file_type is specified, the software uses - the database type specified via the default_data- + When no file_type is specified, the software uses + the database type specified via the default_data- base_type configuration parameter. file_name - The name of the lookup table source file when + The name of the lookup table source file when rebuilding a database. DIAGNOSTICS - Problems are logged to the standard error stream and to - syslogd(8). No output means that no problems were - detected. Duplicate entries are skipped and are flagged + Problems are logged to the standard error stream and to + syslogd(8). No output means that no problems were + detected. Duplicate entries are skipped and are flagged with a warning. - postmap(1) terminates with zero exit status in case of - success (including successful "postmap -q" lookup) and + postmap(1) terminates with zero exit status in case of + success (including successful "postmap -q" lookup) and terminates with non-zero exit status in case of failure. ENVIRONMENT @@ -238,21 +243,21 @@ POSTMAP(1) POSTMAP(1) Enable verbose logging for debugging purposes. CONFIGURATION PARAMETERS - The following main.cf parameters are especially relevant + The following main.cf parameters are especially relevant to this program. The text below provides only a parameter - summary. See postconf(5) for more details including exam- + summary. See postconf(5) for more details including exam- ples. berkeley_db_create_buffer_size (16777216) - The per-table I/O buffer size for programs that + The per-table I/O buffer size for programs that create Berkeley DB hash or btree tables. berkeley_db_read_buffer_size (131072) - The per-table I/O buffer size for programs that + The per-table I/O buffer size for programs that read Berkeley DB hash or btree tables. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and + The default location of the Postfix main.cf and master.cf configuration files. default_database_type (see 'postconf -d' output) @@ -263,8 +268,8 @@ POSTMAP(1) POSTMAP(1) The syslog facility of Postfix logging. syslog_name (see 'postconf -d' output) - 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". SEE ALSO @@ -277,7 +282,7 @@ POSTMAP(1) POSTMAP(1) DATABASE_README, Postfix lookup table overview LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/man/man1/postalias.1 b/postfix/man/man1/postalias.1 index 8e86b8b86..9dda165f6 100644 --- a/postfix/man/man1/postalias.1 +++ b/postfix/man/man1/postalias.1 @@ -127,6 +127,10 @@ This is available on systems with support for \fBdbm\fR databases. .IP \fBhash\fR The output is a hashed file, named \fIfile_name\fB.db\fR. This is available on systems with support for \fBdb\fR databases. +.IP \fBfail\fR +A table that reliably fails all requests. The lookup table +name is used for logging only. This table exists to simplify +Postfix error tests. .IP \fBsdbm\fR The output consists of two files, named \fIfile_name\fB.pag\fR and \fIfile_name\fB.dir\fR. diff --git a/postfix/man/man1/postconf.1 b/postfix/man/man1/postconf.1 index 3711f8dd2..fefde2869 100644 --- a/postfix/man/man1/postconf.1 +++ b/postfix/man/man1/postconf.1 @@ -173,8 +173,8 @@ 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. +name is used for logging. 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 diff --git a/postfix/man/man1/postmap.1 b/postfix/man/man1/postmap.1 index d79ac3510..cf6ae5240 100644 --- a/postfix/man/man1/postmap.1 +++ b/postfix/man/man1/postmap.1 @@ -189,6 +189,10 @@ This is available on systems with support for \fBdbm\fR databases. .IP \fBhash\fR The output file is a hashed file, named \fIfile_name\fB.db\fR. This is available on systems with support for \fBdb\fR databases. +.IP \fBfail\fR +A table that reliably fails all requests. The lookup table +name is used for logging only. This table exists to simplify +Postfix error tests. .IP \fBsdbm\fR The output consists of two files, named \fIfile_name\fB.pag\fR and \fIfile_name\fB.dir\fR. diff --git a/postfix/proto/DATABASE_README.html b/postfix/proto/DATABASE_README.html index ca1627c74..284f02786 100644 --- a/postfix/proto/DATABASE_README.html +++ b/postfix/proto/DATABASE_README.html @@ -295,8 +295,8 @@ variable name. The lookup table name in "environ:table" is ignored.
fail (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.
+name is used for logging only. This table exists to simplify Postfix +error tests.
hash
diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in index 7e28474b9..0dbbc1be5 100644 --- a/postfix/src/cleanup/Makefile.in +++ b/postfix/src/cleanup/Makefile.in @@ -528,7 +528,6 @@ cleanup.o: ../../include/mail_stream.h cleanup.o: ../../include/mail_version.h cleanup.o: ../../include/maps.h cleanup.o: ../../include/match_list.h -cleanup.o: ../../include/match_ops.h cleanup.o: ../../include/milter.h cleanup.o: ../../include/mime_state.h cleanup.o: ../../include/msg.h @@ -565,7 +564,6 @@ cleanup_addr.o: ../../include/mail_proto.h cleanup_addr.o: ../../include/mail_stream.h cleanup_addr.o: ../../include/maps.h cleanup_addr.o: ../../include/match_list.h -cleanup_addr.o: ../../include/match_ops.h cleanup_addr.o: ../../include/milter.h cleanup_addr.o: ../../include/mime_state.h cleanup_addr.o: ../../include/msg.h @@ -604,7 +602,6 @@ cleanup_api.o: ../../include/mail_queue.h cleanup_api.o: ../../include/mail_stream.h cleanup_api.o: ../../include/maps.h cleanup_api.o: ../../include/match_list.h -cleanup_api.o: ../../include/match_ops.h cleanup_api.o: ../../include/milter.h cleanup_api.o: ../../include/mime_state.h cleanup_api.o: ../../include/msg.h @@ -635,7 +632,6 @@ cleanup_body_edit.o: ../../include/mail_conf.h cleanup_body_edit.o: ../../include/mail_stream.h cleanup_body_edit.o: ../../include/maps.h cleanup_body_edit.o: ../../include/match_list.h -cleanup_body_edit.o: ../../include/match_ops.h cleanup_body_edit.o: ../../include/milter.h cleanup_body_edit.o: ../../include/mime_state.h cleanup_body_edit.o: ../../include/msg.h @@ -674,7 +670,6 @@ cleanup_bounce.o: ../../include/mail_queue.h cleanup_bounce.o: ../../include/mail_stream.h cleanup_bounce.o: ../../include/maps.h cleanup_bounce.o: ../../include/match_list.h -cleanup_bounce.o: ../../include/match_ops.h cleanup_bounce.o: ../../include/milter.h cleanup_bounce.o: ../../include/mime_state.h cleanup_bounce.o: ../../include/msg.h @@ -711,7 +706,6 @@ cleanup_envelope.o: ../../include/mail_proto.h cleanup_envelope.o: ../../include/mail_stream.h cleanup_envelope.o: ../../include/maps.h cleanup_envelope.o: ../../include/match_list.h -cleanup_envelope.o: ../../include/match_ops.h cleanup_envelope.o: ../../include/milter.h cleanup_envelope.o: ../../include/mime_state.h cleanup_envelope.o: ../../include/msg.h @@ -749,7 +743,6 @@ cleanup_extracted.o: ../../include/mail_proto.h cleanup_extracted.o: ../../include/mail_stream.h cleanup_extracted.o: ../../include/maps.h cleanup_extracted.o: ../../include/match_list.h -cleanup_extracted.o: ../../include/match_ops.h cleanup_extracted.o: ../../include/milter.h cleanup_extracted.o: ../../include/mime_state.h cleanup_extracted.o: ../../include/msg.h @@ -782,7 +775,6 @@ cleanup_final.o: ../../include/mail_conf.h cleanup_final.o: ../../include/mail_stream.h cleanup_final.o: ../../include/maps.h cleanup_final.o: ../../include/match_list.h -cleanup_final.o: ../../include/match_ops.h cleanup_final.o: ../../include/milter.h cleanup_final.o: ../../include/mime_state.h cleanup_final.o: ../../include/msg.h @@ -817,7 +809,6 @@ cleanup_init.o: ../../include/mail_stream.h cleanup_init.o: ../../include/mail_version.h cleanup_init.o: ../../include/maps.h cleanup_init.o: ../../include/match_list.h -cleanup_init.o: ../../include/match_ops.h cleanup_init.o: ../../include/milter.h cleanup_init.o: ../../include/mime_state.h cleanup_init.o: ../../include/msg.h @@ -848,7 +839,6 @@ cleanup_map11.o: ../../include/mail_conf.h cleanup_map11.o: ../../include/mail_stream.h cleanup_map11.o: ../../include/maps.h cleanup_map11.o: ../../include/match_list.h -cleanup_map11.o: ../../include/match_ops.h cleanup_map11.o: ../../include/milter.h cleanup_map11.o: ../../include/mime_state.h cleanup_map11.o: ../../include/msg.h @@ -880,7 +870,6 @@ cleanup_map1n.o: ../../include/mail_params.h cleanup_map1n.o: ../../include/mail_stream.h cleanup_map1n.o: ../../include/maps.h cleanup_map1n.o: ../../include/match_list.h -cleanup_map1n.o: ../../include/match_ops.h cleanup_map1n.o: ../../include/milter.h cleanup_map1n.o: ../../include/mime_state.h cleanup_map1n.o: ../../include/msg.h @@ -911,7 +900,6 @@ cleanup_masquerade.o: ../../include/mail_params.h cleanup_masquerade.o: ../../include/mail_stream.h cleanup_masquerade.o: ../../include/maps.h cleanup_masquerade.o: ../../include/match_list.h -cleanup_masquerade.o: ../../include/match_ops.h cleanup_masquerade.o: ../../include/milter.h cleanup_masquerade.o: ../../include/mime_state.h cleanup_masquerade.o: ../../include/msg.h @@ -952,7 +940,6 @@ cleanup_message.o: ../../include/mail_proto.h cleanup_message.o: ../../include/mail_stream.h cleanup_message.o: ../../include/maps.h cleanup_message.o: ../../include/match_list.h -cleanup_message.o: ../../include/match_ops.h cleanup_message.o: ../../include/milter.h cleanup_message.o: ../../include/mime_state.h cleanup_message.o: ../../include/msg.h @@ -992,7 +979,6 @@ cleanup_milter.o: ../../include/mail_proto.h cleanup_milter.o: ../../include/mail_stream.h cleanup_milter.o: ../../include/maps.h cleanup_milter.o: ../../include/match_list.h -cleanup_milter.o: ../../include/match_ops.h cleanup_milter.o: ../../include/milter.h cleanup_milter.o: ../../include/mime_state.h cleanup_milter.o: ../../include/msg.h @@ -1029,7 +1015,6 @@ cleanup_out.o: ../../include/mail_params.h cleanup_out.o: ../../include/mail_stream.h cleanup_out.o: ../../include/maps.h cleanup_out.o: ../../include/match_list.h -cleanup_out.o: ../../include/match_ops.h cleanup_out.o: ../../include/milter.h cleanup_out.o: ../../include/mime_state.h cleanup_out.o: ../../include/msg.h @@ -1069,7 +1054,6 @@ cleanup_out_recipient.o: ../../include/mail_queue.h cleanup_out_recipient.o: ../../include/mail_stream.h cleanup_out_recipient.o: ../../include/maps.h cleanup_out_recipient.o: ../../include/match_list.h -cleanup_out_recipient.o: ../../include/match_ops.h cleanup_out_recipient.o: ../../include/milter.h cleanup_out_recipient.o: ../../include/mime_state.h cleanup_out_recipient.o: ../../include/msg.h @@ -1101,7 +1085,6 @@ cleanup_region.o: ../../include/mail_conf.h cleanup_region.o: ../../include/mail_stream.h cleanup_region.o: ../../include/maps.h cleanup_region.o: ../../include/match_list.h -cleanup_region.o: ../../include/match_ops.h cleanup_region.o: ../../include/milter.h cleanup_region.o: ../../include/mime_state.h cleanup_region.o: ../../include/msg.h @@ -1131,7 +1114,6 @@ cleanup_rewrite.o: ../../include/mail_proto.h cleanup_rewrite.o: ../../include/mail_stream.h cleanup_rewrite.o: ../../include/maps.h cleanup_rewrite.o: ../../include/match_list.h -cleanup_rewrite.o: ../../include/match_ops.h cleanup_rewrite.o: ../../include/milter.h cleanup_rewrite.o: ../../include/mime_state.h cleanup_rewrite.o: ../../include/msg.h @@ -1165,7 +1147,6 @@ cleanup_state.o: ../../include/mail_proto.h cleanup_state.o: ../../include/mail_stream.h cleanup_state.o: ../../include/maps.h cleanup_state.o: ../../include/match_list.h -cleanup_state.o: ../../include/match_ops.h cleanup_state.o: ../../include/milter.h cleanup_state.o: ../../include/mime_state.h cleanup_state.o: ../../include/mymalloc.h diff --git a/postfix/src/cleanup/cleanup_map11.c b/postfix/src/cleanup/cleanup_map11.c index 7673667a8..626b9ff3a 100644 --- a/postfix/src/cleanup/cleanup_map11.c +++ b/postfix/src/cleanup/cleanup_map11.c @@ -119,7 +119,7 @@ int cleanup_map11_external(CLEANUP_STATE *state, VSTRING *addr, argv_free(new_addr); if (expand_to_self) return (did_rewrite); - } else if (dict_errno != 0) { + } else if (maps->error != 0) { msg_warn("%s: %s map lookup problem for %s", state->queue_id, maps->title, STR(addr)); state->errs |= CLEANUP_STAT_WRITE; diff --git a/postfix/src/cleanup/cleanup_map1n.c b/postfix/src/cleanup/cleanup_map1n.c index b806a6017..f7088a06b 100644 --- a/postfix/src/cleanup/cleanup_map1n.c +++ b/postfix/src/cleanup/cleanup_map1n.c @@ -155,7 +155,7 @@ ARGV *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr, } myfree(saved_lhs); argv_free(lookup); - } else if (dict_errno != 0) { + } else if (maps->error != 0) { msg_warn("%s: %s map lookup problem for %s -- " "deferring delivery", state->queue_id, maps->title, addr); diff --git a/postfix/src/cleanup/cleanup_milter.ref1 b/postfix/src/cleanup/cleanup_milter.ref1 index 8e35af840..a529c62ce 100644 --- a/postfix/src/cleanup/cleanup_milter.ref1 +++ b/postfix/src/cleanup/cleanup_milter.ref1 @@ -24,28 +24,26 @@ 747 original_recipient: alias@hades.porcupine.org 774 canceled_recipient: root@porcupine.org 794 pointer_record: 1258 - 1258 named_attribute: notify_flags=1 - 1274 original_recipient: xxxx - 1280 recipient: xxxx - 1286 pointer_record: 1303 - 1303 named_attribute: notify_flags=1 - 1319 original_recipient: yyyy - 1325 canceled_recipient: yyyy - 1331 pointer_record: 811 + 1258 original_recipient: xxxx + 1264 recipient: xxxx + 1270 pointer_record: 1287 + 1287 original_recipient: yyyy + 1293 canceled_recipient: yyyy + 1299 pointer_record: 811 811 *** MESSAGE CONTENTS test-queue-file.tmp *** 813 regular_text: Received: from hades.porcupine.org (hades.porcupine.org [168.100.189.10]) 888 regular_text: by hades.porcupine.org (Postfix) with SMTP id 38132290405; 949 regular_text: Sat, 20 Jan 2007 19:52:41 -0500 (EST) - 989 pointer_record: 1348 - 1348 pointer_record: 1399 - 1399 pointer_record: 1365 - 1365 pointer_record: 1492 - 1492 regular_text: X: X-replaced-header replacement header text - 1538 pointer_record: 1433 - 1433 regular_text: X2: test header value 3 - 1458 regular_text: Y: 1234567 - 1470 padding: 0 - 1475 pointer_record: 1047 + 989 pointer_record: 1316 + 1316 pointer_record: 1367 + 1367 pointer_record: 1333 + 1333 pointer_record: 1460 + 1460 regular_text: X: X-replaced-header replacement header text + 1506 pointer_record: 1401 + 1401 regular_text: X2: test header value 3 + 1426 regular_text: Y: 1234567 + 1438 padding: 0 + 1443 pointer_record: 1047 1047 regular_text: Message-Id: <20070121005247.38132290405@hades.porcupine.org> 1109 regular_text: Date: Sat, 20 Jan 2007 19:52:41 -0500 (EST) 1154 regular_text: From: wietse@porcupine.org diff --git a/postfix/src/cleanup/cleanup_milter.ref12 b/postfix/src/cleanup/cleanup_milter.ref12 index 58dc6f573..d5d0f2c04 100644 --- a/postfix/src/cleanup/cleanup_milter.ref12 +++ b/postfix/src/cleanup/cleanup_milter.ref12 @@ -22,12 +22,10 @@ 516 original_recipient: you@porcupine.org 535 recipient: you@porcupine.org 554 pointer_record: 573 - 573 named_attribute: notify_flags=1 - 589 original_recipient: me@porcupine.org - 607 canceled_recipient: me@porcupine.org - 625 pointer_record: 642 - 642 named_attribute: notify_flags=1 - 658 original_recipient: em@porcupine.org - 676 canceled_recipient: em@porcupine.org - 694 pointer_record: 571 + 573 original_recipient: me@porcupine.org + 591 canceled_recipient: me@porcupine.org + 609 pointer_record: 626 + 626 original_recipient: em@porcupine.org + 644 canceled_recipient: em@porcupine.org + 662 pointer_record: 571 571 *** MESSAGE FILE END test-queue-file12.tmp *** diff --git a/postfix/src/cleanup/cleanup_milter.ref13a b/postfix/src/cleanup/cleanup_milter.ref13a index 8a1d610e8..3ccf0282f 100644 --- a/postfix/src/cleanup/cleanup_milter.ref13a +++ b/postfix/src/cleanup/cleanup_milter.ref13a @@ -22,12 +22,10 @@ 516 original_recipient: you@porcupine.org 535 recipient: you@porcupine.org 554 pointer_record: 573 - 573 named_attribute: notify_flags=1 - 589 original_recipient: me@porcupine.org - 607 canceled_recipient: me@porcupine.org - 625 pointer_record: 642 - 642 named_attribute: notify_flags=1 - 658 original_recipient: em@porcupine.org - 676 canceled_recipient: em@porcupine.org - 694 pointer_record: 571 + 573 original_recipient: me@porcupine.org + 591 canceled_recipient: me@porcupine.org + 609 pointer_record: 626 + 626 original_recipient: em@porcupine.org + 644 canceled_recipient: em@porcupine.org + 662 pointer_record: 571 571 *** MESSAGE FILE END test-queue-file13a.tmp *** diff --git a/postfix/src/cleanup/cleanup_milter.ref3 b/postfix/src/cleanup/cleanup_milter.ref3 index 84ae4efb4..656b56194 100644 --- a/postfix/src/cleanup/cleanup_milter.ref3 +++ b/postfix/src/cleanup/cleanup_milter.ref3 @@ -6,42 +6,40 @@ 147 sender_fullname: Wietse Venema 162 sender: me@porcupine.org 180 pointer_record: 573 - 573 named_attribute: notify_flags=1 - 589 original_recipient: me@porcupine.org - 607 canceled_recipient: me@porcupine.org - 625 pointer_record: 1413 - 1413 named_attribute: notify_flags=1 - 1429 original_recipient: em@porcupine.org - 1447 canceled_recipient: em@porcupine.org - 1465 pointer_record: 197 + 573 original_recipient: me@porcupine.org + 591 canceled_recipient: me@porcupine.org + 609 pointer_record: 1397 + 1397 original_recipient: em@porcupine.org + 1415 canceled_recipient: em@porcupine.org + 1433 pointer_record: 197 197 *** MESSAGE CONTENTS test-queue-file3.tmp *** 199 regular_text: Received: by hades.porcupine.org (Postfix, from userid 1001) 261 regular_text: id B85F1290407; Sat, 20 Jan 2007 20:53:59 -0500 (EST) - 317 pointer_record: 858 - 858 pointer_record: 1331 - 1331 pointer_record: 1372 - 1372 pointer_record: 1482 - 1482 pointer_record: 1739 - 1739 pointer_record: 1780 - 1780 regular_text: From: me@porcupine.org - 1804 pointer_record: 1523 - 1523 pointer_record: 1821 - 1821 pointer_record: 1861 - 1861 regular_text: To: you@porcupine.org - 1884 pointer_record: 1563 - 1563 pointer_record: 1901 - 1901 pointer_record: 1980 - 1980 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org> - 2042 pointer_record: 1642 - 1642 pointer_record: 2059 - 2059 pointer_record: 2121 - 2121 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT) - 2166 pointer_record: 1704 - 1704 pointer_record: 2183 - 2183 pointer_record: 2218 - 2218 regular_text: Subject: hey! - 2233 padding: 0 - 2236 pointer_record: 489 + 317 pointer_record: 842 + 842 pointer_record: 1315 + 1315 pointer_record: 1356 + 1356 pointer_record: 1450 + 1450 pointer_record: 1707 + 1707 pointer_record: 1748 + 1748 regular_text: From: me@porcupine.org + 1772 pointer_record: 1491 + 1491 pointer_record: 1789 + 1789 pointer_record: 1829 + 1829 regular_text: To: you@porcupine.org + 1852 pointer_record: 1531 + 1531 pointer_record: 1869 + 1869 pointer_record: 1948 + 1948 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org> + 2010 pointer_record: 1610 + 1610 pointer_record: 2027 + 2027 pointer_record: 2089 + 2089 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT) + 2134 pointer_record: 1672 + 1672 pointer_record: 2151 + 2151 pointer_record: 2186 + 2186 regular_text: Subject: hey! + 2201 padding: 0 + 2204 pointer_record: 489 489 pointer_record: 0 506 regular_text: 508 regular_text: text diff --git a/postfix/src/cleanup/cleanup_milter.ref4 b/postfix/src/cleanup/cleanup_milter.ref4 index 5c8993eee..4c3be60a8 100644 --- a/postfix/src/cleanup/cleanup_milter.ref4 +++ b/postfix/src/cleanup/cleanup_milter.ref4 @@ -24,18 +24,15 @@ 747 original_recipient: alias@hades.porcupine.org 774 recipient: root@porcupine.org 794 pointer_record: 1258 - 1258 named_attribute: notify_flags=1 - 1274 original_recipient: 01 - 1278 canceled_recipient: 01 - 1282 pointer_record: 1299 - 1299 named_attribute: notify_flags=1 - 1315 original_recipient: 02 - 1319 canceled_recipient: 02 - 1323 pointer_record: 1340 - 1340 named_attribute: notify_flags=1 - 1356 original_recipient: 03 - 1360 canceled_recipient: 03 - 1364 pointer_record: 811 + 1258 original_recipient: 01 + 1262 canceled_recipient: 01 + 1266 pointer_record: 1283 + 1283 original_recipient: 02 + 1287 canceled_recipient: 02 + 1291 pointer_record: 1308 + 1308 original_recipient: 03 + 1312 canceled_recipient: 03 + 1316 pointer_record: 811 811 *** MESSAGE CONTENTS test-queue-file4.tmp *** 813 regular_text: Received: from hades.porcupine.org (hades.porcupine.org [168.100.189.10]) 888 regular_text: by hades.porcupine.org (Postfix) with SMTP id 38132290405; diff --git a/postfix/src/flush/Makefile.in b/postfix/src/flush/Makefile.in index 7578940f5..ea0b6df79 100644 --- a/postfix/src/flush/Makefile.in +++ b/postfix/src/flush/Makefile.in @@ -75,7 +75,6 @@ flush.o: ../../include/mail_server.h flush.o: ../../include/mail_version.h flush.o: ../../include/maps.h flush.o: ../../include/match_list.h -flush.o: ../../include/match_ops.h flush.o: ../../include/match_parent_style.h flush.o: ../../include/msg.h flush.o: ../../include/myflock.h diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index e496ca9fc..0a5d596ef 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -31,7 +31,8 @@ SRCS = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \ fold_addr.c header_body_checks.c mkmap_proxy.c data_redirect.c \ match_service.c mail_conf_nint.c addr_match_list.c mail_conf_nbool.c \ smtp_reply_footer.c safe_ultostr.c verify_sender_addr.c \ - dict_memcache.c mail_version.c memcache_proto.c server_acl.c + dict_memcache.c mail_version.c memcache_proto.c server_acl.c \ + mkmap_fail.c OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \ canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \ clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \ @@ -64,7 +65,8 @@ OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \ fold_addr.o header_body_checks.o mkmap_proxy.o data_redirect.o \ match_service.o mail_conf_nint.o addr_match_list.o mail_conf_nbool.o \ smtp_reply_footer.o safe_ultostr.o verify_sender_addr.o \ - dict_memcache.o mail_version.o memcache_proto.o server_acl.o + dict_memcache.o mail_version.o memcache_proto.o server_acl.o \ + mkmap_fail.o HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \ canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \ conv_time.h db_common.h debug_peer.h debug_process.h defer.h \ @@ -596,13 +598,8 @@ 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 @@ -742,7 +739,6 @@ data_redirect.o: mail_params.h db_common.o: ../../include/argv.h db_common.o: ../../include/dict.h db_common.o: ../../include/match_list.h -db_common.o: ../../include/match_ops.h db_common.o: ../../include/msg.h db_common.o: ../../include/mymalloc.h db_common.o: ../../include/sys_defs.h @@ -754,14 +750,9 @@ 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 @@ -878,7 +869,6 @@ dict_ldap.o: ../../include/argv.h dict_ldap.o: ../../include/binhash.h dict_ldap.o: ../../include/dict.h dict_ldap.o: ../../include/match_list.h -dict_ldap.o: ../../include/match_ops.h dict_ldap.o: ../../include/msg.h dict_ldap.o: ../../include/mymalloc.h dict_ldap.o: ../../include/name_code.h @@ -897,7 +887,6 @@ dict_memcache.o: ../../include/argv.h dict_memcache.o: ../../include/auto_clnt.h dict_memcache.o: ../../include/dict.h dict_memcache.o: ../../include/match_list.h -dict_memcache.o: ../../include/match_ops.h dict_memcache.o: ../../include/msg.h dict_memcache.o: ../../include/mymalloc.h dict_memcache.o: ../../include/stringops.h @@ -911,46 +900,10 @@ dict_memcache.o: dict_memcache.c dict_memcache.o: dict_memcache.h dict_memcache.o: memcache_proto.h dict_memcache.o: string_list.h -dict_mysql.o: ../../include/argv.h -dict_mysql.o: ../../include/dict.h -dict_mysql.o: ../../include/events.h -dict_mysql.o: ../../include/find_inet.h -dict_mysql.o: ../../include/match_list.h -dict_mysql.o: ../../include/match_ops.h -dict_mysql.o: ../../include/msg.h -dict_mysql.o: ../../include/mymalloc.h -dict_mysql.o: ../../include/myrand.h -dict_mysql.o: ../../include/split_at.h -dict_mysql.o: ../../include/stringops.h dict_mysql.o: ../../include/sys_defs.h -dict_mysql.o: ../../include/vbuf.h -dict_mysql.o: ../../include/vstream.h -dict_mysql.o: ../../include/vstring.h -dict_mysql.o: cfg_parser.h -dict_mysql.o: db_common.h dict_mysql.o: dict_mysql.c -dict_mysql.o: dict_mysql.h -dict_mysql.o: string_list.h -dict_pgsql.o: ../../include/argv.h -dict_pgsql.o: ../../include/dict.h -dict_pgsql.o: ../../include/events.h -dict_pgsql.o: ../../include/find_inet.h -dict_pgsql.o: ../../include/match_list.h -dict_pgsql.o: ../../include/match_ops.h -dict_pgsql.o: ../../include/msg.h -dict_pgsql.o: ../../include/mymalloc.h -dict_pgsql.o: ../../include/myrand.h -dict_pgsql.o: ../../include/split_at.h -dict_pgsql.o: ../../include/stringops.h dict_pgsql.o: ../../include/sys_defs.h -dict_pgsql.o: ../../include/vbuf.h -dict_pgsql.o: ../../include/vstream.h -dict_pgsql.o: ../../include/vstring.h -dict_pgsql.o: cfg_parser.h -dict_pgsql.o: db_common.h dict_pgsql.o: dict_pgsql.c -dict_pgsql.o: dict_pgsql.h -dict_pgsql.o: string_list.h dict_proxy.o: ../../include/argv.h dict_proxy.o: ../../include/attr.h dict_proxy.o: ../../include/dict.h @@ -970,7 +923,6 @@ dict_proxy.o: mail_proto.h dict_sqlite.o: ../../include/argv.h dict_sqlite.o: ../../include/dict.h dict_sqlite.o: ../../include/match_list.h -dict_sqlite.o: ../../include/match_ops.h dict_sqlite.o: ../../include/msg.h dict_sqlite.o: ../../include/mymalloc.h dict_sqlite.o: ../../include/stringops.h @@ -984,13 +936,8 @@ dict_sqlite.o: dict_sqlite.c dict_sqlite.o: dict_sqlite.h dict_sqlite.o: string_list.h 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 @@ -1083,15 +1030,12 @@ 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/msg.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 @@ -1545,13 +1489,8 @@ 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 @@ -1611,7 +1550,15 @@ mime_state.o: mail_params.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 @@ -1640,11 +1587,22 @@ mkmap_dbm.o: ../../include/vstream.h mkmap_dbm.o: ../../include/vstring.h mkmap_dbm.o: mkmap.h mkmap_dbm.o: mkmap_dbm.c +mkmap_fail.o: ../../include/argv.h +mkmap_fail.o: ../../include/dict.h +mkmap_fail.o: ../../include/dict_fail.h +mkmap_fail.o: ../../include/mymalloc.h +mkmap_fail.o: ../../include/sys_defs.h +mkmap_fail.o: ../../include/vbuf.h +mkmap_fail.o: ../../include/vstream.h +mkmap_fail.o: ../../include/vstring.h +mkmap_fail.o: mkmap.h +mkmap_fail.o: mkmap_fail.c mkmap_open.o: ../../include/argv.h mkmap_open.o: ../../include/dict.h mkmap_open.o: ../../include/dict_cdb.h mkmap_open.o: ../../include/dict_db.h mkmap_open.o: ../../include/dict_dbm.h +mkmap_open.o: ../../include/dict_fail.h mkmap_open.o: ../../include/dict_sdbm.h mkmap_open.o: ../../include/msg.h mkmap_open.o: ../../include/mymalloc.h @@ -1721,13 +1679,8 @@ 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 @@ -1905,7 +1858,6 @@ 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/msg.h resolve_local.o: ../../include/myaddrinfo.h resolve_local.o: ../../include/mymalloc.h @@ -2009,7 +1961,6 @@ 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/mymalloc.h server_acl.o: ../../include/stringops.h @@ -2055,13 +2006,8 @@ 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 @@ -2156,7 +2102,6 @@ user_acl.o: ../../include/argv.h user_acl.o: ../../include/dict.h user_acl.o: ../../include/dict_static.h user_acl.o: ../../include/match_list.h -user_acl.o: ../../include/match_ops.h user_acl.o: ../../include/sys_defs.h user_acl.o: ../../include/vbuf.h user_acl.o: ../../include/vstream.h diff --git a/postfix/src/global/addr_match_list.c b/postfix/src/global/addr_match_list.c index 86cbe9c55..946cf4ae3 100644 --- a/postfix/src/global/addr_match_list.c +++ b/postfix/src/global/addr_match_list.c @@ -37,8 +37,9 @@ /* 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 zero with -/* dict_errno != 0, instead of raising a fatal error. +/* Request that addr_match_list_match() logs a warning and +/* returns zero with list->error set to a non-zero dictionary +/* error code, 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 @@ -120,12 +121,12 @@ int main(int argc, char **argv) while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) vstream_printf("%s: %s\n", vstring_str(buf), addr_match_list_match(list, vstring_str(buf)) ? - "YES" : dict_errno == 0 ? "NO" : "ERROR"); + "YES" : list->error == 0 ? "NO" : "ERROR"); vstring_free(buf); } else { vstream_printf("%s: %s\n", addr, addr_match_list_match(list, addr) > 0 ? - "YES" : dict_errno == 0 ? "NO" : "ERROR"); + "YES" : list->error == 0 ? "NO" : "ERROR"); } vstream_fflush(VSTREAM_OUT); addr_match_list_free(list); diff --git a/postfix/src/global/db_common.c b/postfix/src/global/db_common.c index 4dbeedb93..6b3edbdf8 100644 --- a/postfix/src/global/db_common.c +++ b/postfix/src/global/db_common.c @@ -87,10 +87,10 @@ /* If \fIkey\fR is a fully qualified address, the domain part of the /* address. Otherwise the query against the database is suppressed and /* the lookup returns no results. -/* /* .PP -/* \fIdb_common_check_domain\fR checks domain list so that query optimization -/* can be performed +/* \fIdb_common_check_domain\fR() checks the domain list so +/* that query optimization can be performed. The result is >0 +/* (match found), 0 (no match), or <0 (dictionary error code). /* /* .PP /* \fIdb_common_sql_build_query\fR builds the "default"(backwards compatible) @@ -256,7 +256,7 @@ void db_common_parse_domain(CFG_PARSER *parser, void *ctxPtr) domainlist = cfg_get_str(parser, "domain", "", 0, 0); if (*domainlist) { - ctx->domain = string_list_init(MATCH_FLAG_NONE, domainlist); + ctx->domain = string_list_init(MATCH_FLAG_RETURN, domainlist); if (ctx->domain == 0) /* @@ -528,7 +528,7 @@ int db_common_check_domain(void *ctxPtr, const char *addr) if (domain == NULL || domain == addr + 1) return (0); if (match_list_match(ctx->domain, domain) == 0) - return (0); + return (ctx->domain->error); } return (1); } diff --git a/postfix/src/global/dict_ldap.c b/postfix/src/global/dict_ldap.c index 0a5bb53b9..6398dcc89 100644 --- a/postfix/src/global/dict_ldap.c +++ b/postfix/src/global/dict_ldap.c @@ -86,14 +86,14 @@ /* .IP recursion_limit /* Maximum recursion depth when expanding DN or URL references. /* Queries which exceed the recursion limit fail with -/* dict_errno = DICT_ERR_RETRY. +/* dict->error = DICT_ERR_RETRY. /* .IP expansion_limit /* Limit (if any) on the total number of lookup result values. Lookups which -/* exceed the limit fail with dict_errno=DICT_ERR_RETRY. Note that +/* exceed the limit fail with dict->error=DICT_ERR_RETRY. Note that /* each value of a multivalued result attribute counts as one result. /* .IP size_limit /* Limit on the number of entries returned by individual LDAP queries. -/* Queries which exceed the limit fail with dict_errno=DICT_ERR_RETRY. +/* Queries which exceed the limit fail with dict->error=DICT_ERR_RETRY. /* This is an *entry* count, for any single query performed during the /* possibly recursive lookup. /* .IP chase_referrals @@ -317,7 +317,7 @@ typedef struct { #define DICT_LDAP_UNBIND_RETURN(__ld, __err, __ret) do { \ dict_ldap_unbind(__ld); \ (__ld) = 0; \ - dict_errno = (__err); \ + dict_ldap->dict.error = (__err); \ return ((__ret)); \ } while (0) @@ -728,7 +728,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap) msg_warn("%s: Unable to set LDAP debug level.", myname); #endif - dict_errno = 0; + dict_ldap->dict.error = 0; if (msg_verbose) msg_info("%s: Connecting to server %s", myname, @@ -744,7 +744,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap) if (dict_ldap->ld == NULL) { msg_warn("%s: Unable to init LDAP server %s", myname, dict_ldap->server_host); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; return (-1); } mytimeval.tv_sec = dict_ldap->timeout; @@ -758,7 +758,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap) if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) { msg_warn("%s: Error setting signal handler for open timeout: %m", myname); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; return (-1); } alarm(dict_ldap->timeout); @@ -772,13 +772,13 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap) if (signal(SIGALRM, saved_alarm) == SIG_ERR) { msg_warn("%s: Error resetting signal handler after open: %m", myname); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; return (-1); } if (dict_ldap->ld == NULL) { msg_warn("%s: Unable to connect to LDAP server %s", myname, dict_ldap->server_host); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; return (-1); } #endif @@ -861,13 +861,13 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap) if (signal(SIGALRM, saved_alarm) == SIG_ERR) { msg_warn("%s: Error resetting signal handler after STARTTLS: %m", myname); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; return (-1); } if (rc != LDAP_SUCCESS) { msg_error("%s: Unable to set STARTTLS: %d: %s", myname, rc, ldap_err2string(rc)); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; return (-1); } } @@ -1104,13 +1104,13 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res, * LDAP should not, but may produce more than the requested maximum * number of entries. */ - if (dict_errno == 0 + if (dict_ldap->dict.error == 0 && dict_ldap->size_limit && ++entries > dict_ldap->size_limit) { msg_warn("%s[%d]: %s: Query size limit (%ld) exceeded", myname, recursion, dict_ldap->parser->name, dict_ldap->size_limit); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; } /* @@ -1169,7 +1169,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res, * leaks, but it will likely be more fragile and not worth the * extra code. */ - if (dict_errno != 0 || valcount == 0) { + if (dict_ldap->dict.error != 0 || valcount == 0) { ldap_value_free_len(vals); continue; } @@ -1214,11 +1214,11 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res, msg_warn("%s[%d]: %s: Expansion limit exceeded " "for key: '%s'", myname, recursion, dict_ldap->parser->name, name); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; break; } } - if (dict_errno != 0) + if (dict_ldap->dict.error != 0) continue; if (msg_verbose) msg_info("%s[%d]: search returned %d value(s) for" @@ -1255,7 +1255,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res, msg_warn("%s[%d]: malformed URL %s: %s(%d)", myname, recursion, vals[i]->bv_val, ldap_err2string(rc), rc); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; break; } } else { @@ -1283,17 +1283,17 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res, default: msg_warn("%s[%d]: search error %d: %s ", myname, recursion, rc, ldap_err2string(rc)); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; break; } if (resloop != 0) ldap_msgfree(resloop); - if (dict_errno != 0) + if (dict_ldap->dict.error != 0) break; } - if (msg_verbose && dict_errno == 0) + if (msg_verbose && dict_ldap->dict.error == 0) msg_info("%s[%d]: search returned %d value(s) for" " special result attribute %s", myname, recursion, valcount, attr); @@ -1302,7 +1302,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res, msg_warn("%s[%d]: %s: Recursion limit exceeded" " for special attribute %s=%s", myname, recursion, dict_ldap->parser->name, attr, vals[0]->bv_val); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; } ldap_value_free_len(vals); } @@ -1327,8 +1327,9 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) static VSTRING *result; int rc = 0; int sizelimit; + int domain_rc; - dict_errno = 0; + dict_ldap->dict.error = 0; if (msg_verbose) msg_info("%s: In dict_ldap_lookup", myname); @@ -1358,12 +1359,15 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) * addresses in domains on the list. This can significantly reduce the * load on the LDAP server. */ - if (db_common_check_domain(dict_ldap->ctx, name) == 0) { + if ((domain_rc = db_common_check_domain(dict_ldap->ctx, name)) == 0) { if (msg_verbose) msg_info("%s: %s: Skipping lookup of key '%s': domain mismatch", myname, dict_ldap->parser->name, name); return (0); } + if (domain_rc < 0) + DICT_ERR_VAL_RETURN(dict, domain_rc, (char *) 0); + #define INIT_VSTR(buf, len) do { \ if (buf == 0) \ buf = vstring_alloc(len); \ @@ -1394,9 +1398,9 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) dict_ldap_connect(dict_ldap); /* - * if dict_ldap_connect() set dict_errno, abort. + * if dict_ldap_connect() set dict_ldap->dict.error, abort. */ - if (dict_errno) + if (dict_ldap->dict.error) return (0); } else if (msg_verbose) msg_info("%s: Using existing connection for LDAP source %s", @@ -1414,7 +1418,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) != LDAP_OPT_SUCCESS) { msg_warn("%s: %s: Unable to set query result size limit to %ld.", myname, dict_ldap->parser->name, dict_ldap->size_limit); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; return (0); } @@ -1463,9 +1467,9 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) dict_ldap_connect(dict_ldap); /* - * if dict_ldap_connect() set dict_errno, abort. + * if dict_ldap_connect() set dict_ldap->dict.error, abort. */ - if (dict_errno) + if (dict_ldap->dict.error) return (0); rc = search_st(dict_ldap->ld, vstring_str(base), dict_ldap->scope, @@ -1513,7 +1517,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) msg_warn("%s: %s: Search base '%s' not found: %d: %s", myname, dict_ldap->parser->name, vstring_str(base), rc, ldap_err2string(rc)); - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; break; default: @@ -1534,7 +1538,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) /* * And tell the caller to try again later. */ - dict_errno = DICT_ERR_RETRY; + dict_ldap->dict.error = DICT_ERR_RETRY; break; } @@ -1548,7 +1552,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) * If we had an error, return nothing, Otherwise, return the result, if * any. */ - return (VSTRING_LEN(result) > 0 && !dict_errno ? vstring_str(result) : 0); + return (VSTRING_LEN(result) > 0 && !dict_ldap->dict.error ? vstring_str(result) : 0); } /* dict_ldap_close - disassociate from data base */ diff --git a/postfix/src/global/dict_memcache.c b/postfix/src/global/dict_memcache.c index e6405e633..a60a20e8d 100644 --- a/postfix/src/global/dict_memcache.c +++ b/postfix/src/global/dict_memcache.c @@ -89,7 +89,7 @@ typedef struct { VSTRING *clnt_buf; /* memcache client buffer */ VSTRING *key_buf; /* lookup key */ VSTRING *res_buf; /* lookup result */ - int mc_errno; /* memcache dict_errno */ + int error; /* memcache dict_errno */ DICT *backup; /* persistent backup */ } DICT_MC; @@ -129,22 +129,23 @@ typedef struct { /* dict_memcache_set - set memcache key/value */ -static void dict_memcache_set(DICT_MC *dict_mc, const char *value, int ttl) +static int dict_memcache_set(DICT_MC *dict_mc, const char *value, int ttl) { VSTREAM *fp; int count; int data_len = strlen(value); /* - * If we can't retrieve it, then we must not store it. + * Return a permanent error if we can't store this data. This results in + * loss of information. */ - dict_mc->mc_errno = DICT_ERR_RETRY; /* XXX */ if (data_len > dict_mc->max_data) { msg_warn("database %s:%s: data for key %s is too long (%s=%d) " "-- not stored", DICT_TYPE_MEMCACHE, dict_mc->dict.name, STR(dict_mc->key_buf), DICT_MC_NAME_MAX_DATA, dict_mc->max_data); - return; + /* Not stored! */ + DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, DICT_STAT_FAIL); } for (count = 0; count < dict_mc->max_tries; count++) { if (count > 0) @@ -167,11 +168,11 @@ static void dict_memcache_set(DICT_MC *dict_mc, const char *value, int ttl) STR(dict_mc->clnt_buf)); } else { /* Victory! */ - dict_mc->mc_errno = 0; - break; + DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, DICT_STAT_SUCCESS); } auto_clnt_recover(dict_mc->clnt); } + DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_RETRY, DICT_STAT_ERROR); } /* dict_memcache_get - get memcache key/value */ @@ -180,11 +181,8 @@ static const char *dict_memcache_get(DICT_MC *dict_mc) { VSTREAM *fp; long todo; - const char *retval; int count; - dict_mc->mc_errno = DICT_ERR_RETRY; - retval = 0; for (count = 0; count < dict_mc->max_tries; count++) { if (count > 0) sleep(dict_mc->err_pause); @@ -198,8 +196,7 @@ static const char *dict_memcache_get(DICT_MC *dict_mc) 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; + DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, (char *) 0); } else if (sscanf(STR(dict_mc->clnt_buf), "VALUE %*s %*s %ld", &todo) != 1 || todo < 0 || todo > dict_mc->max_data) { @@ -212,16 +209,14 @@ static const char *dict_memcache_get(DICT_MC *dict_mc) 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; + DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, STR(dict_mc->res_buf)); } auto_clnt_recover(dict_mc->clnt); } - return (retval); + DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_RETRY, (char *) 0); } /* dict_memcache_del - delete memcache key/value */ @@ -230,9 +225,7 @@ static int dict_memcache_del(DICT_MC *dict_mc) { VSTREAM *fp; int count; - int retval = -1; - dict_mc->mc_errno = DICT_ERR_RETRY; for (count = 0; count < dict_mc->max_tries; count++) { if (count > 0) sleep(dict_mc->err_pause); @@ -246,14 +239,10 @@ static int dict_memcache_del(DICT_MC *dict_mc) 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; + DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, DICT_STAT_SUCCESS); } else if (strcmp(STR(dict_mc->clnt_buf), "NOT_FOUND") == 0) { /* Not found! */ - dict_mc->mc_errno = 0; - retval = 1; - break; + DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, DICT_STAT_FAIL); } else { if (count > 0) msg_warn("database %s:%s: delete failed: %.30s", @@ -262,7 +251,7 @@ static int dict_memcache_del(DICT_MC *dict_mc) } auto_clnt_recover(dict_mc->clnt); } - return (retval); + DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_RETRY, DICT_STAT_ERROR); } /* dict_memcache_prepare_key - prepare lookup key */ @@ -311,65 +300,67 @@ static int dict_memcache_valid_key(DICT_MC *dict_mc, void (*log_func) (const char *,...)) { unsigned char *cp; + int rc; #define DICT_MC_SKIP(why) do { \ if (msg_verbose || log_func != msg_info) \ log_func("%s: skipping %s for name \"%s\": %s", \ dict_mc->dict.name, operation, name, (why)); \ - return(0); \ + DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, 0); \ } while (0) if (*name == 0) DICT_MC_SKIP("empty lookup key"); - if (db_common_check_domain(dict_mc->dbc_ctxt, name) == 0) + if ((rc = db_common_check_domain(dict_mc->dbc_ctxt, name)) == 0) DICT_MC_SKIP("domain mismatch"); + if (rc < 0) + DICT_ERR_VAL_RETURN(dict_mc, rc, 0); if (dict_memcache_prepare_key(dict_mc, name) == 0) DICT_MC_SKIP("empty lookup key expansion"); for (cp = (unsigned char *) STR(dict_mc->key_buf); *cp; cp++) if (isascii(*cp) && isspace(*cp)) DICT_MC_SKIP("name contains space"); - return (1); + DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, 1); } /* dict_memcache_update - update memcache */ -static void dict_memcache_update(DICT *dict, const char *name, - const char *value) +static int dict_memcache_update(DICT *dict, const char *name, + const char *value) { const char *myname = "dict_memcache_update"; DICT_MC *dict_mc = (DICT_MC *) dict; DICT *backup = dict_mc->backup; - int backup_errno = 0; + int upd_res; /* * Skip updates with an inapplicable key, noisily. This results in loss * of information. */ - dict_errno = DICT_ERR_RETRY; if (dict_memcache_valid_key(dict_mc, name, "update", msg_warn) == 0) - return; + DICT_ERR_VAL_RETURN(dict, dict_mc->error, DICT_STAT_FAIL); /* * Update the memcache first. */ - dict_memcache_set(dict_mc, value, dict_mc->mc_ttl); + upd_res = dict_memcache_set(dict_mc, value, dict_mc->mc_ttl); + dict->error = dict_mc->error; /* * Update the backup database last. */ if (backup) { - dict_errno = 0; - backup->update(backup, name, value); - backup_errno = dict_errno; + upd_res = backup->update(backup, name, value); + dict->error = backup->error; } if (msg_verbose) msg_info("%s: %s: update key \"%s\"(%s) => \"%s\" %s", myname, dict_mc->dict.name, name, STR(dict_mc->key_buf), - value, dict_mc->mc_errno ? "(memcache error)" : - backup_errno ? "(backup error)" : "(no error)"); + value, dict_mc->error ? "(memcache error)" : (backup + && backup->error) ? "(backup error)" : "(no error)"); - dict_errno = (backup ? backup_errno : dict_mc->mc_errno); + return (upd_res); } /* dict_memcache_lookup - lookup memcache */ @@ -380,39 +371,39 @@ static const char *dict_memcache_lookup(DICT *dict, const char *name) DICT_MC *dict_mc = (DICT_MC *) dict; DICT *backup = dict_mc->backup; const char *retval; - int backup_errno = 0; /* * Skip lookups with an inapplicable key, silently. This is just asking * for information that cannot exist. */ - dict_errno = 0; if (dict_memcache_valid_key(dict_mc, name, "lookup", msg_info) == 0) - return (0); + DICT_ERR_VAL_RETURN(dict, dict_mc->error, (char *) 0); /* * Search the memcache first. */ retval = dict_memcache_get(dict_mc); + dict->error = dict_mc->error; /* * Search the backup database last. Update the memcache if the data is * found. */ - if (retval == 0 && backup) { - retval = backup->lookup(backup, name); - backup_errno = dict_errno; - /* Update the cache. */ - if (retval != 0) - dict_memcache_set(dict_mc, retval, dict_mc->mc_ttl); + if (backup) { + backup->error = 0; + if (retval == 0) { + retval = backup->lookup(backup, name); + dict->error = backup->error; + /* Update the cache. */ + if (retval != 0) + dict_memcache_set(dict_mc, retval, dict_mc->mc_ttl); + } } if (msg_verbose) msg_info("%s: %s: key \"%s\"(%s) => %s", myname, dict_mc->dict.name, name, STR(dict_mc->key_buf), - retval ? retval : dict_mc->mc_errno ? "(memcache error)" : - backup_errno ? "(backup error)" : "(not found)"); - - dict_errno = (backup ? backup_errno : dict_mc->mc_errno); + retval ? retval : dict_mc->error ? "(memcache error)" : + (backup && backup->error) ? "(backup error)" : "(not found)"); return (retval); } @@ -424,37 +415,34 @@ static int dict_memcache_delete(DICT *dict, const char *name) const char *myname = "dict_memcache_delete"; DICT_MC *dict_mc = (DICT_MC *) dict; DICT *backup = dict_mc->backup; - int backup_errno = 0; int del_res; /* - * Skip lookups with an inapplicable key, silently. This is just deleting + * Skip lookups with an inapplicable key, noisily. This is just deleting * information that cannot exist. */ - dict_errno = 0; if (dict_memcache_valid_key(dict_mc, name, "delete", msg_info) == 0) - return (1); + DICT_ERR_VAL_RETURN(dict, dict_mc->error, dict_mc->error ? + DICT_STAT_ERROR : DICT_STAT_FAIL); /* * Update the memcache first. */ del_res = dict_memcache_del(dict_mc); + dict->error = dict_mc->error; /* * Update the persistent database last. */ if (backup) { - dict_errno = 0; del_res = backup->delete(backup, name); - backup_errno = dict_errno; + dict->error = backup->error; } if (msg_verbose) msg_info("%s: %s: delete key \"%s\"(%s) => %s", myname, dict_mc->dict.name, name, STR(dict_mc->key_buf), - dict_mc->mc_errno ? "(memcache error)" : - backup_errno ? "(backup error)" : "(no error)"); - - dict_errno = (backup ? backup_errno : dict_mc->mc_errno); + dict_mc->error ? "(memcache error)" : (backup + && backup->error) ? "(backup error)" : "(no error)"); return (del_res); } @@ -464,15 +452,22 @@ static int dict_memcache_delete(DICT *dict, const char *name) static int dict_memcache_sequence(DICT *dict, int function, const char **key, const char **value) { + const char *myname = "dict_memcache_sequence"; DICT_MC *dict_mc = (DICT_MC *) dict; DICT *backup = dict_mc->backup; + int seq_res; if (backup == 0) { msg_warn("database %s:%s: first/next support requires backup database", DICT_TYPE_MEMCACHE, dict_mc->dict.name); - return (1); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL); } else { - return (backup->sequence(backup, function, key, value)); + seq_res = backup->sequence(backup, function, key, value); + msg_info("%s: %s: key \"%s\" => %s", + myname, dict_mc->dict.name, *key ? *key : "(not found)", + *value ? *value : backup->error ? "(backup error)" : + "(not found)"); + DICT_ERR_VAL_RETURN(dict, backup->error, seq_res); } } diff --git a/postfix/src/global/dict_mysql.c b/postfix/src/global/dict_mysql.c index 8425cd72a..8f7285234 100644 --- a/postfix/src/global/dict_mysql.c +++ b/postfix/src/global/dict_mysql.c @@ -71,7 +71,7 @@ /* the lookup result unchanged. /* .IP expansion_limit /* Limit (if any) on the total number of lookup result values. Lookups which -/* exceed the limit fail with dict_errno=DICT_ERR_RETRY. Note that each +/* exceed the limit fail with dict->error=DICT_ERR_RETRY. Note that each /* non-empty (and non-NULL) column of a multi-column result row counts as /* one result. /* .IP table @@ -237,13 +237,13 @@ typedef struct { #define TYPEINET (1<<1) #define RETRY_CONN_MAX 100 -#define RETRY_CONN_INTV 60 /* 1 minute */ -#define IDLE_CONN_INTV 60 /* 1 minute */ +#define RETRY_CONN_INTV 60 /* 1 minute */ +#define IDLE_CONN_INTV 60 /* 1 minute */ /* internal function declarations */ static PLMYSQL *plmysql_init(ARGV *); static MYSQL_RES *plmysql_query(DICT_MYSQL *, const char *, VSTRING *, char *, - char *, char *); + char *, char *); static void plmysql_dealloc(PLMYSQL *); static void plmysql_close_host(HOST *); static void plmysql_down_host(HOST *); @@ -259,12 +259,12 @@ static HOST *host_init(const char *); static void dict_mysql_quote(DICT *dict, const char *name, VSTRING *result) { DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict; - int len = strlen(name); - int buflen = 2*len + 1; + int len = strlen(name); + int buflen = 2 * len + 1; /* - * We won't get integer overflows in 2*len + 1, because Postfix - * input keys have reasonable size limits, better safe than sorry. + * We won't get integer overflows in 2*len + 1, because Postfix input + * keys have reasonable size limits, better safe than sorry. */ if (buflen < len) msg_panic("dict_mysql_quote: integer overflow in 2*%d+1", len); @@ -286,8 +286,7 @@ static void dict_mysql_quote(DICT *dict, const char *name, VSTRING *result) static const char *dict_mysql_lookup(DICT *dict, const char *name) { const char *myname = "dict_mysql_lookup"; - DICT_MYSQL *dict_mysql = (DICT_MYSQL *)dict; - PLMYSQL *pldb = dict_mysql->pldb; + DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict; MYSQL_RES *query_res; MYSQL_ROW row; static VSTRING *result; @@ -298,8 +297,9 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name) int expansion; const char *r; db_quote_callback_t quote_func = dict_mysql_quote; + int domain_rc; - dict_errno = 0; + dict->error = 0; /* * Optionally fold the key. @@ -312,15 +312,17 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name) } /* - * If there is a domain list for this map, then only search for - * addresses in domains on the list. This can significantly reduce - * the load on the server. + * If there is a domain list for this map, then only search for addresses + * in domains on the list. This can significantly reduce the load on the + * server. */ - if (db_common_check_domain(dict_mysql->ctx, name) == 0) { - if (msg_verbose) + if ((domain_rc = db_common_check_domain(dict_mysql->ctx, name)) == 0) { + if (msg_verbose) msg_info("%s: Skipping lookup of '%s'", myname, name); - return (0); + return (0); } + if (domain_rc < 0) + DICT_ERR_VAL_RETURN(dict, domain_rc, (char *) 0); #define INIT_VSTR(buf, len) do { \ if (buf == 0) \ @@ -333,28 +335,27 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name) /* * Suppress the lookup if the query expansion is empty - * - * This initial expansion is outside the context of any - * specific host connection, we just want to check the - * key pre-requisites, so when quoting happens separately - * for each connection, we don't bother with quoting... + * + * This initial expansion is outside the context of any specific host + * connection, we just want to check the key pre-requisites, so when + * quoting happens separately for each connection, we don't bother with + * quoting... */ #if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000 quote_func = 0; #endif if (!db_common_expand(dict_mysql->ctx, dict_mysql->query, - name, 0, query, quote_func)) - return (0); - - /* do the query - set dict_errno & cleanup if there's an error */ + name, 0, query, quote_func)) + return (0); + + /* do the query - set dict->error & cleanup if there's an error */ if ((query_res = plmysql_query(dict_mysql, name, query, dict_mysql->dbname, dict_mysql->username, dict_mysql->password)) == 0) { - dict_errno = DICT_ERR_RETRY; + dict->error = DICT_ERR_RETRY; return (0); } - numrows = mysql_num_rows(query_res); if (msg_verbose) msg_info("%s: retrieved %d rows", myname, numrows); @@ -362,32 +363,31 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name) mysql_free_result(query_res); return 0; } - INIT_VSTR(result, 10); - for (expansion = i = 0; i < numrows && dict_errno == 0; i++) { + for (expansion = i = 0; i < numrows && dict->error == 0; i++) { row = mysql_fetch_row(query_res); for (j = 0; j < mysql_num_fields(query_res); j++) { if (db_common_expand(dict_mysql->ctx, dict_mysql->result_format, - row[j], name, result, 0) + row[j], name, result, 0) && dict_mysql->expansion_limit > 0 && ++expansion > dict_mysql->expansion_limit) { msg_warn("%s: %s: Expansion limit exceeded for key: '%s'", myname, dict_mysql->parser->name, name); - dict_errno = DICT_ERR_RETRY; + dict->error = DICT_ERR_RETRY; break; } } } mysql_free_result(query_res); r = vstring_str(result); - return ((dict_errno == 0 && *r) ? r : 0); + return ((dict->error == 0 && *r) ? r : 0); } /* dict_mysql_check_stat - check the status of a host */ static int dict_mysql_check_stat(HOST *host, unsigned stat, unsigned type, - time_t t) + time_t t) { if ((host->stat & stat) && (!type || host->type & type)) { /* try not to hammer the dead hosts too often */ @@ -429,7 +429,7 @@ static HOST *dict_mysql_find_host(PLMYSQL *PLDB, unsigned stat, unsigned type) /* dict_mysql_get_active - get an active connection */ static HOST *dict_mysql_get_active(PLMYSQL *PLDB, char *dbname, - char *username, char *password) + char *username, char *password) { const char *myname = "dict_mysql_get_active"; HOST *host; @@ -445,15 +445,15 @@ static HOST *dict_mysql_get_active(PLMYSQL *PLDB, char *dbname, } /* - * Try the remaining hosts. - * "count" is a safety net, in case the loop takes more than - * RETRY_CONN_INTV and the dead hosts are no longer skipped. + * Try the remaining hosts. "count" is a safety net, in case the loop + * takes more than RETRY_CONN_INTV and the dead hosts are no longer + * skipped. */ while (--count > 0 && ((host = dict_mysql_find_host(PLDB, STATUNTRIED | STATFAIL, TYPEUNIX)) != NULL || - (host = dict_mysql_find_host(PLDB, STATUNTRIED | STATFAIL, - TYPEINET)) != NULL)) { + (host = dict_mysql_find_host(PLDB, STATUNTRIED | STATFAIL, + TYPEINET)) != NULL)) { if (msg_verbose) msg_info("%s: attempting to connect to host %s", myname, host->hostname); @@ -485,7 +485,7 @@ static void dict_mysql_event(int unused_event, char *context) static MYSQL_RES *plmysql_query(DICT_MYSQL *dict_mysql, const char *name, - VSTRING *query, + VSTRING *query, char *dbname, char *username, char *password) @@ -497,9 +497,10 @@ static MYSQL_RES *plmysql_query(DICT_MYSQL *dict_mysql, while ((host = dict_mysql_get_active(PLDB, dbname, username, password)) != NULL) { #if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000 + /* - * The active host is used to escape strings in the - * context of the active connection's character encoding. + * The active host is used to escape strings in the context of the + * active connection's character encoding. */ dict_mysql->active_host = host; VSTRING_RESET(query); @@ -584,14 +585,14 @@ static void mysql_parse_config(DICT_MYSQL *dict_mysql, const char *mysqlcf) const char *myname = "mysqlname_parse"; CFG_PARSER *p; VSTRING *buf; - int i; char *hosts; - + p = dict_mysql->parser = cfg_parser_alloc(mysqlcf); dict_mysql->username = cfg_get_str(p, "user", "", 0, 0); dict_mysql->password = cfg_get_str(p, "password", "", 0, 0); dict_mysql->dbname = cfg_get_str(p, "dbname", "", 1, 0); dict_mysql->result_format = cfg_get_str(p, "result_format", "%s", 1, 0); + /* * XXX: The default should be non-zero for safety, but that is not * backwards compatible. @@ -600,10 +601,11 @@ static void mysql_parse_config(DICT_MYSQL *dict_mysql, const char *mysqlcf) "expansion_limit", 0, 0, 0); if ((dict_mysql->query = cfg_get_str(p, "query", NULL, 0, 0)) == 0) { - /* - * No query specified -- fallback to building it from components - * (old style "select %s from %s where %s") - */ + + /* + * No query specified -- fallback to building it from components (old + * style "select %s from %s where %s") + */ buf = vstring_alloc(64); db_common_sql_build_query(buf, p); dict_mysql->query = vstring_export(buf); @@ -619,8 +621,8 @@ static void mysql_parse_config(DICT_MYSQL *dict_mysql, const char *mysqlcf) db_common_parse_domain(p, dict_mysql->ctx); /* - * Maps that use substring keys should only be used with the full - * input key. + * Maps that use substring keys should only be used with the full input + * key. */ if (db_common_dict_partial(dict_mysql->ctx)) dict_mysql->dict.flags |= DICT_FLAG_PATTERN; @@ -728,7 +730,6 @@ static HOST *host_init(const char *hostname) host->name = 0; host->type = TYPEUNIX; } - if (msg_verbose > 1) msg_info("%s: host=%s, port=%d, type=%s", myname, host->name ? host->name : "localhost", @@ -740,7 +741,6 @@ static HOST *host_init(const char *hostname) static void dict_mysql_close(DICT *dict) { - int i; DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict; plmysql_dealloc(dict_mysql->pldb); @@ -751,7 +751,7 @@ static void dict_mysql_close(DICT *dict) myfree(dict_mysql->query); myfree(dict_mysql->result_format); if (dict_mysql->hosts) - argv_free(dict_mysql->hosts); + argv_free(dict_mysql->hosts); if (dict_mysql->ctx) db_common_free_ctx(dict_mysql->ctx); if (dict->fold_buf) diff --git a/postfix/src/global/dict_pgsql.c b/postfix/src/global/dict_pgsql.c index c4c0e5fb8..a98a0c979 100644 --- a/postfix/src/global/dict_pgsql.c +++ b/postfix/src/global/dict_pgsql.c @@ -72,7 +72,7 @@ /* the lookup result unchanged. /* .IP expansion_limit /* Limit (if any) on the total number of lookup result values. Lookups which -/* exceed the limit fail with dict_errno=DICT_ERR_RETRY. Note that each +/* exceed the limit fail with dict->error=DICT_ERR_RETRY. Note that each /* non-empty (and non-NULL) column of a multi-column result row counts as /* one result. /* .IP select_function @@ -182,8 +182,8 @@ #define TYPEINET (1<<1) #define RETRY_CONN_MAX 100 -#define RETRY_CONN_INTV 60 /* 1 minute */ -#define IDLE_CONN_INTV 60 /* 1 minute */ +#define RETRY_CONN_INTV 60 /* 1 minute */ +#define IDLE_CONN_INTV 60 /* 1 minute */ typedef struct { PGconn *db; @@ -223,7 +223,7 @@ typedef struct { /* internal function declarations */ static PLPGSQL *plpgsql_init(ARGV *); static PGSQL_RES *plpgsql_query(DICT_PGSQL *, const char *, VSTRING *, char *, - char *, char *); + char *, char *); static void plpgsql_dealloc(PLPGSQL *); static void plpgsql_close_host(HOST *); static void plpgsql_down_host(HOST *); @@ -238,21 +238,21 @@ static HOST *host_init(const char *); static void dict_pgsql_quote(DICT *dict, const char *name, VSTRING *result) { DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict; - HOST *active_host = dict_pgsql->active_host; - char *myname = "dict_pgsql_quote"; - size_t len = strlen(name); - size_t buflen = 2*len + 1; - int err = 1; + HOST *active_host = dict_pgsql->active_host; + char *myname = "dict_pgsql_quote"; + size_t len = strlen(name); + size_t buflen = 2 * len + 1; + int err = 1; if (active_host == 0) msg_panic("%s: bogus dict_pgsql->active_host", myname); /* - * We won't get arithmetic overflows in 2*len + 1, because Postfix - * input keys have reasonable size limits, better safe than sorry. + * We won't get arithmetic overflows in 2*len + 1, because Postfix input + * keys have reasonable size limits, better safe than sorry. */ if (buflen <= len) - msg_panic("%s: arithmetic overflow in 2*%lu+1", + msg_panic("%s: arithmetic overflow in 2*%lu+1", myname, (unsigned long) len); /* @@ -264,48 +264,48 @@ static void dict_pgsql_quote(DICT *dict, const char *name, VSTRING *result) return; /* - * Escape the input string, using PQescapeStringConn(), because - * the older PQescapeString() is not safe anymore, as stated by the - * documentation. - * + * Escape the input string, using PQescapeStringConn(), because the older + * PQescapeString() is not safe anymore, as stated by the documentation. + * * From current libpq (8.1.4) documentation: - * - * PQescapeStringConn writes an escaped version of the from string - * to the to buffer, escaping special characters so that they cannot - * cause any harm, and adding a terminating zero byte. - * + * + * PQescapeStringConn writes an escaped version of the from string to the to + * buffer, escaping special characters so that they cannot cause any + * harm, and adding a terminating zero byte. + * * ... - * - * The parameter from points to the first character of the string - * that is to be escaped, and the length parameter gives the number - * of bytes in this string. A terminating zero byte is not required, - * and should not be counted in length. - * + * + * The parameter from points to the first character of the string that is to + * be escaped, and the length parameter gives the number of bytes in this + * string. A terminating zero byte is not required, and should not be + * counted in length. + * * ... - * - * (The parameter) to shall point to a buffer that is able to hold - * at least one more byte than twice the value of length, otherwise - * the behavior is undefined. - * + * + * (The parameter) to shall point to a buffer that is able to hold at least + * one more byte than twice the value of length, otherwise the behavior + * is undefined. + * * ... - * + * * If the error parameter is not NULL, then *error is set to zero on - * success, nonzero on error ... The output string is still generated - * on error, but it can be expected that the server will reject it as - * malformed. On error, a suitable message is stored in the conn - * object, whether or not error is NULL. + * success, nonzero on error ... The output string is still generated on + * error, but it can be expected that the server will reject it as + * malformed. On error, a suitable message is stored in the conn object, + * whether or not error is NULL. */ VSTRING_SPACE(result, buflen); PQescapeStringConn(active_host->db, vstring_end(result), name, len, &err); if (err == 0) { VSTRING_SKIP(result); } else { - /* - * PQescapeStringConn() failed. According to the docs, we still - * have a valid, null-terminated output string, but we need not - * rely on this behavior. + + /* + * PQescapeStringConn() failed. According to the docs, we still have + * a valid, null-terminated output string, but we need not rely on + * this behavior. */ - msg_warn("dict pgsql: (host %s) cannot escape input string: %s", + msg_warn("dict pgsql: (host %s) cannot escape input string: %s", active_host->hostname, PQerrorMessage(active_host->db)); active_host->stat = STATFAIL; VSTRING_TERMINATE(result); @@ -328,7 +328,8 @@ static const char *dict_pgsql_lookup(DICT *dict, const char *name) int numcols; int expansion; const char *r; - + int domain_rc; + dict_pgsql = (DICT_PGSQL *) dict; pldb = dict_pgsql->pldb; @@ -342,7 +343,7 @@ static const char *dict_pgsql_lookup(DICT *dict, const char *name) INIT_VSTR(query, 10); INIT_VSTR(result, 10); - dict_errno = 0; + dict->error = 0; /* * Optionally fold the key. @@ -355,37 +356,38 @@ static const char *dict_pgsql_lookup(DICT *dict, const char *name) } /* - * If there is a domain list for this map, then only search for - * addresses in domains on the list. This can significantly reduce - * the load on the server. + * If there is a domain list for this map, then only search for addresses + * in domains on the list. This can significantly reduce the load on the + * server. */ - if (db_common_check_domain(dict_pgsql->ctx, name) == 0) { - if (msg_verbose) + if ((domain_rc = db_common_check_domain(dict_pgsql->ctx, name)) == 0) { + if (msg_verbose) msg_info("%s: Skipping lookup of '%s'", myname, name); - return (0); + return (0); } + if (domain_rc < 0) + DICT_ERR_VAL_RETURN(dict, domain_rc, (char *) 0); /* * Suppress the actual lookup if the expansion is empty. * - * This initial expansion is outside the context of any - * specific host connection, we just want to check the - * key pre-requisites, so when quoting happens separately - * for each connection, we don't bother with quoting... + * This initial expansion is outside the context of any specific host + * connection, we just want to check the key pre-requisites, so when + * quoting happens separately for each connection, we don't bother with + * quoting... */ if (!db_common_expand(dict_pgsql->ctx, dict_pgsql->query, name, 0, query, 0)) return (0); - - /* do the query - set dict_errno & cleanup if there's an error */ + + /* do the query - set dict->error & cleanup if there's an error */ if ((query_res = plpgsql_query(dict_pgsql, name, query, dict_pgsql->dbname, dict_pgsql->username, dict_pgsql->password)) == 0) { - dict_errno = DICT_ERR_RETRY; + dict->error = DICT_ERR_RETRY; return 0; } - numrows = PQntuples(query_res); if (msg_verbose) msg_info("%s: retrieved %d rows", myname, numrows); @@ -395,29 +397,29 @@ static const char *dict_pgsql_lookup(DICT *dict, const char *name) } numcols = PQnfields(query_res); - for (expansion = i = 0; i < numrows && dict_errno == 0; i++) { + for (expansion = i = 0; i < numrows && dict->error == 0; i++) { for (j = 0; j < numcols; j++) { r = PQgetvalue(query_res, i, j); if (db_common_expand(dict_pgsql->ctx, dict_pgsql->result_format, - r, name, result, 0) + r, name, result, 0) && dict_pgsql->expansion_limit > 0 && ++expansion > dict_pgsql->expansion_limit) { msg_warn("%s: %s: Expansion limit exceeded for key: '%s'", myname, dict_pgsql->parser->name, name); - dict_errno = DICT_ERR_RETRY; + dict->error = DICT_ERR_RETRY; break; } } } PQclear(query_res); r = vstring_str(result); - return ((dict_errno == 0 && *r) ? r : 0); + return ((dict->error == 0 && *r) ? r : 0); } /* dict_pgsql_check_stat - check the status of a host */ static int dict_pgsql_check_stat(HOST *host, unsigned stat, unsigned type, - time_t t) + time_t t) { if ((host->stat & stat) && (!type || host->type & type)) { /* try not to hammer the dead hosts too often */ @@ -459,7 +461,7 @@ static HOST *dict_pgsql_find_host(PLPGSQL *PLDB, unsigned stat, unsigned type) /* dict_pgsql_get_active - get an active connection */ static HOST *dict_pgsql_get_active(PLPGSQL *PLDB, char *dbname, - char *username, char *password) + char *username, char *password) { const char *myname = "dict_pgsql_get_active"; HOST *host; @@ -475,15 +477,15 @@ static HOST *dict_pgsql_get_active(PLPGSQL *PLDB, char *dbname, } /* - * Try the remaining hosts. - * "count" is a safety net, in case the loop takes more than - * RETRY_CONN_INTV and the dead hosts are no longer skipped. + * Try the remaining hosts. "count" is a safety net, in case the loop + * takes more than RETRY_CONN_INTV and the dead hosts are no longer + * skipped. */ while (--count > 0 && ((host = dict_pgsql_find_host(PLDB, STATUNTRIED | STATFAIL, - TYPEUNIX)) != NULL || - (host = dict_pgsql_find_host(PLDB, STATUNTRIED | STATFAIL, - TYPEINET)) != NULL)) { + TYPEUNIX)) != NULL || + (host = dict_pgsql_find_host(PLDB, STATUNTRIED | STATFAIL, + TYPEINET)) != NULL)) { if (msg_verbose) msg_info("%s: attempting to connect to host %s", myname, host->hostname); @@ -526,9 +528,10 @@ static PGSQL_RES *plpgsql_query(DICT_PGSQL *dict_pgsql, ExecStatusType status; while ((host = dict_pgsql_get_active(PLDB, dbname, username, password)) != NULL) { + /* - * The active host is used to escape strings in the - * context of the active connection's character encoding. + * The active host is used to escape strings in the context of the + * active connection's character encoding. */ dict_pgsql->active_host = host; VSTRING_RESET(query); @@ -543,40 +546,40 @@ static PGSQL_RES *plpgsql_query(DICT_PGSQL *dict_pgsql, continue; } - /* - * Submit a command to the server. Be paranoid when processing - * the result set: try to enumerate every successful case, and - * reject everything else. - * - * From PostgreSQL 8.1.4 docs: (PQexec) returns a PGresult - * pointer or possibly a null pointer. A non-null pointer will - * generally be returned except in out-of-memory conditions or - * serious errors such as inability to send the command to the - * server. + /* + * Submit a command to the server. Be paranoid when processing the + * result set: try to enumerate every successful case, and reject + * everything else. + * + * From PostgreSQL 8.1.4 docs: (PQexec) returns a PGresult pointer or + * possibly a null pointer. A non-null pointer will generally be + * returned except in out-of-memory conditions or serious errors such + * as inability to send the command to the server. */ if ((res = PQexec(host->db, vstring_str(query))) != 0) { + /* - * XXX Because non-null result pointer does not imply success, - * we need to check the command's result status. - * - * Section 28.3.1: A result of status PGRES_NONFATAL_ERROR - * will never be returned directly by PQexec or other query - * execution functions; results of this kind are instead - * passed to the notice processor. - * - * PGRES_EMPTY_QUERY is being sent by the server when the - * query string is empty. The sanity-checking done by - * the Postfix infrastructure makes this case impossible, - * so we need not handle this situation explicitly. + * XXX Because non-null result pointer does not imply success, we + * need to check the command's result status. + * + * Section 28.3.1: A result of status PGRES_NONFATAL_ERROR will + * never be returned directly by PQexec or other query execution + * functions; results of this kind are instead passed to the + * notice processor. + * + * PGRES_EMPTY_QUERY is being sent by the server when the query + * string is empty. The sanity-checking done by the Postfix + * infrastructure makes this case impossible, so we need not + * handle this situation explicitly. */ switch ((status = PQresultStatus(res))) { case PGRES_TUPLES_OK: case PGRES_COMMAND_OK: /* Success. */ if (msg_verbose) - msg_info("dict_pgsql: successful query from host %s", + msg_info("dict_pgsql: successful query from host %s", host->hostname); - event_request_timer(dict_pgsql_event, (char *) host, + event_request_timer(dict_pgsql_event, (char *) host, IDLE_CONN_INTV); return (res); case PGRES_FATAL_ERROR: @@ -593,16 +596,17 @@ static PGSQL_RES *plpgsql_query(DICT_PGSQL *dict_pgsql, break; } } else { - /* - * This driver treats null pointers like fatal, non-null - * result pointer errors, as suggested by the PostgreSQL - * 8.1.4 documentation. + + /* + * This driver treats null pointers like fatal, non-null result + * pointer errors, as suggested by the PostgreSQL 8.1.4 + * documentation. */ msg_warn("pgsql query failed: fatal error from host %s: %s", host->hostname, PQerrorMessage(host->db)); } - /* + /* * XXX An error occurred. Clean up memory and skip this connection. */ if (res != 0) @@ -628,16 +632,14 @@ static void plpgsql_connect_single(HOST *host, char *dbname, char *username, cha plpgsql_down_host(host); return; } - if (msg_verbose) msg_info("dict_pgsql: successful connection to host %s", host->hostname); /* - * XXX Postfix does not send multi-byte characters. The following - * piece of code is an explicit statement of this fact, and the - * database server should not accept multi-byte information after - * this point. + * XXX Postfix does not send multi-byte characters. The following piece + * of code is an explicit statement of this fact, and the database server + * should not accept multi-byte information after this point. */ if (PQsetClientEncoding(host->db, "LATIN1") != 0) { msg_warn("dict_pgsql: cannot set the encoding to LATIN1, skipping %s", @@ -645,7 +647,6 @@ static void plpgsql_connect_single(HOST *host, char *dbname, char *username, cha plpgsql_down_host(host); return; } - /* Success. */ host->stat = STATACTIVE; } @@ -689,6 +690,7 @@ static void pgsql_parse_config(DICT_PGSQL *dict_pgsql, const char *pgsqlcf) dict_pgsql->password = cfg_get_str(p, "password", "", 0, 0); dict_pgsql->dbname = cfg_get_str(p, "dbname", "", 1, 0); dict_pgsql->result_format = cfg_get_str(p, "result_format", "%s", 1, 0); + /* * XXX: The default should be non-zero for safety, but that is not * backwards compatible. @@ -697,17 +699,18 @@ static void pgsql_parse_config(DICT_PGSQL *dict_pgsql, const char *pgsqlcf) "expansion_limit", 0, 0, 0); if ((dict_pgsql->query = cfg_get_str(p, "query", 0, 0, 0)) == 0) { - /* - * No query specified -- fallback to building it from components - * ( old style "select %s from %s where %s" ) - */ + + /* + * No query specified -- fallback to building it from components ( + * old style "select %s from %s where %s" ) + */ query = vstring_alloc(64); select_function = cfg_get_str(p, "select_function", 0, 0, 0); if (select_function != 0) { vstring_sprintf(query, "SELECT %s('%%s')", select_function); myfree(select_function); } else - db_common_sql_build_query(query, p); + db_common_sql_build_query(query, p); dict_pgsql->query = vstring_export(query); } @@ -721,8 +724,8 @@ static void pgsql_parse_config(DICT_PGSQL *dict_pgsql, const char *pgsqlcf) db_common_parse_domain(p, dict_pgsql->ctx); /* - * Maps that use substring keys should only be used with the full - * input key. + * Maps that use substring keys should only be used with the full input + * key. */ if (db_common_dict_partial(dict_pgsql->ctx)) dict_pgsql->dict.flags |= DICT_FLAG_PATTERN; @@ -765,7 +768,7 @@ DICT *dict_pgsql_open(const char *name, int open_flags, int dict_flags) if (dict_pgsql->pldb == NULL) msg_fatal("couldn't intialize pldb!\n"); dict_pgsql->dict.owner = cfg_get_owner(dict_pgsql->parser); - return (DICT_DEBUG(&dict_pgsql->dict)); + return (DICT_DEBUG (&dict_pgsql->dict)); } /* plpgsql_init - initalize a PGSQL database */ @@ -834,7 +837,7 @@ static void dict_pgsql_close(DICT *dict) myfree(dict_pgsql->query); myfree(dict_pgsql->result_format); if (dict_pgsql->hosts) - argv_free(dict_pgsql->hosts); + argv_free(dict_pgsql->hosts); if (dict_pgsql->ctx) db_common_free_ctx(dict_pgsql->ctx); if (dict->fold_buf) diff --git a/postfix/src/global/dict_proxy.c b/postfix/src/global/dict_proxy.c index 12a41128f..86682f84d 100644 --- a/postfix/src/global/dict_proxy.c +++ b/postfix/src/global/dict_proxy.c @@ -149,15 +149,13 @@ static int dict_proxy_sequence(DICT *dict, int function, case PROXY_STAT_OK: *key = STR(dict_proxy->reskey); *value = STR(dict_proxy->result); - return (0); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS); case PROXY_STAT_NOKEY: - dict_errno = 0; *key = *value = 0; - return (1); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL); case PROXY_STAT_RETRY: - dict_errno = DICT_ERR_RETRY; *key = *value = 0; - return (1); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR); default: msg_warn("%s sequence failed for table \"%s\" function %d: " "unexpected reply status %d", @@ -223,13 +221,11 @@ static const char *dict_proxy_lookup(DICT *dict, const char *key) msg_fatal("%s service is not configured for table \"%s\"", dict_proxy->service, dict->name); case PROXY_STAT_OK: - return (STR(dict_proxy->result)); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, STR(dict_proxy->result)); case PROXY_STAT_NOKEY: - dict_errno = 0; - return (0); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, (char *) 0); case PROXY_STAT_RETRY: - dict_errno = DICT_ERR_RETRY; - return (0); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, (char *) 0); default: msg_warn("%s lookup failed for table \"%s\" key \"%s\": " "unexpected reply status %d", @@ -243,7 +239,7 @@ static const char *dict_proxy_lookup(DICT *dict, const char *key) /* dict_proxy_update - update table entry */ -static void dict_proxy_update(DICT *dict, const char *key, const char *value) +static int dict_proxy_update(DICT *dict, const char *key, const char *value) { const char *myname = "dict_proxy_update"; DICT_PROXY *dict_proxy = (DICT_PROXY *) dict; @@ -292,11 +288,11 @@ static void dict_proxy_update(DICT *dict, const char *key, const char *value) msg_fatal("%s update access is not configured for table \"%s\"", dict_proxy->service, dict->name); case PROXY_STAT_OK: - dict_errno = 0; - return; + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS); + case PROXY_STAT_NOKEY: + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL); case PROXY_STAT_RETRY: - dict_errno = DICT_ERR_RETRY; - return; + DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR); default: msg_warn("%s update failed for table \"%s\" key \"%s\": " "unexpected reply status %d", @@ -359,13 +355,11 @@ static int dict_proxy_delete(DICT *dict, const char *key) msg_fatal("%s update access is not configured for table \"%s\"", dict_proxy->service, dict->name); case PROXY_STAT_OK: - return 0; - case PROXY_STAT_RETRY: - dict_errno = DICT_ERR_RETRY; - return (-1); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS); case PROXY_STAT_NOKEY: - dict_errno = 0; - return (1); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL); + case PROXY_STAT_RETRY: + DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR); default: msg_warn("%s delete failed for table \"%s\" key \"%s\": " "unexpected reply status %d", diff --git a/postfix/src/global/dict_sqlite.c b/postfix/src/global/dict_sqlite.c index 008619c6e..acfcd4084 100644 --- a/postfix/src/global/dict_sqlite.c +++ b/postfix/src/global/dict_sqlite.c @@ -47,7 +47,7 @@ /* returning the lookup result unchanged. /* .IP expansion_limit /* Limit (if any) on the total number of lookup result values. -/* Lookups which exceed the limit fail with dict_errno=DICT_ERR_RETRY. +/* Lookups which exceed the limit fail with dict->error=DICT_ERR_RETRY. /* Note that each non-empty (and non-NULL) column of a /* multi-column result row counts as one result. /* .IP "select_field, where_field, additional_conditions" @@ -149,11 +149,12 @@ static const char *dict_sqlite_lookup(DICT *dict, const char *name) const char *retval; int expansion = 0; int status; + int domain_rc; /* * In case of return without lookup (skipped key, etc.). */ - dict_errno = 0; + dict->error = 0; /* * Don't frustrate future attempts to make Postfix UTF-8 transparent. @@ -178,12 +179,14 @@ static const char *dict_sqlite_lookup(DICT *dict, const char *name) /* * Apply the optional domain filter for email address lookups. */ - if (db_common_check_domain(dict_sqlite->ctx, name) == 0) { + if ((domain_rc = db_common_check_domain(dict_sqlite->ctx, name)) == 0) { if (msg_verbose) msg_info("%s: %s: Skipping lookup of '%s'", myname, dict_sqlite->parser->name, name); return (0); } + if (domain_rc < 0) + DICT_ERR_VAL_RETURN(dict, domain_rc, (char *) 0); /* * Expand the query and query the database. @@ -228,7 +231,7 @@ static const char *dict_sqlite_lookup(DICT *dict, const char *name) && ++expansion > dict_sqlite->expansion_limit) { msg_warn("%s: %s: Expansion limit exceeded for key '%s'", myname, dict_sqlite->parser->name, name); - dict_errno = DICT_ERR_RETRY; + dict->error = DICT_ERR_RETRY; break; } } @@ -237,7 +240,7 @@ static const char *dict_sqlite_lookup(DICT *dict, const char *name) msg_warn("%s: %s: SQL step failed for query '%s': %s\n", myname, dict_sqlite->parser->name, vstring_str(query), sqlite3_errmsg(dict_sqlite->db)); - dict_errno = DICT_ERR_RETRY; + dict->error = DICT_ERR_RETRY; break; } } @@ -250,7 +253,7 @@ static const char *dict_sqlite_lookup(DICT *dict, const char *name) myname, dict_sqlite->parser->name, vstring_str(query), sqlite3_errmsg(dict_sqlite->db)); - return ((dict_errno == 0 && *(retval = vstring_str(result)) != 0) ? + return ((dict->error == 0 && *(retval = vstring_str(result)) != 0) ? retval : 0); } diff --git a/postfix/src/global/domain_list.c b/postfix/src/global/domain_list.c index 79139add5..8433caaf7 100644 --- a/postfix/src/global/domain_list.c +++ b/postfix/src/global/domain_list.c @@ -37,11 +37,12 @@ /* 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 domain foo.com. If this flag is cleared, foo.com matches itself +/* 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 zero with -/* dict_errno != 0, instead of raising a fatal error. +/* Request that domain_list_match() logs a warning and returns +/* zero, with list->error set to a non-zero dictionary error +/* code, 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 @@ -115,7 +116,7 @@ int main(int argc, char **argv) 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" : dict_errno == 0 ? "NO" : "ERROR"); + "YES" : list->error == 0 ? "NO" : "ERROR"); vstream_fflush(VSTREAM_OUT); domain_list_free(list); return (0); diff --git a/postfix/src/global/flush_clnt.c b/postfix/src/global/flush_clnt.c index e60a9e13a..4bff255b8 100644 --- a/postfix/src/global/flush_clnt.c +++ b/postfix/src/global/flush_clnt.c @@ -181,7 +181,7 @@ int flush_send_site(const char *site) 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) + else if (flush_domains->error == 0) status = FLUSH_STAT_DENY; else status = FLUSH_STAT_FAIL; @@ -238,7 +238,7 @@ int flush_add(const char *site, const char *queue_id) ATTR_TYPE_STR, MAIL_ATTR_SITE, site, ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, ATTR_TYPE_END); - else if (dict_errno == 0) + else if (flush_domains->error == 0) status = FLUSH_STAT_DENY; else status = FLUSH_STAT_FAIL; diff --git a/postfix/src/global/mail_addr_find.c b/postfix/src/global/mail_addr_find.c index 6769daa86..ed8caab6d 100644 --- a/postfix/src/global/mail_addr_find.c +++ b/postfix/src/global/mail_addr_find.c @@ -46,7 +46,7 @@ /* The copy includes the recipient address delimiter. /* The caller is expected to pass the copy to myfree(). /* DIAGNOSTICS -/* The global \fIdict_errno\fR is non-zero when the lookup +/* The maps->error value is non-zero when the lookup /* should be tried again. /* SEE ALSO /* maps(3), multi-dictionary search @@ -100,6 +100,7 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp) char *full_key; char *bare_key; char *saved_ext; + int rc = 0; /* * Initialize. @@ -120,7 +121,7 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp) #define FULL 0 #define PARTIAL DICT_FLAG_FIXED - if ((result = maps_find(path, full_key, FULL)) == 0 && dict_errno == 0 + if ((result = maps_find(path, full_key, FULL)) == 0 && path->error == 0 && bare_key != 0 && (result = maps_find(path, bare_key, PARTIAL)) != 0 && extp != 0) { *extp = saved_ext; @@ -131,13 +132,13 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp) * Try user+foo@$myorigin, user+foo@$mydestination or * user+foo@[${proxy,inet}_interfaces]. Then try with +foo stripped off. */ - if (result == 0 && dict_errno == 0 + if (result == 0 && path->error == 0 && (ratsign = strrchr(full_key, '@')) != 0 && (strcasecmp(ratsign + 1, var_myorigin) == 0 - || resolve_local(ratsign + 1))) { + || (rc = resolve_local(ratsign + 1)) > 0)) { *ratsign = 0; result = maps_find(path, full_key, PARTIAL); - if (result == 0 && dict_errno == 0 && bare_key != 0) { + if (result == 0 && path->error == 0 && bare_key != 0) { if ((ratsign = strrchr(bare_key, '@')) == 0) msg_panic("%s: bare key botch", myname); *ratsign = 0; @@ -147,12 +148,13 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp) } } *ratsign = '@'; - } + } else if (rc < 0) + path->error = rc; /* * Try @domain. */ - if (result == 0 && dict_errno == 0 && ratsign) + if (result == 0 && path->error == 0 && ratsign) result = maps_find(path, ratsign, PARTIAL); /* @@ -161,7 +163,7 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp) if (msg_verbose) msg_info("%s: %s -> %s", myname, address, result ? result : - dict_errno ? "(try again)" : + path->error ? "(try again)" : "(not found)"); myfree(full_key); if (bare_key) @@ -205,7 +207,7 @@ int main(int argc, char **argv) extent = 0; result = mail_addr_find(path, STR(buffer), &extent); vstream_printf("%s -> %s (%s)\n", STR(buffer), result ? result : - dict_errno ? "(try again)" : + path->error ? "(try again)" : "(not found)", extent ? extent : "null extension"); vstream_fflush(VSTREAM_OUT); if (extent) diff --git a/postfix/src/global/mail_addr_map.c b/postfix/src/global/mail_addr_map.c index 6f835d399..e8bc6bc29 100644 --- a/postfix/src/global/mail_addr_map.c +++ b/postfix/src/global/mail_addr_map.c @@ -32,7 +32,7 @@ /* DIAGNOSTICS /* Warnings: map lookup returns a non-address result. /* -/* The global \fIdict_errno\fR is non-zero when the lookup +/* The path->error value is non-zero when the lookup /* should be tried again. /* SEE ALSO /* mail_addr_find(3), mail address matching @@ -120,7 +120,7 @@ ARGV *mail_addr_map(MAPS *path, const char *address, int propagate) msg_warn("%s lookup of %s returns non-address result \"%s\"", path->title, address, string); argv = argv_free(argv); - dict_errno = DICT_ERR_RETRY; + path->error = DICT_ERR_RETRY; } } @@ -130,7 +130,7 @@ ARGV *mail_addr_map(MAPS *path, const char *address, int propagate) else { if (msg_verbose) msg_info("%s: %s -> %s", myname, address, - dict_errno ? "(try again)" : "(not found)"); + path->error ? "(try again)" : "(not found)"); } /* diff --git a/postfix/src/global/mail_conf.c b/postfix/src/global/mail_conf.c index 1fc7847fc..ed1b336d1 100644 --- a/postfix/src/global/mail_conf.c +++ b/postfix/src/global/mail_conf.c @@ -171,7 +171,6 @@ void mail_conf_suck(void) * other kinds of trouble. Enter the configuration directory into the * default dictionary. */ - dict_unknown_allowed = 1; if (var_config_dir) myfree(var_config_dir); if ((config_dir = getenv(CONF_ENV_PATH)) == 0) diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 95bf2c2e2..bcb8857fc 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20120102" +#define MAIL_RELEASE_DATE "20120108" #define MAIL_VERSION_NUMBER "2.9" #ifdef SNAPSHOT diff --git a/postfix/src/global/maps.c b/postfix/src/global/maps.c index a4e80d109..6f19eb8fc 100644 --- a/postfix/src/global/maps.c +++ b/postfix/src/global/maps.c @@ -63,8 +63,9 @@ /* to open database. Warnings: null string lookup result. /* /* maps_find() returns a null pointer when the requested -/* information was not found. The global \fIdict_errno\fR -/* variable indicates if the last lookup failed due to a problem. +/* information was not found, and logs a warning when the +/* lookup failed due to error. The maps->error value indicates +/* if the last lookup failed due to error. /* BUGS /* The dictionary name space is flat, so dictionary names allocated /* by maps_create() may collide with dictionary names allocated by @@ -166,7 +167,7 @@ const char *maps_find(MAPS *maps, const char *name, int flags) /* * In case of return without map lookup (empty name or no maps). */ - dict_errno = 0; + maps->error = 0; /* * Temp. workaround, for buggy callers that pass zero-length keys when @@ -186,20 +187,20 @@ const char *maps_find(MAPS *maps, const char *name, int flags) maps->title, name); msg_warn("%s should return NO RESULT in case of NOT FOUND", maps->title); - dict_errno = DICT_ERR_RETRY; + maps->error = DICT_ERR_RETRY; return (0); } if (msg_verbose) msg_info("%s: %s: %s: %s = %s", myname, maps->title, *map_name, name, expansion); return (expansion); - } else if (dict_errno != 0) { + } else if ((maps->error = dict->error) != 0) { msg_warn("%s:%s lookup of %s failed", dict->type, dict->name, name); break; } } if (msg_verbose) - msg_info("%s: %s: %s: %s", myname, maps->title, name, dict_errno ? + msg_info("%s: %s: %s: %s", myname, maps->title, name, maps->error ? "search aborted" : "not found"); return (0); } @@ -239,11 +240,11 @@ int main(int argc, char **argv) maps = maps_create("whatever", argv[1], DICT_FLAG_LOCK); while (vstring_fgets_nonl(buf, VSTREAM_IN)) { - dict_errno = 99; + maps->error = 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) { + } else if (maps->error != 0) { vstream_printf("lookup error\n"); } else { vstream_printf("not found\n"); diff --git a/postfix/src/global/maps.h b/postfix/src/global/maps.h index 015811f69..ccf2c6ac2 100644 --- a/postfix/src/global/maps.h +++ b/postfix/src/global/maps.h @@ -22,6 +22,7 @@ typedef struct MAPS { char *title; struct ARGV *argv; + int error; /* last request only */ } MAPS; extern MAPS *maps_create(const char *, const char *, int); diff --git a/postfix/src/global/match_parent_style.h b/postfix/src/global/match_parent_style.h index 7b51eddf7..59c796e84 100644 --- a/postfix/src/global/match_parent_style.h +++ b/postfix/src/global/match_parent_style.h @@ -14,7 +14,7 @@ /* * Utility library. */ -#include +#include /* * External interface. diff --git a/postfix/src/global/mkmap.h b/postfix/src/global/mkmap.h index 969b2a733..d74a9125d 100644 --- a/postfix/src/global/mkmap.h +++ b/postfix/src/global/mkmap.h @@ -41,6 +41,7 @@ extern MKMAP *mkmap_hash_open(const char *); extern MKMAP *mkmap_btree_open(const char *); extern MKMAP *mkmap_sdbm_open(const char *); extern MKMAP *mkmap_proxy_open(const char *); +extern MKMAP *mkmap_fail_open(const char *); /* LICENSE /* .ad diff --git a/postfix/src/global/mkmap_fail.c b/postfix/src/global/mkmap_fail.c new file mode 100644 index 000000000..c35fe50db --- /dev/null +++ b/postfix/src/global/mkmap_fail.c @@ -0,0 +1,53 @@ +/*++ +/* NAME +/* mkmap_fail 3 +/* SUMMARY +/* create or open database, fail: style +/* SYNOPSIS +/* #include +/* +/* MKMAP *mkmap_fail_open(path) +/* const char *path; +/* +/* DESCRIPTION +/* This module implements support for error testing postmap +/* and postalias with the fail: table type. +/* SEE ALSO +/* dict_fail(3), fail dictionary interface. +/* 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 + +/* Utility library. */ + +#include +#include + +/* Application-specific. */ + +#include +#include + + /* + * Dummy module: the dict_fail module has all the functionality built-in. + */ +MKMAP *mkmap_fail_open(const char *unused_path) +{ + MKMAP *mkmap = (MKMAP *) mymalloc(sizeof(*mkmap)); + + mkmap->open = dict_fail_open; + mkmap->after_open = 0; + mkmap->after_close = 0; + return (mkmap); +} diff --git a/postfix/src/global/mkmap_open.c b/postfix/src/global/mkmap_open.c index 69a0d5727..d939d443d 100644 --- a/postfix/src/global/mkmap_open.c +++ b/postfix/src/global/mkmap_open.c @@ -67,6 +67,7 @@ #include #include #include +#include #include #include @@ -100,6 +101,7 @@ static const MKMAP_OPEN_INFO mkmap_types[] = { DICT_TYPE_HASH, mkmap_hash_open, DICT_TYPE_BTREE, mkmap_btree_open, #endif + DICT_TYPE_FAIL, mkmap_fail_open, 0, }; @@ -109,7 +111,10 @@ static const MKMAP_OPEN_INFO mkmap_types[] = { void mkmap_append(MKMAP *mkmap, const char *key, const char *value) { - dict_put(mkmap->dict, key, value); + DICT *dict = mkmap->dict; + + if (dict_put(dict, key, value) != 0 && dict->error != 0) + msg_fatal("%s:%s: update failed", dict->type, dict->name); } /* mkmap_close - close database */ diff --git a/postfix/src/global/namadr_list.c b/postfix/src/global/namadr_list.c index b3c42d41e..66a1fb934 100644 --- a/postfix/src/global/namadr_list.c +++ b/postfix/src/global/namadr_list.c @@ -46,8 +46,9 @@ /* 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 zero with -/* dict_errno != 0, instead of raising a fatal error. +/* Request that namadr_list_match() logs a warning and returns +/* zero with list->error set to a non-zero dictionary error +/* code, 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 @@ -124,7 +125,7 @@ int main(int argc, char **argv) addr = argv[optind + 2]; vstream_printf("%s/%s: %s\n", host, addr, namadr_list_match(list, host, addr) ? - "YES" : dict_errno == 0 ? "NO" : "ERROR"); + "YES" : list->error == 0 ? "NO" : "ERROR"); vstream_fflush(VSTREAM_OUT); namadr_list_free(list); return (0); diff --git a/postfix/src/global/resolve_local.c b/postfix/src/global/resolve_local.c index 09fcf94d1..98d04b2a8 100644 --- a/postfix/src/global/resolve_local.c +++ b/postfix/src/global/resolve_local.c @@ -16,9 +16,9 @@ /* 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). +/* The result is > 0 if the domain matches the list of local +/* domains and IP addresses, 0 when it does not match, and < 0 +/* in case of error. /* /* resolve_local_init() performs initialization. If this routine is /* not called explicitly ahead of time, it will be called on the fly. @@ -96,12 +96,6 @@ int resolve_local(const char *addr) 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. * @@ -123,8 +117,8 @@ int resolve_local(const char *addr) */ if (string_list_match(resolve_local_list, saved_addr)) RETURN(1); - if (dict_errno != 0) - RETURN(0); + if (resolve_local_list->error != 0) + RETURN(resolve_local_list->error); /* * Compare the destination against the list of interface addresses that @@ -180,15 +174,16 @@ int resolve_local(const char *addr) int main(int argc, char **argv) { + int rc; + if (argc != 3) msg_fatal("usage: %s mydestination domain", argv[0]); mail_conf_read(); 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_printf("mydestination=%s destination=%s %s\n", argv[1], argv[2], + (rc = resolve_local(argv[2])) > 0 ? "YES" : + rc == 0 ? "NO" : "ERROR"); vstream_fflush(VSTREAM_OUT); return (0); } diff --git a/postfix/src/global/server_acl.c b/postfix/src/global/server_acl.c index 9d9fa4950..4ef0eec69 100644 --- a/postfix/src/global/server_acl.c +++ b/postfix/src/global/server_acl.c @@ -169,7 +169,7 @@ int server_acl_eval(const char *client_addr, SERVER_ACL * intern_acl, } else if (STREQ(acl, SERVER_ACL_NAME_WL_MYNETWORKS)) { if (addr_match_list_match(server_acl_mynetworks, client_addr)) return (SERVER_ACL_ACT_PERMIT); - if (dict_errno != 0) { + if (server_acl_mynetworks->error != 0) { msg_warn("%s: %s: mynetworks lookup error -- ignoring the " "remainder of this access list", origin, acl); return (SERVER_ACL_ACT_ERROR); @@ -190,7 +190,7 @@ int server_acl_eval(const char *client_addr, SERVER_ACL * intern_acl, } if (ret != SERVER_ACL_ACT_DUNNO) return (ret); - } else if (dict_errno != 0) { + } else if (dict->error != 0) { msg_warn("%s: %s: table lookup error -- ignoring the remainder " "of this access list", origin, acl); return (SERVER_ACL_ACT_ERROR); diff --git a/postfix/src/global/string_list.c b/postfix/src/global/string_list.c index 4b84ace9f..a24e4e179 100644 --- a/postfix/src/global/string_list.c +++ b/postfix/src/global/string_list.c @@ -34,8 +34,9 @@ /* 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 zero with -/* dict_errno != 0, instead of raising a fatal error. +/* Request that string_list_match() logs a warning and returns +/* zero with list->error set to a non-zero dictionary error +/* code, 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. @@ -105,10 +106,10 @@ int main(int argc, char **argv) } if (argc != optind + 2) usage(argv[0]); - list = string_list_init(MATCH_FLAG_NONE | MATCH_FLAG_RETURN, argv[optind]); + list = string_list_init(MATCH_FLAG_RETURN, argv[optind]); string = argv[optind + 1]; vstream_printf("%s: %s\n", string, string_list_match(list, string) ? - "YES" : dict_errno == 0 ? "NO" : "ERROR"); + "YES" : list->error == 0 ? "NO" : "ERROR"); vstream_fflush(VSTREAM_OUT); string_list_free(list); return (0); diff --git a/postfix/src/local/alias.c b/postfix/src/local/alias.c index a2ead5795..ca5546ec9 100644 --- a/postfix/src/local/alias.c +++ b/postfix/src/local/alias.c @@ -273,7 +273,7 @@ int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, * Deliver. */ alias_count = 0; - if (dict_errno != 0) { + if (owner != 0 && alias_maps->error != 0) { dsb_simple(state.msg_attr.why, "4.3.0", "alias database unavailable"); *statusp = defer_append(BOUNCE_FLAGS(state.request), @@ -369,7 +369,9 @@ int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, * If the alias database was inaccessible for some reason, defer * further delivery for the current top-level recipient. */ - if (dict_errno != 0) { + if (alias_result == 0 && dict->error != 0) { + msg_warn("%s:%s: lookup of '%s' failed", + dict->type, dict->name, name); dsb_simple(state.msg_attr.why, "4.3.0", "alias database unavailable"); *statusp = defer_append(BOUNCE_FLAGS(state.request), diff --git a/postfix/src/local/bounce_workaround.c b/postfix/src/local/bounce_workaround.c index 6938f3d50..8d1670c80 100644 --- a/postfix/src/local/bounce_workaround.c +++ b/postfix/src/local/bounce_workaround.c @@ -98,7 +98,6 @@ int bounce_workaround(LOCAL_STATE state) char *stripped_recipient; char *owner_alias; const char *owner_expansion; - int saved_dict_errno; #define FIND_OWNER(lhs, rhs, addr) { \ lhs = concatenate("owner-", addr, (char *) 0); \ @@ -106,9 +105,8 @@ int bounce_workaround(LOCAL_STATE state) rhs = maps_find(alias_maps, lhs, DICT_FLAG_NONE); \ } - dict_errno = 0; FIND_OWNER(owner_alias, owner_expansion, state.msg_attr.rcpt.address); - if ((saved_dict_errno = dict_errno) == 0 && owner_expansion == 0 + if (alias_maps->error == 0 && owner_expansion == 0 && (stripped_recipient = strip_addr(state.msg_attr.rcpt.address, (char **) 0, *var_rcpt_delim)) != 0) { @@ -116,14 +114,14 @@ int bounce_workaround(LOCAL_STATE state) FIND_OWNER(owner_alias, owner_expansion, stripped_recipient); myfree(stripped_recipient); } - if ((saved_dict_errno = dict_errno) == 0 && owner_expansion != 0) { + if (alias_maps->error == 0 && owner_expansion != 0) { canon_owner = canon_addr_internal(vstring_alloc(10), var_exp_own_alias ? owner_expansion : owner_alias); SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level); } myfree(owner_alias); - if (saved_dict_errno != 0) + if (alias_maps->error != 0) /* At this point, canon_owner == 0. */ return (defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr))); diff --git a/postfix/src/local/mailbox.c b/postfix/src/local/mailbox.c index 5d1f200d3..ca1077241 100644 --- a/postfix/src/local/mailbox.c +++ b/postfix/src/local/mailbox.c @@ -278,15 +278,14 @@ int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp) transp_maps = maps_create(VAR_MBOX_TRANSP_MAPS, var_mbox_transp_maps, DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB); /* The -1 is a hint for the down-stream deliver_completed() function. */ - dict_errno = 0; - if (*var_mbox_transp_maps + if (transp_maps && (map_transport = maps_find(transp_maps, state.msg_attr.user, DICT_FLAG_NONE)) != 0) { state.msg_attr.rcpt.offset = -1L; *statusp = deliver_pass(MAIL_CLASS_PRIVATE, map_transport, state.request, &state.msg_attr.rcpt); return (YES); - } else if (dict_errno != 0) { + } else if (transp_maps && transp_maps->error != 0) { /* Details in the logfile. */ dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure"); *statusp = defer_append(BOUNCE_FLAGS(state.request), @@ -334,12 +333,10 @@ int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp) cmd_maps = maps_create(VAR_MAILBOX_CMD_MAPS, var_mailbox_cmd_maps, DICT_FLAG_LOCK | DICT_FLAG_PARANOID); - dict_errno = 0; - if (*var_mailbox_cmd_maps - && (map_command = maps_find(cmd_maps, state.msg_attr.user, + if (cmd_maps && (map_command = maps_find(cmd_maps, state.msg_attr.user, DICT_FLAG_NONE)) != 0) { status = deliver_command(state, usr_attr, map_command); - } else if (dict_errno != 0) { + } else if (cmd_maps && cmd_maps->error != 0) { /* Details in the logfile. */ dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure"); status = defer_append(BOUNCE_FLAGS(state.request), diff --git a/postfix/src/local/unknown.c b/postfix/src/local/unknown.c index 57e49af84..91c338c1b 100644 --- a/postfix/src/local/unknown.c +++ b/postfix/src/local/unknown.c @@ -110,14 +110,13 @@ int deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr) transp_maps = maps_create(VAR_FBCK_TRANSP_MAPS, var_fbck_transp_maps, DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB); /* The -1 is a hint for the down-stream deliver_completed() function. */ - dict_errno = 0; - if (*var_fbck_transp_maps + if (transp_maps && (map_transport = maps_find(transp_maps, state.msg_attr.user, DICT_FLAG_NONE)) != 0) { state.msg_attr.rcpt.offset = -1L; return (deliver_pass(MAIL_CLASS_PRIVATE, map_transport, state.request, &state.msg_attr.rcpt)); - } else if (dict_errno != 0) { + } else if (transp_maps && transp_maps->error != 0) { /* Details in the logfile. */ dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure"); return (defer_append(BOUNCE_FLAGS(state.request), diff --git a/postfix/src/postalias/Makefile.in b/postfix/src/postalias/Makefile.in index a10bdd1f7..c6161b857 100644 --- a/postfix/src/postalias/Makefile.in +++ b/postfix/src/postalias/Makefile.in @@ -22,7 +22,7 @@ Makefile: Makefile.in update: ../../bin/$(PROG) -tests: test1 test2 +tests: test1 test2 fail_test root_tests: @@ -52,6 +52,11 @@ test2: $(PROG) map.in map-abc2.ref map-ghi2.ref map-uABC2.ref done rm -f map.in.db +fail_test: $(PROG) aliases fail_test.in fail_test.ref + -sh fail_test.in > fail_test.tmp 2>&1 || exit 0 + diff fail_test.ref fail_test.tmp + rm -f fail_test.tmp + ../../bin/$(PROG): $(PROG) cp $(PROG) ../../bin diff --git a/postfix/src/postalias/aliases b/postfix/src/postalias/aliases new file mode 100644 index 000000000..a2a278de4 --- /dev/null +++ b/postfix/src/postalias/aliases @@ -0,0 +1 @@ +xx: yy diff --git a/postfix/src/postalias/fail_test.in b/postfix/src/postalias/fail_test.in new file mode 100644 index 000000000..1502c2ce6 --- /dev/null +++ b/postfix/src/postalias/fail_test.in @@ -0,0 +1,7 @@ +./postalias -q xx fail:aliases +echo xx | ./postalias -q - fail:aliases +./postalias -d xx fail:aliases +echo xx | ./postalias -d - fail:aliases +./postalias -s fail:aliases +./postalias -i fail:aliases < aliases +./postalias fail:aliases diff --git a/postfix/src/postalias/fail_test.ref b/postfix/src/postalias/fail_test.ref new file mode 100644 index 000000000..64d2eef68 --- /dev/null +++ b/postfix/src/postalias/fail_test.ref @@ -0,0 +1,7 @@ +postalias: fatal: fail:aliases: query error: Unknown error: 0 +postalias: fatal: fail:aliases: query error: Unknown error: 0 +postalias: fatal: fail:aliases: delete error: Unknown error: 0 +postalias: fatal: fail:aliases: delete error: Unknown error: 0 +postalias: fatal: fail:aliases: sequence error: Unknown error: 0 +postalias: fatal: fail:aliases: write error: Unknown error: 0 +postalias: fatal: fail:aliases: write error: Unknown error: 0 diff --git a/postfix/src/postalias/postalias.c b/postfix/src/postalias/postalias.c index 9b17d0207..a031ef73d 100644 --- a/postfix/src/postalias/postalias.c +++ b/postfix/src/postalias/postalias.c @@ -121,6 +121,10 @@ /* .IP \fBhash\fR /* The output is a hashed file, named \fIfile_name\fB.db\fR. /* This is available on systems with support for \fBdb\fR databases. +/* .IP \fBfail\fR +/* A table that reliably fails all requests. The lookup table +/* name is used for logging only. This table exists to simplify +/* Postfix error tests. /* .IP \fBsdbm\fR /* The output consists of two files, named \fIfile_name\fB.pag\fR and /* \fIfile_name\fB.dir\fR. @@ -376,6 +380,9 @@ static void postalias(char *map_type, char *path_name, int postalias_flags, * Store the value under a case-insensitive key. */ mkmap_append(mkmap, STR(key_buffer), STR(value_buffer)); + if (mkmap->dict->error) + msg_fatal("%s:%s: write error: %m", + mkmap->dict->type, mkmap->dict->name); } /* @@ -390,6 +397,9 @@ static void postalias(char *map_type, char *path_name, int postalias_flags, * sendmail. */ mkmap_append(mkmap, "@", "@"); + if (mkmap->dict->error) + msg_fatal("%s:%s: write error: %m", + mkmap->dict->type, mkmap->dict->name); /* * NIS compatibility: add time and master info. Unlike other information, @@ -466,6 +476,9 @@ static int postalias_queries(VSTREAM *in, char **maps, const int map_count, found = 1; break; } + if (dicts[n]->error) + msg_fatal("%s:%s: query error: %m", + dicts[n]->type, dicts[n]->name); } } if (found) @@ -501,6 +514,8 @@ static int postalias_query(const char *map_type, const char *map_name, } vstream_printf("%s\n", value); } + if (dict->error) + msg_fatal("%s:%s: query error: %m", dict->type, dict->name); vstream_fflush(VSTREAM_OUT); dict_close(dict); return (value != 0); @@ -542,9 +557,14 @@ static int postalias_deletes(VSTREAM *in, char **maps, const int map_count, /* * Perform all requests. */ - while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) - for (n = 0; n < map_count; n++) + while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) { + for (n = 0; n < map_count; n++) { found |= (dict_del(dicts[n], STR(keybuf)) == 0); + if (dicts[n]->error) + msg_fatal("%s:%s: delete error: %m", + dicts[n]->type, dicts[n]->name); + } + } /* * Cleanup. @@ -573,6 +593,8 @@ static int postalias_delete(const char *map_type, const char *map_name, open_flags = O_RDWR; dict = dict_open3(map_type, map_name, open_flags, dict_flags); status = dict_del(dict, key); + if (dict->error) + msg_fatal("%s:%s: delete error: %m", dict->type, dict->name); dict_close(dict); return (status == 0); } @@ -604,6 +626,8 @@ static void postalias_seq(const char *map_type, const char *map_name, } vstream_printf("%s: %s\n", key, value); } + if (dict->error) + msg_fatal("%s:%s: sequence error: %m", dict->type, dict->name); vstream_fflush(VSTREAM_OUT); dict_close(dict); } diff --git a/postfix/src/postconf/postconf.c b/postfix/src/postconf/postconf.c index d742557b2..6672b694d 100644 --- a/postfix/src/postconf/postconf.c +++ b/postfix/src/postconf/postconf.c @@ -167,8 +167,8 @@ /* 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. +/* name is used for logging. 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 diff --git a/postfix/src/postconf/postconf_main.c b/postfix/src/postconf/postconf_main.c index d566869d8..9411d7dc4 100644 --- a/postfix/src/postconf/postconf_main.c +++ b/postfix/src/postconf/postconf_main.c @@ -105,7 +105,6 @@ void read_parameters(void) * A direct rip-off of mail_conf_read(). XXX Avoid code duplication by * better code decomposition. */ - dict_unknown_allowed = 1; set_config_dir(); path = concatenate(var_config_dir, "/", MAIN_CONF_FILE, (char *) 0); dict_load_file(CONFIG_DICT, path); diff --git a/postfix/src/postmap/Makefile.in b/postfix/src/postmap/Makefile.in index 8d876df71..2684a5d77 100644 --- a/postfix/src/postmap/Makefile.in +++ b/postfix/src/postmap/Makefile.in @@ -25,7 +25,7 @@ update: ../../bin/$(PROG) ../../bin/$(PROG): $(PROG) cp $(PROG) ../../bin -tests: test1 test2 +tests: test1 test2 fail_test root_tests: @@ -55,6 +55,11 @@ test2: $(PROG) map.in map-abc2.ref map-ghi2.ref map-uABC2.ref done rm -f map.in.db +fail_test: $(PROG) aliases fail_test.in fail_test.ref + -sh fail_test.in > fail_test.tmp 2>&1 || exit 0 + diff fail_test.ref fail_test.tmp + rm -f fail_test.tmp + printfck: $(OBJS) $(PROG) rm -rf printfck mkdir printfck diff --git a/postfix/src/postmap/aliases b/postfix/src/postmap/aliases new file mode 100644 index 000000000..cce2b6b80 --- /dev/null +++ b/postfix/src/postmap/aliases @@ -0,0 +1 @@ +xx yy diff --git a/postfix/src/postmap/fail_test.in b/postfix/src/postmap/fail_test.in new file mode 100644 index 000000000..b62c3c5d7 --- /dev/null +++ b/postfix/src/postmap/fail_test.in @@ -0,0 +1,7 @@ +./postmap -q xx fail:aliases +echo xx | ./postmap -q - fail:aliases +./postmap -d xx fail:aliases +echo xx | ./postmap -d - fail:aliases +./postmap -s fail:aliases +./postmap -i fail:aliases < aliases +./postmap fail:aliases diff --git a/postfix/src/postmap/fail_test.ref b/postfix/src/postmap/fail_test.ref new file mode 100644 index 000000000..b9a92da07 --- /dev/null +++ b/postfix/src/postmap/fail_test.ref @@ -0,0 +1,7 @@ +postmap: fatal: fail:aliases: query error: Unknown error: 0 +postmap: fatal: fail:aliases: query error: Unknown error: 0 +postmap: fatal: fail:aliases: delete error: Unknown error: 0 +postmap: fatal: fail:aliases: delete error: Unknown error: 0 +postmap: fatal: fail:aliases: sequence error: Unknown error: 0 +postmap: fatal: fail:aliases: write error: Unknown error: 0 +postmap: fatal: fail:aliases: write error: Unknown error: 0 diff --git a/postfix/src/postmap/postmap.c b/postfix/src/postmap/postmap.c index 19bb02e5b..22718dd65 100644 --- a/postfix/src/postmap/postmap.c +++ b/postfix/src/postmap/postmap.c @@ -179,6 +179,10 @@ /* .IP \fBhash\fR /* The output file is a hashed file, named \fIfile_name\fB.db\fR. /* This is available on systems with support for \fBdb\fR databases. +/* .IP \fBfail\fR +/* A table that reliably fails all requests. The lookup table +/* name is used for logging only. This table exists to simplify +/* Postfix error tests. /* .IP \fBsdbm\fR /* The output consists of two files, named \fIfile_name\fB.pag\fR and /* \fIfile_name\fB.dir\fR. @@ -411,6 +415,9 @@ static void postmap(char *map_type, char *path_name, int postmap_flags, * Store the value under a case-insensitive key. */ mkmap_append(mkmap, key, value); + if (mkmap->dict->error) + msg_fatal("%s:%s: write error: %m", + mkmap->dict->type, mkmap->dict->name); } /* @@ -458,6 +465,9 @@ static void postmap_body(void *ptr, int unused_rec_type, state->found = 1; break; } + if (dicts[n]->error) + msg_fatal("%s:%s: query error: %m", + dicts[n]->type, dicts[n]->name); } } @@ -535,6 +545,9 @@ static int postmap_queries(VSTREAM *in, char **maps, const int map_count, found = 1; break; } + if (dicts[n]->error) + msg_fatal("%s:%s: query error: %m", + dicts[n]->type, dicts[n]->name); } } } else { @@ -616,6 +629,8 @@ static int postmap_query(const char *map_type, const char *map_name, } vstream_printf("%s\n", value); } + if (dict->error) + msg_fatal("%s:%s: query error: %m", dict->type, dict->name); vstream_fflush(VSTREAM_OUT); dict_close(dict); return (value != 0); @@ -657,9 +672,14 @@ static int postmap_deletes(VSTREAM *in, char **maps, const int map_count, /* * Perform all requests. */ - while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) - for (n = 0; n < map_count; n++) + while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) { + for (n = 0; n < map_count; n++) { found |= (dict_del(dicts[n], STR(keybuf)) == 0); + if (dicts[n]->error) + msg_fatal("%s:%s: delete error: %m", + dicts[n]->type, dicts[n]->name); + } + } /* * Cleanup. @@ -688,6 +708,8 @@ static int postmap_delete(const char *map_type, const char *map_name, open_flags = O_RDWR; dict = dict_open3(map_type, map_name, open_flags, dict_flags); status = dict_del(dict, key); + if (dict->error) + msg_fatal("%s:%s: delete error: %m", dict->type, dict->name); dict_close(dict); return (status == 0); } @@ -719,6 +741,8 @@ static void postmap_seq(const char *map_type, const char *map_name, } vstream_printf("%s %s\n", key, value); } + if (dict->error) + msg_fatal("%s:%s: sequence error: %m", dict->type, dict->name); vstream_fflush(VSTREAM_OUT); dict_close(dict); } diff --git a/postfix/src/postscreen/Makefile.in b/postfix/src/postscreen/Makefile.in index fa7f996ba..a7a61837f 100644 --- a/postfix/src/postscreen/Makefile.in +++ b/postfix/src/postscreen/Makefile.in @@ -81,7 +81,6 @@ postscreen.o: ../../include/mail_server.h postscreen.o: ../../include/mail_version.h postscreen.o: ../../include/maps.h postscreen.o: ../../include/match_list.h -postscreen.o: ../../include/match_ops.h postscreen.o: ../../include/msg.h postscreen.o: ../../include/myaddrinfo.h postscreen.o: ../../include/mymalloc.h @@ -103,7 +102,6 @@ postscreen_dict.o: ../../include/events.h postscreen_dict.o: ../../include/htable.h postscreen_dict.o: ../../include/maps.h postscreen_dict.o: ../../include/match_list.h -postscreen_dict.o: ../../include/match_ops.h postscreen_dict.o: ../../include/msg.h postscreen_dict.o: ../../include/server_acl.h postscreen_dict.o: ../../include/string_list.h @@ -127,7 +125,6 @@ postscreen_dnsbl.o: ../../include/mail_params.h postscreen_dnsbl.o: ../../include/mail_proto.h postscreen_dnsbl.o: ../../include/maps.h postscreen_dnsbl.o: ../../include/match_list.h -postscreen_dnsbl.o: ../../include/match_ops.h postscreen_dnsbl.o: ../../include/msg.h postscreen_dnsbl.o: ../../include/myaddrinfo.h postscreen_dnsbl.o: ../../include/mymalloc.h @@ -151,7 +148,6 @@ postscreen_early.o: ../../include/htable.h postscreen_early.o: ../../include/mail_params.h postscreen_early.o: ../../include/maps.h postscreen_early.o: ../../include/match_list.h -postscreen_early.o: ../../include/match_ops.h postscreen_early.o: ../../include/msg.h postscreen_early.o: ../../include/mymalloc.h postscreen_early.o: ../../include/server_acl.h @@ -175,7 +171,6 @@ postscreen_expand.o: ../../include/mail_params.h postscreen_expand.o: ../../include/mail_proto.h postscreen_expand.o: ../../include/maps.h postscreen_expand.o: ../../include/match_list.h -postscreen_expand.o: ../../include/match_ops.h postscreen_expand.o: ../../include/msg.h postscreen_expand.o: ../../include/server_acl.h postscreen_expand.o: ../../include/string_list.h @@ -197,7 +192,6 @@ postscreen_misc.o: ../../include/iostuff.h postscreen_misc.o: ../../include/mail_params.h postscreen_misc.o: ../../include/maps.h postscreen_misc.o: ../../include/match_list.h -postscreen_misc.o: ../../include/match_ops.h postscreen_misc.o: ../../include/msg.h postscreen_misc.o: ../../include/server_acl.h postscreen_misc.o: ../../include/string_list.h @@ -220,7 +214,6 @@ postscreen_send.o: ../../include/mac_parse.h postscreen_send.o: ../../include/mail_params.h postscreen_send.o: ../../include/maps.h postscreen_send.o: ../../include/match_list.h -postscreen_send.o: ../../include/match_ops.h postscreen_send.o: ../../include/msg.h postscreen_send.o: ../../include/server_acl.h postscreen_send.o: ../../include/smtp_reply_footer.h @@ -246,7 +239,6 @@ postscreen_smtpd.o: ../../include/mail_params.h postscreen_smtpd.o: ../../include/mail_proto.h postscreen_smtpd.o: ../../include/maps.h postscreen_smtpd.o: ../../include/match_list.h -postscreen_smtpd.o: ../../include/match_ops.h postscreen_smtpd.o: ../../include/msg.h postscreen_smtpd.o: ../../include/mymalloc.h postscreen_smtpd.o: ../../include/name_code.h @@ -274,7 +266,6 @@ postscreen_starttls.o: ../../include/mail_params.h postscreen_starttls.o: ../../include/mail_proto.h postscreen_starttls.o: ../../include/maps.h postscreen_starttls.o: ../../include/match_list.h -postscreen_starttls.o: ../../include/match_ops.h postscreen_starttls.o: ../../include/msg.h postscreen_starttls.o: ../../include/mymalloc.h postscreen_starttls.o: ../../include/name_code.h @@ -302,7 +293,6 @@ postscreen_state.o: ../../include/mail_proto.h postscreen_state.o: ../../include/mail_server.h postscreen_state.o: ../../include/maps.h postscreen_state.o: ../../include/match_list.h -postscreen_state.o: ../../include/match_ops.h postscreen_state.o: ../../include/msg.h postscreen_state.o: ../../include/mymalloc.h postscreen_state.o: ../../include/name_mask.h @@ -323,7 +313,6 @@ postscreen_tests.o: ../../include/htable.h postscreen_tests.o: ../../include/mail_params.h postscreen_tests.o: ../../include/maps.h postscreen_tests.o: ../../include/match_list.h -postscreen_tests.o: ../../include/match_ops.h postscreen_tests.o: ../../include/msg.h postscreen_tests.o: ../../include/server_acl.h postscreen_tests.o: ../../include/string_list.h diff --git a/postfix/src/postscreen/postscreen_smtpd.c b/postfix/src/postscreen/postscreen_smtpd.c index 5c7c5cd07..402d078fc 100644 --- a/postfix/src/postscreen/postscreen_smtpd.c +++ b/postfix/src/postscreen/postscreen_smtpd.c @@ -874,6 +874,8 @@ static void psc_smtpd_read_event(int event, char *context) state->smtp_client_addr, state->smtp_client_port, STR(state->cmd_buffer), cp); vstring_strcpy(state->cmd_buffer, cp); + } else if (psc_cmd_filter->error != 0) { + /* XXX log something, even if regexps don't soft-fail. */ } } diff --git a/postfix/src/proxymap/proxymap.c b/postfix/src/proxymap/proxymap.c index 024fadc74..f0d4935df 100644 --- a/postfix/src/proxymap/proxymap.c +++ b/postfix/src/proxymap/proxymap.c @@ -339,7 +339,7 @@ static DICT *proxy_map_find(const char *map_type_name, int request_flags, msg_panic("proxy_map_find: dict_open null result"); dict_register(STR(map_type_name_flags), dict); } - dict_errno = 0; + dict->error = 0; return (dict); } @@ -352,6 +352,7 @@ static void proxymap_sequence_service(VSTREAM *client_stream) int request_func; const char *reply_key; const char *reply_value; + int dict_status; int reply_status; /* @@ -369,16 +370,19 @@ static void proxymap_sequence_service(VSTREAM *client_stream) } else if ((dict = proxy_map_find(STR(request_map), request_flags, &reply_status)) == 0) { reply_key = reply_value = ""; - } else if (dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK) - | (request_flags & DICT_FLAG_RQST_MASK)), - dict_seq(dict, request_func, &reply_key, &reply_value) == 0) { - reply_status = PROXY_STAT_OK; - } else if (dict_errno == 0) { - reply_status = PROXY_STAT_NOKEY; - reply_key = reply_value = ""; } else { - reply_status = PROXY_STAT_RETRY; - reply_key = reply_value = ""; + dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK) + | (request_flags & DICT_FLAG_RQST_MASK)); + dict_status = dict_seq(dict, request_func, &reply_key, &reply_value); + if (dict_status == 0) { + reply_status = PROXY_STAT_OK; + } else if (dict->error == 0) { + reply_status = PROXY_STAT_NOKEY; + reply_key = reply_value = ""; + } else { + reply_status = PROXY_STAT_RETRY; + reply_key = reply_value = ""; + } } /* @@ -417,7 +421,7 @@ static void proxymap_lookup_service(VSTREAM *client_stream) | (request_flags & DICT_FLAG_RQST_MASK)), (reply_value = dict_get(dict, STR(request_key))) != 0) { reply_status = PROXY_STAT_OK; - } else if (dict_errno == 0) { + } else if (dict->error == 0) { reply_status = PROXY_STAT_NOKEY; reply_value = ""; } else { @@ -440,6 +444,7 @@ static void proxymap_update_service(VSTREAM *client_stream) { int request_flags; DICT *dict; + int dict_status; int reply_status; /* @@ -469,8 +474,14 @@ static void proxymap_update_service(VSTREAM *client_stream) dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK) | (request_flags & DICT_FLAG_RQST_MASK) | DICT_FLAG_SYNC_UPDATE | DICT_FLAG_DUP_REPLACE); - dict_put(dict, STR(request_key), STR(request_value)); - reply_status = (dict_errno ? PROXY_STAT_RETRY : PROXY_STAT_OK); + dict_status = dict_put(dict, STR(request_key), STR(request_value)); + if (dict_status == 0) { + reply_status = PROXY_STAT_OK; + } else if (dict->error == 0) { + reply_status = PROXY_STAT_NOKEY; + } else { + reply_status = PROXY_STAT_RETRY; + } } /* @@ -514,9 +525,13 @@ static void proxymap_delete_service(VSTREAM *client_stream) | (request_flags & DICT_FLAG_RQST_MASK) | DICT_FLAG_SYNC_UPDATE); dict_status = dict_del(dict, STR(request_key)); - reply_status = (dict_status == 0 ? PROXY_STAT_OK : - dict_status > 0 ? PROXY_STAT_NOKEY : - PROXY_STAT_RETRY); + if (dict_status == 0) { + reply_status = PROXY_STAT_OK; + } else if (dict->error == 0) { + reply_status = PROXY_STAT_NOKEY; + } else { + reply_status = PROXY_STAT_RETRY; + } } /* diff --git a/postfix/src/qmqpd/Makefile.in b/postfix/src/qmqpd/Makefile.in index c180709cf..e54679d48 100644 --- a/postfix/src/qmqpd/Makefile.in +++ b/postfix/src/qmqpd/Makefile.in @@ -75,7 +75,6 @@ qmqpd.o: ../../include/mail_server.h qmqpd.o: ../../include/mail_stream.h qmqpd.o: ../../include/mail_version.h qmqpd.o: ../../include/match_list.h -qmqpd.o: ../../include/match_ops.h qmqpd.o: ../../include/match_parent_style.h qmqpd.o: ../../include/msg.h qmqpd.o: ../../include/mymalloc.h diff --git a/postfix/src/qmqpd/qmqpd.c b/postfix/src/qmqpd/qmqpd.c index e64bc6ebf..559c2e099 100644 --- a/postfix/src/qmqpd/qmqpd.c +++ b/postfix/src/qmqpd/qmqpd.c @@ -689,7 +689,7 @@ static void qmqpd_proto(QMQPD_STATE *state) */ if (namadr_list_match(qmqpd_clients, state->name, state->addr) != 0) { qmqpd_receive(state); - } else if (dict_errno == 0) { + } else if (qmqpd_clients->error == 0) { qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "Error: %s is not authorized to use this service", state->namaddr); diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in index cc0aaf58e..0134a455d 100644 --- a/postfix/src/smtp/Makefile.in +++ b/postfix/src/smtp/Makefile.in @@ -107,7 +107,6 @@ smtp.o: ../../include/mail_server.h smtp.o: ../../include/mail_version.h smtp.o: ../../include/maps.h smtp.o: ../../include/match_list.h -smtp.o: ../../include/match_ops.h smtp.o: ../../include/mime_state.h smtp.o: ../../include/msg.h smtp.o: ../../include/msg_stats.h @@ -147,7 +146,6 @@ smtp_addr.o: ../../include/inet_proto.h smtp_addr.o: ../../include/mail_params.h smtp_addr.o: ../../include/maps.h smtp_addr.o: ../../include/match_list.h -smtp_addr.o: ../../include/match_ops.h smtp_addr.o: ../../include/mime_state.h smtp_addr.o: ../../include/msg.h smtp_addr.o: ../../include/msg_stats.h @@ -189,7 +187,6 @@ smtp_chat.o: ../../include/mail_error.h smtp_chat.o: ../../include/mail_params.h smtp_chat.o: ../../include/maps.h smtp_chat.o: ../../include/match_list.h -smtp_chat.o: ../../include/match_ops.h smtp_chat.o: ../../include/mime_state.h smtp_chat.o: ../../include/msg.h smtp_chat.o: ../../include/msg_stats.h @@ -232,7 +229,6 @@ smtp_connect.o: ../../include/mail_params.h smtp_connect.o: ../../include/mail_proto.h smtp_connect.o: ../../include/maps.h smtp_connect.o: ../../include/match_list.h -smtp_connect.o: ../../include/match_ops.h smtp_connect.o: ../../include/mime_state.h smtp_connect.o: ../../include/msg.h smtp_connect.o: ../../include/msg_stats.h @@ -272,7 +268,6 @@ smtp_map11.o: ../../include/htable.h smtp_map11.o: ../../include/mail_addr_map.h smtp_map11.o: ../../include/maps.h smtp_map11.o: ../../include/match_list.h -smtp_map11.o: ../../include/match_ops.h smtp_map11.o: ../../include/mime_state.h smtp_map11.o: ../../include/msg.h smtp_map11.o: ../../include/msg_stats.h @@ -317,7 +312,6 @@ smtp_proto.o: ../../include/mail_queue.h smtp_proto.o: ../../include/maps.h smtp_proto.o: ../../include/mark_corrupt.h smtp_proto.o: ../../include/match_list.h -smtp_proto.o: ../../include/match_ops.h smtp_proto.o: ../../include/mime_state.h smtp_proto.o: ../../include/msg.h smtp_proto.o: ../../include/msg_stats.h @@ -363,7 +357,6 @@ smtp_rcpt.o: ../../include/htable.h smtp_rcpt.o: ../../include/mail_params.h smtp_rcpt.o: ../../include/maps.h smtp_rcpt.o: ../../include/match_list.h -smtp_rcpt.o: ../../include/match_ops.h smtp_rcpt.o: ../../include/mime_state.h smtp_rcpt.o: ../../include/msg.h smtp_rcpt.o: ../../include/msg_stats.h @@ -396,7 +389,6 @@ smtp_reuse.o: ../../include/htable.h smtp_reuse.o: ../../include/mail_params.h smtp_reuse.o: ../../include/maps.h smtp_reuse.o: ../../include/match_list.h -smtp_reuse.o: ../../include/match_ops.h smtp_reuse.o: ../../include/mime_state.h smtp_reuse.o: ../../include/msg.h smtp_reuse.o: ../../include/msg_stats.h @@ -431,7 +423,6 @@ smtp_sasl_auth_cache.o: ../../include/header_opts.h smtp_sasl_auth_cache.o: ../../include/htable.h smtp_sasl_auth_cache.o: ../../include/maps.h smtp_sasl_auth_cache.o: ../../include/match_list.h -smtp_sasl_auth_cache.o: ../../include/match_ops.h smtp_sasl_auth_cache.o: ../../include/mime_state.h smtp_sasl_auth_cache.o: ../../include/msg.h smtp_sasl_auth_cache.o: ../../include/msg_stats.h @@ -465,7 +456,6 @@ smtp_sasl_glue.o: ../../include/mail_addr_find.h smtp_sasl_glue.o: ../../include/mail_params.h smtp_sasl_glue.o: ../../include/maps.h smtp_sasl_glue.o: ../../include/match_list.h -smtp_sasl_glue.o: ../../include/match_ops.h smtp_sasl_glue.o: ../../include/mime_state.h smtp_sasl_glue.o: ../../include/msg.h smtp_sasl_glue.o: ../../include/msg_stats.h @@ -501,7 +491,6 @@ smtp_sasl_proto.o: ../../include/htable.h smtp_sasl_proto.o: ../../include/mail_params.h smtp_sasl_proto.o: ../../include/maps.h smtp_sasl_proto.o: ../../include/match_list.h -smtp_sasl_proto.o: ../../include/match_ops.h smtp_sasl_proto.o: ../../include/mime_state.h smtp_sasl_proto.o: ../../include/msg.h smtp_sasl_proto.o: ../../include/msg_stats.h @@ -535,7 +524,6 @@ smtp_session.o: ../../include/htable.h smtp_session.o: ../../include/mail_params.h smtp_session.o: ../../include/maps.h smtp_session.o: ../../include/match_list.h -smtp_session.o: ../../include/match_ops.h smtp_session.o: ../../include/mime_state.h smtp_session.o: ../../include/msg.h smtp_session.o: ../../include/msg_stats.h @@ -569,7 +557,6 @@ smtp_state.o: ../../include/htable.h smtp_state.o: ../../include/mail_params.h smtp_state.o: ../../include/maps.h smtp_state.o: ../../include/match_list.h -smtp_state.o: ../../include/match_ops.h smtp_state.o: ../../include/mime_state.h smtp_state.o: ../../include/msg.h smtp_state.o: ../../include/msg_stats.h @@ -604,7 +591,6 @@ smtp_trouble.o: ../../include/htable.h smtp_trouble.o: ../../include/mail_error.h smtp_trouble.o: ../../include/maps.h smtp_trouble.o: ../../include/match_list.h -smtp_trouble.o: ../../include/match_ops.h smtp_trouble.o: ../../include/mime_state.h smtp_trouble.o: ../../include/msg.h smtp_trouble.o: ../../include/msg_stats.h @@ -636,7 +622,6 @@ smtp_unalias.o: ../../include/header_opts.h smtp_unalias.o: ../../include/htable.h smtp_unalias.o: ../../include/maps.h smtp_unalias.o: ../../include/match_list.h -smtp_unalias.o: ../../include/match_ops.h smtp_unalias.o: ../../include/mime_state.h smtp_unalias.o: ../../include/msg.h smtp_unalias.o: ../../include/msg_stats.h diff --git a/postfix/src/smtp/smtp_chat.c b/postfix/src/smtp/smtp_chat.c index 7cb1e11f3..213055e3d 100644 --- a/postfix/src/smtp/smtp_chat.c +++ b/postfix/src/smtp/smtp_chat.c @@ -300,6 +300,8 @@ SMTP_RESP *smtp_chat_resp(SMTP_SESSION *session) smtp_chat_append(session, "Replaced-by: ", ""); smtp_chat_append(session, " ", new_reply); } + } else if (smtp_chat_resp_filter->error != 0) { + /* XXX log something, even if regexps don't soft-fail. */ } } if (chat_append_flag) { diff --git a/postfix/src/smtp/smtp_map11.c b/postfix/src/smtp/smtp_map11.c index 23b2937e0..8d7f75817 100644 --- a/postfix/src/smtp/smtp_map11.c +++ b/postfix/src/smtp/smtp_map11.c @@ -91,7 +91,7 @@ int smtp_map11_external(VSTRING *addr, MAPS *maps, int propagate) argv_free(new_addr); return (1); } else { - if (dict_errno != 0) + if (maps->error != 0) msg_fatal("%s map lookup problem for %s", maps->title, STR(addr)); if (msg_verbose) msg_info("%s: %s not found", myname, STR(addr)); diff --git a/postfix/src/smtp/smtp_sasl_auth_cache.c b/postfix/src/smtp/smtp_sasl_auth_cache.c index 682c4fba3..4f0d7e89a 100644 --- a/postfix/src/smtp/smtp_sasl_auth_cache.c +++ b/postfix/src/smtp/smtp_sasl_auth_cache.c @@ -239,7 +239,7 @@ int smtp_sasl_auth_cache_find(SMTP_SASL_AUTH_CACHE *auth_cache, if ((valid = smtp_sasl_auth_cache_valid_value(auth_cache, entry, session->sasl_passwd)) == 0) /* Remove expired, password changed, or malformed cache entry. */ - if (dict_del(auth_cache->dict, key) == 0) + if (dict_del(auth_cache->dict, key) != 0) msg_warn("SASL auth failure map %s: entry not deleted: %s", auth_cache->dict->name, key); myfree(key); diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in index f053b1679..a311c77ec 100644 --- a/postfix/src/smtpd/Makefile.in +++ b/postfix/src/smtpd/Makefile.in @@ -177,7 +177,6 @@ smtpd.o: ../../include/mail_stream.h smtpd.o: ../../include/mail_version.h smtpd.o: ../../include/maps.h smtpd.o: ../../include/match_list.h -smtpd.o: ../../include/match_ops.h smtpd.o: ../../include/milter.h smtpd.o: ../../include/msg.h smtpd.o: ../../include/myaddrinfo.h @@ -285,7 +284,6 @@ smtpd_check.o: ../../include/mail_proto.h smtpd_check.o: ../../include/mail_stream.h smtpd_check.o: ../../include/maps.h smtpd_check.o: ../../include/match_list.h -smtpd_check.o: ../../include/match_ops.h smtpd_check.o: ../../include/match_parent_style.h smtpd_check.o: ../../include/milter.h smtpd_check.o: ../../include/msg.h diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 6e90bf10d..a489981fd 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -4649,6 +4649,8 @@ static void smtpd_proto(SMTPD_STATE *state) msg_info("%s: replacing command \"%.100s\" with \"%.100s\"", state->namaddr, STR(state->buffer), cp); vstring_strcpy(state->buffer, cp); + } else if (smtpd_cmd_filter->error != 0) { + /* XXX log something, even if regexps don't soft-fail. */ } } if ((argc = smtpd_token(vstring_str(state->buffer), &argv)) == 0) { diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index 4461cb384..51616b616 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -254,9 +254,8 @@ static jmp_buf smtpd_check_buf; /* - * Results of restrictions. + * Results of restrictions. Errors are negative; see dict.h. */ -#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 */ @@ -922,10 +921,9 @@ static const char *check_mail_addr_find(SMTPD_STATE *state, { const char *result; - dict_errno = 0; - if ((result = mail_addr_find(maps, key, ext)) != 0 || dict_errno == 0) + if ((result = mail_addr_find(maps, key, ext)) != 0 || maps->error == 0) return (result); - if (dict_errno == DICT_ERR_RETRY) + if (maps->error == DICT_ERR_RETRY) reject_dict_retry(state, reply_name); else reject_server_error(state); @@ -1010,10 +1008,10 @@ static int permit_mynetworks(SMTPD_STATE *state) if (namadr_list_match(mynetworks, state->name, state->addr)) return (SMTPD_CHECK_OK); - else if (dict_errno == 0) + else if (mynetworks->error == 0) return (SMTPD_CHECK_DUNNO); else - return (SMTPD_CHECK_ERROR); + return (mynetworks->error); } /* dup_if_truncate - save hostname and truncate if it ends in dot */ @@ -1242,8 +1240,6 @@ static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs) #ifdef USE_TLS const char *found = 0; - dict_errno = 0; - if (!state->tls_context) return SMTPD_CHECK_DUNNO; @@ -1264,25 +1260,23 @@ static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs) prints[0] = state->tls_context->peer_fingerprint; prints[1] = state->tls_context->peer_pkey_fprint; - /* After lookup error, leave dict_errno at non-zero value. */ + /* After lookup error, leave relay_ccerts->error at non-zero value. */ for (i = 0; i < 2; ++i) { found = maps_find(relay_ccerts, prints[i], DICT_FLAG_NONE); if (found != 0) { if (msg_verbose) msg_info("Relaying allowed for certified client: %s", found); return (SMTPD_CHECK_OK); - } else if (dict_errno != 0) { + } else if (relay_ccerts->error != 0) { msg_warn("relay_clientcerts: lookup error for fingerprint '%s', " "pkey fingerprint %s", prints[0], prints[1]); - return (SMTPD_CHECK_ERROR); + return (relay_ccerts->error); } } if (msg_verbose) msg_info("relay_clientcerts: No match for fingerprint '%s', " "pkey fingerprint %s", prints[0], prints[1]); } -#else - dict_errno = 0; #endif return (SMTPD_CHECK_DUNNO); } @@ -1462,7 +1456,7 @@ static int all_auth_mx_addr(SMTPD_STATE *state, char *host, msg_info("%s: checking: %s", myname, hostaddr.buf); if (!namadr_list_match(perm_mx_networks, host, hostaddr.buf)) { - if (dict_errno == 0) { + if (perm_mx_networks->error == 0) { /* * Reject: at least one IP address is not listed in @@ -1556,7 +1550,7 @@ static int i_am_mx(SMTPD_STATE *state, DNS_RR *mx_list, for (mx = mx_list; mx != 0; mx = mx->next) { if (msg_verbose) msg_info("%s: resolve hostname: %s", myname, (char *) mx->data); - if (resolve_local((char *) mx->data)) + if (resolve_local((char *) mx->data) > 0) return (YUP); /* if no match or error, match interface addresses instead. */ } @@ -2367,7 +2361,7 @@ static int check_access(SMTPD_STATE *state, const char *table, const char *name, CHK_ACCESS_RETURN(check_table_result(state, table, value, name, reply_name, reply_class, def_acl), FOUND); - if (dict_errno != 0) { + if (dict->error != 0) { msg_warn("%s: table lookup problem", table); value = "451 4.3.5 Server configuration error"; CHK_ACCESS_RETURN(check_table_result(state, table, value, name, @@ -2418,7 +2412,7 @@ static int check_domain_access(SMTPD_STATE *state, const char *table, CHK_DOMAIN_RETURN(check_table_result(state, table, value, domain, reply_name, reply_class, def_acl), FOUND); - if (dict_errno != 0) { + if (dict->error != 0) { msg_warn("%s: table lookup problem", table); value = "451 4.3.5 Server configuration error"; CHK_DOMAIN_RETURN(check_table_result(state, table, value, @@ -2482,7 +2476,7 @@ static int check_addr_access(SMTPD_STATE *state, const char *table, CHK_ADDR_RETURN(check_table_result(state, table, value, address, reply_name, reply_class, def_acl), FOUND); - if (dict_errno != 0) { + if (dict->error != 0) { msg_warn("%s: table lookup problem", table); value = "451 4.3.5 Server configuration error"; CHK_ADDR_RETURN(check_table_result(state, table, value, address, @@ -4068,8 +4062,8 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, if (msg_verbose) msg_info("%s: name=%s status=%d", myname, name, status); - if (status == SMTPD_CHECK_ERROR) { - if (dict_errno == DICT_ERR_RETRY) + if (status < 0) { + if (status == DICT_ERR_RETRY) reject_dict_retry(state, reply_name); else reject_server_error(state); @@ -4143,12 +4137,11 @@ char *smtpd_check_rewrite(SMTPD_STATE *state) } else if (is_map_command(state, name, CHECK_ADDR_MAP, &cpp)) { if ((dict = dict_handle(*cpp)) == 0) msg_panic("%s: dictionary not found: %s", myname, *cpp); - dict_errno = 0; if (dict_get(dict, state->addr) != 0) status = SMTPD_CHECK_OK; - else if (dict_errno != 0) { + else if (dict->error != 0) { msg_warn("%s: %s: lookup error", VAR_LOC_RWR_CLIENTS, *cpp); - status = SMTPD_CHECK_ERROR; + status = dict->error; } } else if (strcasecmp(name, PERMIT_SASL_AUTH) == 0) { #ifdef USE_SASL_AUTH @@ -4165,8 +4158,8 @@ char *smtpd_check_rewrite(SMTPD_STATE *state) VAR_LOC_RWR_CLIENTS, name); continue; } - if (status == SMTPD_CHECK_ERROR) { - if (dict_errno == DICT_ERR_RETRY) { + if (status < 0) { + if (status == DICT_ERR_RETRY) { state->error_mask |= MAIL_ERROR_RESOURCE; log_whatsup(state, "reject", "451 4.3.0 Temporary lookup error"); @@ -5226,6 +5219,7 @@ void resolve_clnt(const char *class, const char *unused_sender, const char *a RESOLVE_REPLY *reply) { const char *domain; + int rc; if (addr == CONST_STR(reply->recipient)) msg_panic("resolve_clnt_query: result clobbers input"); @@ -5234,29 +5228,29 @@ void resolve_clnt(const char *class, const char *unused_sender, const char *a if ((domain = strrchr(addr, '@')) == 0) msg_fatal("%s: unqualified address", addr); domain += 1; - if (resolve_local(domain)) { + if ((rc = resolve_local(domain)) > 0) { reply->flags = RESOLVE_CLASS_LOCAL; vstring_strcpy(reply->transport, MAIL_SERVICE_LOCAL); vstring_strcpy(reply->nexthop, domain); - } else if (dict_errno) { + } else if (rc < 0) { 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) { + } else if (virt_alias_doms->error) { 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) { + } else if (virt_mailbox_doms->error) { 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) { + } else if (relay_domains->error) { reply->flags = RESOLVE_FLAG_FAIL; } else { reply->flags = RESOLVE_CLASS_DEFAULT; diff --git a/postfix/src/trivial-rewrite/Makefile.in b/postfix/src/trivial-rewrite/Makefile.in index 6f4e24e8f..199585680 100644 --- a/postfix/src/trivial-rewrite/Makefile.in +++ b/postfix/src/trivial-rewrite/Makefile.in @@ -74,7 +74,6 @@ resolve.o: ../../include/mail_params.h resolve.o: ../../include/mail_proto.h resolve.o: ../../include/maps.h resolve.o: ../../include/match_list.h -resolve.o: ../../include/match_ops.h resolve.o: ../../include/match_parent_style.h resolve.o: ../../include/msg.h resolve.o: ../../include/mymalloc.h @@ -124,7 +123,7 @@ transport.o: ../../include/iostuff.h transport.o: ../../include/mail_params.h transport.o: ../../include/mail_proto.h transport.o: ../../include/maps.h -transport.o: ../../include/match_ops.h +transport.o: ../../include/match_list.h transport.o: ../../include/match_parent_style.h transport.o: ../../include/msg.h transport.o: ../../include/mymalloc.h diff --git a/postfix/src/trivial-rewrite/resolve.c b/postfix/src/trivial-rewrite/resolve.c index 6b49b3dbd..c237b312f 100644 --- a/postfix/src/trivial-rewrite/resolve.c +++ b/postfix/src/trivial-rewrite/resolve.c @@ -155,6 +155,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr, const char *relay; const char *xport; const char *sender_key; + int rc; *flags = 0; vstring_strcpy(channel, "CHANNEL NOT UPDATED"); @@ -259,8 +260,8 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr, * requestor. */ if ((domain = tok822_rfind_type(tree->tail, '@')) != 0) { - if (domain->next && RESOLVE_LOCAL(domain->next) == 0) { - if (dict_errno != 0) { + if (domain->next && (rc = RESOLVE_LOCAL(domain->next)) <= 0) { + if (rc < 0) { *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; } @@ -377,9 +378,9 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr, vstring_insert(nextrcpt, rcpt_domain - STR(nextrcpt), "[", 1); vstring_strcat(nextrcpt, "]"); rcpt_domain = strrchr(STR(nextrcpt), '@') + 1; - if (resolve_local(rcpt_domain)) /* XXX */ + if ((rc = resolve_local(rcpt_domain)) > 0) /* XXX */ domain = 0; - else if (dict_errno != 0) { + else if (rc < 0) { *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; } @@ -427,7 +428,6 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr, */ #define STREQ(x,y) (strcmp((x), (y)) == 0) - dict_errno = 0; if (domain != 0) { /* @@ -457,7 +457,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr, var_show_unk_rcpt_table ? " in virtual alias table" : ""); *flags |= RESOLVE_CLASS_ALIAS; - } else if (dict_errno != 0) { + } else if (virt_alias_doms && virt_alias_doms->error != 0) { msg_warn("%s lookup failure", VAR_VIRT_ALIAS_DOMS); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; @@ -479,7 +479,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr, vstring_strcpy(nexthop, rcpt_domain); blame = rp->virt_transport_name; *flags |= RESOLVE_CLASS_VIRTUAL; - } else if (dict_errno != 0) { + } else if (virt_mailbox_doms && virt_mailbox_doms->error != 0) { msg_warn("%s lookup failure", VAR_VIRT_MAILBOX_DOMS); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; @@ -493,7 +493,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr, 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 (relay_domains && relay_domains->error != 0) { msg_warn("%s lookup failure", VAR_RELAY_DOMAINS); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; @@ -516,7 +516,8 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr, vstring_strcpy(channel, strcasecmp(xport, "DUNNO") == 0 ? RES_PARAM_VALUE(rp->def_transport) : xport); blame = rp->snd_def_xp_maps_name; - } else if (dict_errno != 0) { + } else if (rp->snd_def_xp_info + && rp->snd_def_xp_info->error != 0) { msg_warn("%s lookup failure", rp->snd_def_xp_maps_name); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; @@ -543,7 +544,8 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr, } vstring_strcpy(nexthop, strcasecmp(relay, "DUNNO") == 0 ? rcpt_domain : relay); - } else if (dict_errno != 0) { + } else if (rp->snd_relay_info + && rp->snd_relay_info->error != 0) { msg_warn("%s lookup failure", rp->snd_relay_maps_name); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; @@ -632,7 +634,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr, if (rp->transport_info && !(*flags & RESOLVE_CLASS_ALIAS)) { if (transport_lookup(rp->transport_info, STR(nextrcpt), rcpt_domain, channel, nexthop) == 0 - && dict_errno != 0) { + && rp->transport_info->transport_path->error != 0) { msg_warn("%s lookup failure", rp->transport_maps_name); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; @@ -658,7 +660,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr, vstring_strcpy(channel, MAIL_SERVICE_ERROR); /* 5.1.6 is the closest match, but not perfect. */ vstring_sprintf(nexthop, "5.1.6 User has moved to %s", newloc); - } else if (dict_errno != 0) { + } else if (relocated_maps->error != 0) { msg_warn("%s lookup failure", VAR_RELOCATED_MAPS); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; diff --git a/postfix/src/trivial-rewrite/transport.c b/postfix/src/trivial-rewrite/transport.c index 4b3c98bc7..29720541c 100644 --- a/postfix/src/trivial-rewrite/transport.c +++ b/postfix/src/trivial-rewrite/transport.c @@ -169,11 +169,6 @@ static int find_transport_entry(TRANSPORT_INFO *tp, const char *key, const char *host; const char *value; - /* - * Reset previous error history. - */ - dict_errno = 0; - #define FOUND 1 #define NOTFOUND 0 @@ -241,7 +236,7 @@ static void transport_wildcard_init(TRANSPORT_INFO *tp) msg_info("wildcard_{chan:hop}={%s:%s}", vstring_str(channel), vstring_str(nexthop)); } else { - tp->wildcard_errno = dict_errno; + tp->wildcard_errno = tp->transport_path->error; vstring_free(channel); vstring_free(nexthop); tp->wildcard_channel = 0; @@ -282,7 +277,7 @@ int transport_lookup(TRANSPORT_INFO *tp, const char *addr, if (find_transport_entry(tp, addr, rcpt_domain, FULL, channel, nexthop)) return (FOUND); - if (dict_errno != 0) + if (tp->transport_path->error != 0) return (NOTFOUND); /* @@ -298,7 +293,7 @@ int transport_lookup(TRANSPORT_INFO *tp, const char *addr, myfree(stripped_addr); if (found) return (FOUND); - if (dict_errno != 0) + if (tp->transport_path->error != 0) return (NOTFOUND); } @@ -321,7 +316,7 @@ int transport_lookup(TRANSPORT_INFO *tp, const char *addr, for (name = ratsign + 1; *name != 0; name = next) { if (find_transport_entry(tp, name, rcpt_domain, PARTIAL, channel, nexthop)) return (FOUND); - if (dict_errno != 0) + if (tp->transport_path->error != 0) return (NOTFOUND); if ((next = strchr(name + 1, '.')) == 0) break; @@ -335,7 +330,7 @@ int transport_lookup(TRANSPORT_INFO *tp, const char *addr, if (tp->wildcard_errno || event_time() > tp->expire) transport_wildcard_init(tp); if (tp->wildcard_errno) { - dict_errno = tp->wildcard_errno; + tp->transport_path->error = tp->wildcard_errno; return (NOTFOUND); } else if (tp->wildcard_channel) { update_entry(STR(tp->wildcard_channel), STR(tp->wildcard_nexthop), diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 3687fe12d..368a1cea8 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -34,7 +34,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.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 \ - dict_fail.c + dict_fail.c msg_rate_delay.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 \ @@ -70,7 +70,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.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 \ - dict_fail.o + dict_fail.o msg_rate_delay.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 \ @@ -80,7 +80,7 @@ HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \ get_domainname.h get_hostname.h hex_code.h hex_quote.h host_port.h \ htable.h inet_addr_host.h inet_addr_list.h inet_addr_local.h \ inet_proto.h iostuff.h line_wrap.h listen.h lstat_as.h mac_expand.h \ - mac_parse.h make_dirs.h mask_addr.h match_list.h match_ops.h msg.h \ + mac_parse.h make_dirs.h mask_addr.h match_list.h msg.h \ msg_output.h msg_syslog.h msg_vstream.h mvect.h myaddrinfo.h myflock.h \ mymalloc.h myrand.h name_code.h name_mask.h netstring.h nvtable.h \ open_as.h open_lock.h percentm.h posix_signals.h readlline.h ring.h \ @@ -109,7 +109,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \ attr_scan0 host_port attr_scan_plain attr_print_plain htable \ unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \ myaddrinfo myaddrinfo4 inet_proto sane_basename format_tv \ - valid_utf_8 ip_match base32_code + valid_utf_8 ip_match base32_code msg_rate_delay LIB_DIR = ../../lib INC_DIR = ../../include @@ -434,6 +434,11 @@ base32_code: $(LIB) $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o +msg_rate_delay: $(LIB) + mv $@.o junk + $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) + mv junk $@.o + tests: valid_hostname_test mac_expand_test dict_test unescape_test \ hex_quote_test ctable_test inet_addr_list_test base64_code_test \ attr_scan64_test attr_scan0_test dict_pcre_test host_port_test \ @@ -1352,7 +1357,6 @@ match_list.o: argv.h match_list.o: dict.h match_list.o: match_list.c match_list.o: match_list.h -match_list.o: match_ops.h match_list.o: msg.h match_list.o: mymalloc.h match_list.o: stringops.h @@ -1364,8 +1368,8 @@ match_list.o: vstring_vstream.h match_ops.o: argv.h match_ops.o: cidr_match.h match_ops.o: dict.h +match_ops.o: match_list.h match_ops.o: match_ops.c -match_ops.o: match_ops.h match_ops.o: msg.h match_ops.o: myaddrinfo.h match_ops.o: mymalloc.h @@ -1389,6 +1393,12 @@ msg_output.o: sys_defs.h msg_output.o: vbuf.h msg_output.o: vstream.h msg_output.o: vstring.h +msg_rate_delay.o: events.h +msg_rate_delay.o: msg.h +msg_rate_delay.o: msg_rate_delay.c +msg_rate_delay.o: sys_defs.h +msg_rate_delay.o: vbuf.h +msg_rate_delay.o: vstring.h msg_syslog.o: msg.h msg_syslog.o: msg_output.h msg_syslog.o: msg_syslog.c diff --git a/postfix/src/util/dict.c b/postfix/src/util/dict.c index 30a51b9f2..baeff9d20 100644 --- a/postfix/src/util/dict.c +++ b/postfix/src/util/dict.c @@ -6,9 +6,6 @@ /* SYNOPSIS /* #include /* -/* extern int dict_unknown_allowed; -/* extern int dict_errno; -/* /* void dict_register(dict_name, dict_info) /* const char *dict_name; /* DICT *dict_info; @@ -19,7 +16,7 @@ /* void dict_unregister(dict_name) /* const char *dict_name; /* -/* void dict_update(dict_name, member, value) +/* int dict_update(dict_name, member, value) /* const char *dict_name; /* const char *member; /* const char *value; @@ -47,6 +44,9 @@ /* void (*action)(dict_name, dict_handle, context) /* char *context; /* +/* int dict_error(dict_name) +/* const char *dict_name; +/* /* const char *dict_changed_name() /* AUXILIARY FUNCTIONS /* void dict_load_file(dict_name, path) @@ -76,10 +76,11 @@ /* value of \fIname\fR. The forms $(\fIname\fR) and ${\fIname\fR} are /* also supported. /* .IP "unknown names" -/* References to unknown dictionary or dictionary member names either -/* default to an empty dictionary or null pointer value, or cause a -/* run-time error. The behavior is controlled by the global -/* \fIdict_unknown_allowed\fR boolean variable. +/* An update request for an unknown dictionary name will trigger +/* the instantiation of an in-memory dictionary with that name. +/* A lookup request (including delete and sequence) for an +/* unknown dictionary will result in a "not found" and "no +/* error" result. /* .PP /* dict_register() adds a new dictionary, including access methods, /* to the list of known dictionaries, or increments the reference @@ -97,7 +98,8 @@ /* /* dict_update() updates the value of the named dictionary member. /* The dictionary member and the named dictionary are instantiated -/* on the fly. +/* on the fly. The result value is zero (DICT_STAT_SUCCESS) +/* when the update was made. /* /* dict_lookup() returns the value of the named member (i.e. without /* expanding macros in the member value). The \fIdict_name\fR argument @@ -107,9 +109,8 @@ /* modified, or if the result is to survive multiple dict_lookup() calls. /* /* dict_delete() removes the named member from the named dictionary. -/* The result value is zero when the member was found, > 0 if -/* it was not found, and < 0 in case of error (a database may -/* not return after error). +/* The result value is zero (DICT_STAT_SUCCESS) when the member +/* was found. /* /* dict_sequence() steps through the named dictionary and returns /* keys and values in some implementation-defined order. The func @@ -117,8 +118,8 @@ /* entry or DICT_SEQ_FUN_NEXT to select the next entry. The result /* is owned by the underlying dictionary method. Make a copy if the /* result is to be modified, or if the result is to survive multiple -/* dict_sequence() calls. The result value is zero when a member -/* was found. +/* dict_sequence() calls. The result value is zero (DICT_STAT_SUCCESS) +/* when a member was found. /* /* dict_eval() expands macro references in the specified string. /* The result is owned by the dictionary manager. Make a copy if the @@ -155,16 +156,30 @@ /* htable(3) /* BUGS /* DIAGNOSTICS -/* Fatal errors: out of memory, reference to unknown name, -/* malformed macro name. +/* Fatal errors: out of memory, malformed macro name. /* -/* The lookup routines may set the \fIdict_errno\fR variable when -/* they were unable to find the requested result. The lookup -/* routines must reset \fIdict_errno\fR before each lookup operation. -/* \fIdict_errno\fR can have the following values: -/* .IP DICT_ERR_RETRY +/* The lookup routine returns non-null when the request is +/* satisfied. The update, delete and sequence routines return +/* zero (DICT_STAT_SUCCESS) when the request is satisfied. +/* The dict_error() function returns non-zero only when the +/* last operation was not satisfied due to a dictionary access +/* error. The result can have the following values: +/* .IP DICT_ERR_NONE(zero) +/* There was no dictionary access error. For example, the +/* request was satisfied, the requested information did not +/* exist in the dictionary, or the information already existed +/* when it should not exist (collision). +/* .IP DICT_ERR_RETRY(<0) /* The dictionary was temporarily unavailable. This can happen /* with network-based services. +/* .IP DICT_ERR_CONFIG(<0) +/* The dictionary was unavailable due to a configuration error. +/* .PP +/* Generally, a program is expected to test the function result +/* value for "success" first. If the operation was not successful, +/* a program is expected to test for a non-zero dict->error +/* status to distinguish between a data notfound/collision +/* condition or a dictionary access error. /* LICENSE /* .ad /* .fi @@ -200,12 +215,6 @@ #include "dict.h" #include "dict_ht.h" - /* - * By default, use a sane default for an unknown name. - */ -int dict_unknown_allowed = 1; -int dict_errno = 0; - static HTABLE *dict_table; /* @@ -222,6 +231,27 @@ typedef struct { #define dict_node(dict) \ (dict_table ? (DICT_NODE *) htable_find(dict_table, dict) : 0) +/* Find a dictionary handle by name for lookup purposes. */ + +#define DICT_FIND_FOR_LOOKUP(dict, dict_name) do { \ + DICT_NODE *node; \ + if ((node = dict_node(dict_name)) != 0) \ + dict = node->dict; \ + else \ + dict = 0; \ +} while (0) + +/* Find a dictionary handle by name for update purposes. */ + +#define DICT_FIND_FOR_UPDATE(dict, dict_name) do { \ + DICT_NODE *node; \ + if ((node = dict_node(dict_name)) == 0) { \ + dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0); \ + dict_register(dict_name, dict); \ + } else \ + dict = node->dict; \ +} while (0) + #define STR(x) vstring_str(x) /* dict_register - make association with dictionary */ @@ -283,22 +313,15 @@ void dict_unregister(const char *dict_name) /* dict_update - replace or add dictionary entry */ -void dict_update(const char *dict_name, const char *member, const char *value) +int dict_update(const char *dict_name, const char *member, const char *value) { const char *myname = "dict_update"; - DICT_NODE *node; DICT *dict; - if ((node = dict_node(dict_name)) == 0) { - if (dict_unknown_allowed == 0) - msg_fatal("%s: unknown dictionary: %s", myname, dict_name); - dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0); - dict_register(dict_name, dict); - } else - dict = node->dict; + DICT_FIND_FOR_UPDATE(dict, dict_name); if (msg_verbose > 1) msg_info("%s: %s = %s", myname, member, value); - dict->update(dict, member, value); + return (dict->update(dict, member, value)); } /* dict_lookup - look up dictionary entry */ @@ -306,22 +329,21 @@ void dict_update(const char *dict_name, const char *member, const char *value const char *dict_lookup(const char *dict_name, const char *member) { const char *myname = "dict_lookup"; - DICT_NODE *node; DICT *dict; - const char *ret = 0; + const char *ret; - if ((node = dict_node(dict_name)) == 0) { - if (dict_unknown_allowed == 0) - msg_fatal("%s: unknown dictionary: %s", myname, dict_name); - } else { - dict = node->dict; + DICT_FIND_FOR_LOOKUP(dict, dict_name); + if (dict != 0) { ret = dict->lookup(dict, member); - if (ret == 0 && dict_unknown_allowed == 0) - msg_fatal("dictionary %s: unknown member: %s", dict_name, member); + if (msg_verbose > 1) + msg_info("%s: %s = %s", myname, member, ret ? ret : + dict->error ? "(error)" : "(notfound)"); + return (ret); + } else { + if (msg_verbose > 1) + msg_info("%s: %s = %s", myname, member, "(notfound)"); + return (0); } - if (msg_verbose > 1) - msg_info("%s: %s = %s", myname, member, ret ? ret : "(notfound)"); - return (ret); } /* dict_delete - delete dictionary entry */ @@ -329,23 +351,12 @@ const char *dict_lookup(const char *dict_name, const char *member) int dict_delete(const char *dict_name, const char *member) { const char *myname = "dict_delete"; - DICT_NODE *node; DICT *dict; - int result; - if ((node = dict_node(dict_name)) == 0) { - if (dict_unknown_allowed == 0) - msg_fatal("%s: unknown dictionary: %s", myname, dict_name); - dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0); - dict_register(dict_name, dict); - } else - dict = node->dict; + DICT_FIND_FOR_LOOKUP(dict, dict_name); if (msg_verbose > 1) msg_info("%s: delete %s", myname, member); - if ((result = dict->delete(dict, member)) != 0 && dict_unknown_allowed == 0) - msg_fatal("%s: dictionary %s: unknown member: %s", - myname, dict_name, member); - return (result); + return (dict ? dict->delete(dict, member) : DICT_STAT_FAIL); } /* dict_sequence - traverse dictionary */ @@ -354,19 +365,22 @@ int dict_sequence(const char *dict_name, const int func, const char **member, const char **value) { const char *myname = "dict_sequence"; - DICT_NODE *node; DICT *dict; - if ((node = dict_node(dict_name)) == 0) { - if (dict_unknown_allowed == 0) - msg_fatal("%s: unknown dictionary: %s", myname, dict_name); - dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0); - dict_register(dict_name, dict); - } else - dict = node->dict; + DICT_FIND_FOR_LOOKUP(dict, dict_name); if (msg_verbose > 1) msg_info("%s: sequence func %d", myname, func); - return (dict->sequence(dict, func, member, value)); + return (dict ? dict->sequence(dict, func, member, value) : DICT_STAT_FAIL); +} + +/* dict_error - return last error */ + +int dict_error(const char *dict_name) +{ + DICT *dict; + + DICT_FIND_FOR_LOOKUP(dict, dict_name); + return (dict ? dict->error : DICT_ERR_NONE); } /* dict_load_file - read entries from text file */ @@ -410,20 +424,12 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp) int lineno; const char *err; struct stat st; - DICT_NODE *node; DICT *dict; /* * Instantiate the dictionary even if the file is empty. */ - if ((node = dict_node(dict_name)) == 0) { - if (dict_unknown_allowed == 0) - msg_fatal("%s: unknown dictionary: %s", myname, dict_name); - dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0); - dict_register(dict_name, dict); - } else - dict = node->dict; - + DICT_FIND_FOR_UPDATE(dict, dict_name); buf = vstring_alloc(100); lineno = 0; @@ -435,7 +441,9 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp) VSTREAM_PATH(fp), lineno, err, STR(buf)); if (msg_verbose > 1) msg_info("%s: %s = %s", myname, member, val); - dict->update(dict, member, val); + if (dict->update(dict, member, val) != 0) + msg_fatal("%s, line %d: unable to update %s:%s", + VSTREAM_PATH(fp), lineno, dict->type, dict->name); } vstring_free(buf); dict->owner.uid = st.st_uid; @@ -447,14 +455,16 @@ void dict_load_fp(const char *dict_name, VSTREAM *fp) static const char *dict_eval_lookup(const char *key, int unused_type, char *dict_name) { - const char *pp; + const char *pp = 0; + DICT *dict; /* * XXX how would one recover? */ - if ((pp = dict_lookup(dict_name, key)) == 0 && dict_errno != 0) - msg_fatal("dictionary %s: lookup %s: temporary error", dict_name, key); - + DICT_FIND_FOR_LOOKUP(dict, dict_name); + if (dict != 0 + && (pp = dict->lookup(dict, key)) == 0 && dict->error != 0) + msg_fatal("dictionary %s: lookup %s: operation failed", dict_name, key); return (pp); } diff --git a/postfix/src/util/dict.h b/postfix/src/util/dict.h index b7811b7e2..90536a226 100644 --- a/postfix/src/util/dict.h +++ b/postfix/src/util/dict.h @@ -44,7 +44,7 @@ typedef struct DICT { char *name; /* for diagnostics */ int flags; /* see below */ const char *(*lookup) (struct DICT *, const char *); - void (*update) (struct DICT *, const char *, const char *); + int (*update) (struct DICT *, const char *, const char *); int (*delete) (struct DICT *, const char *); int (*sequence) (struct DICT *, int, const char **, const char **); void (*close) (struct DICT *); @@ -53,6 +53,7 @@ typedef struct DICT { time_t mtime; /* mod time at open */ VSTRING *fold_buf; /* key folding buffer */ DICT_OWNER owner; /* provenance */ + int error; /* last operation only */ } DICT; extern DICT *dict_alloc(const char *, const char *, ssize_t); @@ -113,12 +114,24 @@ extern DICT *dict_debug(DICT *); DICT_FLAG_PARANOID) #define DICT_FLAG_INST_MASK ~(DICT_FLAG_IMPL_MASK | DICT_FLAG_RQST_MASK) -extern int dict_unknown_allowed; -extern int dict_errno; - + /* + * dict->error values. Errors must be negative; smtpd_check depends on this. + */ #define DICT_ERR_NONE 0 /* no error */ -#define DICT_ERR_RETRY 1 /* soft error */ -#define DICT_ERR_CONFIG 2 /* configuration error */ +#define DICT_ERR_RETRY (-1) /* soft error */ +#define DICT_ERR_CONFIG (-2) /* configuration error */ + + /* + * FAIL/ERROR are suggested result values, not meant for use in comparisons. + */ +#define DICT_STAT_FAIL 1 /* any value > 0: notfound, conflict */ +#define DICT_STAT_SUCCESS 0 /* request satisfied */ +#define DICT_STAT_ERROR (-1) /* any value < 0: database error */ + +#define DICT_ERR_VAL_RETURN(dict, err, val) do { \ + (dict)->error = (err); \ + return (val); \ + } while (0) /* * Sequence function types. @@ -137,13 +150,14 @@ extern ARGV *dict_mapnames(void); extern void dict_register(const char *, DICT *); extern DICT *dict_handle(const char *); extern void dict_unregister(const char *); -extern void dict_update(const char *, const char *, const char *); +extern int dict_update(const char *, const char *, const char *); extern const char *dict_lookup(const char *, const char *); extern int dict_delete(const char *, const char *); extern int dict_sequence(const char *, const int, const char **, const char **); extern void dict_load_file(const char *, const char *); extern void dict_load_fp(const char *, VSTREAM *); extern const char *dict_eval(const char *, const char *, int); +extern int dict_error(const char *); /* * Low-level interface, with physical dictionary handles. diff --git a/postfix/src/util/dict_alloc.c b/postfix/src/util/dict_alloc.c index 0f97d1b6e..b68421021 100644 --- a/postfix/src/util/dict_alloc.c +++ b/postfix/src/util/dict_alloc.c @@ -71,8 +71,8 @@ static const char *dict_default_lookup(DICT *dict, const char *unused_key) /* dict_default_update - trap unimplemented operation */ -static void dict_default_update(DICT *dict, const char *unused_key, - const char *unused_value) +static int dict_default_update(DICT *dict, const char *unused_key, + const char *unused_value) { msg_fatal("%s table %s: update operation is not supported", dict->type, dict->name); @@ -123,6 +123,7 @@ DICT *dict_alloc(const char *dict_type, const char *dict_name, ssize_t size) dict->fold_buf = 0; dict->owner.status = DICT_OWNER_UNKNOWN; dict->owner.uid = ~0; + dict->error = DICT_ERR_NONE; return dict; } diff --git a/postfix/src/util/dict_cache.c b/postfix/src/util/dict_cache.c index 506a7d09b..94907dd12 100644 --- a/postfix/src/util/dict_cache.c +++ b/postfix/src/util/dict_cache.c @@ -141,10 +141,19 @@ /* .IP table /* A bare dictonary handle. /* DIAGNOSTICS -/* These routines terminate with a fatal run-time error -/* for unrecoverable database errors. This allows the -/* program to restart and reset the database to an -/* empty initial state. +/* When a request is satisfied, the lookup routine returns +/* non-null, and the update, delete and sequence routines +/* return zero. The cache->error value is zero when a request +/* could not be satisfied because an item did not exist (delete, +/* sequence) or if it could not be updated. The cache->error +/* value is non-zero only when a request could not be satisfied, +/* and the cause was a database error. +/* +/* Cache access errors are logged with a warning message. To +/* avoid spamming the log, each type of operation logs no more +/* than one cache access error per second, per cache. Specify +/* the DICT_CACHE_FLAG_VERBOSE flag (see above) to log all +/* warnings. /* BUGS /* There should be a way to suspend automatic program suicide /* until a cache cleanup run is completed. Some entries may @@ -201,6 +210,7 @@ struct DICT_CACHE { int cache_flags; /* see below */ int user_flags; /* logging */ DICT *db; /* database handle */ + int error; /* last operation only */ /* Delete-behind support. */ char *saved_curr_key; /* "current" cache lookup key */ @@ -212,10 +222,22 @@ struct DICT_CACHE { char *exp_context; /* call-back context */ int retained; /* entries retained in cleanup run */ int dropped; /* entries removed in cleanup run */ + + /* Rate-limited logging support. */ + int log_delay; + time_t upd_log_stamp; /* last update warning */ + time_t get_log_stamp; /* last lookup warning */ + time_t del_log_stamp; /* last delete warning */ + time_t seq_log_stamp; /* last sequence warning */ }; #define DC_FLAG_DEL_SAVED_CURRENT_KEY (1<<0) /* delete-behind is scheduled */ + /* + * Don't log cache access errors more than once per second. + */ +#define DC_DEF_LOG_DELAY 1 + /* * Macros to make obscure code more readable. */ @@ -243,6 +265,7 @@ const char *dict_cache_lookup(DICT_CACHE *cp, const char *cache_key) { const char *myname = "dict_cache_lookup"; const char *cache_val; + DICT *db = cp->db; /* * Search for the cache entry. Don't return an entry that is scheduled @@ -253,29 +276,29 @@ const char *dict_cache_lookup(DICT_CACHE *cp, const char *cache_key) if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) msg_info("%s: key=%s (pretend not found - scheduled for deletion)", myname, cache_key); - dict_errno = 0; - return (0); + DICT_ERR_VAL_RETURN(cp, DICT_ERR_NONE, (char *) 0); } else { - cache_val = dict_get(cp->db, cache_key); -#if 0 - if (cache_val == 0 && dict_errno != 0) - msg_warn("%s: cache lookup for '%s' failed due to error", - cp->name, cache_key); -#endif + cache_val = dict_get(db, cache_key); + if (cache_val == 0 && db->error != 0) + msg_rate_delay(&cp->get_log_stamp, cp->log_delay, msg_warn, + "%s: cache lookup for '%s' failed due to error", + cp->name, cache_key); if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) msg_info("%s: key=%s value=%s", myname, cache_key, - cache_val ? cache_val : dict_errno ? + cache_val ? cache_val : db->error ? "error" : "(not found)"); - return (cache_val); + DICT_ERR_VAL_RETURN(cp, db->error, cache_val); } } /* dict_cache_update - save entry to cache */ -void dict_cache_update(DICT_CACHE *cp, const char *cache_key, +int dict_cache_update(DICT_CACHE *cp, const char *cache_key, const char *cache_val) { const char *myname = "dict_cache_update"; + DICT *db = cp->db; + int put_res; /* * Store the cache entry and cancel the delete-behind operation. @@ -288,7 +311,11 @@ void dict_cache_update(DICT_CACHE *cp, const char *cache_key, } if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) msg_info("%s: key=%s value=%s", myname, cache_key, cache_val); - dict_put(cp->db, cache_key, cache_val); + put_res = dict_put(db, cache_key, cache_val); + if (put_res != 0) + msg_rate_delay(&cp->upd_log_stamp, cp->log_delay, msg_warn, + "%s: could not update entry for %s", cp->name, cache_key); + DICT_ERR_VAL_RETURN(cp, db->error, put_res); } /* dict_cache_delete - delete entry from cache */ @@ -296,7 +323,8 @@ void dict_cache_update(DICT_CACHE *cp, const char *cache_key, int dict_cache_delete(DICT_CACHE *cp, const char *cache_key) { const char *myname = "dict_cache_delete"; - int zero_means_found; + int del_res; + DICT *db = cp->db; /* * Delete the entry, unless we would delete the current first/next entry. @@ -308,18 +336,18 @@ int dict_cache_delete(DICT_CACHE *cp, const char *cache_key) if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) msg_info("%s: key=%s (current entry - schedule for delete-behind)", myname, cache_key); - zero_means_found = 0; + DICT_ERR_VAL_RETURN(cp, DICT_ERR_NONE, DICT_STAT_SUCCESS); } else { - zero_means_found = dict_del(cp->db, cache_key); -#if 0 - if (zero_means_found != 0) - msg_warn("%s: could not delete entry for %s", cp->name, cache_key); -#endif + del_res = dict_del(db, cache_key); + if (del_res != 0) + msg_rate_delay(&cp->del_log_stamp, cp->log_delay, msg_warn, + "%s: could not delete entry for %s", cp->name, cache_key); if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) msg_info("%s: key=%s (%s)", myname, cache_key, - zero_means_found == 0 ? "found" : "not found"); + del_res == 0 ? "found" : + db->error ? "error" : "not found"); + DICT_ERR_VAL_RETURN(cp, db->error, del_res); } - return (zero_means_found); } /* dict_cache_sequence - look up the first/next cache entry */ @@ -329,26 +357,31 @@ int dict_cache_sequence(DICT_CACHE *cp, int first_next, const char **cache_val) { const char *myname = "dict_cache_sequence"; - int zero_means_found; + int seq_res; const char *raw_cache_key; const char *raw_cache_val; char *previous_curr_key; char *previous_curr_val; + DICT *db = cp->db; /* * Find the first or next database entry. Hide the record with the cache * cleanup completion time stamp. */ - zero_means_found = - dict_seq(cp->db, first_next, &raw_cache_key, &raw_cache_val); - if (zero_means_found == 0 + seq_res = dict_seq(db, first_next, &raw_cache_key, &raw_cache_val); + if (seq_res == 0 && strcmp(raw_cache_key, DC_LAST_CACHE_CLEANUP_COMPLETED) == 0) - zero_means_found = - dict_seq(cp->db, DICT_SEQ_FUN_NEXT, &raw_cache_key, &raw_cache_val); + seq_res = + dict_seq(db, DICT_SEQ_FUN_NEXT, &raw_cache_key, &raw_cache_val); if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) msg_info("%s: key=%s value=%s", myname, - zero_means_found == 0 ? raw_cache_key : "(not found)", - zero_means_found == 0 ? raw_cache_val : "(not found)"); + seq_res == 0 ? raw_cache_key : db->error ? + "(error)" : "(not found)", + seq_res == 0 ? raw_cache_val : db->error ? + "(error)" : "(not found)"); + if (db->error) + msg_rate_delay(&cp->seq_log_stamp, cp->log_delay, msg_warn, + "%s: sequence error", cp->name); /* * Save the current cache_key and cache_val before they are clobbered by @@ -360,7 +393,7 @@ int dict_cache_sequence(DICT_CACHE *cp, int first_next, */ previous_curr_key = cp->saved_curr_key; previous_curr_val = cp->saved_curr_val; - if (zero_means_found == 0) { + if (seq_res == 0) { cp->saved_curr_key = mystrdup(raw_cache_key); cp->saved_curr_val = mystrdup(raw_cache_val); } else { @@ -371,14 +404,15 @@ int dict_cache_sequence(DICT_CACHE *cp, int first_next, /* * Delete behind. */ - if (DC_IS_SCHEDULED_FOR_DELETE_BEHIND(cp)) { + if (db->error == 0 && DC_IS_SCHEDULED_FOR_DELETE_BEHIND(cp)) { DC_CANCEL_DELETE_BEHIND(cp); if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) msg_info("%s: delete-behind key=%s value=%s", myname, previous_curr_key, previous_curr_val); - if (dict_del(cp->db, previous_curr_key) != 0) - msg_warn("%s: could not delete entry for %s", - cp->name, previous_curr_key); + if (dict_del(db, previous_curr_key) != 0) + msg_rate_delay(&cp->del_log_stamp, cp->log_delay, msg_warn, + "%s: could not delete entry for %s", + cp->name, previous_curr_key); } /* @@ -394,7 +428,7 @@ int dict_cache_sequence(DICT_CACHE *cp, int first_next, */ *cache_key = (cp)->saved_curr_key; *cache_val = (cp)->saved_curr_val; - return (zero_means_found); + DICT_ERR_VAL_RETURN(cp, db->error, seq_res); } /* dict_cache_delete_behind_reset - reset "delete behind" state */ @@ -476,14 +510,11 @@ static void dict_cache_clean_event(int unused_event, char *cache_context) /* * Cache cleanup completed. Report vital statistics. */ -#if 0 - else if (dict_errno != 0) { - msg_warn("%s: cache cleanup scan failed due to error", cp->name); + else if (cp->error != 0) { + msg_warn("%s: cache cleanup scan terminated due to error", cp->name); dict_cache_clean_stat_log_reset(cp, "partial"); next_interval = cp->exp_interval; - } -#endif - else { + } else { if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) msg_info("%s: done %s cache cleanup scan", myname, cp->name); dict_cache_clean_stat_log_reset(cp, "full"); @@ -518,6 +549,8 @@ void dict_cache_control(DICT_CACHE *cp,...) break; case DICT_CACHE_CTL_FLAGS: cp->user_flags = va_arg(ap, int); + cp->log_delay = (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) ? + 0 : DC_DEF_LOG_DELAY; break; case DICT_CACHE_CTL_INTERVAL: cp->exp_interval = va_arg(ap, int); @@ -606,6 +639,9 @@ DICT_CACHE *dict_cache_open(const char *dbname, int open_flags, int dict_flags) cp->exp_context = 0; cp->retained = 0; cp->dropped = 0; + cp->log_delay = DC_DEF_LOG_DELAY; + cp->upd_log_stamp = cp->get_log_stamp = + cp->del_log_stamp = cp->seq_log_stamp = 0; return (cp); } diff --git a/postfix/src/util/dict_cache.h b/postfix/src/util/dict_cache.h index 33d606124..20dcab613 100644 --- a/postfix/src/util/dict_cache.h +++ b/postfix/src/util/dict_cache.h @@ -25,7 +25,7 @@ typedef int (*DICT_CACHE_VALIDATOR_FN) (const char *, const char *, char *); extern DICT_CACHE *dict_cache_open(const char *, int, int); extern void dict_cache_close(DICT_CACHE *); extern const char *dict_cache_lookup(DICT_CACHE *, const char *); -extern void dict_cache_update(DICT_CACHE *, const char *, const char *); +extern int dict_cache_update(DICT_CACHE *, const char *, const char *); extern int dict_cache_delete(DICT_CACHE *, const char *); extern int dict_cache_sequence(DICT_CACHE *, int, const char **, const char **); extern void dict_cache_control(DICT_CACHE *,...); diff --git a/postfix/src/util/dict_cdb.c b/postfix/src/util/dict_cdb.c index 36437abc3..099ecc99d 100644 --- a/postfix/src/util/dict_cdb.c +++ b/postfix/src/util/dict_cdb.c @@ -103,7 +103,7 @@ static const char *dict_cdbq_lookup(DICT *dict, const char *name) static unsigned len; const char *result = 0; - dict_errno = 0; + dict->error = 0; /* CDB is constant, so do not try to acquire a lock. */ @@ -229,12 +229,14 @@ static DICT *dict_cdbq_open(const char *path, int dict_flags) /* dict_cdbm_update - add database entry, create mode */ -static void dict_cdbm_update(DICT *dict, const char *name, const char *value) +static int dict_cdbm_update(DICT *dict, const char *name, const char *value) { DICT_CDBM *dict_cdbm = (DICT_CDBM *) dict; unsigned ksize, vsize; int r; + dict->error = 0; + /* * Optionally fold the key. */ @@ -281,9 +283,11 @@ static void dict_cdbm_update(DICT *dict, const char *name, const char *value) msg_fatal("%s: duplicate entry: \"%s\"", dict_cdbm->dict.name, name); } + return (r); #else if (cdb_make_add(&dict_cdbm->cdbm, name, ksize, value, vsize) < 0) msg_fatal("error writing %s: %m", dict_cdbm->tmp_path); + return (0); #endif } diff --git a/postfix/src/util/dict_cidr.c b/postfix/src/util/dict_cidr.c index 82480119d..97f4867db 100644 --- a/postfix/src/util/dict_cidr.c +++ b/postfix/src/util/dict_cidr.c @@ -79,7 +79,7 @@ static const char *dict_cidr_lookup(DICT *dict, const char *key) if (msg_verbose) msg_info("dict_cidr_lookup: %s: %s", dict->name, key); - dict_errno = 0; + dict->error = 0; if ((entry = (DICT_CIDR_ENTRY *) cidr_match_execute(&(dict_cidr->head->cidr_info), key)) != 0) diff --git a/postfix/src/util/dict_db.c b/postfix/src/util/dict_db.c index 7fb00985a..898dab53a 100644 --- a/postfix/src/util/dict_db.c +++ b/postfix/src/util/dict_db.c @@ -181,13 +181,14 @@ static const char *dict_db_lookup(DICT *dict, const char *name) int status; const char *result = 0; + dict->error = 0; + /* * Sanity check. */ if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) msg_panic("dict_db_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag"); - dict_errno = 0; memset(&db_key, 0, sizeof(db_key)); memset(&db_value, 0, sizeof(db_value)); @@ -250,7 +251,7 @@ static const char *dict_db_lookup(DICT *dict, const char *name) /* dict_db_update - add or update database entry */ -static void dict_db_update(DICT *dict, const char *name, const char *value) +static int dict_db_update(DICT *dict, const char *name, const char *value) { DICT_DB *dict_db = (DICT_DB *) dict; DB *db = dict_db->db; @@ -258,6 +259,8 @@ static void dict_db_update(DICT *dict, const char *name, const char *value) DBT db_value; int status; + dict->error = 0; + /* * Sanity check. */ @@ -332,6 +335,8 @@ static void dict_db_update(DICT *dict, const char *name, const char *value) if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) msg_fatal("%s: unlock dictionary: %m", dict_db->dict.name); + + return (status); } /* delete one entry from the dictionary */ @@ -344,6 +349,8 @@ static int dict_db_delete(DICT *dict, const char *name) int status = 1; int flags = 0; + dict->error = 0; + /* * Sanity check. */ @@ -420,12 +427,13 @@ static int dict_db_sequence(DICT *dict, int function, int status = 0; int db_function; + dict->error = 0; + #if DB_VERSION_MAJOR > 1 /* * Initialize. */ - dict_errno = 0; memset(&db_key, 0, sizeof(db_key)); memset(&db_value, 0, sizeof(db_value)); diff --git a/postfix/src/util/dict_dbm.c b/postfix/src/util/dict_dbm.c index 0a0a256a1..bdc4c3888 100644 --- a/postfix/src/util/dict_dbm.c +++ b/postfix/src/util/dict_dbm.c @@ -82,14 +82,14 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name) datum dbm_value; const char *result = 0; + dict->error = 0; + /* * Sanity check. */ if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) msg_panic("dict_dbm_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag"); - dict_errno = 0; - /* * Optionally fold the key. */ @@ -147,13 +147,15 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name) /* dict_dbm_update - add or update database entry */ -static void dict_dbm_update(DICT *dict, const char *name, const char *value) +static int dict_dbm_update(DICT *dict, const char *name, const char *value) { DICT_DBM *dict_dbm = (DICT_DBM *) dict; datum dbm_key; datum dbm_value; int status; + dict->error = 0; + /* * Sanity check. */ @@ -223,6 +225,8 @@ static void dict_dbm_update(DICT *dict, const char *name, const char *value) if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) msg_fatal("%s: unlock dictionary: %m", dict_dbm->dict.name); + + return (status); } /* dict_dbm_delete - delete one entry from the dictionary */ @@ -233,6 +237,8 @@ static int dict_dbm_delete(DICT *dict, const char *name) datum dbm_key; int status = 1; + dict->error = 0; + /* * Sanity check. */ @@ -311,6 +317,8 @@ static int dict_dbm_sequence(DICT *dict, int function, datum dbm_value; int status; + dict->error = 0; + /* * Acquire a shared lock. */ diff --git a/postfix/src/util/dict_debug.c b/postfix/src/util/dict_debug.c index 9b85f1e54..3d9a44325 100644 --- a/postfix/src/util/dict_debug.c +++ b/postfix/src/util/dict_debug.c @@ -56,23 +56,28 @@ typedef struct { static const char *dict_debug_lookup(DICT *dict, const char *key) { DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict; + DICT *real_dict = dict_debug->real_dict; const char *result; - result = dict_get(dict_debug->real_dict, key); + result = dict_get(real_dict, key); msg_info("%s:%s lookup: \"%s\" = \"%s\"", dict->type, dict->name, key, - result ? result : dict_errno ? "try again" : "not_found"); - return (result); + result ? result : real_dict->error ? "error" : "not_found"); + DICT_ERR_VAL_RETURN(dict, real_dict->error, result); } /* dict_debug_update - log update operation */ -static void dict_debug_update(DICT *dict, const char *key, const char *value) +static int dict_debug_update(DICT *dict, const char *key, const char *value) { DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict; + DICT *real_dict = dict_debug->real_dict; + int result; - msg_info("%s:%s update: \"%s\" = \"%s\"", dict->type, dict->name, - key, value); - dict_put(dict_debug->real_dict, key, value); + result = dict_put(real_dict, key, value); + msg_info("%s:%s update: \"%s\" = \"%s\": %s", dict->type, dict->name, + key, value, result == 0 ? "success" : real_dict->error ? + "error" : "failed"); + DICT_ERR_VAL_RETURN(dict, real_dict->error, result); } /* dict_debug_delete - log delete operation */ @@ -80,12 +85,14 @@ static void dict_debug_update(DICT *dict, const char *key, const char *value) static int dict_debug_delete(DICT *dict, const char *key) { DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict; + DICT *real_dict = dict_debug->real_dict; int result; - result = dict_del(dict_debug->real_dict, key); - msg_info("%s:%s delete: \"%s\" = \"%s\"", dict->type, dict->name, key, - result ? "failed" : "success"); - return (result); + result = dict_del(real_dict, key); + msg_info("%s:%s delete: \"%s\": %s", dict->type, dict->name, key, + result == 0 ? "success" : real_dict->error ? + "error" : "failed"); + DICT_ERR_VAL_RETURN(dict, real_dict->error, result); } /* dict_debug_sequence - log sequence operation */ @@ -94,15 +101,16 @@ static int dict_debug_sequence(DICT *dict, int function, const char **key, const char **value) { DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict; + DICT *real_dict = dict_debug->real_dict; int result; - result = dict_seq(dict_debug->real_dict, function, key, value); + result = dict_seq(real_dict, function, key, value); if (result == 0) msg_info("%s:%s sequence: \"%s\" = \"%s\"", dict->type, dict->name, *key, *value); else msg_info("%s:%s sequence: found EOF", dict->type, dict->name); - return (result); + DICT_ERR_VAL_RETURN(dict, real_dict->error, result); } /* dict_debug_close - log operation */ diff --git a/postfix/src/util/dict_env.c b/postfix/src/util/dict_env.c index bc15d6c92..1635b8d82 100644 --- a/postfix/src/util/dict_env.c +++ b/postfix/src/util/dict_env.c @@ -48,8 +48,9 @@ /* dict_env_update - update environment array */ -static void dict_env_update(DICT *dict, const char *name, const char *value) +static int dict_env_update(DICT *dict, const char *name, const char *value) { + dict->error = 0; /* * Optionally fold the key. @@ -62,13 +63,15 @@ static void dict_env_update(DICT *dict, const char *name, const char *value) } if (setenv(name, value, 1)) msg_fatal("setenv: %m"); + + return (DICT_STAT_SUCCESS); } /* dict_env_lookup - access environment array */ static const char *dict_env_lookup(DICT *dict, const char *name) { - dict_errno = 0; + dict->error = 0; /* * Optionally fold the key. diff --git a/postfix/src/util/dict_fail.c b/postfix/src/util/dict_fail.c index b0ad3f2c5..c4f8f54d5 100644 --- a/postfix/src/util/dict_fail.c +++ b/postfix/src/util/dict_fail.c @@ -12,7 +12,7 @@ /* int dict_flags; /* DESCRIPTION /* dict_fail_open() implements a dummy dictionary that fails -/* all operations. The name specifies the dict_errno value. +/* all operations. The name can be used for logging. /* SEE ALSO /* dict(3) generic dictionary manager /* LICENSE @@ -29,7 +29,6 @@ /* System library. */ #include -#include /* Utility library. */ @@ -48,22 +47,21 @@ typedef struct { /* dict_fail_sequence - fail lookup */ static int dict_fail_sequence(DICT *dict, int unused_func, - const char **key, const char **value) + const char **key, const char **value) { DICT_FAIL *dp = (DICT_FAIL *) dict; - dict_errno = dp->dict_errno; - return (1); + DICT_ERR_VAL_RETURN(dict, dp->dict_errno, DICT_STAT_ERROR); } /* dict_fail_update - fail lookup */ -static void dict_fail_update(DICT *dict, const char *unused_name, - const char *unused_value) +static int 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_ERR_VAL_RETURN(dict, dp->dict_errno, DICT_STAT_ERROR); } /* dict_fail_lookup - fail lookup */ @@ -72,8 +70,7 @@ 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_ERR_VAL_RETURN(dict, dp->dict_errno, (char *) 0); } /* dict_fail_delete - fail delete */ @@ -82,8 +79,7 @@ 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_ERR_VAL_RETURN(dict, dp->dict_errno, DICT_STAT_ERROR); } /* dict_fail_close - close fail dictionary */ @@ -108,9 +104,7 @@ DICT *dict_fail_open(const char *name, int open_flags, int dict_flags) 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); - if (dp->dict_errno == 0) - dp->dict_errno = 1; + dp->dict_errno = DICT_ERR_RETRY; dp->dict.owner.status = DICT_OWNER_TRUSTED; return (DICT_DEBUG (&dp->dict)); } diff --git a/postfix/src/util/dict_ht.c b/postfix/src/util/dict_ht.c index 0eff0810a..aaa4f90fe 100644 --- a/postfix/src/util/dict_ht.c +++ b/postfix/src/util/dict_ht.c @@ -54,8 +54,6 @@ static const char *dict_ht_lookup(DICT *dict, const char *name) { DICT_HT *dict_ht = (DICT_HT *) dict; - dict_errno = 0; - /* * Optionally fold the key. */ @@ -65,12 +63,12 @@ static const char *dict_ht_lookup(DICT *dict, const char *name) vstring_strcpy(dict->fold_buf, name); name = lowercase(vstring_str(dict->fold_buf)); } - return (htable_find(dict_ht->table, name)); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, htable_find(dict_ht->table, name)); } /* dict_ht_update - add or update hash-table entry */ -static void dict_ht_update(DICT *dict, const char *name, const char *value) +static int dict_ht_update(DICT *dict, const char *name, const char *value) { DICT_HT *dict_ht = (DICT_HT *) dict; HTABLE_INFO *ht; @@ -91,6 +89,7 @@ static void dict_ht_update(DICT *dict, const char *name, const char *value) ht = htable_enter(dict_ht->table, name, (char *) 0); } ht->value = saved_value; + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS); } /* dict_ht_sequence - first/next iterator */ @@ -108,11 +107,11 @@ static int dict_ht_sequence(DICT *dict, int how, const char **name, if (ht != 0) { *name = ht->key; *value = ht->value; - return (0); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS); } else { *name = 0; *value = 0; - return (1); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL); } } diff --git a/postfix/src/util/dict_ni.c b/postfix/src/util/dict_ni.c index 569188c0c..4210c0b64 100644 --- a/postfix/src/util/dict_ni.c +++ b/postfix/src/util/dict_ni.c @@ -80,8 +80,6 @@ static const char *dict_ni_do_lookup(char *path, char *key_prop, ni_status r; ni_id dir; - dict_errno = 0; - if (msg_verbose) msg_info("ni_lookup %s %s=%s", path, key_prop, key_value); @@ -150,6 +148,8 @@ static const char *dict_ni_lookup(DICT *dict, const char *key) { DICT_NI *d = (DICT_NI *) dict; + dict->error = 0; + /* * Optionally fold the key. */ diff --git a/postfix/src/util/dict_nis.c b/postfix/src/util/dict_nis.c index 27a20a54e..a06e5f359 100644 --- a/postfix/src/util/dict_nis.c +++ b/postfix/src/util/dict_nis.c @@ -144,13 +144,14 @@ static const char *dict_nis_lookup(DICT *dict, const char *key) int err; static VSTRING *buf; + dict->error = 0; + /* * Sanity check. */ if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) msg_panic("dict_nis_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag"); - dict_errno = 0; if (dict_nis_domain == dict_nis_disabled) return (0); @@ -204,7 +205,7 @@ static const char *dict_nis_lookup(DICT *dict, const char *key) msg_warn("lookup %s, NIS domain %s, map %s: %s", key, dict_nis_domain, dict_nis->dict.name, dict_nis_strerror(err)); - dict_errno = DICT_ERR_RETRY; + dict->error = DICT_ERR_RETRY; } return (0); } diff --git a/postfix/src/util/dict_nisplus.c b/postfix/src/util/dict_nisplus.c index c10fa45b9..819bf0750 100644 --- a/postfix/src/util/dict_nisplus.c +++ b/postfix/src/util/dict_nisplus.c @@ -126,10 +126,11 @@ static const char *dict_nisplus_lookup(DICT *dict, const char *key) int last_col; int ch; + dict->error = 0; + /* * Initialize. */ - dict_errno = 0; if (quoted_key == 0) { query = vstring_alloc(100); retval = vstring_alloc(100); @@ -222,7 +223,7 @@ static const char *dict_nisplus_lookup(DICT *dict, const char *key) msg_warn("lookup %s, NIS+ map %s: %s", key, dict_nisplus->dict.name, nis_sperrno(reply->status)); - dict_errno = DICT_ERR_RETRY; + dict->error = DICT_ERR_RETRY; } else { if (msg_verbose) msg_info("%s: not found: query %s", myname, STR(query)); diff --git a/postfix/src/util/dict_open.c b/postfix/src/util/dict_open.c index 76d946be4..49e2b2c3c 100644 --- a/postfix/src/util/dict_open.c +++ b/postfix/src/util/dict_open.c @@ -17,7 +17,7 @@ /* int open_flags; /* int dict_flags; /* -/* void dict_put(dict, key, value) +/* int dict_put(dict, key, value) /* DICT *dict; /* const char *key; /* const char *value; @@ -30,7 +30,7 @@ /* DICT *dict; /* const char *key; /* -/* void dict_seq(dict, func, key, value) +/* int dict_seq(dict, func, key, value) /* DICT *dict; /* int func; /* const char **key; @@ -99,7 +99,7 @@ /* With file-based maps, flush I/O buffers to file after each update. /* Thus feature is not supported with some file-based dictionaries. /* .IP DICT_FLAG_NO_REGSUB -/* Disallow regular expression substitution from left-hand side data +/* Disallow regular expression substitution from left-hand side data /* into the right-hand side. /* .IP DICT_FLAG_NO_PROXY /* Disallow access through the \fBproxymap\fR service. @@ -148,15 +148,16 @@ /* or if the result is to survive multiple table lookups. /* /* dict_put() stores the specified key and value into the named -/* dictionary. +/* dictionary. A zero (DICT_STAT_SUCCESS) result means the +/* update was made. /* -/* dict_del() removes a dictionary entry, and returns zero -/* in case of success. +/* dict_del() removes a dictionary entry, and returns +/* DICT_STAT_SUCCESS in case of success. /* /* dict_seq() iterates over all members in the named dictionary. /* func is define DICT_SEQ_FUN_FIRST (select first member) or -/* DICT_SEQ_FUN_NEXT (select next member). A zero result means -/* that an entry was found. +/* DICT_SEQ_FUN_NEXT (select next member). A zero (DICT_STAT_SUCCESS) +/* result means that an entry was found. /* /* dict_close() closes the specified dictionary and cleans up the /* associated data structures. @@ -168,6 +169,29 @@ /* DIAGNOSTICS /* Fatal error: open error, unsupported dictionary type, attempt to /* update non-writable dictionary. +/* +/* The lookup routine returns non-null when the request is +/* satisfied. The update, delete and sequence routines return +/* zero (DICT_STAT_SUCCESS) when the request is satisfied. +/* The dict->errno value is non-zero only when the last operation +/* was not satisfied due to a dictionary access error. This +/* can have the following values: +/* .IP DICT_ERR_NONE(zero) +/* There was no dictionary access error. For example, the +/* request was satisfied, the requested information did not +/* exist in the dictionary, or the information already existed +/* when it should not exist (collision). +/* .IP DICT_ERR_RETRY(<0) +/* The dictionary was temporarily unavailable. This can happen +/* with network-based services. +/* .IP DICT_ERR_CONFIG(<0) +/* The dictionary was unavailable due to a configuration error. +/* .PP +/* Generally, a program is expected to test the function result +/* value for "success" first. If the operation was not successful, +/* a program is expected to test for a non-zero dict->error +/* status to distinguish between a data notfound/collision +/* condition or a dictionary access error. /* LICENSE /* .ad /* .fi diff --git a/postfix/src/util/dict_pcre.c b/postfix/src/util/dict_pcre.c index f7a692153..067416442 100644 --- a/postfix/src/util/dict_pcre.c +++ b/postfix/src/util/dict_pcre.c @@ -257,7 +257,7 @@ static const char *dict_pcre_lookup(DICT *dict, const char *lookup_string) DICT_PCRE_EXPAND_CONTEXT ctxt; int nesting = 0; - dict_errno = 0; + dict->error = 0; if (msg_verbose) msg_info("dict_pcre_lookup: %s: %s", dict->name, lookup_string); diff --git a/postfix/src/util/dict_regexp.c b/postfix/src/util/dict_regexp.c index c88d2bd55..b7b08c62f 100644 --- a/postfix/src/util/dict_regexp.c +++ b/postfix/src/util/dict_regexp.c @@ -217,7 +217,7 @@ static const char *dict_regexp_lookup(DICT *dict, const char *lookup_string) int error; int nesting = 0; - dict_errno = 0; + dict->error = 0; if (msg_verbose) msg_info("dict_regexp_lookup: %s: %s", dict->name, lookup_string); diff --git a/postfix/src/util/dict_sdbm.c b/postfix/src/util/dict_sdbm.c index c6a374914..3a30d9c65 100644 --- a/postfix/src/util/dict_sdbm.c +++ b/postfix/src/util/dict_sdbm.c @@ -76,14 +76,14 @@ static const char *dict_sdbm_lookup(DICT *dict, const char *name) datum dbm_value; const char *result = 0; + dict->error = 0; + /* * Sanity check. */ if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) msg_panic("dict_sdbm_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag"); - dict_errno = 0; - /* * Optionally fold the key. */ @@ -141,13 +141,15 @@ static const char *dict_sdbm_lookup(DICT *dict, const char *name) /* dict_sdbm_update - add or update database entry */ -static void dict_sdbm_update(DICT *dict, const char *name, const char *value) +static int dict_sdbm_update(DICT *dict, const char *name, const char *value) { DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict; datum dbm_key; datum dbm_value; int status; + dict->error = 0; + /* * Sanity check. */ @@ -217,6 +219,8 @@ static void dict_sdbm_update(DICT *dict, const char *name, const char *value) if ((dict->flags & DICT_FLAG_LOCK) && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) msg_fatal("%s: unlock dictionary: %m", dict_sdbm->dict.name); + + return (status); } /* dict_sdbm_delete - delete one entry from the dictionary */ @@ -227,6 +231,8 @@ static int dict_sdbm_delete(DICT *dict, const char *name) datum dbm_key; int status = 1; + dict->error = 0; + /* * Sanity check. */ @@ -303,6 +309,9 @@ static int dict_sdbm_sequence(DICT *dict, const int function, DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict; datum dbm_key; datum dbm_value; + int status; + + dict->error = 0; /* * Acquire a shared lock. @@ -344,6 +353,7 @@ static int dict_sdbm_sequence(DICT *dict, const int function, * Copy the value so that it is guaranteed null terminated. */ *value = SCOPY(dict_sdbm->val_buf, dbm_value.dptr, dbm_value.dsize); + status = 0; } else { /* @@ -352,7 +362,7 @@ static int dict_sdbm_sequence(DICT *dict, const int function, */ if (sdbm_error(dict_sdbm->dbm)) msg_fatal("error seeking %s: %m", dict_sdbm->dict.name); - return (1); /* no error: eof/not found + status = 1; /* no error: eof/not found * (should not happen!) */ } } else { @@ -362,7 +372,7 @@ static int dict_sdbm_sequence(DICT *dict, const int function, */ if (sdbm_error(dict_sdbm->dbm)) msg_fatal("error seeking %s: %m", dict_sdbm->dict.name); - return (1); /* no error: eof/not found */ + status = 1; /* no error: eof/not found */ } /* @@ -372,7 +382,7 @@ static int dict_sdbm_sequence(DICT *dict, const int function, && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) msg_fatal("%s: unlock dictionary: %m", dict_sdbm->dict.name); - return (0); + return (status); } /* dict_sdbm_close - disassociate from data base */ diff --git a/postfix/src/util/dict_static.c b/postfix/src/util/dict_static.c index 723a24dcf..f20dc6ccf 100644 --- a/postfix/src/util/dict_static.c +++ b/postfix/src/util/dict_static.c @@ -44,9 +44,7 @@ static const char *dict_static_lookup(DICT *dict, const char *unused_name) { - dict_errno = 0; - - return (dict->name); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, dict->name); } /* dict_static_close - close static dictionary */ diff --git a/postfix/src/util/dict_tcp.c b/postfix/src/util/dict_tcp.c index 94f93e23d..1f85b5f10 100644 --- a/postfix/src/util/dict_tcp.c +++ b/postfix/src/util/dict_tcp.c @@ -159,7 +159,7 @@ static const char *dict_tcp_lookup(DICT *dict, const char *key) char *start; int last_ch; -#define RETURN(errval, result) { dict_errno = errval; return (result); } +#define RETURN(errval, result) { dict->error = errval; return (result); } if (msg_verbose) msg_info("%s: key %s", myname, key); @@ -286,8 +286,6 @@ DICT *dict_tcp_open(const char *map, int open_flags, int dict_flags) { DICT_TCP *dict_tcp; - dict_errno = 0; - /* * Sanity checks. */ diff --git a/postfix/src/util/dict_test.c b/postfix/src/util/dict_test.c index b2f57dfa9..68165e2fb 100644 --- a/postfix/src/util/dict_test.c +++ b/postfix/src/util/dict_test.c @@ -107,30 +107,28 @@ void dict_test(int argc, char **argv) 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 ? + vstream_printf("%s: %s\n", key, dict->error ? "error" : "not found"); } else { vstream_printf("%s=%s\n", key, value); } } else if (strcmp(cmd, "put") == 0 && key && value) { - /* XXX dict_put returns void, so dict_memcache sets dict_errno. */ - dict_errno = 0; - dict_put(dict, key, value); - if (dict_errno) - vstream_printf("%s: error\n", key); + if (dict_put(dict, key, value) != 0) + vstream_printf("%s: %s\n", key, dict->error ? + "error" : "not updated"); 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 ? + vstream_printf("%s\n", dict->error ? "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 ? + vstream_printf("%s\n", dict->error ? "error" : "not found"); } else if (strcmp(cmd, "flags") == 0 && !key && !value) { vstream_printf("dict flags %s\n", diff --git a/postfix/src/util/dict_thash.c b/postfix/src/util/dict_thash.c index 9099a2878..a03dc3f4b 100644 --- a/postfix/src/util/dict_thash.c +++ b/postfix/src/util/dict_thash.c @@ -57,7 +57,7 @@ typedef struct { HTABLE *table; /* in-memory hash */ HTABLE_INFO **info; /* for iterator */ HTABLE_INFO **cursor; /* ditto */ -} DICT_THASH; +} DICT_THASH; #define STR vstring_str @@ -68,8 +68,6 @@ static const char *dict_thash_lookup(DICT *dict, const char *name) DICT_THASH *dict_thash = (DICT_THASH *) dict; const char *result = 0; - dict_errno = 0; - /* * Optionally fold the key. */ @@ -85,7 +83,7 @@ static const char *dict_thash_lookup(DICT *dict, const char *name) */ result = htable_find(dict_thash->table, name); - return (result); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, result); } /* dict_thash_sequence - traverse the dictionary */ @@ -96,8 +94,6 @@ static int dict_thash_sequence(DICT *dict, int function, const char *myname = "dict_thash_sequence"; DICT_THASH *dict_thash = (DICT_THASH *) dict; - dict_errno = 0; - /* * Determine and execute the seek function. */ @@ -121,9 +117,11 @@ static int dict_thash_sequence(DICT *dict, int function, if (dict_thash->cursor[0]) { *key = dict_thash->cursor[0]->key; *value = dict_thash->cursor[0]->value; - return (0); + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS); } else { - return (1); + *key = 0; + *value = 0; + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL); } } diff --git a/postfix/src/util/dict_unix.c b/postfix/src/util/dict_unix.c index 66baba8eb..cd103cb40 100644 --- a/postfix/src/util/dict_unix.c +++ b/postfix/src/util/dict_unix.c @@ -69,7 +69,7 @@ static const char *dict_unix_getpwnam(DICT *dict, const char *key) static VSTRING *buf; static int sanity_checked; - dict_errno = 0; + dict->error = 0; /* * Optionally fold the key. @@ -86,7 +86,7 @@ static const char *dict_unix_getpwnam(DICT *dict, const char *key) errno = 0; if (getpwuid(0) == 0) { msg_warn("cannot access UNIX password database: %m"); - dict_errno = DICT_ERR_RETRY; + dict->error = DICT_ERR_RETRY; } } return (0); @@ -111,7 +111,7 @@ static const char *dict_unix_getgrnam(DICT *dict, const char *key) char **cpp; static int sanity_checked; - dict_errno = 0; + dict->error = 0; /* * Optionally fold the key. @@ -128,7 +128,7 @@ static const char *dict_unix_getgrnam(DICT *dict, const char *key) errno = 0; if (getgrgid(0) == 0) { msg_warn("cannot access UNIX group database: %m"); - dict_errno = DICT_ERR_RETRY; + dict->error = DICT_ERR_RETRY; } } return (0); @@ -173,8 +173,6 @@ DICT *dict_unix_open(const char *map, int unused_flags, int dict_flags) }; struct dict_unix_lookup *lp; - dict_errno = 0; - dict_unix = (DICT_UNIX *) dict_alloc(DICT_TYPE_UNIX, map, sizeof(*dict_unix)); for (lp = dict_unix_lookup; /* void */ ; lp++) { diff --git a/postfix/src/util/match_list.c b/postfix/src/util/match_list.c index ebc13886f..c15f995aa 100644 --- a/postfix/src/util/match_list.c +++ b/postfix/src/util/match_list.c @@ -36,8 +36,9 @@ /* 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 match_list_match() returns zero (with dict_errno -/* set) instead of raising a fatal run-time error. +/* Request that match_list_match() logs a warning and returns +/* zero (with list->error set to a non-zero dictionary error +/* code) 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 @@ -51,7 +52,7 @@ /* match_list_free() releases storage allocated by match_list_init(). /* DIAGNOSTICS /* Fatal error: unable to open or read a match_list file; invalid -/* match_list pattern. +/* match_list pattern. /* SEE ALSO /* host_match(3) match hosts by name or by address /* LICENSE @@ -84,19 +85,10 @@ #include #include #include -#include #include /* Application-specific */ -struct MATCH_LIST { - int flags; /* processing options */ - ARGV *patterns; /* one pattern each */ - int match_count; /* match function/argument count */ - MATCH_LIST_FN *match_func; /* match functions */ - const char **match_args; /* match arguments */ -}; - #define MATCH_DICTIONARY(pattern) \ ((pattern)[0] != '[' && strchr((pattern), ':') != 0) @@ -209,14 +201,14 @@ int match_list_match(MATCH_LIST *list,...) list->match_args[i] = va_arg(ap, const char *); va_end(ap); - dict_errno = 0; + list->error = 0; for (cpp = list->patterns->argv; (pat = *cpp) != 0; cpp++) { 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 (list->match_func[i] (list, list->match_args[i], pat)) return (match); - else if (dict_errno != 0) + else if (list->error != 0) return (0); } if (msg_verbose) diff --git a/postfix/src/util/match_list.h b/postfix/src/util/match_list.h index cbbc71a36..d51b6e831 100644 --- a/postfix/src/util/match_list.h +++ b/postfix/src/util/match_list.h @@ -14,18 +14,41 @@ /* * Utility library. */ -#include +#include /* * External interface. */ typedef struct MATCH_LIST MATCH_LIST; -typedef int (*MATCH_LIST_FN) (int, const char *, const char *); + +typedef int (*MATCH_LIST_FN) (MATCH_LIST *, const char *, const char *); + +struct MATCH_LIST { + int flags; /* processing options */ + ARGV *patterns; /* one pattern each */ + int match_count; /* match function/argument count */ + MATCH_LIST_FN *match_func; /* match functions */ + const char **match_args; /* match arguments */ + int error; /* last operation */ +}; + +#define MATCH_FLAG_NONE 0 +#define MATCH_FLAG_PARENT (1<<0) +#define MATCH_FLAG_RETURN (1<<1) +#define MATCH_FLAG_ALL (MATCH_FLAG_PARENT | MATCH_FLAG_RETURN) extern MATCH_LIST *match_list_init(int, const char *, int,...); extern int match_list_match(MATCH_LIST *,...); extern void match_list_free(MATCH_LIST *); + /* + * The following functions are not part of the public interface. These + * functions may be called only through match_list_match(). + */ +extern int match_string(MATCH_LIST *, const char *, const char *); +extern int match_hostname(MATCH_LIST *, const char *, const char *); +extern int match_hostaddr(MATCH_LIST *, const char *, const char *); + /* LICENSE /* .ad /* .fi @@ -38,3 +61,4 @@ extern void match_list_free(MATCH_LIST *); /*--*/ #endif + diff --git a/postfix/src/util/match_ops.c b/postfix/src/util/match_ops.c index 62aa77ab5..d138d0579 100644 --- a/postfix/src/util/match_ops.c +++ b/postfix/src/util/match_ops.c @@ -4,20 +4,20 @@ /* SUMMARY /* simple string or host pattern matching /* SYNOPSIS -/* #include +/* #include /* -/* int match_string(flags, string, pattern) -/* int flags; +/* int match_string(list, string, pattern) +/* MATCH_LIST *list; /* const char *string; /* const char *pattern; /* -/* int match_hostname(flags, name, pattern) -/* int flags; +/* int match_hostname(list, name, pattern) +/* MATCH_LIST *list; /* const char *name; /* const char *pattern; /* -/* int match_hostaddr(flags, addr, pattern) -/* int flags; +/* int match_hostaddr(list, addr, pattern) +/* MATCH_LIST *list; /* const char *addr; /* const char *pattern; /* DESCRIPTION @@ -38,8 +38,9 @@ /* 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 "not found" and set dict_errno, instead of raising -/* a fatal run-time error. +/* Log a warning, return "not found", and set list->error to +/* a non-zero dictionary error code, instead of raising a fatal +/* run-time error. /* .RE /* Specify MATCH_FLAG_NONE to request none of the above. /* @@ -77,7 +78,7 @@ #include #include #include -#include +#include #include #include @@ -86,7 +87,7 @@ /* match_error - return or raise fatal error */ -static int match_error(int flags, const char *fmt,...) +static int match_error(MATCH_LIST *list, const char *fmt,...) { VSTRING *buf = vstring_alloc(100); va_list ap; @@ -97,7 +98,7 @@ static int match_error(int flags, const char *fmt,...) va_start(ap, fmt); vstring_vsprintf(buf, fmt, ap); va_end(ap); - if (flags & MATCH_FLAG_RETURN) { + if (list->flags & MATCH_FLAG_RETURN) { msg_warn("%s", vstring_str(buf)); } else { msg_fatal("%s", vstring_str(buf)); @@ -108,7 +109,7 @@ static int match_error(int flags, const char *fmt,...) /* match_string - match a string literal */ -int match_string(int flags, const char *string, const char *pattern) +int match_string(MATCH_LIST *list, const char *string, const char *pattern) { const char *myname = "match_string"; DICT *dict; @@ -124,8 +125,8 @@ int match_string(int flags, const char *string, const char *pattern) msg_panic("%s: unknown dictionary: %s", myname, pattern); if (dict_get(dict, string) != 0) return (1); - if (dict_errno != 0) - return (match_error(flags, "%s:%s: table lookup problem", + if ((list->error = dict->error) != 0) + return (match_error(list, "%s:%s: table lookup problem", dict->type, dict->name)); return (0); } @@ -145,7 +146,7 @@ int match_string(int flags, const char *string, const char *pattern) /* match_hostname - match a host by name */ -int match_hostname(int flags, const char *name, const char *pattern) +int match_hostname(MATCH_LIST *list, const char *name, const char *pattern) { const char *myname = "match_hostname"; const char *pd; @@ -175,13 +176,13 @@ int match_hostname(int flags, const char *name, const char *pattern) match ? "found" : "notfound"); if (match != 0) break; - if (dict_errno != 0) - return (match_error(flags, "%s:%s: table lookup problem", + if ((list->error = dict->error) != 0) + return (match_error(list, "%s:%s: table lookup problem", dict->type, dict->name)); } if ((next = strchr(entry + 1, '.')) == 0) break; - if (flags & MATCH_FLAG_PARENT) + if (list->flags & MATCH_FLAG_PARENT) next += 1; } return (match); @@ -198,7 +199,7 @@ int match_hostname(int flags, const char *name, const char *pattern) * See if the pattern is a parent domain of the hostname. */ else { - if (flags & MATCH_FLAG_PARENT) { + if (list->flags & MATCH_FLAG_PARENT) { pd = name + strlen(name) - strlen(pattern); if (pd > name && pd[-1] == '.' && strcasecmp(pd, pattern) == 0) return (1); @@ -213,7 +214,7 @@ int match_hostname(int flags, const char *name, const char *pattern) /* match_hostaddr - match host by address */ -int match_hostaddr(int flags, const char *addr, const char *pattern) +int match_hostaddr(MATCH_LIST *list, const char *addr, const char *pattern) { const char *myname = "match_hostaddr"; char *saved_patt; @@ -239,8 +240,8 @@ int match_hostaddr(int flags, const char *addr, const char *pattern) msg_panic("%s: unknown dictionary: %s", myname, pattern); if (dict_get(dict, addr) != 0) return (1); - if (dict_errno != 0) - return (match_error(flags, "%s:%s: table lookup problem", + if ((list->error = dict->error) != 0) + return (match_error(list, "%s:%s: table lookup problem", dict->type, dict->name)); return (0); } @@ -296,8 +297,8 @@ int match_hostaddr(int flags, const char *addr, const char *pattern) err = cidr_match_parse(&match_info, saved_patt, (VSTRING *) 0); myfree(saved_patt); if (err != 0) { - dict_errno = DICT_ERR_CONFIG; - rc = match_error(flags, "%s", vstring_str(err)); + list->error = DICT_ERR_CONFIG; + rc = match_error(list, "%s", vstring_str(err)); vstring_free(err); return (rc); } diff --git a/postfix/src/util/match_ops.h b/postfix/src/util/match_ops.h deleted file mode 100644 index 055c4f7dd..000000000 --- a/postfix/src/util/match_ops.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _MATCH_OPS_H_INCLUDED_ -#define _MATCH_OPS_H_INCLUDED_ - -/*++ -/* NAME -/* match_ops 3h -/* SUMMARY -/* simple string or host pattern matching -/* SYNOPSIS -/* #include -/* DESCRIPTION -/* .nf - - /* - * Utility library. - */ -#include - - /* - * External interface. - */ -#define MATCH_FLAG_NONE 0 -#define MATCH_FLAG_PARENT (1<<0) -#define MATCH_FLAG_RETURN (1<<1) -#define MATCH_FLAG_ALL (MATCH_FLAG_PARENT | MATCH_FLAG_RETURN) - -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 *); - -/* 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 -/*--*/ - -#endif diff --git a/postfix/src/util/msg.h b/postfix/src/util/msg.h index 42198a2a7..4b1c6d0bf 100644 --- a/postfix/src/util/msg.h +++ b/postfix/src/util/msg.h @@ -11,6 +11,11 @@ /* DESCRIPTION /* .nf +/* + * System library. + */ +#include + /* * External interface. */ @@ -29,6 +34,10 @@ extern int msg_error_limit(int); extern void msg_error_clear(void); extern MSG_CLEANUP_FN msg_cleanup(MSG_CLEANUP_FN); +extern void PRINTFLIKE(4, 5) msg_rate_delay(time_t *, int, + void (*log_fn) (const char *,...), + const char *,...); + /* LICENSE /* .ad /* .fi diff --git a/postfix/src/util/msg_rate_delay.c b/postfix/src/util/msg_rate_delay.c new file mode 100644 index 000000000..e21b0214a --- /dev/null +++ b/postfix/src/util/msg_rate_delay.c @@ -0,0 +1,138 @@ +/*++ +/* NAME +/* msg_rate_delay 3 +/* SUMMARY +/* diagnostic interface +/* SYNOPSIS +/* #include +/* +/* void msg_rate_delay(stamp, delay, log_fn, fmt, ...) +/* time_t *stamp; +/* int delay; +/* void (*log_fn)(const char *fmt, ...); +/* const char *fmt; +/* DESCRIPTION +/* msg_rate_delay() produces log output at a reduced rate: no +/* more than one message per 'delay' seconds. It discards log +/* output that would violate the output rate policy. +/* +/* This is typically used to log errors accessing a cache with +/* high-frequency access but low-value information, to avoid +/* spamming the logfile with the same kind of message. +/* +/* Arguments: +/* .IP stamp +/* Time stamp of last log output; specify a zero time stamp +/* on the first call. This is an input-output parameter. +/* This parameter is ignored when verbose logging is enabled +/* or when the delay value is zero. +/* .IP delay +/* The minimum time between log outputs; specify zero to log +/* all output for debugging purposes. This parameter is ignored +/* when verbose logging is enabled. +/* .IP log_fn +/* The function that produces log output. Typically, this will +/* be msg_info() or msg_warn(). +/* .IP fmt +/* Format string as used with msg(3) routines. +/* SEE ALSO +/* msg(3) diagnostics interface +/* DIAGNOSTICS +/* Fatal errors: memory allocation problem. +/* 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 +#include + +/* Utility library. */ + +#include +#include +#include + +/* SLMs. */ + +#define STR(x) vstring_str(x) + +/* msg_rate_delay - rate-limit message logging */ + +void msg_rate_delay(time_t *stamp, int delay, + void (*log_fn) (const char *,...), + const char *fmt,...) +{ + const char *myname = "msg_rate_delay"; + static time_t saved_event_time; + time_t now; + VSTRING *buf; + va_list ap; + + /* + * Sanity check. + */ + if (delay < 0) + msg_panic("%s: bad message rate delay: %d", myname, delay); + + /* + * This function may be called frequently. Avoid an unnecessary syscall + * if possible. Deal with the possibility that a program does not use the + * events(3) engine, so that event_time() always produces the same + * result. + */ + if (msg_verbose == 0 && delay > 0) { + if (saved_event_time == 0) + now = saved_event_time = event_time(); + else if ((now = event_time()) == saved_event_time) + now = time((time_t *) 0); + + /* + * Don't log if time is too early. + */ + if (*stamp + delay > now) + return; + *stamp = now; + } + + /* + * OK to log. This is a low-rate event, so we can afford some overhead. + */ + buf = vstring_alloc(100); + va_start(ap, fmt); + vstring_vsprintf(buf, fmt, ap); + va_end(ap); + log_fn("%s", STR(buf)); + vstring_free(buf); +} + +#ifdef TEST + + /* + * Proof-of-concept test program: log messages but skip messages during a + * two-second gap. + */ +#include + +int main(int argc, char **argv) +{ + int n; + time_t stamp = 0; + + for (n = 0; n < 6; n++) { + msg_rate_delay(&stamp, 2, msg_info, "text here %d", n); + sleep(1); + } + return (0); +} + +#endif diff --git a/postfix/src/virtual/mailbox.c b/postfix/src/virtual/mailbox.c index f0ad6eb4a..e04c42682 100644 --- a/postfix/src/virtual/mailbox.c +++ b/postfix/src/virtual/mailbox.c @@ -195,7 +195,7 @@ int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp) mailbox_res = mail_addr_find(virtual_mailbox_maps, state.msg_attr.user, IGNORE_EXTENSION); if (mailbox_res == 0) { - if (dict_errno == 0) + if (virtual_mailbox_maps->error == 0) return (NO); msg_warn("table %s: lookup %s: %m", virtual_mailbox_maps->title, state.msg_attr.user);