diff --git a/postfix/HISTORY b/postfix/HISTORY index ca5a6f902..cda458ed7 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -19165,3 +19165,21 @@ Apologies for any names omitted. Cleanup: removed redundant sort operation. Viktor Dukhovni. File: tls/tls_dane.c. + +20131119 + + Bugfix (introduced: 20111211): the Postfix memcache client + did not propagate a persistent "open()" lock to the optional + backup database. File: global/dict_memcache.c. + + Feature: a Postfix LMDB database can now be used as shared + cache. Until now only the Postfix memcache database could + be used in this manner. This is implemented by allowing a + database to downgrade the permanent DICT_FLAG_OPEN_LOCK + method to the temporary DICT_FLAG_LOCK method. Files: + util/dict.h, util/dict_alloc.c, util/dict_open.c, + util/dict_lmdb.c. + + Internal: DNS client support to report reply RCODE information, + in addition to the simplified DNS_NOTFOUND, DNS_RETRY etc. + Files: dns/dns.h. dns/dns_lookup.c, dns/test_dns_lookup.c. diff --git a/postfix/html/ldap_table.5.html b/postfix/html/ldap_table.5.html index dcb3a9ee7..423b4fa45 100644 --- a/postfix/html/ldap_table.5.html +++ b/postfix/html/ldap_table.5.html @@ -10,9 +10,9 @@ LDAP_TABLE(5) LDAP_TABLE(5) ldap_table - Postfix LDAP client configuration SYNOPSIS - postmap -q "string" ldap:/etc/postfix/filename + postmap -q "string" ldap:/etc/postfix/filename - postmap -q - ldap:/etc/postfix/filename <inputfile + postmap -q - ldap:/etc/postfix/filename <inputfile DESCRIPTION The Postfix mail system uses optional tables for address diff --git a/postfix/html/memcache_table.5.html b/postfix/html/memcache_table.5.html index ef3ac47bf..e8b3536f3 100644 --- a/postfix/html/memcache_table.5.html +++ b/postfix/html/memcache_table.5.html @@ -10,7 +10,7 @@ MEMCACHE_TABLE(5) MEMCACHE_TABLE(5) memcache_table - Postfix memcache client configuration SYNOPSIS - postmap -q "string" memcache:/etc/postfix/filename + postmap -q "string" memcache:/etc/postfix/filename postmap -q - memcache:/etc/postfix/filename <inputfile diff --git a/postfix/html/mysql_table.5.html b/postfix/html/mysql_table.5.html index c40b1723c..a59893514 100644 --- a/postfix/html/mysql_table.5.html +++ b/postfix/html/mysql_table.5.html @@ -10,7 +10,7 @@ MYSQL_TABLE(5) MYSQL_TABLE(5) mysql_table - Postfix MySQL client configuration SYNOPSIS - postmap -q "string" mysql:/etc/postfix/filename + postmap -q "string" mysql:/etc/postfix/filename postmap -q - mysql:/etc/postfix/filename <inputfile diff --git a/postfix/html/pgsql_table.5.html b/postfix/html/pgsql_table.5.html index 14c337a0d..a378ef7ed 100644 --- a/postfix/html/pgsql_table.5.html +++ b/postfix/html/pgsql_table.5.html @@ -10,7 +10,7 @@ PGSQL_TABLE(5) PGSQL_TABLE(5) pgsql_table - Postfix PostgreSQL client configuration SYNOPSIS - postmap -q "string" pgsql:/etc/postfix/filename + postmap -q "string" pgsql:/etc/postfix/filename postmap -q - pgsql:/etc/postfix/filename <inputfile diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index c1523c001..7f646f1de 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -8571,7 +8571,8 @@ address, and one address extension per email address.
extension by the first character that matches the recipient_delimiter set. -When used in forward_path, ${recipient_delimiter} is replaced +
When used in command_execution_directory, forward_path, or +luser_relay, ${recipient_delimiter} is replaced with the recipient delimiter that was found in the recipient email address (Postfix 2.11 and later), or it is replaced with the main.cf recipient_delimiter parameter value (Postfix 2.10 and earlier). diff --git a/postfix/html/sqlite_table.5.html b/postfix/html/sqlite_table.5.html index acf9f90a4..80302fdae 100644 --- a/postfix/html/sqlite_table.5.html +++ b/postfix/html/sqlite_table.5.html @@ -10,7 +10,7 @@ SQLITE_TABLE(5) SQLITE_TABLE(5) sqlite_table - Postfix SQLite configuration SYNOPSIS - postmap -q "string" sqlite:/etc/postfix/filename + postmap -q "string" sqlite:/etc/postfix/filename postmap -q - sqlite:/etc/postfix/filename <inputfile diff --git a/postfix/man/man5/cidr_table.5 b/postfix/man/man5/cidr_table.5 index 5619b2b09..1c436fdf1 100644 --- a/postfix/man/man5/cidr_table.5 +++ b/postfix/man/man5/cidr_table.5 @@ -10,7 +10,7 @@ format of Postfix CIDR tables .nf \fBpostmap -q "\fIstring\fB" cidr:/etc/postfix/\fIfilename\fR -\fBpostmap -q - cidr:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +\fBpostmap -q - cidr:/etc/postfix/\fIfilename\fB <\fIinputfile\fR .SH DESCRIPTION .ad .fi diff --git a/postfix/man/man5/ldap_table.5 b/postfix/man/man5/ldap_table.5 index 67fa8244e..9a68f7501 100644 --- a/postfix/man/man5/ldap_table.5 +++ b/postfix/man/man5/ldap_table.5 @@ -8,9 +8,9 @@ Postfix LDAP client configuration .SH "SYNOPSIS" .na .nf -\fBpostmap -q "\fIstring\fB" ldap:/etc/postfix/filename\fR +\fBpostmap -q "\fIstring\fB" ldap:/etc/postfix/\fIfilename\fR -\fBpostmap -q - ldap:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +\fBpostmap -q - ldap:/etc/postfix/\fIfilename\fB <\fIinputfile\fR .SH DESCRIPTION .ad .fi diff --git a/postfix/man/man5/memcache_table.5 b/postfix/man/man5/memcache_table.5 index a672cedf0..5b355c306 100644 --- a/postfix/man/man5/memcache_table.5 +++ b/postfix/man/man5/memcache_table.5 @@ -8,9 +8,9 @@ Postfix memcache client configuration .SH "SYNOPSIS" .na .nf -\fBpostmap -q "\fIstring\fB" memcache:/etc/postfix/filename\fR +\fBpostmap -q "\fIstring\fB" memcache:/etc/postfix/\fIfilename\fR -\fBpostmap -q - memcache:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +\fBpostmap -q - memcache:/etc/postfix/\fIfilename\fB <\fIinputfile\fR .SH DESCRIPTION .ad .fi diff --git a/postfix/man/man5/mysql_table.5 b/postfix/man/man5/mysql_table.5 index dd3ec9b4c..0b332e486 100644 --- a/postfix/man/man5/mysql_table.5 +++ b/postfix/man/man5/mysql_table.5 @@ -8,9 +8,9 @@ Postfix MySQL client configuration .SH "SYNOPSIS" .na .nf -\fBpostmap -q "\fIstring\fB" mysql:/etc/postfix/filename\fR +\fBpostmap -q "\fIstring\fB" mysql:/etc/postfix/\fIfilename\fR -\fBpostmap -q - mysql:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +\fBpostmap -q - mysql:/etc/postfix/\fIfilename\fB <\fIinputfile\fR .SH DESCRIPTION .ad .fi diff --git a/postfix/man/man5/nisplus_table.5 b/postfix/man/man5/nisplus_table.5 index d4dd670a1..65ae659b2 100644 --- a/postfix/man/man5/nisplus_table.5 +++ b/postfix/man/man5/nisplus_table.5 @@ -10,7 +10,7 @@ Postfix NIS+ client .nf \fBpostmap -q "\fIstring\fB" "nisplus:[\fIname\fB=%s];\fIname.name.\fB"\fR -\fBpostmap -q - "nisplus:[\fIname\fB=%s];\fIname.name.\fB"\fR <\fIinputfile\fR +\fBpostmap -q - "nisplus:[\fIname\fB=%s];\fIname.name.\fB" <\fIinputfile\fR .SH DESCRIPTION .ad .fi diff --git a/postfix/man/man5/pcre_table.5 b/postfix/man/man5/pcre_table.5 index 37a65dd79..2a4333059 100644 --- a/postfix/man/man5/pcre_table.5 +++ b/postfix/man/man5/pcre_table.5 @@ -10,7 +10,7 @@ format of Postfix PCRE tables .nf \fBpostmap -q "\fIstring\fB" pcre:/etc/postfix/\fIfilename\fR -\fBpostmap -q - pcre:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +\fBpostmap -q - pcre:/etc/postfix/\fIfilename\fB <\fIinputfile\fR .SH DESCRIPTION .ad .fi diff --git a/postfix/man/man5/pgsql_table.5 b/postfix/man/man5/pgsql_table.5 index ce072f2fc..5aac06912 100644 --- a/postfix/man/man5/pgsql_table.5 +++ b/postfix/man/man5/pgsql_table.5 @@ -8,9 +8,9 @@ Postfix PostgreSQL client configuration .SH "SYNOPSIS" .na .nf -\fBpostmap -q "\fIstring\fB" pgsql:/etc/postfix/filename\fR +\fBpostmap -q "\fIstring\fB" pgsql:/etc/postfix/\fIfilename\fR -\fBpostmap -q - pgsql:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +\fBpostmap -q - pgsql:/etc/postfix/\fIfilename\fB <\fIinputfile\fR .SH DESCRIPTION .ad .fi diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index 4f9068d19..8058abb27 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -5144,7 +5144,8 @@ When the recipient_delimiter set contains multiple characters extension by the first character that matches the recipient_delimiter set. .PP -When used in forward_path, ${recipient_delimiter} is replaced +When used in command_execution_directory, forward_path, or +luser_relay, ${recipient_delimiter} is replaced with the recipient delimiter that was found in the recipient email address (Postfix 2.11 and later), or it is replaced with the main.cf recipient_delimiter parameter value (Postfix 2.10 and earlier). diff --git a/postfix/man/man5/regexp_table.5 b/postfix/man/man5/regexp_table.5 index cc8979c70..ba7fe3f5e 100644 --- a/postfix/man/man5/regexp_table.5 +++ b/postfix/man/man5/regexp_table.5 @@ -10,7 +10,7 @@ format of Postfix regular expression tables .nf \fBpostmap -q "\fIstring\fB" regexp:/etc/postfix/\fIfilename\fR -\fBpostmap -q - regexp:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +\fBpostmap -q - regexp:/etc/postfix/\fIfilename\fB <\fIinputfile\fR .SH DESCRIPTION .ad .fi diff --git a/postfix/man/man5/sqlite_table.5 b/postfix/man/man5/sqlite_table.5 index 7da052390..40495546c 100644 --- a/postfix/man/man5/sqlite_table.5 +++ b/postfix/man/man5/sqlite_table.5 @@ -8,9 +8,9 @@ Postfix SQLite configuration .SH "SYNOPSIS" .na .nf -\fBpostmap -q "\fIstring\fB" sqlite:/etc/postfix/filename\fR +\fBpostmap -q "\fIstring\fB" sqlite:/etc/postfix/\fIfilename\fR -\fBpostmap -q - sqlite:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +\fBpostmap -q - sqlite:/etc/postfix/\fIfilename\fB <\fIinputfile\fR .SH DESCRIPTION .ad .fi diff --git a/postfix/man/man5/tcp_table.5 b/postfix/man/man5/tcp_table.5 index 6eb90fedd..d5d195c44 100644 --- a/postfix/man/man5/tcp_table.5 +++ b/postfix/man/man5/tcp_table.5 @@ -10,7 +10,7 @@ Postfix client/server table lookup protocol .nf \fBpostmap -q "\fIstring\fB" tcp:\fIhost:port\fR -\fBpostmap -q - tcp:\fIhost:port\fR <\fIinputfile\fR +\fBpostmap -q - tcp:\fIhost:port\fB <\fIinputfile\fR .SH DESCRIPTION .ad .fi diff --git a/postfix/proto/cidr_table b/postfix/proto/cidr_table index 0f1706ad1..2658ad941 100644 --- a/postfix/proto/cidr_table +++ b/postfix/proto/cidr_table @@ -6,7 +6,7 @@ # SYNOPSIS # \fBpostmap -q "\fIstring\fB" cidr:/etc/postfix/\fIfilename\fR # -# \fBpostmap -q - cidr:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +# \fBpostmap -q - cidr:/etc/postfix/\fIfilename\fB <\fIinputfile\fR # DESCRIPTION # The Postfix mail system uses optional lookup tables. # These tables are usually in \fBdbm\fR or \fBdb\fR format. diff --git a/postfix/proto/ldap_table b/postfix/proto/ldap_table index 7b0e564f1..32204b8f1 100644 --- a/postfix/proto/ldap_table +++ b/postfix/proto/ldap_table @@ -4,9 +4,9 @@ # SUMMARY # Postfix LDAP client configuration # SYNOPSIS -# \fBpostmap -q "\fIstring\fB" ldap:/etc/postfix/filename\fR +# \fBpostmap -q "\fIstring\fB" ldap:/etc/postfix/\fIfilename\fR # -# \fBpostmap -q - ldap:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +# \fBpostmap -q - ldap:/etc/postfix/\fIfilename\fB <\fIinputfile\fR # DESCRIPTION # The Postfix mail system uses optional tables for address # rewriting or mail routing. These tables are usually in diff --git a/postfix/proto/memcache_table b/postfix/proto/memcache_table index 3a99b5eb2..726de6131 100644 --- a/postfix/proto/memcache_table +++ b/postfix/proto/memcache_table @@ -4,9 +4,9 @@ # SUMMARY # Postfix memcache client configuration # SYNOPSIS -# \fBpostmap -q "\fIstring\fB" memcache:/etc/postfix/filename\fR +# \fBpostmap -q "\fIstring\fB" memcache:/etc/postfix/\fIfilename\fR # -# \fBpostmap -q - memcache:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +# \fBpostmap -q - memcache:/etc/postfix/\fIfilename\fB <\fIinputfile\fR # DESCRIPTION # The Postfix mail system uses optional tables for address # rewriting or mail routing. These tables are usually in diff --git a/postfix/proto/mysql_table b/postfix/proto/mysql_table index d422e7d46..9300a15dd 100644 --- a/postfix/proto/mysql_table +++ b/postfix/proto/mysql_table @@ -4,9 +4,9 @@ # SUMMARY # Postfix MySQL client configuration # SYNOPSIS -# \fBpostmap -q "\fIstring\fB" mysql:/etc/postfix/filename\fR +# \fBpostmap -q "\fIstring\fB" mysql:/etc/postfix/\fIfilename\fR # -# \fBpostmap -q - mysql:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +# \fBpostmap -q - mysql:/etc/postfix/\fIfilename\fB <\fIinputfile\fR # DESCRIPTION # The Postfix mail system uses optional tables for address # rewriting or mail routing. These tables are usually in diff --git a/postfix/proto/nisplus_table b/postfix/proto/nisplus_table index f7ace421a..40da70cee 100644 --- a/postfix/proto/nisplus_table +++ b/postfix/proto/nisplus_table @@ -6,7 +6,7 @@ # SYNOPSIS # \fBpostmap -q "\fIstring\fB" "nisplus:[\fIname\fB=%s];\fIname.name.\fB"\fR # -# \fBpostmap -q - "nisplus:[\fIname\fB=%s];\fIname.name.\fB"\fR <\fIinputfile\fR +# \fBpostmap -q - "nisplus:[\fIname\fB=%s];\fIname.name.\fB" <\fIinputfile\fR # DESCRIPTION # The Postfix mail system uses optional lookup tables. # These tables are usually in \fBdbm\fR or \fBdb\fR format. diff --git a/postfix/proto/pcre_table b/postfix/proto/pcre_table index 7cf6ea4e7..56ddcb94b 100644 --- a/postfix/proto/pcre_table +++ b/postfix/proto/pcre_table @@ -6,7 +6,7 @@ # SYNOPSIS # \fBpostmap -q "\fIstring\fB" pcre:/etc/postfix/\fIfilename\fR # -# \fBpostmap -q - pcre:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +# \fBpostmap -q - pcre:/etc/postfix/\fIfilename\fB <\fIinputfile\fR # DESCRIPTION # The Postfix mail system uses optional tables for address # rewriting, mail routing, or access control. These tables diff --git a/postfix/proto/pgsql_table b/postfix/proto/pgsql_table index fcb86ab15..a086dd831 100644 --- a/postfix/proto/pgsql_table +++ b/postfix/proto/pgsql_table @@ -4,9 +4,9 @@ # SUMMARY # Postfix PostgreSQL client configuration # SYNOPSIS -# \fBpostmap -q "\fIstring\fB" pgsql:/etc/postfix/filename\fR +# \fBpostmap -q "\fIstring\fB" pgsql:/etc/postfix/\fIfilename\fR # -# \fBpostmap -q - pgsql:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +# \fBpostmap -q - pgsql:/etc/postfix/\fIfilename\fB <\fIinputfile\fR # DESCRIPTION # The Postfix mail system uses optional tables for address # rewriting or mail routing. These tables are usually in diff --git a/postfix/proto/regexp_table b/postfix/proto/regexp_table index 1f1de40a1..49b3d50ec 100644 --- a/postfix/proto/regexp_table +++ b/postfix/proto/regexp_table @@ -6,7 +6,7 @@ # SYNOPSIS # \fBpostmap -q "\fIstring\fB" regexp:/etc/postfix/\fIfilename\fR # -# \fBpostmap -q - regexp:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +# \fBpostmap -q - regexp:/etc/postfix/\fIfilename\fB <\fIinputfile\fR # DESCRIPTION # The Postfix mail system uses optional tables for address # rewriting, mail routing, or access control. These tables diff --git a/postfix/proto/sqlite_table b/postfix/proto/sqlite_table index b981134e2..9103f7f2b 100644 --- a/postfix/proto/sqlite_table +++ b/postfix/proto/sqlite_table @@ -4,9 +4,9 @@ # SUMMARY # Postfix SQLite configuration # SYNOPSIS -# \fBpostmap -q "\fIstring\fB" sqlite:/etc/postfix/filename\fR +# \fBpostmap -q "\fIstring\fB" sqlite:/etc/postfix/\fIfilename\fR # -# \fBpostmap -q - sqlite:/etc/postfix/\fIfilename\fR <\fIinputfile\fR +# \fBpostmap -q - sqlite:/etc/postfix/\fIfilename\fB <\fIinputfile\fR # DESCRIPTION # The Postfix mail system uses optional tables for address # rewriting or mail routing. These tables are usually in diff --git a/postfix/proto/tcp_table b/postfix/proto/tcp_table index 9b91db600..e8de8a266 100644 --- a/postfix/proto/tcp_table +++ b/postfix/proto/tcp_table @@ -6,7 +6,7 @@ # SYNOPSIS # \fBpostmap -q "\fIstring\fB" tcp:\fIhost:port\fR # -# \fBpostmap -q - tcp:\fIhost:port\fR <\fIinputfile\fR +# \fBpostmap -q - tcp:\fIhost:port\fB <\fIinputfile\fR # DESCRIPTION # The Postfix mail system uses optional tables for address # rewriting or mail routing. These tables are usually in diff --git a/postfix/src/dns/dns.h b/postfix/src/dns/dns.h index 7a5d20c86..999f71528 100644 --- a/postfix/src/dns/dns.h +++ b/postfix/src/dns/dns.h @@ -207,12 +207,20 @@ extern int dns_rr_eq_sa(DNS_RR *, struct sockaddr *); /* * dns_lookup.c */ -extern int dns_lookup(const char *, unsigned, unsigned, DNS_RR **, - VSTRING *, VSTRING *); -extern int dns_lookup_l(const char *, unsigned, DNS_RR **, VSTRING *, - VSTRING *, int,...); -extern int dns_lookup_v(const char *, unsigned, DNS_RR **, VSTRING *, - VSTRING *, int, unsigned *); +extern int dns_lookup_r(const char *, unsigned, unsigned, DNS_RR **, + VSTRING *, VSTRING *, int *); +extern int dns_lookup_rl(const char *, unsigned, DNS_RR **, VSTRING *, + VSTRING *, int *, int,...); +extern int dns_lookup_rv(const char *, unsigned, DNS_RR **, VSTRING *, + VSTRING *, int *, int, unsigned *); +#define dns_lookup(name, type, rflags, list, fqdn, why) \ + dns_lookup_r((name), (type), (rflags), (list), (fqdn), (why), (int *) 0) +#define dns_lookup_l(name, rflags, list, fqdn, why, lflags, ...) \ + dns_lookup_rl((name), (rflags), (list), (fqdn), (why), (int *) 0, \ + (lflags), __VA_ARGS__) +#define dns_lookup_v(name, rflags, list, fqdn, why, lflags, ltype) \ + dns_lookup_rv((name), (rflags), (list), (fqdn), (why), (int *) 0, \ + (lflags), (ltype)) /* * Request flags. diff --git a/postfix/src/dns/dns_lookup.c b/postfix/src/dns/dns_lookup.c index b751fc7a8..4fe4b2ef3 100644 --- a/postfix/src/dns/dns_lookup.c +++ b/postfix/src/dns/dns_lookup.c @@ -31,6 +31,37 @@ /* VSTRING *why; /* int lflags; /* unsigned *ltype; +/* AUXILIARY FUNCTIONS +/* int dns_lookup_r(name, type, rflags, list, fqdn, why, rcode) +/* const char *name; +/* unsigned type; +/* unsigned rflags; +/* DNS_RR **list; +/* VSTRING *fqdn; +/* VSTRING *why; +/* int *rcode; +/* +/* int dns_lookup_rl(name, rflags, list, fqdn, why, rcode, lflags, +/* ltype, ...) +/* const char *name; +/* unsigned rflags; +/* DNS_RR **list; +/* VSTRING *fqdn; +/* VSTRING *why; +/* int *rcode; +/* int lflags; +/* unsigned ltype; +/* +/* int dns_lookup_rv(name, rflags, list, fqdn, why, rcode, lflags, +/* ltype) +/* const char *name; +/* unsigned rflags; +/* DNS_RR **list; +/* VSTRING *fqdn; +/* VSTRING *why; +/* int *rcode; +/* int lflags; +/* unsigned *ltype; /* DESCRIPTION /* dns_lookup() looks up DNS resource records. When requested to /* look up data other than type CNAME, it will follow a limited @@ -42,6 +73,9 @@ /* /* dns_lookup_l() and dns_lookup_v() allow the user to specify /* a list of resource types. +/* +/* dns_lookup_r(), dns_lookup_rl() and dns_lookup_rv() provide +/* additional information. /* INPUTS /* .ad /* .fi @@ -64,6 +98,9 @@ /* Request DNSSEC validation. This flag is silently ignored /* when the system stub resolver API, resolver(3), does not /* implement DNSSEC. +/* .IP +/* Pointer to storage for the reply RCODE value. This gives +/* more detailed information than DNS_FAIL, DNS_RETRY, etc. /* .RE /* .IP lflags /* Multi-type request control for dns_lookup_l() and dns_lookup_v(). @@ -161,11 +198,12 @@ * Structure to keep track of things while decoding a name server reply. */ #define DEF_DNS_REPLY_SIZE 4096 /* in case we're using TCP */ -#define MAX_DNS_REPLY_SIZE 32768 /* in case we're using TCP */ +#define MAX_DNS_REPLY_SIZE 65536 /* in case we're using TCP */ typedef struct DNS_REPLY { unsigned char *buf; /* raw reply data */ size_t buf_len; /* reply buffer length */ + int rcode; /* unfiltered reply code */ int dnssec_valid; /* DNSSEC AD bit */ int query_count; /* number of queries */ int answer_count; /* number of answers */ @@ -238,6 +276,8 @@ static int dns_query(const char *name, int type, int flags, len = res_search((char *) name, C_IN, type, reply->buf, reply->buf_len); _res.options &= ~flags; _res.options |= saved_options; + reply_header = (HEADER *) reply->buf; + reply->rcode = reply_header->rcode; if (len < 0) { if (why) vstring_sprintf(why, "Host or domain name not found. " @@ -259,7 +299,6 @@ static int dns_query(const char *name, int type, int flags, if (msg_verbose) msg_info("dns_query: %s (%s): OK", name, dns_strtype(type)); - reply_header = (HEADER *) reply->buf; if (reply_header->tc == 0 || reply->buf_len >= MAX_DNS_REPLY_SIZE) break; reply->buf = (unsigned char *) @@ -602,10 +641,11 @@ static int dns_get_answer(const char *orig_name, DNS_REPLY *reply, int type, return (not_found_status); } -/* dns_lookup - DNS lookup user interface */ +/* dns_lookup_r - DNS lookup user interface */ -int dns_lookup(const char *name, unsigned type, unsigned flags, - DNS_RR **rrlist, VSTRING *fqdn, VSTRING *why) +int dns_lookup_r(const char *name, unsigned type, unsigned flags, + DNS_RR **rrlist, VSTRING *fqdn, VSTRING *why, + int *rcode) { char cname[DNS_NAME_LEN]; int c_len = sizeof(cname); @@ -648,7 +688,10 @@ int dns_lookup(const char *name, unsigned type, unsigned flags, /* * Perform the DNS lookup, and pre-parse the name server reply. */ - if ((status = dns_query(name, type, flags, &reply, why)) != DNS_OK) + status = dns_query(name, type, flags, &reply, why); + if (rcode) + *rcode = reply.rcode; + if (status != DNS_OK) return (status); /* @@ -680,10 +723,11 @@ int dns_lookup(const char *name, unsigned type, unsigned flags, return (DNS_NOTFOUND); } -/* dns_lookup_l - DNS lookup interface with types list */ +/* dns_lookup_rl - DNS lookup interface with types list */ -int dns_lookup_l(const char *name, unsigned flags, DNS_RR **rrlist, - VSTRING *fqdn, VSTRING *why, int lflags,...) +int dns_lookup_rl(const char *name, unsigned flags, DNS_RR **rrlist, + VSTRING *fqdn, VSTRING *why, int *rcode, + int lflags,...) { va_list ap; unsigned type; @@ -699,8 +743,8 @@ int dns_lookup_l(const char *name, unsigned flags, DNS_RR **rrlist, if (msg_verbose) msg_info("lookup %s type %s flags %d", name, dns_strtype(type), flags); - status = dns_lookup(name, type, flags, rrlist ? &rr : (DNS_RR **) 0, - fqdn, why); + status = dns_lookup_r(name, type, flags, rrlist ? &rr : (DNS_RR **) 0, + fqdn, why, rcode); if (status == DNS_OK) { non_err = 1; if (rrlist) @@ -719,11 +763,11 @@ int dns_lookup_l(const char *name, unsigned flags, DNS_RR **rrlist, return (non_err ? DNS_OK : soft_err ? DNS_RETRY : status); } -/* dns_lookup_v - DNS lookup interface with types vector */ +/* dns_lookup_rv - DNS lookup interface with types vector */ -int dns_lookup_v(const char *name, unsigned flags, DNS_RR **rrlist, - VSTRING *fqdn, VSTRING *why, int lflags, - unsigned *types) +int dns_lookup_rv(const char *name, unsigned flags, DNS_RR **rrlist, + VSTRING *fqdn, VSTRING *why, int *rcode, + int lflags, unsigned *types) { unsigned type; int status = DNS_NOTFOUND; @@ -737,8 +781,8 @@ int dns_lookup_v(const char *name, unsigned flags, DNS_RR **rrlist, if (msg_verbose) msg_info("lookup %s type %s flags %d", name, dns_strtype(type), flags); - status = dns_lookup(name, type, flags, rrlist ? &rr : (DNS_RR **) 0, - fqdn, why); + status = dns_lookup_r(name, type, flags, rrlist ? &rr : (DNS_RR **) 0, + fqdn, why, rcode); if (status == DNS_OK) { non_err = 1; if (rrlist) diff --git a/postfix/src/dns/test_dns_lookup.c b/postfix/src/dns/test_dns_lookup.c index 109bb8832..4c6c781b1 100644 --- a/postfix/src/dns/test_dns_lookup.c +++ b/postfix/src/dns/test_dns_lookup.c @@ -102,6 +102,7 @@ int main(int argc, char **argv) char *name; VSTRING *fqdn = vstring_alloc(100); VSTRING *why = vstring_alloc(100); + int rcode; DNS_RR *rr; int i; @@ -117,10 +118,10 @@ int main(int argc, char **argv) argv_free(types_argv); name = argv[2]; msg_verbose = 1; - switch (dns_lookup_v(name, RES_DEBUG | RES_USE_DNSSEC, &rr, fqdn, why, - DNS_REQ_FLAG_NONE, types)) { + switch (dns_lookup_rv(name, RES_DEBUG | RES_USE_DNSSEC, &rr, fqdn, why, + &rcode, DNS_REQ_FLAG_NONE, types)) { default: - msg_fatal("%s", vstring_str(why)); + msg_fatal("%s (rcode=%d)", vstring_str(why), rcode); case DNS_OK: printf("%s: fqdn: %s\n", name, vstring_str(fqdn)); print_rr(rr); diff --git a/postfix/src/global/dict_memcache.c b/postfix/src/global/dict_memcache.c index e3ce92538..34c0a7383 100644 --- a/postfix/src/global/dict_memcache.c +++ b/postfix/src/global/dict_memcache.c @@ -574,10 +574,29 @@ DICT *dict_memcache_open(const char *name, int open_flags, int dict_flags) (char *) 0, 0, 0); if (backup) { dict_mc->backup = dict_open(backup, open_flags, dict_flags); + /* Expose backup lock and status to caller. */ + dict_mc->dict.lock = dict_mc->backup->lock; + dict_mc->dict.lock_type = dict_mc->backup->lock_type; + dict_mc->dict.lock_fd = dict_mc->backup->lock_fd; + dict_mc->dict.stat_fd = dict_mc->backup->stat_fd; myfree(backup); } else dict_mc->backup = 0; + /* + * Memcached is write-share safe. If the backup database is also + * write-share safe, e.g. it has downgraded its persistent lock to + * temporary, then expose that downgraded lock to the caller. + */ + if ((dict_flags & DICT_FLAG_OPEN_LOCK) != 0 + && (dict_mc->backup == 0 + || dict_mc->backup->lock_fd < 0 + || ((dict_mc->backup->flags & DICT_FLAG_OPEN_LOCK) == 0 + && (dict_mc->backup->flags & DICT_FLAG_LOCK) != 0))) { + dict_mc->dict.flags &= ~DICT_FLAG_OPEN_LOCK; + dict_mc->dict.flags |= DICT_FLAG_LOCK; + } + /* * Parse templates and common database parameters. Maps that use * substring keys should only be used with the full input key. diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index b6e7770d3..3799c7bbf 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 "20131118" +#define MAIL_RELEASE_DATE "20131119" #define MAIL_VERSION_NUMBER "2.11" #ifdef SNAPSHOT diff --git a/postfix/src/smtpstone/smtp-source.c b/postfix/src/smtpstone/smtp-source.c index 592b9b0bc..491f3d7c0 100644 --- a/postfix/src/smtpstone/smtp-source.c +++ b/postfix/src/smtpstone/smtp-source.c @@ -244,9 +244,7 @@ static int random_interval(int interval) static void command(VSTREAM *stream, char *fmt,...) { - VSTRING *buf; va_list ap; - va_list ap2; va_start(ap, fmt); @@ -255,12 +253,11 @@ static void command(VSTREAM *stream, char *fmt,...) * what the program is trying to do. */ if (msg_verbose) { - buf = vstring_alloc(100); + va_list ap2; + VA_COPY(ap2, ap); - vstring_vsprintf(buf, fmt, ap2); + vmsg_info(fmt, ap2); va_end(ap2); - msg_info("%s", vstring_str(buf)); - vstring_free(buf); } smtp_vprintf(stream, fmt, ap); va_end(ap); diff --git a/postfix/src/util/dict.h b/postfix/src/util/dict.h index c8564f6bd..2efb1f5b4 100644 --- a/postfix/src/util/dict.h +++ b/postfix/src/util/dict.h @@ -57,7 +57,8 @@ typedef struct DICT { int (*sequence) (struct DICT *, int, const char **, const char **); int (*lock) (struct DICT *, int); void (*close) (struct DICT *); - int lock_fd; /* for dict_update() lock */ + int lock_type; /* for read/write lock */ + int lock_fd; /* for read/write lock */ int stat_fd; /* change detection */ time_t mtime; /* mod time at open */ VSTRING *fold_buf; /* key folding buffer */ diff --git a/postfix/src/util/dict_alloc.c b/postfix/src/util/dict_alloc.c index fc35dc0a8..eb2b40c9a 100644 --- a/postfix/src/util/dict_alloc.c +++ b/postfix/src/util/dict_alloc.c @@ -28,7 +28,8 @@ /* /* One exception is the default lock function. When the /* dictionary provides a file handle for locking, the default -/* lock function returns the result from myflock(), otherwise +/* lock function returns the result from myflock with the +/* locking method specified in the lock_type member, otherwise /* it returns 0. Presently, the lock function is used only to /* implement the DICT_FLAG_OPEN_LOCK feature (lock the database /* exclusively after it is opened) for databases that are not @@ -115,7 +116,7 @@ static int dict_default_sequence(DICT *dict, int unused_function, static int dict_default_lock(DICT *dict, int operation) { if (dict->lock_fd >= 0) { - return (myflock(dict->lock_fd, INTERNAL_LOCK, operation)); + return (myflock(dict->lock_fd, dict->lock_type, operation)); } else { return (0); } @@ -144,6 +145,7 @@ DICT *dict_alloc(const char *dict_type, const char *dict_name, ssize_t size) dict->sequence = dict_default_sequence; dict->close = dict_default_close; dict->lock = dict_default_lock; + dict->lock_type = INTERNAL_LOCK; dict->lock_fd = -1; dict->stat_fd = -1; dict->mtime = 0; diff --git a/postfix/src/util/dict_lmdb.c b/postfix/src/util/dict_lmdb.c index 2dd36f6ea..5b079e374 100644 --- a/postfix/src/util/dict_lmdb.c +++ b/postfix/src/util/dict_lmdb.c @@ -646,6 +646,7 @@ DICT *dict_lmdb_open(const char *path, int open_flags, int dict_flags) if (fstat(db_fd, &st) < 0) msg_fatal("dict_lmdb_open: fstat: %m"); dict_lmdb->dict.lock_fd = dict_lmdb->dict.stat_fd = db_fd; + dict_lmdb->dict.lock_type = MYFLOCK_STYLE_FCNTL; dict_lmdb->dict.mtime = st.st_mtime; dict_lmdb->dict.owner.uid = st.st_uid; dict_lmdb->dict.owner.status = (st.st_uid != 0); @@ -672,6 +673,12 @@ DICT *dict_lmdb_open(const char *path, int open_flags, int dict_flags) if (dict_flags & DICT_FLAG_BULK_UPDATE) dict_jmp_alloc(&dict_lmdb->dict); + /* LMDB is write-share safe; downgrade a persistent lock to temporary. */ + if (dict_flags & DICT_FLAG_OPEN_LOCK) { + dict_lmdb->dict.flags &= ~DICT_FLAG_OPEN_LOCK; + dict_lmdb->dict.flags |= DICT_FLAG_LOCK; + } + /* * The following requests return an error result only if we have serious * memory corruption problem. diff --git a/postfix/src/util/dict_open.c b/postfix/src/util/dict_open.c index a8b5a0a72..d0a9bacff 100644 --- a/postfix/src/util/dict_open.c +++ b/postfix/src/util/dict_open.c @@ -90,10 +90,15 @@ /* .IP DICT_FLAG_LOCK /* With maps where this is appropriate, acquire an exclusive lock /* before writing, and acquire a shared lock before reading. +/* Release the lock when the operation completes. /* .IP DICT_FLAG_OPEN_LOCK /* With databases that are not multi-writer safe, request that /* dict_open() acquires an exclusive lock, or that it terminates /* with a fatal run-time error. +/* +/* With databases that are multi-writer safe, downgrade from +/* DICT_FLAG_OPEN_LOCK (persistent lock) to DICT_FLAG_LOCK +/* (temporary lock). /* .IP DICT_FLAG_FOLD_FIX /* With databases whose lookup fields are fixed-case strings, /* fold the search string to lower case before accessing the @@ -384,9 +389,10 @@ DICT *dict_open3(const char *dict_type, const char *dict_name, "cannot open %s:%s: %m", dict_type, dict_name)); if (msg_verbose) msg_info("%s: %s:%s", myname, dict_type, dict_name); - /* XXX the choice between wait-for-lock or no-wait is hard-coded. */ - if (dict_flags & DICT_FLAG_OPEN_LOCK) { - if (dict_flags & DICT_FLAG_LOCK) + /* Write-share safe maps may downgrade a persistent lock to temporary. */ + /* XXX The choice between wait-for-lock or no-wait is hard-coded. */ + if (dict->flags & DICT_FLAG_OPEN_LOCK) { + if (dict->flags & DICT_FLAG_LOCK) msg_panic("%s: attempt to open %s:%s with both \"open\" lock and \"access\" lock", myname, dict_type, dict_name); if (dict->lock(dict, MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT) < 0)