]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.12-20150111-nonprod
authorWietse Venema <wietse@porcupine.org>
Sun, 11 Jan 2015 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Mon, 12 Jan 2015 04:12:39 +0000 (23:12 -0500)
46 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/README_FILES/SMTPUTF8_README
postfix/WISHLIST
postfix/html/SMTPUTF8_README.html
postfix/proto/SMTPUTF8_README.html
postfix/src/cleanup/cleanup_init.c
postfix/src/global/Makefile.in
postfix/src/global/dict_ldap.c
postfix/src/global/dict_sqlite.c
postfix/src/global/mail_addr_find.c
postfix/src/global/mail_addr_map.c
postfix/src/global/mail_params.c
postfix/src/global/mail_version.h
postfix/src/global/mkmap_open.c
postfix/src/global/server_acl.c
postfix/src/local/local.c
postfix/src/local/mailbox.c
postfix/src/local/unknown.c
postfix/src/postalias/postalias.c
postfix/src/postmap/postmap.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp_map11.c
postfix/src/smtp/smtp_sasl_auth_cache.c
postfix/src/smtp/smtp_sasl_glue.c
postfix/src/smtp/smtp_tls_policy.c
postfix/src/smtpd/smtpd_check.c
postfix/src/smtpd/smtpd_error.ref
postfix/src/tls/tls_scache.c
postfix/src/trivial-rewrite/resolve.c
postfix/src/trivial-rewrite/transport.c
postfix/src/trivial-rewrite/trivial-rewrite.c
postfix/src/util/Makefile.in
postfix/src/util/dict.c
postfix/src/util/dict.h
postfix/src/util/dict_inline.c
postfix/src/util/dict_inline.ref
postfix/src/util/dict_open.c
postfix/src/util/dict_test.c
postfix/src/util/dict_thash.c
postfix/src/util/dict_utf8.c
postfix/src/util/dict_utf8_test.in
postfix/src/util/dict_utf8_test.ref
postfix/src/util/match_list.c
postfix/src/verify/verify.c
postfix/src/virtual/virtual.c

index b9f3a9ea13396362747966a7760e8da152eecf42..c15aa635347ce43fb7e3480b316b0795993d362b 100644 (file)
 -TDICT_THASH
 -TDICT_UNION
 -TDICT_UNIX
+-TDICT_UTF8_BACKUP
 -TDNS_FIXED
 -TDNS_REPLY
 -TDNS_RR
index 832c995bddf267a46815bde43ebcaafb63984dae..9871221caac736cc42ebb7a39ad40eb3a1e57bfa 100644 (file)
@@ -21313,9 +21313,35 @@ Apologies for any names omitted.
 
        As a first step, with "smtputf8_enable = yes" all features
        based on Postfix matchlists enable UTF-8 syntax checks and
-       casefolding support for table queries and results. That
-       includes mynetworks, mydestination, relay_domains,
-       virtual_alias_domains, and virtual_mailbox_domains.
-
-       The next step is to turn on UTF-8 syntax checks and casefolding
-       support for access maps, address rewriting and routing.
+       UTF-8 casefolding for table patterns, but NOT YET for string
+       patterns. The list of features includes authorized_flush_users,
+       authorized_mailq_users, authorized_submit_users, debug_peer_list,
+       fast_flush_domains, mydestination, permit_mx_backup_networks,
+       qmqpd_authorized_clients, smtp_connection_cache_destinations,
+       smtpd_authorized_verp_clients, smtpd_authorized_xclient_hosts,
+       smtpd_authorized_xforward_hosts,
+       smtpd_client_event_limit_exceptions,
+       smtpd_log_access_permit_actions, smtpd_sasl_exceptions_networks,
+       the "domains" feature in ldap_table(5), memcache_table(5)
+       mysql_table(5), pgsql_table(5) and sqlite_table(5),
+       virtual_alias_domains, virtual_mailbox_domains.
+
+20140111
+
+       Cleanup: simplified the interposition layer that adds UTF-8
+       support to Postfix lookup tables. Files: util/dict_utf8.c.
+
+       With "smtputf8_enable = yes", Enable UTF-8 syntax checks
+       and UTF-8 casefolding for SMTP server access maps, alias_maps,
+       canonical_maps, fallback_transport_maps,
+       lmtp_tls_session_cache_database, local_recipient_maps,
+       mailbox_command_maps, mailbox_transport_maps, rbl_reply_maps,
+       recipient_bcc_maps, recipient_canonical_maps, relay_recipient_maps,
+       relocated_maps, sender_bcc_maps, sender_canonical_maps,
+       sender_dependent_relayhost_maps, sender_dependent_transport_maps,
+       smtp_generic_maps, smtp_sasl_auth_cache_name,
+       smtp_sasl_password_maps, smtp_tls_per_site, smtp_tls_policy_maps,
+       smtp_tls_session_cache_database, smtpd_sender_login_maps,
+       smtpd_tls_session_cache_database, transport_maps,
+       virtual_alias_maps, virtual_gid_maps, virtual_mailbox_maps,
+       virtual_uid_maps.
index c0aa9ae8b8a20b8a745c4e73b917f9257468913d..8dc081a1f0decea6d2cadd631dc3550d641d69cf 100644 (file)
@@ -65,8 +65,25 @@ With SMTPUTF8 support enabled, Postfix changes behavior with respect to earlier
 Postfix releases:
 
   * UTF-8 is permitted in the myorigin parameter value. However, the myhostname
-    and mydomain parameters must specify ASCII-only domain names. This
-    limitation may be removed later.
+    and mydomain parameters must currently specify ASCII-only domain names.
+    This limitation may be removed later.
+
+  * UTF-8 is the only form of non-ASCII text that Postfix supports in access
+    tables, address rewriting tables, and other tables that are indexed with an
+    email address, hostname, or domain name.
+
+  * The header_checks-like and body_checks-like features are not UTF-8 enabled,
+    and therefore they do not enforce UTF-8 syntax rules on inputs and outputs.
+    The reason is that non-ASCII text may be sent in encodings other than UTF-
+    8, and that real email sometimes contains malformed headers. Instead of
+    skipping non-UTF-8 content, Postfix should be able to filter it. You may
+    try to enable UTF-8 processing by starting a PCRE pattern with the sequence
+    (*UTF8), but this is will result in "message not accepted, try again later"
+    errors when the PCRE pattern matcher encounters non-UTF-8 input. Other
+    features that are not UTF-8 enabled are smtpd_command_filter,
+    smtp_reply_filter, the *_delivery_status_filter features, and the
+    *_dns_reply_filter features (the latter because DNS is by definition an
+    ASCII protocol).
 
   * The Postfix SMTP server announces SMTPUTF8 support in the EHLO response.
 
@@ -185,7 +202,7 @@ the ASCII (xn--mumble) form. The initial Postfix SMTPUTF8 implementation
 performs no automatic conversions on UTF8 strings beyond what is needed to
 perform DNS lookups.
 
-N\bNo\bc\bch\bha\bar\bra\bac\bct\bte\ber\brs\bse\bet\bt c\bca\ban\bno\bon\bni\bic\bca\bal\bli\biz\bza\bat\bti\bio\bon\bn f\bfo\bor\br n\bno\bon\bn-\b-A\bAS\bSC\bCI\bII\bI d\bdo\bom\bma\bai\bin\bn n\bna\bam\bme\bes\bs.\b.
+N\bNo\ba\bau\but\bto\bom\bma\bat\bti\bic\bc c\bco\bon\bnv\bve\ber\brs\bsi\bio\bon\bns\bs b\bbe\bet\btw\bwe\bee\ben\bn A\bAS\bSC\bCI\bII\bI a\ban\bnd\bd U\bUT\bTF\bF-\b-8\b8 d\bdo\bom\bma\bai\bin\bn n\bna\bam\bme\bes\bs.\b.
 
 Postfix currently does not translate domain names from UTF-8 into ASCII (or
 ASCII into UTF-8) before looking up the domain name in mydestination,
@@ -194,12 +211,19 @@ using the domain name in a policy daemon or Milter request. You will have to
 configure both UTF-8 and ASCII forms in Postfix configuration files; and both
 forms will have to be handled by logfile tools, policy daemons and Milters.
 
-N\bNo\bo c\bca\bas\bse\be c\bca\ban\bno\bon\bni\bic\bca\bal\bli\biz\bza\bat\bti\bio\bon\bn f\bfo\bor\br n\bno\bon\bn-\b-A\bAS\bSC\bCI\bII\bI c\bch\bha\bar\bra\bac\bct\bte\ber\brs\bs.\b.
+I\bIm\bmp\bpl\ble\bem\bme\ben\bnt\bte\bed\bd:\b: c\bca\bas\bse\be-\b-i\bin\bns\bse\ben\bns\bsi\bit\bti\biv\bve\be t\bta\bab\bbl\ble\be s\bse\bea\bar\brc\bch\bh w\bwi\bit\bth\bh n\bno\bon\bn-\b-A\bAS\bSC\bCI\bII\bI t\bte\bex\bxt\bt.\b.
 
-Postfix currently does not case-fold non-ASCII characters when looking up an
-"Internationalized" domain name in mydestination, relay_domains, access maps,
-etc. Some non-ASCII scripts do not distinguish between upper and lower case,
-some have different numbers of upper and lower case characters.
+Postfix will casefold UTF-8 when searching with an "Internationalized" domain
+name or email address in mydestination, relay_domains, access maps,
+transport_maps, etc., and when maintaining tables with the postmap(1) and
+postalias(1) commands.
+
+N\bNo\bo c\bca\bas\bse\be-\b-i\bin\bns\bse\ben\bns\bsi\bit\bti\biv\bve\be m\bma\bat\btc\bch\bhi\bin\bng\bg o\bof\bf n\bno\bon\bn-\b-A\bAS\bSC\bCI\bII\bI s\bst\btr\bri\bin\bng\bg p\bpa\bat\btt\bte\ber\brn\bns\bs i\bin\bn m\bma\bat\btc\bch\bhl\bli\bis\bst\bts\bs.\b.
+
+Postfix currently does not yet implement case-insensitive string comparison for
+non-ASCII string patterns in list features such as mydestination,
+relay_domains, etc. For now, use "inline:{string}" instead of "string". This
+limitation will be removed before the stable release.
 
 C\bCo\bom\bmp\bpa\bat\bti\bib\bbi\bil\bli\bit\bty\by w\bwi\bit\bth\bh p\bpr\bre\be-\b-S\bSM\bMT\bTP\bPU\bUT\bTF\bF8\b8 e\ben\bnv\bvi\bir\bro\bon\bnm\bme\ben\bnt\bts\bs
 
index 48bdf4958dd33c6a47db3acdbae7424706590279..a8f3b85b9cf7a4ec1510f64957899ba0bdc88ea6 100644 (file)
@@ -8,6 +8,20 @@ Wish list:
 
        Things to do after the stable release:
 
+       Expose UTF8 flag in server_acl API. Some applications such
+       as postscreen don't need UTF8 support.
+
+       Expose UTF8 flag in match_list API. Some applications
+       such as address lists don't need UTF8 support.
+
+       Implement UTF8 casefolding in match_list for non-table
+       patterns.
+
+       UTF8 DNS[BW]L domain name.
+
+       Consolidate maps flags in mail_params.h instead of having
+       multiple copies scattered across programs.
+
        Try to allow UTF-8 myhostname/mydomain, at least in bounce
        template expansion.
 
index 3c3a593e5eb105d85d776779a2dc8a46439785a1..33c101be7e92d6fb1462059e74e79075a679a86c 100644 (file)
@@ -110,8 +110,27 @@ respect to earlier Postfix releases: </p>
 <ul>
 
 <li> <p> UTF-8 is permitted in the <a href="postconf.5.html#myorigin">myorigin</a> parameter value. However,
-the <a href="postconf.5.html#myhostname">myhostname</a> and <a href="postconf.5.html#mydomain">mydomain</a> parameters must specify ASCII-only
-domain names. This limitation may be removed later. </p>
+the <a href="postconf.5.html#myhostname">myhostname</a> and <a href="postconf.5.html#mydomain">mydomain</a> parameters must currently specify
+ASCII-only domain names. This limitation may be removed later. </p>
+
+<li> <p> UTF-8 is the only form of non-ASCII text that Postfix
+supports in access tables, address rewriting tables, and other
+tables that are indexed with an email address, hostname, or domain
+name. </p>
+
+<li> <p> The <a href="postconf.5.html#header_checks">header_checks</a>-like and <a href="postconf.5.html#body_checks">body_checks</a>-like features are
+not UTF-8 enabled, and therefore they do not enforce UTF-8 syntax
+rules on inputs and outputs.  The reason is that non-ASCII text may
+be sent in encodings other than UTF-8, and that real email sometimes
+contains malformed headers.  Instead of skipping non-UTF-8 content,
+Postfix should be able to filter it.  You may try to enable UTF-8
+processing by starting a PCRE pattern with the sequence (*UTF8),
+but this is will result in "message not accepted, try again later"
+errors when the PCRE pattern matcher encounters non-UTF-8 input.
+Other features that are not UTF-8 enabled are <a href="postconf.5.html#smtpd_command_filter">smtpd_command_filter</a>,
+<a href="postconf.5.html#smtp_reply_filter">smtp_reply_filter</a>, the *_delivery_status_filter features, and the
+*_dns_reply_filter features (the latter because DNS is by definition
+an ASCII protocol).  </p>
 
 <li> <p> The Postfix SMTP server announces SMTPUTF8 support in the
 EHLO response. </p>
@@ -262,8 +281,7 @@ UTF-8 form, and the ASCII (xn--mumble) form. The initial Postfix
 SMTPUTF8 implementation performs no automatic conversions on UTF8
 strings beyond what is needed to perform DNS lookups. </p>
 
-<h3> No characterset canonicalization for non-ASCII domain names.
-</h3>
+<h3> No automatic conversions between ASCII and UTF-8 domain names. </h3>
 
 <p> Postfix currently does not translate domain names from UTF-8
 into ASCII (or ASCII into UTF-8) before looking up the domain name
@@ -273,13 +291,20 @@ or Milter request. You will have to configure both UTF-8 and ASCII
 forms in Postfix configuration files; and both forms will have to
 be handled by logfile tools, policy daemons and Milters. </p>
 
-<h3> No case canonicalization for non-ASCII characters. </h3>
+<h3> Implemented: case-insensitive table search with non-ASCII text. </h3>
 
-<p> Postfix currently does not case-fold non-ASCII characters when
-looking up an "Internationalized" domain name in <a href="postconf.5.html#mydestination">mydestination</a>,
-<a href="postconf.5.html#relay_domains">relay_domains</a>, access maps, etc. Some non-ASCII scripts do not
-distinguish between upper and lower case, some have different numbers
-of upper and lower case characters. </p>
+<p> Postfix will casefold UTF-8 when searching with an "Internationalized"
+domain name or email address in <a href="postconf.5.html#mydestination">mydestination</a>, <a href="postconf.5.html#relay_domains">relay_domains</a>, access
+maps, <a href="postconf.5.html#transport_maps">transport_maps</a>, etc., and when maintaining tables with the
+<a href="postmap.1.html">postmap(1)</a> and <a href="postalias.1.html">postalias(1)</a> commands. </p>
+
+<h3> No case-insensitive matching of non-ASCII string patterns in matchlists. </h3>
+
+<p> Postfix currently does not yet implement case-insensitive string
+comparison for non-ASCII string patterns in list features such as
+<a href="postconf.5.html#mydestination">mydestination</a>, <a href="postconf.5.html#relay_domains">relay_domains</a>, etc. For now, use "<a href="DATABASE_README.html#types">inline</a>:{string}"
+instead of "string". This limitation will be removed before the
+stable release.  </p>
 
 <h2> <a name="compatibility">Compatibility with pre-SMTPUTF8
 environments</a> </h2>
index a68059ff3cbe7e19bf67d2418978dc27033e8fe3..9461ea6b5ad93f56730a7b1e5ccc667187849ef0 100644 (file)
@@ -110,8 +110,27 @@ respect to earlier Postfix releases: </p>
 <ul>
 
 <li> <p> UTF-8 is permitted in the myorigin parameter value. However,
-the myhostname and mydomain parameters must specify ASCII-only
-domain names. This limitation may be removed later. </p>
+the myhostname and mydomain parameters must currently specify
+ASCII-only domain names. This limitation may be removed later. </p>
+
+<li> <p> UTF-8 is the only form of non-ASCII text that Postfix
+supports in access tables, address rewriting tables, and other
+tables that are indexed with an email address, hostname, or domain
+name. </p>
+
+<li> <p> The header_checks-like and body_checks-like features are
+not UTF-8 enabled, and therefore they do not enforce UTF-8 syntax
+rules on inputs and outputs.  The reason is that non-ASCII text may
+be sent in encodings other than UTF-8, and that real email sometimes
+contains malformed headers.  Instead of skipping non-UTF-8 content,
+Postfix should be able to filter it.  You may try to enable UTF-8
+processing by starting a PCRE pattern with the sequence (*UTF8),
+but this is will result in "message not accepted, try again later"
+errors when the PCRE pattern matcher encounters non-UTF-8 input.
+Other features that are not UTF-8 enabled are smtpd_command_filter,
+smtp_reply_filter, the *_delivery_status_filter features, and the
+*_dns_reply_filter features (the latter because DNS is by definition
+an ASCII protocol).  </p>
 
 <li> <p> The Postfix SMTP server announces SMTPUTF8 support in the
 EHLO response. </p>
@@ -262,8 +281,7 @@ UTF-8 form, and the ASCII (xn--mumble) form. The initial Postfix
 SMTPUTF8 implementation performs no automatic conversions on UTF8
 strings beyond what is needed to perform DNS lookups. </p>
 
-<h3> No characterset canonicalization for non-ASCII domain names.
-</h3>
+<h3> No automatic conversions between ASCII and UTF-8 domain names. </h3>
 
 <p> Postfix currently does not translate domain names from UTF-8
 into ASCII (or ASCII into UTF-8) before looking up the domain name
@@ -273,13 +291,20 @@ or Milter request. You will have to configure both UTF-8 and ASCII
 forms in Postfix configuration files; and both forms will have to
 be handled by logfile tools, policy daemons and Milters. </p>
 
-<h3> No case canonicalization for non-ASCII characters. </h3>
+<h3> Implemented: case-insensitive table search with non-ASCII text. </h3>
 
-<p> Postfix currently does not case-fold non-ASCII characters when
-looking up an "Internationalized" domain name in mydestination,
-relay_domains, access maps, etc. Some non-ASCII scripts do not
-distinguish between upper and lower case, some have different numbers
-of upper and lower case characters. </p>
+<p> Postfix will casefold UTF-8 when searching with an "Internationalized"
+domain name or email address in mydestination, relay_domains, access
+maps, transport_maps, etc., and when maintaining tables with the
+postmap(1) and postalias(1) commands. </p>
+
+<h3> No case-insensitive matching of non-ASCII string patterns in matchlists. </h3>
+
+<p> Postfix currently does not yet implement case-insensitive string
+comparison for non-ASCII string patterns in list features such as
+mydestination, relay_domains, etc. For now, use "inline:{string}"
+instead of "string". This limitation will be removed before the
+stable release.  </p>
 
 <h2> <a name="compatibility">Compatibility with pre-SMTPUTF8
 environments</a> </h2>
index a117500d2f846056b2408aacc6c06324c5b7df1f..f43f34f2c4a92084e942ee7b7cb20043efcebf9f 100644 (file)
@@ -333,20 +333,24 @@ void    cleanup_pre_jail(char *unused_name, char **unused_argv)
     if (*var_canonical_maps)
        cleanup_comm_canon_maps =
            maps_create(VAR_CANONICAL_MAPS, var_canonical_maps,
-                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                       | DICT_FLAG_UTF8_REQUEST);
     if (*var_send_canon_maps)
        cleanup_send_canon_maps =
            maps_create(VAR_SEND_CANON_MAPS, var_send_canon_maps,
-                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                       | DICT_FLAG_UTF8_REQUEST);
     if (*var_rcpt_canon_maps)
        cleanup_rcpt_canon_maps =
            maps_create(VAR_RCPT_CANON_MAPS, var_rcpt_canon_maps,
-                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                       | DICT_FLAG_UTF8_REQUEST);
     if (*var_virt_alias_maps)
        cleanup_virt_alias_maps = maps_create(VAR_VIRT_ALIAS_MAPS,
                                              var_virt_alias_maps,
                                              DICT_FLAG_LOCK
-                                             | DICT_FLAG_FOLD_FIX);
+                                             | DICT_FLAG_FOLD_FIX
+                                             | DICT_FLAG_UTF8_REQUEST);
     if (*var_canon_classes)
        cleanup_comm_canon_flags =
            name_mask(VAR_CANON_CLASSES, canon_class_table,
@@ -382,11 +386,13 @@ void    cleanup_pre_jail(char *unused_name, char **unused_argv)
     if (*var_send_bcc_maps)
        cleanup_send_bcc_maps =
            maps_create(VAR_SEND_BCC_MAPS, var_send_bcc_maps,
-                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                       | DICT_FLAG_UTF8_REQUEST);
     if (*var_rcpt_bcc_maps)
        cleanup_rcpt_bcc_maps =
            maps_create(VAR_RCPT_BCC_MAPS, var_rcpt_bcc_maps,
-                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                       | DICT_FLAG_UTF8_REQUEST);
     if (*var_cleanup_milters)
        cleanup_milters = milter_create(var_cleanup_milters,
                                        var_milt_conn_time,
index 763fb89bdd1823345129f79b6a80273d33039ddb..e994fb9f54fdc949e27ba9a414cf1cf4dd57664c 100644 (file)
@@ -2003,6 +2003,7 @@ mkmap_open.o: ../../include/msg.h
 mkmap_open.o: ../../include/myflock.h
 mkmap_open.o: ../../include/mymalloc.h
 mkmap_open.o: ../../include/sigdelay.h
+mkmap_open.o: ../../include/stringops.h
 mkmap_open.o: ../../include/sys_defs.h
 mkmap_open.o: ../../include/vbuf.h
 mkmap_open.o: ../../include/vstream.h
index 02db79894ad671bc969d92144e89439c7d4ae252..2acf69fe994da4cdbaf93025014b7813d7e92b90 100644 (file)
@@ -1340,7 +1340,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
     /*
      * Don't frustrate future attempts to make Postfix UTF-8 transparent.
      */
-    if (DICT_IS_ENABLE_UTF8(dict->flags) == 0
+    if ((dict->flags & DICT_FLAG_UTF8_ACTIVE) == 0
        && !valid_utf8_string(name, strlen(name))) {
        if (msg_verbose)
            msg_info("%s: %s: Skipping lookup of non-UTF-8 key '%s'",
index 92ef7d992d1d3d1e023643e2052c84807e8bb3b7..3f581abfba9ba56d62eddef94737c0bf0950c033 100644 (file)
@@ -165,7 +165,7 @@ static const char *dict_sqlite_lookup(DICT *dict, const char *name)
     /*
      * Don't frustrate future attempts to make Postfix UTF-8 transparent.
      */
-    if (DICT_IS_ENABLE_UTF8(dict->flags) == 0
+    if ((dict->flags & DICT_FLAG_UTF8_ACTIVE) == 0
        && !valid_utf8_string(name, strlen(name))) {
        if (msg_verbose)
            msg_info("%s: %s: Skipping lookup of non-UTF-8 key '%s'",
index e21dd360018da3ca0d806276167dd012de90e410..f3a478be099fcdf09894c0a7f9e7e180b54e1dc2 100644 (file)
@@ -202,7 +202,8 @@ int     main(int argc, char **argv)
      * Initialize.
      */
     mail_conf_read();
-    path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+    path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX \
+                      | DICT_FLAG_UTF8_REQUEST);
     while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
        extent = 0;
        result = mail_addr_find(path, STR(buffer), &extent);
index e8bc6bc29af27475f5e7ff7566b0c758bc2637dd..6a0479643e61651411539dfa835e3d5ea64f0298 100644 (file)
@@ -175,7 +175,8 @@ int     main(int argc, char **argv)
     msg_verbose = 1;
     if (chdir(var_queue_dir) < 0)
        msg_fatal("chdir %s: %m", var_queue_dir);
-    path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+    path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX \
+                      | DICT_FLAGS_UTF8_REQUEST);
     while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
        msg_info("=== Address extension on, extension propagation on ===");
        UPDATE(var_rcpt_delim, "+");
index 67b7a1130fb2e7500795bd07fca2ab7ea3e85253..03c54eb1769545b0269704f5830e588123d878eb 100644 (file)
@@ -636,6 +636,11 @@ void    mail_params_init()
        VAR_DAEMON_OPEN_FATAL, DEF_DAEMON_OPEN_FATAL, &var_daemon_open_fatal,
        0,
     };
+    static const CONFIG_NBOOL_TABLE first_nbool_defaults[] = {
+       /* read and process the following before opening tables. */
+       VAR_SMTPUTF8_ENABLE, DEF_SMTPUTF8_ENABLE, &var_smtputf8_enable,
+       0,
+    };
     static const CONFIG_STR_FN_TABLE function_str_defaults[] = {
        VAR_MYHOSTNAME, check_myhostname, &var_myhostname, 1, 0,
        VAR_MYDOMAIN, check_mydomainname, &var_mydomain, 1, 0,
@@ -758,10 +763,6 @@ void    mail_params_init()
        VAR_STRICT_SMTPUTF8, DEF_STRICT_SMTPUTF8, &var_strict_smtputf8,
        0,
     };
-    static const CONFIG_NBOOL_TABLE nbool_defaults[] = {
-       VAR_SMTPUTF8_ENABLE, DEF_SMTPUTF8_ENABLE, &var_smtputf8_enable,
-       0,
-    };
     const char *cp;
 
     /*
@@ -790,6 +791,23 @@ void    mail_params_init()
     if (var_daemon_open_fatal)
        dict_allow_surrogate = 0;
 
+    /*
+     * Should we open tables with UTF8 support, or in the legacy 8-bit clean
+     * mode with ASCII-only casefolding?
+     */
+    get_mail_conf_nbool_table(first_nbool_defaults);
+
+    /*
+     * Report run-time versus compile-time discrepancies.
+     */
+#ifdef NO_EAI
+    if (var_smtputf8_enable)
+       msg_warn("%s is true, but EAI support is not compiled in",
+                VAR_SMTPUTF8_ENABLE);
+    var_smtputf8_enable = 0;
+#endif
+    util_utf8_enable = var_smtputf8_enable;
+
     /*
      * What protocols should we attempt to support? The result is stored in
      * the global inet_proto_table variable.
@@ -833,7 +851,6 @@ void    mail_params_init()
     get_mail_conf_int_table(other_int_defaults);
     get_mail_conf_long_table(long_defaults);
     get_mail_conf_bool_table(bool_defaults);
-    get_mail_conf_nbool_table(nbool_defaults);
     get_mail_conf_time_table(time_defaults);
     check_default_privs();
     check_mail_owner();
@@ -843,17 +860,6 @@ void    mail_params_init()
     dict_lmdb_map_size = var_lmdb_map_size;
     inet_windowsize = var_inet_windowsize;
 
-    /*
-     * Report run-time versus compile-time discrepancies.
-     */
-#ifdef NO_EAI
-    if (var_smtputf8_enable)
-       msg_warn("%s is true, but EAI support is not compiled in",
-                VAR_SMTPUTF8_ENABLE);
-    var_smtputf8_enable = 0;
-#endif
-    util_utf8_enable = var_smtputf8_enable;
-
     /*
      * Variables whose defaults are determined at runtime, after other
      * variables have been set. This dependency is admittedly a bit tricky.
index 3fd05a693d22496140172b3d0fe84e209efa3e49..27ad964d2931a9efad39a466d4e9c740f0380944 100644 (file)
@@ -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      "20141228"
+#define MAIL_RELEASE_DATE      "20150111"
 #define MAIL_VERSION_NUMBER    "2.12"
 
 #ifdef SNAPSHOT
index 10806495e8865188e3007eec4946f39219324362..9d15eec30a27f0557c590458e1cddc165ad45e01 100644 (file)
@@ -99,6 +99,7 @@
 #include <dict_fail.h>
 #include <sigdelay.h>
 #include <mymalloc.h>
+#include <stringops.h>
 
 /* Global library. */
 
@@ -298,9 +299,9 @@ MKMAP  *mkmap_open(const char *type, const char *path,
     /*
      * Wrap the dictionary for UTF-8 syntax checks and casefolding.
      */
-    if ((mkmap->dict->flags & DICT_FLAG_UTF8_PROXY) == 0
-        && DICT_IS_ENABLE_UTF8(dict_flags))
-       mkmap->dict = dict_utf8_encapsulate(mkmap->dict);
+    if ((mkmap->dict->flags & DICT_FLAG_UTF8_ACTIVE) == 0
+       && DICT_NEED_UTF8_ACTIVATION(util_utf8_enable, dict_flags))
+       mkmap->dict = dict_utf8_activate(mkmap->dict);
 
     /*
      * Resume signal delivery if multi-writer safe.
index 7605e5f5976fdbd31c0f208c22ab77fa6d3ec649..2caf063c8b4f07c12e604aa0361b4a7e9c3b1db9 100644 (file)
@@ -138,7 +138,8 @@ SERVER_ACL *server_acl_parse(const char *extern_acl, const char *origin)
            } else {
                if (dict_handle(acl) == 0)
                    dict_register(acl, dict_open(acl, O_RDONLY, DICT_FLAG_LOCK
-                                                | DICT_FLAG_FOLD_FIX));
+                                                | DICT_FLAG_FOLD_FIX
+                                                | DICT_FLAG_UTF8_REQUEST));
            }
        }
        argv_add(intern_acl, acl, (char *) 0);
index 8a517a06183a6024a7f298236613eea800d37b95..bd77fbc9d69c26fc4e26cef8be828b15c07c9e77 100644 (file)
@@ -865,7 +865,8 @@ static void pre_init(char *unused_name, char **unused_argv)
     }
     alias_maps = maps_create("aliases", var_alias_maps,
                             DICT_FLAG_LOCK | DICT_FLAG_PARANOID
-                            | DICT_FLAG_FOLD_FIX);
+                            | DICT_FLAG_FOLD_FIX
+                            | DICT_FLAG_UTF8_REQUEST);
 
     flush_init();
 }
index b46018e9ee15c3b1113b46adb71cec10014a1fbb..887333c62791d0fb87389d5a48c4f33da17c9b5f 100644 (file)
@@ -277,7 +277,8 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
      */
     if (*var_mbox_transp_maps && transp_maps == 0)
        transp_maps = maps_create(VAR_MBOX_TRANSP_MAPS, var_mbox_transp_maps,
-                                 DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB);
+                                 DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB
+                                 | DICT_FLAG_UTF8_REQUEST);
     /* The -1 is a hint for the down-stream deliver_completed() function. */
     if (transp_maps
        && (map_transport = maps_find(transp_maps, state.msg_attr.user,
@@ -332,10 +333,11 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
 
     if (*var_mailbox_cmd_maps && cmd_maps == 0)
        cmd_maps = maps_create(VAR_MAILBOX_CMD_MAPS, var_mailbox_cmd_maps,
-                              DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
+                              DICT_FLAG_LOCK | DICT_FLAG_PARANOID
+                              | DICT_FLAG_UTF8_REQUEST);
 
     if (cmd_maps && (map_command = maps_find(cmd_maps, state.msg_attr.user,
-                                   DICT_FLAG_NONE)) != 0) {
+                                            DICT_FLAG_NONE)) != 0) {
        status = deliver_command(state, usr_attr, map_command);
     } else if (cmd_maps && cmd_maps->error != 0) {
        /* Details in the logfile. */
index 9fbe6ea5b2bfd352f30bac0e84f103043fc5127c..733aa1350dbf00fb85048bbf1719b28b2ab9df3a 100644 (file)
@@ -109,7 +109,8 @@ int     deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr)
      */
     if (*var_fbck_transp_maps && transp_maps == 0)
        transp_maps = maps_create(VAR_FBCK_TRANSP_MAPS, var_fbck_transp_maps,
-                                 DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB);
+                                 DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB
+                                 | DICT_FLAG_UTF8_REQUEST);
     /* The -1 is a hint for the down-stream deliver_completed() function. */
     if (transp_maps
        && (map_transport = maps_find(transp_maps, state.msg_attr.user,
index 8285fcef9ccb37fe020a77463891dc9879dcbdb4..7826725c6ec63eed537569082c954cd8683ade87 100644 (file)
@@ -348,7 +348,7 @@ static void postalias(char *map_type, char *path_name, int postalias_flags,
            /*
             * First some UTF-8 checks sans casefolding.
             */
-           if (DICT_IS_ENABLE_UTF8(dict_flags)
+           if ((mkmap->dict->flags & DICT_FLAG_UTF8_ACTIVE)
                && !allascii(STR(line_buffer))
                && !valid_utf8_string(STR(line_buffer), LEN(line_buffer))) {
                msg_warn("%s, line %d: non-UTF-8 input \"%s\"",
@@ -689,7 +689,7 @@ int     main(int argc, char **argv)
     int     postalias_flags = POSTALIAS_FLAG_AS_OWNER | POSTALIAS_FLAG_SAVE_PERM;
     int     open_flags = O_RDWR | O_CREAT | O_TRUNC;
     int     dict_flags = (DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_FIX
-                         | DICT_FLAG_UTF8_ENABLE);
+                         | DICT_FLAG_UTF8_REQUEST);
     char   *query = 0;
     char   *delkey = 0;
     int     sequence = 0;
@@ -788,7 +788,7 @@ int     main(int argc, char **argv)
            sequence = 1;
            break;
        case 'u':
-           dict_flags &= ~DICT_FLAG_UTF8_ENABLE;
+           dict_flags &= ~DICT_FLAG_UTF8_REQUEST;
            break;
        case 'v':
            msg_verbose++;
index 3730ffaf7ced76d618b57fb9817b1e6cff389c1a..b1e0eab2d91462a4cb77b6f9d4adc056e6da41a2 100644 (file)
@@ -424,7 +424,7 @@ static void postmap(char *map_type, char *path_name, int postmap_flags,
            /*
             * First some UTF-8 checks sans casefolding.
             */
-           if (DICT_IS_ENABLE_UTF8(dict_flags)
+           if ((mkmap->dict->flags & DICT_FLAG_UTF8_ACTIVE)
                && !allascii(STR(line_buffer))
                && !valid_utf8_string(STR(line_buffer), LEN(line_buffer))) {
                msg_warn("%s, line %d: non-UTF-8 input \"%s\"",
@@ -816,12 +816,12 @@ int     main(int argc, char **argv)
     int     postmap_flags = POSTMAP_FLAG_AS_OWNER | POSTMAP_FLAG_SAVE_PERM;
     int     open_flags = O_RDWR | O_CREAT | O_TRUNC;
     int     dict_flags = (DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_FIX
-                         | DICT_FLAG_UTF8_ENABLE);
+                         | DICT_FLAG_UTF8_REQUEST);
     char   *query = 0;
     char   *delkey = 0;
     int     sequence = 0;
     int     found;
-    int force_utf8 = 0;
+    int     force_utf8 = 0;
 
     /*
      * Fingerprint executables and core dumps.
@@ -925,7 +925,7 @@ int     main(int argc, char **argv)
            sequence = 1;
            break;
        case 'u':
-           dict_flags &= ~DICT_FLAG_UTF8_ENABLE;
+           dict_flags &= ~DICT_FLAG_UTF8_REQUEST;
            break;
        case 'U':
            force_utf8 = 1;
@@ -950,10 +950,10 @@ int     main(int argc, char **argv)
        && (postmap_flags & POSTMAP_FLAG_ANY_KEY)
        == (postmap_flags & POSTMAP_FLAG_MIME_KEY))
        msg_warn("ignoring -m option without -b or -h");
-    if ((postmap_flags & (POSTMAP_FLAG_ANY_KEY & ~POSTMAP_FLAG_MIME_KEY)) 
+    if ((postmap_flags & (POSTMAP_FLAG_ANY_KEY & ~POSTMAP_FLAG_MIME_KEY))
        && force_utf8 == 0)
        dict_flags &= ~DICT_FLAG_UTF8_MASK;
-       
+
     /*
      * Use the map type specified by the user, or fall back to a default
      * database type.
index 977f8eb955e3644ee63c176b5f12d33f11dd45df..45961764c42685be1e4ceb15cbd55973470ef6c1 100644 (file)
@@ -1213,7 +1213,8 @@ static void pre_init(char *unused_name, char **unused_argv)
     if (*var_smtp_generic_maps)
        smtp_generic_maps =
            maps_create(VAR_LMTP_SMTP(GENERIC_MAPS), var_smtp_generic_maps,
-                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                       | DICT_FLAG_UTF8_REQUEST);
 
     /*
      * Header/body checks.
index 96326ebe66b7e817787f1ad407aca5fa7eb26415..8579f915eb77b8e498c690e4dc77d51cca254770 100644 (file)
@@ -142,7 +142,9 @@ int     main(int argc, char **argv)
     if (argc < 3)
        msg_fatal("usage: %s maptype:mapname address...", argv[0]);
 
-    maps = maps_create(argv[1], argv[1], DICT_FLAG_FOLD_FIX);
+    util_utf8_enable = 1;
+    maps = maps_create(argv[1], argv[1], DICT_FLAG_FOLD_FIX
+                      | DICT_FLAG_UTF8_REQUEST);
     mail_params_init();
     if (chdir(var_queue_dir) < 0)
        msg_fatal("chdir(%s): %m", var_queue_dir);
index 29ad938cb8c6a01f279f564f0176e040ed916c5e..b0ae35730b09b0a88aea21171cadb29f50c2e0cc 100644 (file)
@@ -131,7 +131,7 @@ SMTP_SASL_AUTH_CACHE *smtp_sasl_auth_cache_init(const char *map, int ttl)
      * dict_proxy module one level down in the build dependency hierachy.
      */
 #define CACHE_DICT_OPEN_FLAGS \
-       (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE)
+       (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE | DICT_FLAG_UTF8_REQUEST)
 #define PROXY_COLON    DICT_TYPE_PROXY ":"
 #define PROXY_COLON_LEN        (sizeof(PROXY_COLON) - 1)
 
index 951369466b8ad6462c908a281923b49fb1cc3b65..09ef734c8271eb9662f39ab2809a111a1bb094c8 100644 (file)
@@ -234,9 +234,10 @@ void    smtp_sasl_initialize(void)
      * Open the per-host password table and initialize the SASL library. Use
      * shared locks for reading, just in case someone updates the table.
      */
-    smtp_sasl_passwd_map = maps_create("smtp_sasl_passwd",
+    smtp_sasl_passwd_map = maps_create(VAR_LMTP_SMTP(SASL_PASSWD),
                                       var_smtp_sasl_passwd,
-                                      DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                                      DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                                      | DICT_FLAG_UTF8_REQUEST);
     if ((smtp_sasl_impl = xsasl_client_init(var_smtp_sasl_type,
                                            var_smtp_sasl_path)) == 0)
        msg_fatal("SASL library initialization");
@@ -258,7 +259,7 @@ void    smtp_sasl_initialize(void)
                                      var_smtp_sasl_auth_cache_time);
 #else
        msg_warn("not compiled with TLS support -- "
-                "ignoring the %s setting", VAR_LMTP_SMTP(SASL_AUTH_CACHE_NAME));
+           "ignoring the %s setting", VAR_LMTP_SMTP(SASL_AUTH_CACHE_NAME));
 #endif
     }
 }
index 07e3c4a6f76ae917b64cee2eb9b68e0fd8e46160..22b76ab492b0fb51a57e640e9ee1d3812046aee2 100644 (file)
@@ -132,7 +132,8 @@ void    smtp_tls_list_init(void)
     if (*var_smtp_tls_policy) {
        tls_policy = maps_create(VAR_LMTP_SMTP(TLS_POLICY),
                                 var_smtp_tls_policy,
-                                DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                                DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                                | DICT_FLAG_UTF8_REQUEST);
        if (*var_smtp_tls_per_site)
            msg_warn("%s ignored when %s is not empty.",
                     VAR_LMTP_SMTP(TLS_PER_SITE), VAR_LMTP_SMTP(TLS_POLICY));
@@ -141,7 +142,8 @@ void    smtp_tls_list_init(void)
     if (*var_smtp_tls_per_site) {
        tls_per_site = maps_create(VAR_LMTP_SMTP(TLS_PER_SITE),
                                   var_smtp_tls_per_site,
-                                  DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                                  DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                                  | DICT_FLAG_UTF8_REQUEST);
     }
 }
 
index ea77741d342c7fbb47355d17e0790472f4dda051..27de37bf2e71c0669f9726e1c6f113b55a0d1a74 100644 (file)
@@ -607,7 +607,8 @@ static ARGV *smtpd_check_parse(int flags, const char *checks)
        else if ((flags & SMTPD_CHECK_PARSE_MAPS)
                 && strchr(name, ':') && dict_handle(name) == 0) {
            dict_register(name, dict_open(name, O_RDONLY, DICT_FLAG_LOCK
-                                         | DICT_FLAG_FOLD_FIX));
+                                         | DICT_FLAG_FOLD_FIX
+                                         | DICT_FLAG_UTF8_REQUEST));
        }
        last = name;
     }
@@ -726,18 +727,24 @@ void    smtpd_check_init(void)
      * Pre-parse and pre-open the recipient maps.
      */
     local_rcpt_maps = maps_create(VAR_LOCAL_RCPT_MAPS, var_local_rcpt_maps,
-                                 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                                 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                                 | DICT_FLAG_UTF8_REQUEST);
     rcpt_canon_maps = maps_create(VAR_RCPT_CANON_MAPS, var_rcpt_canon_maps,
-                                 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                                 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                                 | DICT_FLAG_UTF8_REQUEST);
     canonical_maps = maps_create(VAR_CANONICAL_MAPS, var_canonical_maps,
-                                DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                                DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                                | DICT_FLAG_UTF8_REQUEST);
     virt_alias_maps = maps_create(VAR_VIRT_ALIAS_MAPS, var_virt_alias_maps,
-                                 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                                 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                                 | DICT_FLAG_UTF8_REQUEST);
     virt_mailbox_maps = maps_create(VAR_VIRT_MAILBOX_MAPS,
                                    var_virt_mailbox_maps,
-                                   DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                                   DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                                   | DICT_FLAG_UTF8_REQUEST);
     relay_rcpt_maps = maps_create(VAR_RELAY_RCPT_MAPS, var_relay_rcpt_maps,
-                                 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                                 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                                 | DICT_FLAG_UTF8_REQUEST);
 
 #ifdef TEST
     virt_alias_doms = string_list_init(MATCH_FLAG_NONE, var_virt_alias_doms);
@@ -750,14 +757,16 @@ void    smtpd_check_init(void)
      * Templates for RBL rejection replies.
      */
     rbl_reply_maps = maps_create(VAR_RBL_REPLY_MAPS, var_rbl_reply_maps,
-                                DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                                DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                                | DICT_FLAG_UTF8_REQUEST);
 
     /*
      * Sender to login name mapping.
      */
     smtpd_sender_login_maps = maps_create(VAR_SMTPD_SND_AUTH_MAPS,
                                          var_smtpd_snd_auth_maps,
-                                      DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                                         DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                                         | DICT_FLAG_UTF8_REQUEST);
 
     /*
      * error_text is used for returning error responses.
@@ -1113,7 +1122,7 @@ static const char *check_mail_addr_find(SMTPD_STATE *state,
                                                char **ext)
 {
     const char *result;
-     
+
     if ((result = mail_addr_find(maps, key, ext)) != 0 || maps->error == 0)
        return (result);
     if (maps->error == DICT_ERR_RETRY)
@@ -5982,7 +5991,7 @@ int     main(int argc, char **argv)
                UPDATE_STRING(var_virt_alias_maps, args->argv[1]);
                UPDATE_MAPS(virt_alias_maps, VAR_VIRT_ALIAS_MAPS,
                            var_virt_alias_maps, DICT_FLAG_LOCK
-                           | DICT_FLAG_FOLD_FIX);
+                           | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
                resp = 0;
                break;
            }
@@ -5997,7 +6006,7 @@ int     main(int argc, char **argv)
                UPDATE_STRING(var_virt_mailbox_maps, args->argv[1]);
                UPDATE_MAPS(virt_mailbox_maps, VAR_VIRT_MAILBOX_MAPS,
                            var_virt_mailbox_maps, DICT_FLAG_LOCK
-                           | DICT_FLAG_FOLD_FIX);
+                           | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
                resp = 0;
                break;
            }
@@ -6012,7 +6021,7 @@ int     main(int argc, char **argv)
                UPDATE_STRING(var_local_rcpt_maps, args->argv[1]);
                UPDATE_MAPS(local_rcpt_maps, VAR_LOCAL_RCPT_MAPS,
                            var_local_rcpt_maps, DICT_FLAG_LOCK
-                           | DICT_FLAG_FOLD_FIX);
+                           | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
                resp = 0;
                break;
            }
@@ -6020,7 +6029,7 @@ int     main(int argc, char **argv)
                UPDATE_STRING(var_relay_rcpt_maps, args->argv[1]);
                UPDATE_MAPS(relay_rcpt_maps, VAR_RELAY_RCPT_MAPS,
                            var_relay_rcpt_maps, DICT_FLAG_LOCK
-                           | DICT_FLAG_FOLD_FIX);
+                           | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
                resp = 0;
                break;
            }
@@ -6028,7 +6037,7 @@ int     main(int argc, char **argv)
                UPDATE_STRING(var_canonical_maps, args->argv[1]);
                UPDATE_MAPS(canonical_maps, VAR_CANONICAL_MAPS,
                            var_canonical_maps, DICT_FLAG_LOCK
-                           | DICT_FLAG_FOLD_FIX);
+                           | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
                resp = 0;
                break;
            }
@@ -6036,7 +6045,7 @@ int     main(int argc, char **argv)
                UPDATE_STRING(var_rbl_reply_maps, args->argv[1]);
                UPDATE_MAPS(rbl_reply_maps, VAR_RBL_REPLY_MAPS,
                            var_rbl_reply_maps, DICT_FLAG_LOCK
-                           | DICT_FLAG_FOLD_FIX);
+                           | DICT_FLAG_FOLD_FIX | DICT_FLAG_UTF8_REQUEST);
                resp = 0;
                break;
            }
index 44675cb2ef7a97dc0f86d405d8832217abba7c42..2316ac54ac248a236c3dc423999c06becf30dfe2 100644 (file)
@@ -11,8 +11,8 @@ OK
 >>> # Expect: REJECT (temporary lookup failure)
 >>> helo foobar
 ./smtpd_check: warning: fail:1_helo_access: table lookup problem
-./smtpd_check: <queue id>: reject: HELO from localhost[127.0.0.1]: 451 4.3.5 <foobar>: Helo command rejected: Server configuration error; proto=SMTP helo=<foobar>
-451 4.3.5 <foobar>: Helo command rejected: Server configuration error
+./smtpd_check: <queue id>: reject: HELO from localhost[127.0.0.1]: 451 4.3.0 <foobar>: Temporary lookup failure; proto=SMTP helo=<foobar>
+451 4.3.0 <foobar>: Temporary lookup failure
 >>> #
 >>> # Test check_namadr_access()
 >>> #
@@ -21,8 +21,8 @@ OK
 >>> # Expect: REJECT (temporary lookup failure)
 >>> client foo.dunno.com 131.155.210.17
 ./smtpd_check: warning: fail:1_client_access: table lookup problem
-./smtpd_check: <queue id>: reject: CONNECT from foo.dunno.com[131.155.210.17]: 451 4.3.5 <foo.dunno.com[131.155.210.17]>: Client host rejected: Server configuration error; proto=SMTP helo=<foobar>
-451 4.3.5 <foo.dunno.com[131.155.210.17]>: Client host rejected: Server configuration error
+./smtpd_check: <queue id>: reject: CONNECT from foo.dunno.com[131.155.210.17]: 451 4.3.0 <foo.dunno.com[131.155.210.17]>: Temporary lookup failure; proto=SMTP helo=<foobar>
+451 4.3.0 <foo.dunno.com[131.155.210.17]>: Temporary lookup failure
 >>> #
 >>> # Test check_mail_access()
 >>> #
@@ -31,8 +31,8 @@ OK
 >>> # Expect: REJECT (temporary lookup failure)
 >>> mail reject@dunno.domain
 ./smtpd_check: warning: fail:1_sender_access: table lookup problem
-./smtpd_check: <queue id>: reject: MAIL from foo.dunno.com[131.155.210.17]: 451 4.3.5 <reject@dunno.domain>: Sender address rejected: Server configuration error; from=<reject@dunno.domain> proto=SMTP helo=<foobar>
-451 4.3.5 <reject@dunno.domain>: Sender address rejected: Server configuration error
+./smtpd_check: <queue id>: reject: MAIL from foo.dunno.com[131.155.210.17]: 451 4.3.0 <reject@dunno.domain>: Temporary lookup failure; from=<reject@dunno.domain> proto=SMTP helo=<foobar>
+451 4.3.0 <reject@dunno.domain>: Temporary lookup failure
 >>> #
 >>> # Test check_rcpt_access()
 >>> #
@@ -41,8 +41,8 @@ OK
 >>> # Expect: REJECT (temporary lookup failure)
 >>> rcpt reject@dunno.domain
 ./smtpd_check: warning: fail:1_rcpt_access: table lookup problem
-./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.5 <reject@dunno.domain>: Recipient address rejected: Server configuration error; from=<reject@dunno.domain> to=<reject@dunno.domain> proto=SMTP helo=<foobar>
-451 4.3.5 <reject@dunno.domain>: Recipient address rejected: Server configuration error
+./smtpd_check: <queue id>: reject: RCPT from foo.dunno.com[131.155.210.17]: 451 4.3.0 <reject@dunno.domain>: Temporary lookup failure; from=<reject@dunno.domain> to=<reject@dunno.domain> proto=SMTP helo=<foobar>
+451 4.3.0 <reject@dunno.domain>: Temporary lookup failure
 >>> # Expect: OK
 >>> rcpt postmaster
 OK
@@ -79,8 +79,8 @@ OK
 OK
 >>> mail <>
 ./smtpd_check: warning: fail:1_sender_access: table lookup problem
-./smtpd_check: <queue id>: reject: MAIL from foo.dunno.com[131.155.210.17]: 451 4.3.5 <>: Sender address rejected: Server configuration error; from=<> proto=SMTP helo=<foobar>
-451 4.3.5 <>: Sender address rejected: Server configuration error
+./smtpd_check: <queue id>: reject: MAIL from foo.dunno.com[131.155.210.17]: 451 4.3.0 <>: Temporary lookup failure; from=<> proto=SMTP helo=<foobar>
+451 4.3.0 <>: Temporary lookup failure
 >>> #
 >>> # Test permit_tls_client_certs in generic_restrictions
 >>> #
index 1c1a29e5fb93dba2f695245dc47fd1c3351b59ca..ca86cc2580ed78cccdc5e84405e25d862a528d88 100644 (file)
@@ -481,10 +481,12 @@ TLS_SCACHE *tls_scache_open(const char *dbname, const char *cache_label,
      * opening a damaged file after some process terminated abnormally.
      */
 #ifdef SINGLE_UPDATER
-#define DICT_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_OPEN_LOCK)
+#define DICT_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_OPEN_LOCK \
+                   | DICT_FLAG_UTF8_REQUEST)
 #else
 #define DICT_FLAGS \
-       (DICT_FLAG_DUP_REPLACE | DICT_FLAG_LOCK | DICT_FLAG_SYNC_UPDATE)
+       (DICT_FLAG_DUP_REPLACE | DICT_FLAG_LOCK | DICT_FLAG_SYNC_UPDATE \
+        | DICT_FLAG_UTF8_REQUEST)
 #endif
 
     dict = dict_open(dbname, O_RDWR | O_CREAT | O_TRUNC, DICT_FLAGS);
index 7d7b0b95735b3958da6f304f0a4a2663d5bdb1c1..5291b121649675f4fdeb90d116a2316c0ace7919 100644 (file)
@@ -810,5 +810,6 @@ void    resolve_init(void)
     if (*var_relocated_maps)
        relocated_maps =
            maps_create(VAR_RELOCATED_MAPS, var_relocated_maps,
-                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+                       DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
+                       | DICT_FLAG_UTF8_REQUEST);
 }
index ec571cdb559e58a8f92f161dfd33e505937bf8b2..f270b8ddef1d1576be97f77ed5b7e4d54a60cc1c 100644 (file)
@@ -99,7 +99,8 @@ TRANSPORT_INFO *transport_pre_init(const char *transport_maps_name,
     tp = (TRANSPORT_INFO *) mymalloc(sizeof(*tp));
     tp->transport_path = maps_create(transport_maps_name, transport_maps,
                                     DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
-                                    | DICT_FLAG_NO_REGSUB);
+                                    | DICT_FLAG_NO_REGSUB
+                                    | DICT_FLAG_UTF8_REQUEST);
     tp->wildcard_channel = tp->wildcard_nexthop = 0;
     tp->wildcard_errno = 0;
     tp->expire = 0;
index 4a71ec0e91a368a8bddc96b35b8a838fc5da82a7..31ae822e3859222579b4d9d3c23934a7ecdbbe6e 100644 (file)
@@ -542,25 +542,25 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
            maps_create(resolve_regular.snd_relay_maps_name,
                        RES_PARAM_VALUE(resolve_regular.snd_relay_maps),
                        DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
-                       | DICT_FLAG_NO_REGSUB);
+                       | DICT_FLAG_NO_REGSUB | DICT_FLAG_UTF8_REQUEST);
     if (*RES_PARAM_VALUE(resolve_verify.snd_relay_maps))
        resolve_verify.snd_relay_info =
            maps_create(resolve_verify.snd_relay_maps_name,
                        RES_PARAM_VALUE(resolve_verify.snd_relay_maps),
                        DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
-                       | DICT_FLAG_NO_REGSUB);
+                       | DICT_FLAG_NO_REGSUB | DICT_FLAG_UTF8_REQUEST);
     if (*RES_PARAM_VALUE(resolve_regular.snd_def_xp_maps))
        resolve_regular.snd_def_xp_info =
            maps_create(resolve_regular.snd_def_xp_maps_name,
                        RES_PARAM_VALUE(resolve_regular.snd_def_xp_maps),
                        DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
-                       | DICT_FLAG_NO_REGSUB);
+                       | DICT_FLAG_NO_REGSUB | DICT_FLAG_UTF8_REQUEST);
     if (*RES_PARAM_VALUE(resolve_verify.snd_def_xp_maps))
        resolve_verify.snd_def_xp_info =
            maps_create(resolve_verify.snd_def_xp_maps_name,
                        RES_PARAM_VALUE(resolve_verify.snd_def_xp_maps),
                        DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
-                       | DICT_FLAG_NO_REGSUB);
+                       | DICT_FLAG_NO_REGSUB | DICT_FLAG_UTF8_REQUEST);
 }
 
 /* post_jail_init - initialize after entering chroot jail */
index 2090191bb388c5bb10651c7ba4fe78d61fa4716e..4dee5e51f60e5705098d9d8a004d354f3398f0c5 100644 (file)
@@ -752,6 +752,8 @@ dict_inline_test: dict_open dict_inline.ref
        $(SHLIB_ENV) ./dict_open inline:'{ foo=xx {x=y}x}' read </dev/null; \
        (echo get foo; echo get bar; echo get baz) | $(SHLIB_ENV) \
            ./dict_open inline:'{ foo=XX, { bAr = lotsa stuff }}' read fold_fix; \
+       (echo get foo; echo get bar; echo get baz) | $(SHLIB_ENV) \
+           ./dict_open inline:'{ foo=XX, { bAr = lotsa stuff }}' read 'fold_fix,utf8_request'; \
        ) >dict_inline.tmp 2>&1
        diff dict_inline.ref dict_inline.tmp
        rm -f dict_inline.tmp
index 0ec4a3d75878654343798079421d2f2804401d44..75fd949721874e507e462db716f821320e2aa182 100644 (file)
@@ -637,8 +637,8 @@ static const NAME_MASK dict_mask[] = {
     "open_lock", DICT_FLAG_OPEN_LOCK,  /* permanent lock upon open */
     "bulk_update", DICT_FLAG_BULK_UPDATE,      /* bulk update if supported */
     "multi_writer", DICT_FLAG_MULTI_WRITER,    /* multi-writer safe */
-    "utf8_enable", DICT_FLAG_UTF8_ENABLE,      /* enable UTF-8 checks/fold */
-    "utf8_proxy", DICT_FLAG_UTF8_PROXY,        /* UTF-8 proxy is present */
+    "utf8_request", DICT_FLAG_UTF8_REQUEST,    /* request UTF-8 activation */
+    "utf8_active", DICT_FLAG_UTF8_ACTIVE,      /* UTF-8 is activated */
     0,
 };
 
index e48b81c45ae6cf20ce423acd7f052424a3be332d..b86bad8ace2000d1db0cc295ea9bfb84293ee61f 100644 (file)
@@ -127,10 +127,10 @@ extern DICT *dict_debug(DICT *);
 #define DICT_FLAG_OPEN_LOCK    (1<<16) /* perm lock if not multi-writer safe */
 #define DICT_FLAG_BULK_UPDATE  (1<<17) /* optimize for bulk updates */
 #define DICT_FLAG_MULTI_WRITER (1<<18) /* multi-writer safe map */
-#define DICT_FLAG_UTF8_ENABLE  (1<<19) /* enable UTF-8 checks */
-#define DICT_FLAG_UTF8_PROXY   (1<<20) /* UTF-8 proxy layer is present */
+#define DICT_FLAG_UTF8_REQUEST (1<<19) /* activate UTF-8 if possible */
+#define DICT_FLAG_UTF8_ACTIVE  (1<<20) /* UTF-8 proxy layer is present */
 
-#define DICT_FLAG_UTF8_MASK    (DICT_FLAG_UTF8_ENABLE)
+#define DICT_FLAG_UTF8_MASK    (DICT_FLAG_UTF8_REQUEST)
 
  /* IMPORTANT: Update the dict_mask[] table when the above changes */
 
@@ -168,10 +168,8 @@ extern DICT *dict_debug(DICT *);
  /*
   * Feature tests.
   */
-extern int util_utf8_enable;
-
-#define DICT_IS_ENABLE_UTF8(flags) \
-       (util_utf8_enable && (flags & DICT_FLAG_UTF8_MASK))
+#define DICT_NEED_UTF8_ACTIVATION(enable, flags) \
+       ((enable) && ((flags) & DICT_FLAG_UTF8_MASK))
 
  /*
   * dict->error values. Errors must be negative; smtpd_check depends on this.
@@ -251,7 +249,7 @@ extern void dict_type_override(DICT *, const char *);
  /*
   * Check and convert UTF-8 keys and values.
   */
-extern DICT *dict_utf8_encapsulate(DICT *);
+extern DICT *dict_utf8_activate(DICT *);
 extern char *dict_utf8_check_fold(DICT *, const char *, CONST_CHAR_STAR *);
 extern int dict_utf8_check(const char *, CONST_CHAR_STAR *);
 
index 7e223117108460d79cff927e43a964cdf707f43a..c6202a6ac0bf1f5b26a6585e95e9747e80cc05a8 100644 (file)
@@ -80,7 +80,7 @@ DICT   *dict_inline_open(const char *name, int open_flags, int dict_flags)
     /*
      * UTF-8 syntax check.
      */
-    if (DICT_IS_ENABLE_UTF8(dict_flags)
+    if (DICT_NEED_UTF8_ACTIVATION(util_utf8_enable, dict_flags)
        && allascii(name) == 0
        && valid_utf8_string(name, strlen(name)) == 0)
        DICT_INLINE_RETURN(dict_surrogate(DICT_TYPE_INLINE, name,
index 38332d5268d0a3f17786bb96d81d02b65c009e62..e64e6d040656fb4053b9ad706110a13dbd5f357c 100644 (file)
@@ -15,3 +15,10 @@ foo=XX
 bar=lotsa stuff
 > get baz
 baz: not found
+owner=trusted (uid=2147483647)
+> get foo
+foo=XX
+> get bar
+bar=lotsa stuff
+> get baz
+baz: not found
index 4b11986d602cea44836d09af38a6bc0f6157e93c..a18a6ce34a68136775bf784644ecbd00fba729ac 100644 (file)
@@ -479,9 +479,9 @@ DICT   *dict_open3(const char *dict_type, const char *dict_name,
                      dict_type, dict_name);
     }
     /* Last step: insert proxy for UTF-8 syntax checks and casefolding. */
-    if ((dict->flags & DICT_FLAG_UTF8_PROXY) == 0
-       && DICT_IS_ENABLE_UTF8(dict_flags))
-       dict = dict_utf8_encapsulate(dict);
+    if ((dict->flags & DICT_FLAG_UTF8_ACTIVE) == 0
+       && DICT_NEED_UTF8_ACTIVATION(util_utf8_enable, dict_flags))
+       dict = dict_utf8_activate(dict);
     return (dict);
 }
 
@@ -559,7 +559,7 @@ DICT_MAPNAMES_EXTEND_FN dict_mapnames_extend(DICT_MAPNAMES_EXTEND_FN new_cb)
 
 /* dict_type_override - disguise a dictionary type */
 
-void dict_type_override(DICT *dict, const char *type)
+void    dict_type_override(DICT *dict, const char *type)
 {
     myfree(dict->type);
     dict->type = mystrdup(type);
index 836798592ae6c6880328532d7023fec0eb6160a5..5f394ff81c65b549b34da351cb36dfb79af7a6bc 100644 (file)
@@ -76,7 +76,7 @@ void    dict_test(int argc, char **argv)
        dict_flags |= DICT_FLAG_LOCK;
     if ((dict_flags & (DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_IGNORE)) == 0)
        dict_flags |= DICT_FLAG_DUP_REPLACE;
-    dict_flags |= DICT_FLAG_UTF8_ENABLE;
+    dict_flags |= DICT_FLAG_UTF8_REQUEST;
     vstream_fflush(VSTREAM_OUT);
     dict_name = argv[optind];
     dict_allow_surrogate = 1;
index c638bb6e34a2f674a5eab28d8fbae4a5b20d5601..cad181cfd13c47a2b9acae9d3b8d294bea06020c 100644 (file)
@@ -115,7 +115,7 @@ DICT   *dict_thash_open(const char *path, int open_flags, int dict_flags)
            /*
             * First some UTF-8 checks sans casefolding.
             */
-           if (DICT_IS_ENABLE_UTF8(dict_flags)
+           if ((dict->flags & DICT_FLAG_UTF8_ACTIVE)
                && allascii(STR(line_buffer)) == 0
                && valid_utf8_string(STR(line_buffer), LEN(line_buffer)) == 0) {
                msg_warn("%s, line %d: non-UTF-8 input \"%s\""
index b07c6e0954c60d75680a6899c139606556a23b9b..eecabf68a42966c67f31e1531c6b6e415111d452 100644 (file)
@@ -6,7 +6,7 @@
 /* SYNOPSIS
 /*     #include <dict.h>
 /*
-/*     DICT    *dict_utf8_encapsulate(
+/*     DICT    *dict_utf8_activate(
 /*     DICT    *dict)
 /*
 /*     char    *dict_utf8_check_fold(
 /*     const char *string,
 /*     CONST_CHAR_STAR *err)
 /* DESCRIPTION
-/*     dict_utf8_encapsulate() wraps a dictionary's lookup/update/delete
+/*     dict_utf8_activate() wraps a dictionary's lookup/update/delete
 /*     methods with code that enforces UTF-8 checks on keys and
 /*     values, and that logs a warning when incorrect UTF-8 is
 /*     encountered. The original dictionary handle becomes invalid.
 /*
 /*     The wrapper code enforces a policy that maximizes application
-/*     robustness.  Attempts to store non-UTF-8 keys or values are
-/*     skipped while reporting success, attempts to look up or
-/*     delete non-UTF-8 keys are skipped while reporting success,
-/*     and attempts to look up a non-UTF-8 value are flagged while
-/*     reporting a configuration error.
+/*     robustness (it avoids the need for new error-handling code
+/*     paths in application code).  Attempts to store non-UTF-8
+/*     keys or values are skipped while reporting a non-error
+/*     status, attempts to look up or delete non-UTF-8 keys are
+/*     skipped while reporting a non-error status, and attempts
+/*     to look up a non-UTF-8 value are flagged while reporting a
+/*     configuration error.
 /*
 /*     The dict_utf8_check* functions may be invoked to perform
 /*     UTF-8 validity checks when util_utf8_enable is non-zero and
@@ -42,6 +44,8 @@
 /*
 /*     dict_utf8_check() checks a string for UTF-8 validity. The
 /*     result is zero in case of error.
+/* BUGS
+/*     dict_utf8_activate() does not nest.
 /* LICENSE
 /* .ad
 /* .fi
 #include <mymalloc.h>
 #include <msg.h>
 
+ /*
+  * Backed-up accessor function pointers.
+  */
+typedef struct {
+    const char *(*lookup) (struct DICT *, const char *);
+    int     (*update) (struct DICT *, const char *, const char *);
+    int     (*delete) (struct DICT *, const char *);
+} DICT_UTF8_BACKUP;
+
  /*
   * The goal is to maximize robustness: bad UTF-8 should not appear in keys,
   * because those are derived from controlled inputs, and values should be
@@ -113,7 +126,7 @@ char   *dict_utf8_check_fold(DICT *dict, const char *string,
     /*
      * Casefold and implicitly validate UTF-8.
      */
-    if (fold_flag != 0 && (fold_flag == (dict->flags & DICT_FLAG_FIXED) ?
+    if (fold_flag != 0 && (fold_flag & (dict->flags & DICT_FLAG_FIXED) ?
                           DICT_FLAG_FOLD_FIX : DICT_FLAG_FOLD_MUL)) {
        if (dict->fold_buf == 0)
            dict->fold_buf = vstring_alloc(10);
@@ -145,39 +158,40 @@ int     dict_utf8_check(const char *string, CONST_CHAR_STAR *err)
 
 /* dict_utf8_lookup - UTF-8 lookup method wrapper */
 
-static const char *dict_utf8_lookup(DICT *self, const char *key)
+static const char *dict_utf8_lookup(DICT *dict, const char *key)
 {
-    DICT   *dict;
+    DICT_UTF8_BACKUP *backup;
     const char *utf8_err;
     const char *fold_res;
     const char *value;
+    int     saved_flags;
 
     /*
      * Validate and optionally fold the key, and if invalid skip the request.
      */
-    if ((fold_res = dict_utf8_check_fold(self, key, &utf8_err)) == 0) {
+    if ((fold_res = dict_utf8_check_fold(dict, key, &utf8_err)) == 0) {
        msg_warn("%s:%s: non-UTF-8 key \"%s\": %s",
-                      self->type, self->name, key, utf8_err);
-       self->error = DICT_ERR_NONE;
+                dict->type, dict->name, key, utf8_err);
+       dict->error = DICT_ERR_NONE;
        return (0);
     }
 
     /*
-     * Proxy the request.
+     * Proxy the request with casefolding turned off.
      */
-    dict = (void *) self - self->size;
-    dict->flags = self->flags;
-    value = dict->lookup(dict, fold_res);
-    self->flags = dict->flags;
-    self->error = dict->error;
+    saved_flags = (dict->flags & DICT_FLAG_FOLD_ANY);
+    dict->flags &= ~DICT_FLAG_FOLD_ANY;
+    backup = (void *) dict + dict->size;
+    value = backup->lookup(dict, fold_res);
+    dict->flags |= saved_flags;
 
     /*
      * Validate the result, and if invalid fail the request.
      */
     if (value != 0 && dict_utf8_check(value, &utf8_err) == 0) {
        msg_warn("%s:%s: key \"%s\": non-UTF-8 value \"%s\": %s",
-                      self->type, self->name, key, value, utf8_err);
-       self->error = DICT_ERR_CONFIG;
+                dict->type, dict->name, key, value, utf8_err);
+       dict->error = DICT_ERR_CONFIG;
        return (0);
     } else {
        return (value);
@@ -186,20 +200,21 @@ static const char *dict_utf8_lookup(DICT *self, const char *key)
 
 /* dict_utf8_update - UTF-8 update method wrapper */
 
-static int dict_utf8_update(DICT *self, const char *key, const char *value)
+static int dict_utf8_update(DICT *dict, const char *key, const char *value)
 {
-    DICT   *dict;
+    DICT_UTF8_BACKUP *backup;
     const char *utf8_err;
     const char *fold_res;
+    int     saved_flags;
     int     status;
 
     /*
      * Validate or fold the key, and if invalid skip the request.
      */
-    if ((fold_res = dict_utf8_check_fold(self, key, &utf8_err)) == 0) {
+    if ((fold_res = dict_utf8_check_fold(dict, key, &utf8_err)) == 0) {
        msg_warn("%s:%s: non-UTF-8 key \"%s\": %s",
-                      self->type, self->name, key, utf8_err);
-       self->error = DICT_ERR_NONE;
+                dict->type, dict->name, key, utf8_err);
+       dict->error = DICT_ERR_NONE;
        return (DICT_STAT_SUCCESS);
     }
 
@@ -208,111 +223,100 @@ static int dict_utf8_update(DICT *self, const char *key, const char *value)
      */
     else if (dict_utf8_check(value, &utf8_err) == 0) {
        msg_warn("%s:%s: key \"%s\": non-UTF-8 value \"%s\": %s",
-                      self->type, self->name, key, value, utf8_err);
-       self->error = DICT_ERR_NONE;
+                dict->type, dict->name, key, value, utf8_err);
+       dict->error = DICT_ERR_NONE;
        return (DICT_STAT_SUCCESS);
     }
 
     /*
-     * Proxy the request.
+     * Proxy the request with casefolding turned off.
      */
     else {
-       dict = (void *) self - self->size;
-       dict->flags = self->flags;
-       status = dict->update(dict, fold_res, value);
-       self->flags = dict->flags;
-       self->error = dict->error;
+       saved_flags = (dict->flags & DICT_FLAG_FOLD_ANY);
+       dict->flags &= ~DICT_FLAG_FOLD_ANY;
+       backup = (void *) dict + dict->size;
+       status = backup->update(dict, fold_res, value);
+       dict->flags |= saved_flags;
        return (status);
     }
 }
 
 /* dict_utf8_delete - UTF-8 delete method wrapper */
 
-static int dict_utf8_delete(DICT *self, const char *key)
+static int dict_utf8_delete(DICT *dict, const char *key)
 {
-    DICT   *dict;
+    DICT_UTF8_BACKUP *backup;
     const char *utf8_err;
     const char *fold_res;
+    int     saved_flags;
     int     status;
 
     /*
      * Validate and optionally fold the key, and if invalid skip the request.
      */
-    if ((fold_res = dict_utf8_check_fold(self, key, &utf8_err)) == 0) {
+    if ((fold_res = dict_utf8_check_fold(dict, key, &utf8_err)) == 0) {
        msg_warn("%s:%s: non-UTF-8 key \"%s\": %s",
-                      self->type, self->name, key, utf8_err);
-       self->error = DICT_ERR_NONE;
+                dict->type, dict->name, key, utf8_err);
+       dict->error = DICT_ERR_NONE;
        return (DICT_STAT_SUCCESS);
     }
 
     /*
-     * Proxy the request.
+     * Proxy the request with casefolding turned off.
      */
     else {
-       dict = (void *) self - self->size;
-       dict->flags = self->flags;
-       status = dict->delete(dict, fold_res);
-       self->flags = dict->flags;
-       self->error = dict->error;
+       saved_flags = (dict->flags & DICT_FLAG_FOLD_ANY);
+       dict->flags &= ~DICT_FLAG_FOLD_ANY;
+       backup = (void *) dict + dict->size;
+       status = backup->delete(dict, fold_res);
+       dict->flags |= saved_flags;
        return (status);
     }
 }
 
-/* dict_utf8_close - dummy */
+/* dict_utf8_activate - wrap a legacy dict object for UTF-8 processing */
 
-static void dict_utf8_close(DICT *self)
+DICT   *dict_utf8_activate(DICT *dict)
 {
-    DICT   *dict;
-
-    /*
-     * Destroy the dict object that we are appended to, and thereby destroy
-     * ourselves.
-     */
-    dict = (void *) self - self->size;
-    dict->close(dict);
-}
-
-/* dict_utf8_encapsulate - wrap a legacy dict object for UTF-8 processing */
-
-DICT   *dict_utf8_encapsulate(DICT *dict)
-{
-    DICT   *self;
+    DICT_UTF8_BACKUP *backup;
 
     /*
      * Sanity check.
      */
-    if (dict->flags & DICT_FLAG_UTF8_PROXY)
-       msg_panic("dict_utf8_encapsulate: %s:%s is already encapsulated",
+    if (dict->flags & DICT_FLAG_UTF8_ACTIVE)
+       msg_panic("dict_utf8_activate: %s:%s is already encapsulated",
                  dict->type, dict->name);
 
     /*
-     * Append ourselves to the dict object, so that dict_close(dict) will do
-     * the right thing. dict->size is based on the actual size of the dict
-     * object's subclass, so we don't have to worry about alignment problems.
+     * Unlike dict_debug(3) we do not put a proxy dict object in front of the
+     * encapsulated object, because then we would have to bidirectionally
+     * propagate changes in the data members (errors, flags, jbuf, and so on)
+     * between proxy object and encapsulated object.
      * 
-     * XXX Add dict_flags argument to dict_alloc() so that it can allocate the
-     * right memory amount, and we can avoid having to resize an object.
+     * Instead we append ourselves to the encapsulated dict object itself, and
+     * redirect some function pointers. This approach does not yet generalize
+     * to arbitrary levels of encapsulation. That is, it does not co-exist
+     * with dict_debug(3) which is broken for the reasons stated above.
      */
-    dict = myrealloc(dict, dict->size + sizeof(*self));
-    self = (void *) dict + dict->size;
-    *self = *dict;
+    dict = myrealloc(dict, dict->size + sizeof(*backup));
+    backup = (void *) dict + dict->size;
 
     /*
-     * Interpose on the lookup/update/delete/close methods. In particular we
-     * do not interpose on the iterator. Invalid keys are not stored, and we
-     * want to be able to delete an invalid value.
+     * Interpose on the lookup/update/delete methods. It is a conscious
+     * decision not to tinker with the iterator or destructor.
      */
-    self->lookup = dict_utf8_lookup;
-    self->update = dict_utf8_update;
-    self->delete = dict_utf8_delete;
-    self->close = dict_utf8_close;
+    backup->lookup = dict->lookup;
+    backup->update = dict->update;
+    backup->delete = dict->delete;
+
+    dict->lookup = dict_utf8_lookup;
+    dict->update = dict_utf8_update;
+    dict->delete = dict_utf8_delete;
 
     /*
-     * Finally, disable casefolding in the dict object. It now happens in the
-     * lookup/update/delete wrappers.
+     * Leave our mark. See sanity check above.
      */
-    dict->flags &= ~DICT_FLAG_FOLD_ANY;
-    self->flags |= DICT_FLAG_UTF8_PROXY;
+    dict->flags |= DICT_FLAG_UTF8_ACTIVE;
 
-    return (self);
+    return (dict);
 }
index 9f7743a4e822b79f42dbfaa4c2d43e969db7ab69..748d25b36db338ab9067604f718cd329024d8e20 100644 (file)
@@ -9,4 +9,4 @@ awk 'BEGIN {
        printf "put xxx %c%c%c\n", 128, 128, 128
        printf "get xxx\n"
        exit
-}' | ./dict_open internal:whatever write utf8_enable
+}' | ./dict_open internal:whatever write utf8_request
index 2a13513d81d40b472882c22da66af7162585b8d5..c29a336cfa0700caa776ecd6bdfd75fc8b5b4eed 100644 (file)
@@ -1,6 +1,6 @@
 owner=trusted (uid=2147483647)
 > flags
-dict flags fixed|lock|replace|utf8_enable|utf8_proxy
+dict flags fixed|lock|replace|utf8_request|utf8_active
 > verbose
 > get foo
 foo: not found
index 714d474a5cd9c7b19cb126f187459fcc24becd4d..9626562119108e333a585da1a416bca8d70a4a0b 100644 (file)
@@ -108,7 +108,7 @@ static ARGV *match_list_parse(ARGV *list, char *string, int init_match)
 
 #define OPEN_FLAGS     O_RDONLY
 #define DICT_FLAGS     (DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX \
-                       | DICT_FLAG_UTF8_ENABLE)
+                       | DICT_FLAG_UTF8_REQUEST)
 #define STR(x)         vstring_str(x)
 
     /*
index fb36540b0c7d8b7c321d4e46663ffa0cdd4d8ac1..009396ef9f6c0ed30cbd6047602f22ad7ab04c9b 100644 (file)
@@ -680,7 +680,7 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
      * Start the cache cleanup thread after permanently dropping privileges.
      */
 #define VERIFY_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE \
-           | DICT_FLAG_OPEN_LOCK)
+           | DICT_FLAG_OPEN_LOCK | DICT_FLAG_UTF8_REQUEST)
 
     saved_mask = umask(022);
     verify_map =
index 69252c308955a1b8ae822114e40508a2b5a59582..487b3a2d7637d3f2fd8e60630c6657afd940c9d8 100644 (file)
@@ -457,15 +457,18 @@ static void post_init(char *unused_name, char **unused_argv)
      */
     virtual_mailbox_maps =
        maps_create(VAR_VIRT_MAILBOX_MAPS, var_virt_mailbox_maps,
-                   DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
+                   DICT_FLAG_LOCK | DICT_FLAG_PARANOID
+                   | DICT_FLAG_UTF8_REQUEST);
 
     virtual_uid_maps =
        maps_create(VAR_VIRT_UID_MAPS, var_virt_uid_maps,
-                   DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
+                   DICT_FLAG_LOCK | DICT_FLAG_PARANOID
+                   | DICT_FLAG_UTF8_REQUEST);
 
     virtual_gid_maps =
        maps_create(VAR_VIRT_GID_MAPS, var_virt_gid_maps,
-                   DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
+                   DICT_FLAG_LOCK | DICT_FLAG_PARANOID
+                   | DICT_FLAG_UTF8_REQUEST);
 
     virtual_mbox_lock_mask = mbox_lock_mask(var_virt_mailbox_lock);
 }