From: Wietse Venema Date: Sat, 17 Mar 2007 05:00:00 +0000 (-0500) Subject: postfix-2.4.0-RC6 X-Git-Tag: v2.4.0-RC6^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b29cbb10d495cbe7123e3fdc5538ebe3b3402526;p=thirdparty%2Fpostfix.git postfix-2.4.0-RC6 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 0ed26a406..bd0bb978b 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -13339,6 +13339,33 @@ Apologies for any names omitted. compatibility with Postfix versions that pre-date Milter support. File: cleanup/cleanup_out.c. +20070314 + + Bitrot: move the "don't run this daemon by hand" message + before other tests. Files: master/*server.c. + +20070315 + + Bitrot: New OpenLDAP APIs deprecate simplified interfaces, + that are the only ones available in Sun's LDAP SDK. Define + suitable macros that work with new OpenLDAP and Sun's code. + Victor Duchovni, Morgan Stanley. File: src/global/dict_ldap.c + + Cleanup: new "leaf" and "terminal" result attributes support + fine-tuning of LDAP group expansion, and provide a solution + for the problem case where DN recursion returns both the + group address and the addresses of the member objects. + Victor Duchovni, Morgan Stanley. Files: src/global/dict_ldap.c, + proto/LDAP_README.html, proto/ldap_table + +20070317 + + Idioten Sicherheit: stamp every executable file and every + core dump file with "mail_version=xxxxx". Adding version + stamps and checks to every IPC message is too much change + after code freeze, and requires too much time for testing. + File: src/global/mail_version.h and every main program file. + Wish list: Update message content length when adding/removing headers. diff --git a/postfix/README_FILES/ADDRESS_VERIFICATION_README b/postfix/README_FILES/ADDRESS_VERIFICATION_README index 5db4991d1..70948cde9 100644 --- a/postfix/README_FILES/ADDRESS_VERIFICATION_README +++ b/postfix/README_FILES/ADDRESS_VERIFICATION_README @@ -5,9 +5,9 @@ PPoossttffiixx AAddddrreessss VVeerriiffiiccaattiioonn WWAARRNNIINNGG The sender/recipient address verification feature described in this document is -suitable only for low-traffic sites. It performs poorly under high load and may -cause your site to be blacklisted by some providers. See the "Limitations" -section below for details. +suitable only for low-traffic sites. It performs poorly under high load; +excessive sender address verification activity may even cause your site to be +blacklisted by some providers. See the "Limitations" section below for details. WWhhaatt PPoossttffiixx aaddddrreessss vveerriiffiiccaattiioonn ccaann ddoo ffoorr yyoouu diff --git a/postfix/README_FILES/LDAP_README b/postfix/README_FILES/LDAP_README index 12f31d110..dead25113 100644 --- a/postfix/README_FILES/LDAP_README +++ b/postfix/README_FILES/LDAP_README @@ -18,6 +18,7 @@ Topics covered in this document: * Configuring LDAP lookups * Example: aliases * Example: virtual domains/addresses + * Example: expanding LDAP groups * Other uses of LDAP lookups * Notes and things to think about * Feedback @@ -96,12 +97,12 @@ in main.cf, you have: and in ldap:/etc/postfix/ldap-aliases.cf you have: - server_host = ldap.my.com - search_base = dc=my, dc=com + server_host = ldap.example.com + search_base = dc=example, dc=com Upon receiving mail for a local address "ldapuser" that isn't found in the / etc/aliases database, Postfix will search the LDAP server listening at port 389 -on ldap.my.com. It will bind anonymously, search for any directory entries +on ldap.example.com. It will bind anonymously, search for any directory entries whose mailacceptinggeneralid attribute is "ldapuser", read the "maildrop" attributes of those found, and build a list of their maildrops, which will be treated as RFC822 addresses to which the message will be delivered. @@ -116,7 +117,7 @@ want to make sure all of your virtual recipient's mailacceptinggeneralid attributes are fully qualified with their virtual domains. Finally, if you want to designate a directory entry as the default user for a virtual domain, just give it an additional mailacceptinggeneralid (or the equivalent in your -directory) of "@virtual.dom". That's right, no user part. If you don't want a +directory) of "@fake.dom". That's right, no user part. If you don't want a catchall user, omit this step and mail to unknown users in the domain will simply bounce. @@ -143,12 +144,183 @@ this: Normal users might simply have one mailacceptinggeneralid and maildrop, e.g. "normaluser@fake.dom" and "normaluser@real.dom". +EExxaammppllee:: eexxppaannddiinngg LLDDAAPP ggrroouuppss + +LDAP is frequently used to store group member information, and Postfix supports +expanding a group's email address to the list of email addresses of the group +members. There are a number of ways of handling LDAP groups, which will be +illustrated via the mock LDAP entries and implied schema below. This shows two +group entries "agroup" and "bgroup" and four user entries "auser", "buser", +"cuser" and "duser". The group "agroup" has the users "auser" (1) and "buser" +(2) as members via DN references in the multi-valued attribute "memberdn", and +direct email addresses of two external users "auser@example.org" (3) and +"buser@example.org" (4) stored in the multi-valued attribute "memberaddr". The +same is true of "bgroup" and "cuser"/"duser" (6)/(7)/(8)/(9), but "bgroup" also +has a "maildrop" attribute of "bgroup@mlm.example.com" (5): + + dn: cn=agroup, dc=example, dc=com + objectclass: top + objectclass: ldapgroup + cn: agroup + mail: agroup@example.com + 1 -> memberdn: uid=auser, dc=example, dc=com + 2 -> memberdn: uid=buser, dc=example, dc=com + 3 -> memberaddr: auser@example.org + 4 -> memberaddr: buser@example.org + + dn: cn=bgroup, dc=example, dc=com + objectclass: top + objectclass: ldapgroup + cn: bgroup + mail: bgroup@example.com + 5 -> maildrop: bgroup@mlm.example.com + 6 -> memberdn: uid=cuser, dc=example, dc=com + 7 -> memberdn: uid=duser, dc=example, dc=com + 8 -> memberaddr: cuser@example.org + 9 -> memberaddr: duser@example.org + + dn: uid=auser, dc=example, dc=com + objectclass: top + objectclass: ldapuser + uid: auser + 10 -> mail: auser@example.com + 11 -> maildrop: auser@mailhub.example.com + + dn: uid=buser, dc=example, dc=com + objectclass: top + objectclass: ldapuser + uid: buser + 12 -> mail: buser@example.com + 13 -> maildrop: buser@mailhub.example.com + + dn: uid=cuser, dc=example, dc=com + objectclass: top + objectclass: ldapuser + uid: cuser + 14 -> mail: cuser@example.com + + dn: uid=duser, dc=example, dc=com + objectclass: top + objectclass: ldapuser + uid: duser + 15 -> mail: duser@example.com + +Our first use case ignores the "memberdn" attributes, and assumes that groups +hold only direct "memberaddr" strings as in (3), (4), (8) and (9). The goal is +to map the group address to the list of constituent "memberaddr" values. This +is simple, ignoring the various connection related settings (hosts, ports, bind +settings, timeouts, ...) we have: + + simple.cf: + ... + search_base = dc=example, dc=com + query_filter = mail=%s + result_attribute = memberaddr + $ postmap -q agroup@example.com ldap:simple.cf + auser@example.org,buser@example.org + +We search "dc=example, dc=com". The "mail" attribute is used in the +query_filter to locate the right group, the "result_attribute" setting +described in ldap_table(5) is used to specify that "memberaddr" values from the +matching group are to be returned as a comma separated list. Always check +tables using postmap(1) with the "-q" option, before deploying them into +production use in main.cf. + +Our second use case also expands "memberdn" attributes (1), (2), (6) and (7), +follows the DN references and returns the "maildrop" of the referenced user +entries. Here we use the "special_result_attribute" setting from ldap_table(5) +to designate the "memberdn" attribute as holding DNs of the desired member +entries. The "result_attribute" setting selects which attributes are returned +from the selected DNs. It is important to choose a result attribute that is not +also present in the group object, because result attributes are collected from +both the group and the member DNs. In this case we choose "maildrop" and assume +for the moment that groups never have a "maildrop" (the "bgroup" "maildrop" +attribute is for a different use case). The returned data for "auser" and +"buser" is from items (11) and (13) in the mock data. + + special.cf: + ... + search_base = dc=example, dc=com + query_filter = mail=%s + result_attribute = memberaddr, maildrop + special_result_attribute = memberdn + $ postmap -q agroup@example.com ldap:special.cf + + auser@mailhub.example.com,buser@mailhub.example.com,auser@example.org,buser@example.org + +Note: if the desired member object result attribute is always also present in +the group, you get suprising results, the expansion also returns the address of +the group. This is a known limitation of Postfix releases prior to 2.4, and is +addressed in the new with Postfix 2.4 "leaf_result_attribute" feature described +in ldap_table(5). + +Our third use case has some groups that are expanded immediately, and other +groups that are forwarded to a dedicated mailing list manager host for delayed +expansion. This uses two LDAP tables, one for users and forwarded groups and a +second for groups that can be expanded immediately. It is assumed that groups +that require forwarding are never nested members of groups that are directly +expanded. + + no_expand.cf: + ... + search_base = dc=example, dc=com + query_filter = mail=%s + result_attribute = maildrop + expand.cf + ... + search_base = dc=example, dc=com + query_filter = mail=%s + result_attribute = memberaddr, maildrop + special_result_attribute = memberdn + $ postmap -q auser@example.com ldap:no_expand.cf ldap:expand.cf + auser@mailhub.example.com + $ postmap -q agroup@example.com ldap:no_expand.cf ldap:expand.cf + + auser@mailhub.example.com,buser@mailhub.example.com,auser@example.org,buser@example.org + $ postmap -q bgroup@example.com ldap:no_expand.cf ldap:expand.cf + bgroup@mlm.example.com + +Non-group objects and groups with delayed expansion (those that have a maildrop +attribute) are rewritten to a single maildrop value. Groups that don't have a +maildrop are expanded as the second use case. This admits a more elegant +solution with Postfix 2.4 and later. + +Our final use case is the same as the third, but this time uses new features in +Postfix 2.4. We now are able to use just one LDAP table and no longer need to +assume that forwarded groups are never nested inside expanded groups. + + fancy.cf: + ... + search_base = dc=example, dc=com + query_filter = mail=%s + result_attribute = memberaddr + special_result_attribute = memberdn + terminal_result_attribute = maildrop + leaf_result_attribute = mail + $ postmap -q auser@example.com ldap:fancy.cf + auser@mailhub.example.com + $ postmap -q cuser@example.com ldap:fancy.cf + cuser@example.com + $ postmap -q agroup@example.com ldap:fancy.cf + + auser@mailhub.example.com,buser@mailhub.example.com,auser@example.org,buser@example.org + $ postmap -q bgroup@example.com ldap:fancy.cf + bgroup@mlm.example.com + +Above, delayed expansion is enabled via "terminal_result_attribute", which, if +present, is used as the sole result and all other expansion is suppressed. +Otherwise, the "leaf_result_attribute" is only returned for leaf objects that +don't have a "special_result_attribute" (non-groups), while the +"result_attribute" (direct member address of groups) is returned at every level +of recursive expansion, not just the leaf nodes. This fancy example illustrates +all the features of Postfix 2.4 group expansion. + OOtthheerr uusseess ooff LLDDAAPP llooookkuuppss Other common uses for LDAP lookups include rewriting senders and recipients with Postfix's canonical lookups, for example in order to make mail leaving -your site appear to be coming from "First.Last@site.dom" instead of -"userid@site.dom". +your site appear to be coming from "First.Last@example.com" instead of +"userid@example.com". NNootteess aanndd tthhiinnggss ttoo tthhiinnkk aabboouutt @@ -166,9 +338,9 @@ NNootteess aanndd tthhiinnggss ttoo tthhiinnkk aabboouu define an entry intended for use as a mailing list that looks like this (Warning! Schema made up just for this example): - dn: cn=Accounting Staff List, dc=my, dc=com + dn: cn=Accounting Staff List, dc=example, dc=com cn: Accounting Staff List - o: my.com + o: example.com objectclass: maillist mailacceptinggeneralid: accountingstaff mailacceptinggeneralid: accounting-staff diff --git a/postfix/README_FILES/SASL_README b/postfix/README_FILES/SASL_README index efc0eebfe..ee39ad617 100644 --- a/postfix/README_FILES/SASL_README +++ b/postfix/README_FILES/SASL_README @@ -254,7 +254,7 @@ Note: some Cyrus SASL distributions look for the smtpd.conf file in /etc/sasl2. a pam". IMPORTANT: saslauthd usually establishes a UNIX domain socket in /var/run/ - saslauthd and waits for authentication requests. postfix processes must + saslauthd and waits for authentication requests. Postfix processes must have read+execute permission to this directory or authentication attempts will fail. diff --git a/postfix/html/ADDRESS_VERIFICATION_README.html b/postfix/html/ADDRESS_VERIFICATION_README.html index 7f6ab85ca..0f14fb030 100644 --- a/postfix/html/ADDRESS_VERIFICATION_README.html +++ b/postfix/html/ADDRESS_VERIFICATION_README.html @@ -21,7 +21,8 @@

The sender/recipient address verification feature described in this document is suitable only for low-traffic sites. It performs poorly -under high load and may cause your site to be blacklisted by some +under high load; excessive sender address verification activity may +even cause your site to be blacklisted by some providers. See the "Limitations" section below for details.

diff --git a/postfix/html/LDAP_README.html b/postfix/html/LDAP_README.html index e828b2848..6fe7ef71b 100644 --- a/postfix/html/LDAP_README.html +++ b/postfix/html/LDAP_README.html @@ -41,6 +41,8 @@ it to each.

  • Example: virtual domains/addresses +
  • Example: expanding LDAP groups +
  • Other uses of LDAP lookups
  • Notes and things to think about @@ -124,7 +126,7 @@ option (e.g. '-R') so the executables can find it at runtime.

    Configuring LDAP lookups

    In order to use LDAP lookups, define an LDAP source -as a table lookup in main.cf, for example:

    +as a table lookup in main.cf, for example:

    @@ -140,7 +142,7 @@ page. 

    Example: local(8) aliases

    Here's a basic example for using LDAP to look up local(8) -aliases. Assume that in main.cf, you have:

    +aliases. Assume that in main.cf, you have:

    @@ -152,14 +154,14 @@ aliases. Assume that in main.cf, you have: 

    -server_host = ldap.my.com
    -search_base = dc=my, dc=com
    +server_host = ldap.example.com
    +search_base = dc=example, dc=com
     

    Upon receiving mail for a local address "ldapuser" that isn't found in the /etc/aliases database, Postfix will search the LDAP -server listening at port 389 on ldap.my.com. It will bind anonymously, +server listening at port 389 on ldap.example.com. It will bind anonymously, search for any directory entries whose mailacceptinggeneralid attribute is "ldapuser", read the "maildrop" attributes of those found, and build a list of their maildrops, which will be treated @@ -176,7 +178,7 @@ of your virtual recipient's mailacceptinggeneralid attributes are fully qualified with their virtual domains. Finally, if you want to designate a directory entry as the default user for a virtual domain, just give it an additional mailacceptinggeneralid (or the -equivalent in your directory) of "@virtual.dom". That's right, no +equivalent in your directory) of "@fake.dom". That's right, no user part. If you don't want a catchall user, omit this step and mail to unknown users in the domain will simply bounce.

    @@ -212,12 +214,221 @@ go to this entry ...

    maildrop, e.g. "normaluser@fake.dom" and "normaluser@real.dom".

    +

    Example: expanding LDAP groups

    + +

    LDAP is frequently used to store group member information, and Postfix +supports expanding a group's email address to the list of email addresses +of the group members. There are a number of ways of handling LDAP groups, +which will be illustrated via the mock LDAP entries and implied schema +below. This shows two group entries "agroup" and "bgroup" and four +user entries "auser", "buser", "cuser" and "duser". The group "agroup" +has the users "auser" (1) and "buser" (2) as members via DN references +in the multi-valued attribute "memberdn", and direct email addresses of +two external users "auser@example.org" (3) and "buser@example.org" (4) +stored in the multi-valued attribute "memberaddr". The same is true of +"bgroup" and "cuser"/"duser" (6)/(7)/(8)/(9), but "bgroup" also has a +"maildrop" attribute of "bgroup@mlm.example.com" (5):

    + +
    +
    +     dn: cn=agroup, dc=example, dc=com
    +     objectclass: top
    +     objectclass: ldapgroup
    +     cn: agroup
    +     mail: agroup@example.com
    +1 -> memberdn: uid=auser, dc=example, dc=com
    +2 -> memberdn: uid=buser, dc=example, dc=com
    +3 -> memberaddr: auser@example.org
    +4 -> memberaddr: buser@example.org
    +
    +
    + +
    +     dn: cn=bgroup, dc=example, dc=com
    +     objectclass: top
    +     objectclass: ldapgroup
    +     cn: bgroup
    +     mail: bgroup@example.com
    +5 -> maildrop: bgroup@mlm.example.com
    +6 -> memberdn: uid=cuser, dc=example, dc=com
    +7 -> memberdn: uid=duser, dc=example, dc=com
    +8 -> memberaddr: cuser@example.org
    +9 -> memberaddr: duser@example.org
    +
    +
    + +
    +     dn: uid=auser, dc=example, dc=com
    +     objectclass: top
    +     objectclass: ldapuser
    +     uid: auser
    +10 -> mail: auser@example.com
    +11 -> maildrop: auser@mailhub.example.com
    +
    +
    + +
    +     dn: uid=buser, dc=example, dc=com
    +     objectclass: top
    +     objectclass: ldapuser
    +     uid: buser
    +12 -> mail: buser@example.com
    +13 -> maildrop: buser@mailhub.example.com
    +
    +
    + +
    +     dn: uid=cuser, dc=example, dc=com
    +     objectclass: top
    +     objectclass: ldapuser
    +     uid: cuser
    +14 -> mail: cuser@example.com
    +
    +
    + +
    +     dn: uid=duser, dc=example, dc=com
    +     objectclass: top
    +     objectclass: ldapuser
    +     uid: duser
    +15 -> mail: duser@example.com
    +
    +
    + +
    + +

    Our first use case ignores the "memberdn" attributes, and assumes +that groups hold only direct "memberaddr" strings as in (3), (4), (8) and +(9). The goal is to map the group address to the list of constituent +"memberaddr" values. This is simple, ignoring the various connection +related settings (hosts, ports, bind settings, timeouts, ...) we have: +

    + +
    +
    +    simple.cf:
    +        ...
    +        search_base = dc=example, dc=com
    +        query_filter = mail=%s
    +        result_attribute = memberaddr
    +    $ postmap -q agroup@example.com ldap:simple.cf
    +    auser@example.org,buser@example.org
    +
    +
    + +

    We search "dc=example, dc=com". The "mail" attribute is used in the +query_filter to locate the right group, the "result_attribute" setting +described in ldap_table(5) is used to specify that "memberaddr" values +from the matching group are to be returned as a comma separated list. +Always check tables using postmap(1) with the "-q" option, before +deploying them into production use in main.cf.

    + +

    Our second use case also expands "memberdn" attributes (1), (2), +(6) and (7), follows the DN references and returns the "maildrop" of the +referenced user entries. Here we use the "special_result_attribute" +setting from ldap_table(5) to designate the "memberdn" attribute +as holding DNs of the desired member entries. The "result_attribute" +setting selects which attributes are returned from the selected DNs. It +is important to choose a result attribute that is not also present in +the group object, because result attributes are collected from both +the group and the member DNs. In this case we choose "maildrop" and +assume for the moment that groups never have a "maildrop" (the "bgroup" +"maildrop" attribute is for a different use case). The returned data for +"auser" and "buser" is from items (11) and (13) in the mock data.

    + +
    +
    +    special.cf:
    +        ...
    +        search_base = dc=example, dc=com
    +        query_filter = mail=%s
    +        result_attribute = memberaddr, maildrop
    +        special_result_attribute = memberdn
    +    $ postmap -q agroup@example.com ldap:special.cf
    +    auser@mailhub.example.com,buser@mailhub.example.com,auser@example.org,buser@example.org
    +
    +
    + +

    Note: if the desired member object result attribute is always also +present in the group, you get suprising results, the expansion also +returns the address of the group. This is a known limitation of Postfix +releases prior to 2.4, and is addressed in the new with Postfix 2.4 +"leaf_result_attribute" feature described in ldap_table(5).

    + +

    Our third use case has some groups that are expanded immediately, +and other groups that are forwarded to a dedicated mailing list manager +host for delayed expansion. This uses two LDAP tables, one for users +and forwarded groups and a second for groups that can be expanded +immediately. It is assumed that groups that require forwarding are +never nested members of groups that are directly expanded.

    + +
    +
    +    no_expand.cf:
    +        ...
    +        search_base = dc=example, dc=com
    +        query_filter = mail=%s
    +        result_attribute = maildrop
    +    expand.cf
    +        ...
    +        search_base = dc=example, dc=com
    +        query_filter = mail=%s
    +        result_attribute = memberaddr, maildrop
    +        special_result_attribute = memberdn
    +    $ postmap -q auser@example.com ldap:no_expand.cf ldap:expand.cf
    +    auser@mailhub.example.com
    +    $ postmap -q agroup@example.com ldap:no_expand.cf ldap:expand.cf
    +    auser@mailhub.example.com,buser@mailhub.example.com,auser@example.org,buser@example.org
    +    $ postmap -q bgroup@example.com ldap:no_expand.cf ldap:expand.cf
    +    bgroup@mlm.example.com
    +
    +
    + +

    Non-group objects and groups with delayed expansion (those that have a +maildrop attribute) are rewritten to a single maildrop value. Groups that +don't have a maildrop are expanded as the second use case. This admits +a more elegant solution with Postfix 2.4 and later.

    + +

    Our final use case is the same as the third, but this time uses new +features in Postfix 2.4. We now are able to use just one LDAP table and +no longer need to assume that forwarded groups are never nested inside +expanded groups.

    + +
    +
    +    fancy.cf:
    +        ...
    +        search_base = dc=example, dc=com
    +        query_filter = mail=%s
    +        result_attribute = memberaddr
    +        special_result_attribute = memberdn
    +        terminal_result_attribute = maildrop
    +        leaf_result_attribute = mail
    +    $ postmap -q auser@example.com ldap:fancy.cf
    +    auser@mailhub.example.com
    +    $ postmap -q cuser@example.com ldap:fancy.cf
    +    cuser@example.com
    +    $ postmap -q agroup@example.com ldap:fancy.cf
    +    auser@mailhub.example.com,buser@mailhub.example.com,auser@example.org,buser@example.org
    +    $ postmap -q bgroup@example.com ldap:fancy.cf
    +    bgroup@mlm.example.com
    +
    +
    + +

    Above, delayed expansion is enabled via "terminal_result_attribute", +which, if present, is used as the sole result and all other expansion is +suppressed. Otherwise, the "leaf_result_attribute" is only returned for +leaf objects that don't have a "special_result_attribute" (non-groups), +while the "result_attribute" (direct member address of groups) is returned +at every level of recursive expansion, not just the leaf nodes. This fancy +example illustrates all the features of Postfix 2.4 group expansion.

    +

    Other uses of LDAP lookups

    Other common uses for LDAP lookups include rewriting senders and recipients with Postfix's canonical lookups, for example in order to make mail leaving your site appear to be coming from -"First.Last@site.dom" instead of "userid@site.dom". +"First.Last@example.com" instead of "userid@example.com".

    Notes and things to think about

    @@ -240,9 +451,9 @@ to make mail leaving your site appear to be coming from
    -dn: cn=Accounting Staff List, dc=my, dc=com
    +dn: cn=Accounting Staff List, dc=example, dc=com
     cn: Accounting Staff List
    -o: my.com
    +o: example.com
     objectclass: maillist
     mailacceptinggeneralid: accountingstaff
     mailacceptinggeneralid: accounting-staff
    @@ -341,7 +552,7 @@ contents, please include the applicable bits of some directory entries. 

    external files (ldap:/path/ldap.cf) needed to securely store passwords for plain auth. -
  • Liviu Daia revised the configuration interface and added the main.cf +
  • Liviu Daia revised the configuration interface and added the main.cf configuration feature.
  • Liviu Daia with further refinements from Jose Luis Tallon and diff --git a/postfix/html/SASL_README.html b/postfix/html/SASL_README.html index 5d1728947..3824e7de2 100644 --- a/postfix/html/SASL_README.html +++ b/postfix/html/SASL_README.html @@ -391,7 +391,7 @@ can authenticate against PAM and various other sources. To use PAM, start saslauthd with "-a pam".

    IMPORTANT: saslauthd usually establishes a UNIX domain socket -in /var/run/saslauthd and waits for authentication requests. postfix +in /var/run/saslauthd and waits for authentication requests. Postfix processes must have read+execute permission to this directory or authentication attempts will fail.

    diff --git a/postfix/html/ldap_table.5.html b/postfix/html/ldap_table.5.html index ef9d1cf53..238197abc 100644 --- a/postfix/html/ldap_table.5.html +++ b/postfix/html/ldap_table.5.html @@ -24,6 +24,7 @@ LDAP_TABLE(5) LDAP_TABLE(5) In order to use LDAP lookups, define an LDAP source as a lookup table in main.cf, for example: + alias_maps = ldap:/etc/postfix/ldap-aliases.cf The file /etc/postfix/ldap-aliases.cf has the same format @@ -87,10 +88,12 @@ LDAP_TABLE(5) LDAP_TABLE(5) For example, NEVER do this in a map defining $mydestina- tion: + query_filter = domain=* result_attribute = domain Do this instead: + query_filter = domain=%s result_attribute = domain @@ -102,6 +105,7 @@ LDAP_TABLE(5) LDAP_TABLE(5) server_host (default: localhost) The name of the host running the LDAP server, e.g. + server_host = ldap.example.com Depending on the LDAP client library you're using, @@ -110,10 +114,12 @@ LDAP_TABLE(5) LDAP_TABLE(5) the first one fail. It should also be possible to give each server in the list a different port (overriding server_port below), by naming them like + server_host = ldap.example.com:1444 With OpenLDAP, a (list of) LDAP URLs can be used to specify both the hostname(s) and the port(s): + server_host = ldap://ldap.example.com:1444 ldap://ldap2.example.com:1444 @@ -121,21 +127,25 @@ LDAP_TABLE(5) LDAP_TABLE(5) supported, including connections over UNIX domain sockets, and LDAP SSL (the last one provided that OpenLDAP was compiled with support for SSL): + server_host = ldapi://%2Fsome%2Fpath ldaps://ldap.example.com:636 server_port (default: 389) The port the LDAP server listens on, e.g. + server_port = 778 timeout (default: 10 seconds) The number of seconds a search can take before tim- ing out, e.g. + timeout = 5 search_base (No default; you must configure this) The RFC2253 base DN at which to conduct the search, e.g. + search_base = dc=your, dc=com With Postfix 2.2 and later this parameter supports @@ -184,6 +194,7 @@ LDAP_TABLE(5) LDAP_TABLE(5) The RFC2254 filter used to search the directory, where %s is a substitute for the address Postfix is trying to resolve, e.g. + query_filter = (&(mail=%s)(paid_up=true)) This parameter supports the following '%' expan- @@ -315,6 +326,7 @@ LDAP_TABLE(5) LDAP_TABLE(5) lookups, bare domain lookups and "@domain" lookups are not performed. This can significantly reduce the query load on the LDAP server. + domain = postfix.org, hash:/etc/postfix/search- domains @@ -330,13 +342,15 @@ LDAP_TABLE(5) LDAP_TABLE(5) The attribute(s) Postfix will read from any direc- tory entries returned by the lookup, to be resolved to an email address. + result_attribute = mailbox, maildrop - special_result_attribute (No default) + special_result_attribute (default: empty) The attribute(s) of directory entries that can con- tain DNs or URLs. If found, a recursive subsequent search is done using their values. - special_result_attribute = member + + special_result_attribute = memberdn DN recursion retrieves the same result_attributes as the main query, including the special attributes @@ -347,6 +361,51 @@ LDAP_TABLE(5) LDAP_TABLE(5) map's special result attributes, these are also retrieved and used recursively. + terminal_result_attribute (default: empty) + When one or more terminal result attributes are + found in an LDAP entry, all other result attributes + are ignored and only the terminal result attributes + are returned. This is useful for delegating expan- + sion of group members to a particular host, by + using an optional "maildrop" attribute on selected + groups to route the group to a specific host, where + the group is expanded, possibly via mailing-list + manager or other special processing. + + terminal_result_attribute = maildrop + + This feature is available with Postfix >= 2.4. + + leaf_result_attribute (default: empty) + When one or more special result attributes are + found in a non-terminal (see above) LDAP entry, + leaf result attributes are excluded from the expan- + sion of that entry. This is useful when expanding + groups and the desired mail address attribute(s) of + the member objects obtained via DN or URI recursion + are also present in the group object. To only + return the attribute values from the leaf objects + and not the containing group, add the attribute to + the leaf_result_attribute list, and not the + result_attribute list, which is always expanded. + Note, the default value of "result_attribute" is + not empty, you may want to set it explicitly empty + when using "leaf_result_attribute" to expand the + group to a list of member DN addresses. If groups + have both member DN references AND attributes that + hold multiple string valued rfc822 addresses, then + the string attributes go in "result_attribute". + The attributes that represent the email addresses + of objects referenced via a DN (or LDAP URI) go in + "leaf_result_attribute". + + result_attribute = memberaddr + special_result_attribute = memberdn + terminal_result_attribute = maildrop + leaf_result_attribute = mail + + This feature is available with Postfix >= 2.4. + scope (default: sub) The LDAP search scope: sub, base, or one. These translate into LDAP_SCOPE_SUBTREE, LDAP_SCOPE_BASE, @@ -356,6 +415,7 @@ LDAP_TABLE(5) LDAP_TABLE(5) Whether or not to bind to the LDAP server. Newer LDAP implementations don't require clients to bind, which saves time. Example: + bind = no If you do need to bind, you might consider config- @@ -369,6 +429,7 @@ LDAP_TABLE(5) LDAP_TABLE(5) bind_dn (default: empty) If you do have to bind, do it with this distin- guished name. Example: + bind_dn = uid=postfix, dc=your, dc=com bind_pw (default: empty) @@ -381,6 +442,7 @@ LDAP_TABLE(5) LDAP_TABLE(5) because main.cf needs to be world readable to allow local accounts to submit mail via the sendmail com- mand. Example: + bind_pw = postfixpw cache (IGNORED with a warning) @@ -459,13 +521,16 @@ LDAP_TABLE(5) LDAP_TABLE(5) LDAP SSL service can be requested by using a LDAP SSL URL in the server_host parameter: + server_host = ldaps://ldap.example.com:636 STARTTLS can be turned on with the start_tls parameter: + start_tls = yes Both forms require LDAP protocol version 3, which has to be set explicitly with: + version = 3 If any of the Postfix programs querying the map is config- @@ -530,22 +595,24 @@ LDAP_TABLE(5) LDAP_TABLE(5) EXAMPLE Here's a basic example for using LDAP to look up local(8) aliases. Assume that in main.cf, you have: + alias_maps = hash:/etc/aliases, ldap:/etc/postfix/ldap-aliases.cf and in ldap:/etc/postfix/ldap-aliases.cf you have: - server_host = ldap.my.com - search_base = dc=my, dc=com + + server_host = ldap.example.com + search_base = dc=example, dc=com Upon receiving mail for a local address "ldapuser" that isn't found in the /etc/aliases database, Postfix will - search the LDAP server listening at port 389 on - ldap.my.com. It will bind anonymously, search for any - directory entries whose mailacceptinggeneralid attribute - is "ldapuser", read the "maildrop" attributes of those - found, and build a list of their maildrops, which will be - treated as RFC822 addresses to which the message will be - delivered. + search the LDAP server listening at port 389 on ldap.exam- + ple.com. It will bind anonymously, search for any direc- + tory entries whose mailacceptinggeneralid attribute is + "ldapuser", read the "maildrop" attributes of those found, + and build a list of their maildrops, which will be treated + as RFC822 addresses to which the message will be deliv- + ered. SEE ALSO postmap(1), Postfix lookup table manager diff --git a/postfix/man/man5/ldap_table.5 b/postfix/man/man5/ldap_table.5 index 4e22f4987..1cb4f4918 100644 --- a/postfix/man/man5/ldap_table.5 +++ b/postfix/man/man5/ldap_table.5 @@ -22,6 +22,7 @@ Alternatively, lookup tables can be specified as LDAP databases. In order to use LDAP lookups, define an LDAP source as a lookup table in main.cf, for example: + .ti +4 alias_maps = ldap:/etc/postfix/ldap-aliases.cf @@ -87,6 +88,7 @@ an arbitrary value. With LDAP databases it is not uncommon to return the key itself. For example, NEVER do this in a map defining $mydestination: + .in +4 query_filter = domain=* .br @@ -94,6 +96,7 @@ result_attribute = domain .in -4 Do this instead: + .in +4 query_filter = domain=%s .br @@ -110,6 +113,7 @@ Postfix configuration routines understand how to deal with quoted strings. .IP "\fBserver_host (default: localhost)\fR" The name of the host running the LDAP server, e.g. + .ti +4 server_host = ldap.example.com @@ -118,11 +122,13 @@ be possible to specify multiple servers here, with the library trying them in order should the first one fail. It should also be possible to give each server in the list a different port (overriding \fBserver_port\fR below), by naming them like + .ti +4 server_host = ldap.example.com:1444 With OpenLDAP, a (list of) LDAP URLs can be used to specify both the hostname(s) and the port(s): + .ti +4 server_host = ldap://ldap.example.com:1444 .ti +8 @@ -132,20 +138,24 @@ All LDAP URLs accepted by the OpenLDAP library are supported, including connections over UNIX domain sockets, and LDAP SSL (the last one provided that OpenLDAP was compiled with support for SSL): + .ti +4 server_host = ldapi://%2Fsome%2Fpath .ti +8 ldaps://ldap.example.com:636 .IP "\fBserver_port (default: 389)\fR" The port the LDAP server listens on, e.g. + .ti +4 server_port = 778 .IP "\fBtimeout (default: 10 seconds)\fR" The number of seconds a search can take before timing out, e.g. + .ti +4 timeout = 5 .IP "\fBsearch_base (No default; you must configure this)\fR" The RFC2253 base DN at which to conduct the search, e.g. + .ti +4 search_base = dc=your, dc=com .IP @@ -188,6 +198,7 @@ no results. The RFC2254 filter used to search the directory, where \fB%s\fR is a substitute for the address Postfix is trying to resolve, e.g. + .ti +4 query_filter = (&(mail=%s)(paid_up=true)) @@ -297,6 +308,7 @@ keys with a *non-empty* localpart and a matching domain are eligible for lookup: 'user' lookups, bare domain lookups and "@domain" lookups are not performed. This can significantly reduce the query load on the LDAP server. + .ti +4 domain = postfix.org, hash:/etc/postfix/searchdomains @@ -310,14 +322,16 @@ This feature is available in Postfix 1.0 and later. The attribute(s) Postfix will read from any directory entries returned by the lookup, to be resolved to an email address. + .ti +4 result_attribute = mailbox, maildrop -.IP "\fBspecial_result_attribute (No default)\fR" +.IP "\fBspecial_result_attribute (default: empty)\fR" The attribute(s) of directory entries that can contain DNs or URLs. If found, a recursive subsequent search is done using their values. + .ti +4 -special_result_attribute = member +special_result_attribute = memberdn DN recursion retrieves the same result_attributes as the main query, including the special attributes for further @@ -326,6 +340,47 @@ that are included in the URI definition and are *also* listed in "result_attribute". If the URI lists any of the map's special result attributes, these are also retrieved and used recursively. +.IP "\fBterminal_result_attribute (default: empty)\fR" +When one or more terminal result attributes are found in an LDAP +entry, all other result attributes are ignored and only the terminal +result attributes are returned. This is useful for delegating expansion +of group members to a particular host, by using an optional "maildrop" +attribute on selected groups to route the group to a specific host, +where the group is expanded, possibly via mailing-list manager or +other special processing. + +.ti +4 +terminal_result_attribute = maildrop + +This feature is available with Postfix >= 2.4. +.IP "\fBleaf_result_attribute (default: empty)\fR" +When one or more special result attributes are found in a non-terminal +(see above) LDAP entry, leaf result attributes are excluded from the +expansion of that entry. This is useful when expanding groups and the +desired mail address attribute(s) of the member objects obtained via +DN or URI recursion are also present in the group object. To only +return the attribute values from the leaf objects and not the +containing group, add the attribute to the leaf_result_attribute list, +and not the result_attribute list, which is always expanded. Note, +the default value of "result_attribute" is not empty, you may want to +set it explicitly empty when using "leaf_result_attribute" to expand +the group to a list of member DN addresses. If groups have both +member DN references AND attributes that hold multiple string valued +rfc822 addresses, then the string attributes go in "result_attribute". +The attributes that represent the email addresses of objects +referenced via a DN (or LDAP URI) go in "leaf_result_attribute". + +.in +4 +result_attribute = memberaddr +.br +special_result_attribute = memberdn +.br +terminal_result_attribute = maildrop +.br +leaf_result_attribute = mail +.in -4 + +This feature is available with Postfix >= 2.4. .IP "\fBscope (default: sub)\fR" The LDAP search scope: \fBsub\fR, \fBbase\fR, or \fBone\fR. These translate into LDAP_SCOPE_SUBTREE, LDAP_SCOPE_BASE, @@ -334,6 +389,7 @@ and LDAP_SCOPE_ONELEVEL. Whether or not to bind to the LDAP server. Newer LDAP implementations don't require clients to bind, which saves time. Example: + .ti +4 bind = no @@ -346,6 +402,7 @@ should prevent the password from traversing the network in the clear. .IP "\fBbind_dn (default: empty)\fR" If you do have to bind, do it with this distinguished name. Example: + .ti +4 bind_dn = uid=postfix, dc=your, dc=com .IP "\fBbind_pw (default: empty)\fR" @@ -357,6 +414,7 @@ main.cf, it is not possible to securely store the bind password. This is because main.cf needs to be world readable to allow local accounts to submit mail via the sendmail command. Example: + .ti +4 bind_pw = postfixpw .IP "\fBcache (IGNORED with a warning)\fR" @@ -426,15 +484,18 @@ issue the STARTTLS command. LDAP SSL service can be requested by using a LDAP SSL URL in the server_host parameter: + .ti +4 server_host = ldaps://ldap.example.com:636 STARTTLS can be turned on with the start_tls parameter: + .ti +4 start_tls = yes Both forms require LDAP protocol version 3, which has to be set explicitly with: + .ti +4 version = 3 @@ -488,21 +549,23 @@ Cipher suite to use in SSL/TLS negotiations. Here's a basic example for using LDAP to look up local(8) aliases. Assume that in main.cf, you have: + .ti +4 alias_maps = hash:/etc/aliases, .ti +8 ldap:/etc/postfix/ldap-aliases.cf and in ldap:/etc/postfix/ldap-aliases.cf you have: + .in +4 -server_host = ldap.my.com +server_host = ldap.example.com .br -search_base = dc=my, dc=com +search_base = dc=example, dc=com .in -4 Upon receiving mail for a local address "ldapuser" that isn't found in the /etc/aliases database, Postfix will -search the LDAP server listening at port 389 on ldap.my.com. +search the LDAP server listening at port 389 on ldap.example.com. It will bind anonymously, search for any directory entries whose mailacceptinggeneralid attribute is "ldapuser", read the "maildrop" attributes of those found, and build a list diff --git a/postfix/proto/ADDRESS_VERIFICATION_README.html b/postfix/proto/ADDRESS_VERIFICATION_README.html index 1d66b4fe9..d3ff04385 100644 --- a/postfix/proto/ADDRESS_VERIFICATION_README.html +++ b/postfix/proto/ADDRESS_VERIFICATION_README.html @@ -21,7 +21,8 @@

    The sender/recipient address verification feature described in this document is suitable only for low-traffic sites. It performs poorly -under high load and may cause your site to be blacklisted by some +under high load; excessive sender address verification activity may +even cause your site to be blacklisted by some providers. See the "Limitations" section below for details.

    diff --git a/postfix/proto/LDAP_README.html b/postfix/proto/LDAP_README.html index f9573a897..7b8b60857 100644 --- a/postfix/proto/LDAP_README.html +++ b/postfix/proto/LDAP_README.html @@ -41,6 +41,8 @@ it to each.

  • Example: virtual domains/addresses +
  • Example: expanding LDAP groups +
  • Other uses of LDAP lookups
  • Notes and things to think about @@ -152,14 +154,14 @@ alias_maps = hash:/etc/aliases, ldap:/etc/postfix/ldap-aliases.cf
    -server_host = ldap.my.com
    -search_base = dc=my, dc=com
    +server_host = ldap.example.com
    +search_base = dc=example, dc=com
     

    Upon receiving mail for a local address "ldapuser" that isn't found in the /etc/aliases database, Postfix will search the LDAP -server listening at port 389 on ldap.my.com. It will bind anonymously, +server listening at port 389 on ldap.example.com. It will bind anonymously, search for any directory entries whose mailacceptinggeneralid attribute is "ldapuser", read the "maildrop" attributes of those found, and build a list of their maildrops, which will be treated @@ -176,7 +178,7 @@ of your virtual recipient's mailacceptinggeneralid attributes are fully qualified with their virtual domains. Finally, if you want to designate a directory entry as the default user for a virtual domain, just give it an additional mailacceptinggeneralid (or the -equivalent in your directory) of "@virtual.dom". That's right, no +equivalent in your directory) of "@fake.dom". That's right, no user part. If you don't want a catchall user, omit this step and mail to unknown users in the domain will simply bounce.

    @@ -212,12 +214,221 @@ go to this entry ...

    maildrop, e.g. "normaluser@fake.dom" and "normaluser@real.dom".

    +

    Example: expanding LDAP groups

    + +

    LDAP is frequently used to store group member information, and Postfix +supports expanding a group's email address to the list of email addresses +of the group members. There are a number of ways of handling LDAP groups, +which will be illustrated via the mock LDAP entries and implied schema +below. This shows two group entries "agroup" and "bgroup" and four +user entries "auser", "buser", "cuser" and "duser". The group "agroup" +has the users "auser" (1) and "buser" (2) as members via DN references +in the multi-valued attribute "memberdn", and direct email addresses of +two external users "auser@example.org" (3) and "buser@example.org" (4) +stored in the multi-valued attribute "memberaddr". The same is true of +"bgroup" and "cuser"/"duser" (6)/(7)/(8)/(9), but "bgroup" also has a +"maildrop" attribute of "bgroup@mlm.example.com" (5):

    + +
    +
    +     dn: cn=agroup, dc=example, dc=com
    +     objectclass: top
    +     objectclass: ldapgroup
    +     cn: agroup
    +     mail: agroup@example.com
    +1 -> memberdn: uid=auser, dc=example, dc=com
    +2 -> memberdn: uid=buser, dc=example, dc=com
    +3 -> memberaddr: auser@example.org
    +4 -> memberaddr: buser@example.org
    +
    +
    + +
    +     dn: cn=bgroup, dc=example, dc=com
    +     objectclass: top
    +     objectclass: ldapgroup
    +     cn: bgroup
    +     mail: bgroup@example.com
    +5 -> maildrop: bgroup@mlm.example.com
    +6 -> memberdn: uid=cuser, dc=example, dc=com
    +7 -> memberdn: uid=duser, dc=example, dc=com
    +8 -> memberaddr: cuser@example.org
    +9 -> memberaddr: duser@example.org
    +
    +
    + +
    +     dn: uid=auser, dc=example, dc=com
    +     objectclass: top
    +     objectclass: ldapuser
    +     uid: auser
    +10 -> mail: auser@example.com
    +11 -> maildrop: auser@mailhub.example.com
    +
    +
    + +
    +     dn: uid=buser, dc=example, dc=com
    +     objectclass: top
    +     objectclass: ldapuser
    +     uid: buser
    +12 -> mail: buser@example.com
    +13 -> maildrop: buser@mailhub.example.com
    +
    +
    + +
    +     dn: uid=cuser, dc=example, dc=com
    +     objectclass: top
    +     objectclass: ldapuser
    +     uid: cuser
    +14 -> mail: cuser@example.com
    +
    +
    + +
    +     dn: uid=duser, dc=example, dc=com
    +     objectclass: top
    +     objectclass: ldapuser
    +     uid: duser
    +15 -> mail: duser@example.com
    +
    +
    + +
    + +

    Our first use case ignores the "memberdn" attributes, and assumes +that groups hold only direct "memberaddr" strings as in (3), (4), (8) and +(9). The goal is to map the group address to the list of constituent +"memberaddr" values. This is simple, ignoring the various connection +related settings (hosts, ports, bind settings, timeouts, ...) we have: +

    + +
    +
    +    simple.cf:
    +        ...
    +        search_base = dc=example, dc=com
    +        query_filter = mail=%s
    +        result_attribute = memberaddr
    +    $ postmap -q agroup@example.com ldap:simple.cf
    +    auser@example.org,buser@example.org
    +
    +
    + +

    We search "dc=example, dc=com". The "mail" attribute is used in the +query_filter to locate the right group, the "result_attribute" setting +described in ldap_table(5) is used to specify that "memberaddr" values +from the matching group are to be returned as a comma separated list. +Always check tables using postmap(1) with the "-q" option, before +deploying them into production use in main.cf.

    + +

    Our second use case also expands "memberdn" attributes (1), (2), +(6) and (7), follows the DN references and returns the "maildrop" of the +referenced user entries. Here we use the "special_result_attribute" +setting from ldap_table(5) to designate the "memberdn" attribute +as holding DNs of the desired member entries. The "result_attribute" +setting selects which attributes are returned from the selected DNs. It +is important to choose a result attribute that is not also present in +the group object, because result attributes are collected from both +the group and the member DNs. In this case we choose "maildrop" and +assume for the moment that groups never have a "maildrop" (the "bgroup" +"maildrop" attribute is for a different use case). The returned data for +"auser" and "buser" is from items (11) and (13) in the mock data.

    + +
    +
    +    special.cf:
    +        ...
    +        search_base = dc=example, dc=com
    +        query_filter = mail=%s
    +        result_attribute = memberaddr, maildrop
    +        special_result_attribute = memberdn
    +    $ postmap -q agroup@example.com ldap:special.cf
    +    auser@mailhub.example.com,buser@mailhub.example.com,auser@example.org,buser@example.org
    +
    +
    + +

    Note: if the desired member object result attribute is always also +present in the group, you get suprising results, the expansion also +returns the address of the group. This is a known limitation of Postfix +releases prior to 2.4, and is addressed in the new with Postfix 2.4 +"leaf_result_attribute" feature described in ldap_table(5).

    + +

    Our third use case has some groups that are expanded immediately, +and other groups that are forwarded to a dedicated mailing list manager +host for delayed expansion. This uses two LDAP tables, one for users +and forwarded groups and a second for groups that can be expanded +immediately. It is assumed that groups that require forwarding are +never nested members of groups that are directly expanded.

    + +
    +
    +    no_expand.cf:
    +        ...
    +        search_base = dc=example, dc=com
    +        query_filter = mail=%s
    +        result_attribute = maildrop
    +    expand.cf
    +        ...
    +        search_base = dc=example, dc=com
    +        query_filter = mail=%s
    +        result_attribute = memberaddr, maildrop
    +        special_result_attribute = memberdn
    +    $ postmap -q auser@example.com ldap:no_expand.cf ldap:expand.cf
    +    auser@mailhub.example.com
    +    $ postmap -q agroup@example.com ldap:no_expand.cf ldap:expand.cf
    +    auser@mailhub.example.com,buser@mailhub.example.com,auser@example.org,buser@example.org
    +    $ postmap -q bgroup@example.com ldap:no_expand.cf ldap:expand.cf
    +    bgroup@mlm.example.com
    +
    +
    + +

    Non-group objects and groups with delayed expansion (those that have a +maildrop attribute) are rewritten to a single maildrop value. Groups that +don't have a maildrop are expanded as the second use case. This admits +a more elegant solution with Postfix 2.4 and later.

    + +

    Our final use case is the same as the third, but this time uses new +features in Postfix 2.4. We now are able to use just one LDAP table and +no longer need to assume that forwarded groups are never nested inside +expanded groups.

    + +
    +
    +    fancy.cf:
    +        ...
    +        search_base = dc=example, dc=com
    +        query_filter = mail=%s
    +        result_attribute = memberaddr
    +        special_result_attribute = memberdn
    +        terminal_result_attribute = maildrop
    +        leaf_result_attribute = mail
    +    $ postmap -q auser@example.com ldap:fancy.cf
    +    auser@mailhub.example.com
    +    $ postmap -q cuser@example.com ldap:fancy.cf
    +    cuser@example.com
    +    $ postmap -q agroup@example.com ldap:fancy.cf
    +    auser@mailhub.example.com,buser@mailhub.example.com,auser@example.org,buser@example.org
    +    $ postmap -q bgroup@example.com ldap:fancy.cf
    +    bgroup@mlm.example.com
    +
    +
    + +

    Above, delayed expansion is enabled via "terminal_result_attribute", +which, if present, is used as the sole result and all other expansion is +suppressed. Otherwise, the "leaf_result_attribute" is only returned for +leaf objects that don't have a "special_result_attribute" (non-groups), +while the "result_attribute" (direct member address of groups) is returned +at every level of recursive expansion, not just the leaf nodes. This fancy +example illustrates all the features of Postfix 2.4 group expansion.

    +

    Other uses of LDAP lookups

    Other common uses for LDAP lookups include rewriting senders and recipients with Postfix's canonical lookups, for example in order to make mail leaving your site appear to be coming from -"First.Last@site.dom" instead of "userid@site.dom". +"First.Last@example.com" instead of "userid@example.com".

    Notes and things to think about

    @@ -240,9 +451,9 @@ to make mail leaving your site appear to be coming from
    -dn: cn=Accounting Staff List, dc=my, dc=com
    +dn: cn=Accounting Staff List, dc=example, dc=com
     cn: Accounting Staff List
    -o: my.com
    +o: example.com
     objectclass: maillist
     mailacceptinggeneralid: accountingstaff
     mailacceptinggeneralid: accounting-staff
    diff --git a/postfix/proto/ldap_table b/postfix/proto/ldap_table
    index d8d2d2ef0..8d11e7176 100644
    --- a/postfix/proto/ldap_table
    +++ b/postfix/proto/ldap_table
    @@ -16,6 +16,7 @@
     #
     #	In order to use LDAP lookups, define an LDAP source as a lookup
     #	table in main.cf, for example:
    +#
     # .ti +4
     #	alias_maps = ldap:/etc/postfix/ldap-aliases.cf
     #
    @@ -77,6 +78,7 @@
     #	return the key itself.
     #
     #	For example, NEVER do this in a map defining $mydestination:
    +#
     # .in +4
     #	query_filter = domain=* 
     # .br
    @@ -84,6 +86,7 @@
     # .in -4
     #
     #	Do this instead:
    +#
     # .in +4
     #	query_filter = domain=%s 
     # .br
    @@ -98,6 +101,7 @@
     #	strings.
     # .IP "\fBserver_host (default: localhost)\fR"
     #	The name of the host running the LDAP server, e.g.
    +#
     # .ti +4
     #	server_host = ldap.example.com
     #
    @@ -106,11 +110,13 @@
     #	trying them in order should the first one fail. It should also
     #	be possible to give each server in the list a different port
     #	(overriding \fBserver_port\fR below), by naming them like
    +#
     # .ti +4
     #	server_host = ldap.example.com:1444
     #
     #	With OpenLDAP, a (list of) LDAP URLs can be used to specify both
     #	the hostname(s) and the port(s):
    +#
     # .ti +4
     #	server_host = ldap://ldap.example.com:1444
     # .ti +8
    @@ -120,20 +126,24 @@
     #	including connections over UNIX domain sockets, and LDAP SSL
     #	(the last one provided that OpenLDAP was compiled with support
     #	for SSL):
    +#
     # .ti +4
     #	server_host = ldapi://%2Fsome%2Fpath
     # .ti +8
     #		ldaps://ldap.example.com:636
     # .IP "\fBserver_port (default: 389)\fR"
     #	The port the LDAP server listens on, e.g.
    +#
     # .ti +4
     #	server_port = 778
     # .IP "\fBtimeout (default: 10 seconds)\fR"
     #	The number of seconds a search can take before timing out, e.g.
    +#
     # .ti +4
     #	timeout = 5
     # .IP "\fBsearch_base (No default; you must configure this)\fR"
     #	The RFC2253 base DN at which to conduct the search, e.g.
    +#
     # .ti +4
     #	search_base = dc=your, dc=com
     # .IP
    @@ -176,6 +186,7 @@
     #	The RFC2254 filter used to search the directory, where \fB%s\fR
     #	is a substitute for the address Postfix is trying to resolve,
     #	e.g.
    +#
     # .ti +4
     #	query_filter = (&(mail=%s)(paid_up=true))
     #
    @@ -285,6 +296,7 @@
     #	are eligible for lookup: 'user' lookups, bare domain lookups
     #	and "@domain" lookups are not performed. This can significantly
     #	reduce the query load on the LDAP server.
    +#
     # .ti +4
     #	domain = postfix.org, hash:/etc/postfix/searchdomains
     #
    @@ -298,14 +310,16 @@
     #	The attribute(s) Postfix will read from any directory
     #	entries returned by the lookup, to be resolved to an email
     #	address.
    +#
     # .ti +4
     #	result_attribute = mailbox, maildrop
    -# .IP "\fBspecial_result_attribute (No default)\fR"
    +# .IP "\fBspecial_result_attribute (default: empty)\fR"
     #	The attribute(s) of directory entries that can contain DNs
     #	or URLs. If found, a recursive subsequent search is done
     #	using their values.
    +#
     # .ti +4
    -#	special_result_attribute = member
    +#	special_result_attribute = memberdn
     #
     #	DN recursion retrieves the same result_attributes as the
     #	main query, including the special attributes for further
    @@ -314,6 +328,47 @@
     #	listed in "result_attribute". If the URI lists any of the
     #	map's special result attributes, these are also retrieved
     #	and used recursively.
    +# .IP "\fBterminal_result_attribute (default: empty)\fR"
    +#	When one or more terminal result attributes are found in an LDAP
    +#	entry, all other result attributes are ignored and only the terminal
    +#	result attributes are returned. This is useful for delegating expansion
    +#	of group members to a particular host, by using an optional "maildrop"
    +#	attribute on selected groups to route the group to a specific host,
    +#	where the group is expanded, possibly via mailing-list manager or
    +#	other special processing.
    +#
    +# .ti +4
    +#	terminal_result_attribute = maildrop
    +#
    +#	This feature is available with Postfix >= 2.4.
    +# .IP "\fBleaf_result_attribute (default: empty)\fR"
    +#	When one or more special result attributes are found in a non-terminal
    +#	(see above) LDAP entry, leaf result attributes are excluded from the
    +#	expansion of that entry. This is useful when expanding groups and the
    +#	desired mail address attribute(s) of the member objects obtained via
    +#	DN or URI recursion are also present in the group object. To only
    +#	return the attribute values from the leaf objects and not the
    +#	containing group, add the attribute to the leaf_result_attribute list,
    +#	and not the result_attribute list, which is always expanded. Note,
    +#	the default value of "result_attribute" is not empty, you may want to
    +#	set it explicitly empty when using "leaf_result_attribute" to expand
    +#	the group to a list of member DN addresses. If groups have both
    +#	member DN references AND attributes that hold multiple string valued
    +#	rfc822 addresses, then the string attributes go in "result_attribute".
    +#	The attributes that represent the email addresses of objects
    +#	referenced via a DN (or LDAP URI) go in "leaf_result_attribute".
    +#
    +# .in +4
    +#	result_attribute = memberaddr
    +# .br
    +#	special_result_attribute = memberdn
    +# .br
    +#	terminal_result_attribute = maildrop
    +# .br
    +#	leaf_result_attribute = mail
    +# .in -4
    +#
    +#	This feature is available with Postfix >= 2.4.
     # .IP "\fBscope (default: sub)\fR"
     #	The LDAP search scope: \fBsub\fR, \fBbase\fR, or \fBone\fR.
     #	These translate into LDAP_SCOPE_SUBTREE, LDAP_SCOPE_BASE,
    @@ -322,6 +377,7 @@
     #	Whether or not to bind to the LDAP server. Newer LDAP
     #	implementations don't require clients to bind, which saves
     #	time. Example:
    +#
     # .ti +4
     #	bind = no
     #
    @@ -334,6 +390,7 @@
     #	the clear.
     # .IP "\fBbind_dn (default: empty)\fR"
     #	If you do have to bind, do it with this distinguished name. Example:
    +#
     # .ti +4
     #	bind_dn = uid=postfix, dc=your, dc=com
     # .IP "\fBbind_pw (default: empty)\fR"
    @@ -345,6 +402,7 @@
     #	password. This is because main.cf needs to be world readable
     #	to allow local accounts to submit mail via the sendmail
     #	command. Example:
    +#
     # .ti +4
     #	bind_pw = postfixpw
     # .IP "\fBcache (IGNORED with a warning)\fR"
    @@ -412,15 +470,18 @@
     #
     #	LDAP SSL service can be requested by using a LDAP SSL URL
     #	in the server_host parameter:
    +#
     # .ti +4
     #	server_host = ldaps://ldap.example.com:636
     #
     #	STARTTLS can be turned on with the start_tls parameter:
    +#
     # .ti +4
     #	start_tls = yes
     #
     #	Both forms require LDAP protocol version 3, which has to be set
     #	explicitly with:
    +#
     # .ti +4
     #	version = 3
     #
    @@ -472,21 +533,23 @@
     #	Here's a basic example for using LDAP to look up local(8)
     #	aliases.
     #	Assume that in main.cf, you have:
    +#
     # .ti +4
     #	alias_maps = hash:/etc/aliases,
     # .ti +8
     #	ldap:/etc/postfix/ldap-aliases.cf
     #
     #	and in ldap:/etc/postfix/ldap-aliases.cf you have:
    +#
     # .in +4
    -#	server_host = ldap.my.com
    +#	server_host = ldap.example.com
     # .br
    -#	search_base = dc=my, dc=com
    +#	search_base = dc=example, dc=com
     # .in -4
     #
     #	Upon receiving mail for a local address "ldapuser" that
     #	isn't found in the /etc/aliases database, Postfix will
    -#	search the LDAP server listening at port 389 on ldap.my.com.
    +#	search the LDAP server listening at port 389 on ldap.example.com.
     #	It will bind anonymously, search for any directory entries
     #	whose mailacceptinggeneralid attribute is "ldapuser", read
     #	the "maildrop" attributes of those found, and build a list
    diff --git a/postfix/src/anvil/Makefile.in b/postfix/src/anvil/Makefile.in
    index 62946461e..14772fa32 100644
    --- a/postfix/src/anvil/Makefile.in
    +++ b/postfix/src/anvil/Makefile.in
    @@ -67,6 +67,7 @@ anvil.o: ../../include/mail_conf.h
     anvil.o: ../../include/mail_params.h
     anvil.o: ../../include/mail_proto.h
     anvil.o: ../../include/mail_server.h
    +anvil.o: ../../include/mail_version.h
     anvil.o: ../../include/msg.h
     anvil.o: ../../include/mymalloc.h
     anvil.o: ../../include/stringops.h
    diff --git a/postfix/src/anvil/anvil.c b/postfix/src/anvil/anvil.c
    index 0308f8d26..ab42073a4 100644
    --- a/postfix/src/anvil/anvil.c
    +++ b/postfix/src/anvil/anvil.c
    @@ -267,6 +267,7 @@
     
     #include 
     #include 
    +#include 
     #include 
     #include 
     
    @@ -945,6 +946,8 @@ static void post_jail_init(char *unused_name, char **unused_argv)
     	var_idle_limit = var_anvil_time_unit;
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the multi-threaded skeleton */
     
     int     main(int argc, char **argv)
    @@ -955,6 +958,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         multi_server_main(argc, argv, anvil_service,
     		      MAIL_SERVER_TIME_TABLE, time_table,
     		      MAIL_SERVER_POST_INIT, post_jail_init,
    diff --git a/postfix/src/bounce/Makefile.in b/postfix/src/bounce/Makefile.in
    index ddfaaa2eb..09de6e9d0 100644
    --- a/postfix/src/bounce/Makefile.in
    +++ b/postfix/src/bounce/Makefile.in
    @@ -107,6 +107,7 @@ bounce.o: ../../include/mail_params.h
     bounce.o: ../../include/mail_proto.h
     bounce.o: ../../include/mail_queue.h
     bounce.o: ../../include/mail_server.h
    +bounce.o: ../../include/mail_version.h
     bounce.o: ../../include/msg.h
     bounce.o: ../../include/msg_stats.h
     bounce.o: ../../include/rcpt_buf.h
    @@ -166,6 +167,7 @@ bounce_notify_service.o: ../../include/deliver_request.h
     bounce_notify_service.o: ../../include/dsn.h
     bounce_notify_service.o: ../../include/dsn_buf.h
     bounce_notify_service.o: ../../include/dsn_mask.h
    +bounce_notify_service.o: ../../include/int_filt.h
     bounce_notify_service.o: ../../include/mail_addr.h
     bounce_notify_service.o: ../../include/mail_error.h
     bounce_notify_service.o: ../../include/mail_params.h
    @@ -191,6 +193,7 @@ bounce_notify_util.o: ../../include/dsn.h
     bounce_notify_util.o: ../../include/dsn_buf.h
     bounce_notify_util.o: ../../include/dsn_mask.h
     bounce_notify_util.o: ../../include/events.h
    +bounce_notify_util.o: ../../include/int_filt.h
     bounce_notify_util.o: ../../include/iostuff.h
     bounce_notify_util.o: ../../include/is_header.h
     bounce_notify_util.o: ../../include/lex_822.h
    @@ -228,6 +231,7 @@ bounce_notify_verp.o: ../../include/deliver_request.h
     bounce_notify_verp.o: ../../include/dsn.h
     bounce_notify_verp.o: ../../include/dsn_buf.h
     bounce_notify_verp.o: ../../include/dsn_mask.h
    +bounce_notify_verp.o: ../../include/int_filt.h
     bounce_notify_verp.o: ../../include/mail_addr.h
     bounce_notify_verp.o: ../../include/mail_error.h
     bounce_notify_verp.o: ../../include/mail_params.h
    @@ -254,6 +258,7 @@ bounce_one_service.o: ../../include/deliver_request.h
     bounce_one_service.o: ../../include/dsn.h
     bounce_one_service.o: ../../include/dsn_buf.h
     bounce_one_service.o: ../../include/dsn_mask.h
    +bounce_one_service.o: ../../include/int_filt.h
     bounce_one_service.o: ../../include/mail_addr.h
     bounce_one_service.o: ../../include/mail_error.h
     bounce_one_service.o: ../../include/mail_params.h
    @@ -309,6 +314,7 @@ bounce_trace_service.o: ../../include/deliver_request.h
     bounce_trace_service.o: ../../include/dsn.h
     bounce_trace_service.o: ../../include/dsn_buf.h
     bounce_trace_service.o: ../../include/dsn_mask.h
    +bounce_trace_service.o: ../../include/int_filt.h
     bounce_trace_service.o: ../../include/mail_addr.h
     bounce_trace_service.o: ../../include/mail_error.h
     bounce_trace_service.o: ../../include/mail_params.h
    @@ -332,6 +338,7 @@ bounce_warn_service.o: ../../include/cleanup_user.h
     bounce_warn_service.o: ../../include/dsn.h
     bounce_warn_service.o: ../../include/dsn_buf.h
     bounce_warn_service.o: ../../include/dsn_mask.h
    +bounce_warn_service.o: ../../include/int_filt.h
     bounce_warn_service.o: ../../include/mail_addr.h
     bounce_warn_service.o: ../../include/mail_error.h
     bounce_warn_service.o: ../../include/mail_params.h
    diff --git a/postfix/src/bounce/bounce.c b/postfix/src/bounce/bounce.c
    index bef13b961..483aa54c9 100644
    --- a/postfix/src/bounce/bounce.c
    +++ b/postfix/src/bounce/bounce.c
    @@ -154,6 +154,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -576,8 +577,8 @@ static void post_jail_init(char *service_name, char **unused_argv)
         /*
          * Special case: dump bounce templates. This is not part of the master(5)
          * public interface. This internal interface is used by the postconf
    -     * command. It was implemented before bounce templates were isolated
    -     * into modules that could have been called directly.
    +     * command. It was implemented before bounce templates were isolated into
    +     * modules that could have been called directly.
          */
         if (strcmp(service_name, "dump_templates") == 0) {
     	bounce_templates_dump(VSTREAM_OUT, bounce_templates);
    @@ -604,6 +605,8 @@ static void post_jail_init(char *service_name, char **unused_argv)
         dsn_buf = dsb_create();
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - the main program */
     
     int     main(int argc, char **argv)
    @@ -626,6 +629,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Pass control to the single-threaded service skeleton.
          */
    diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in
    index ecd317a6c..fa98471ae 100644
    --- a/postfix/src/cleanup/Makefile.in
    +++ b/postfix/src/cleanup/Makefile.in
    @@ -319,6 +319,7 @@ cleanup.o: ../../include/mail_params.h
     cleanup.o: ../../include/mail_proto.h
     cleanup.o: ../../include/mail_server.h
     cleanup.o: ../../include/mail_stream.h
    +cleanup.o: ../../include/mail_version.h
     cleanup.o: ../../include/maps.h
     cleanup.o: ../../include/match_list.h
     cleanup.o: ../../include/match_ops.h
    diff --git a/postfix/src/cleanup/cleanup.c b/postfix/src/cleanup/cleanup.c
    index 0f41b8a3b..5747f8c94 100644
    --- a/postfix/src/cleanup/cleanup.c
    +++ b/postfix/src/cleanup/cleanup.c
    @@ -386,6 +386,7 @@
     #include 
     #include 
     #include 
    +#include 
     
     /* Single-threaded server skeleton. */
     
    @@ -502,11 +503,18 @@ static void pre_accept(char *unused_name, char **unused_argv)
         }
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - the main program */
     
     int     main(int argc, char **argv)
     {
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Clean up an incomplete queue file in case of a fatal run-time error,
          * or after receiving SIGTERM from the master at shutdown time.
    diff --git a/postfix/src/discard/Makefile.in b/postfix/src/discard/Makefile.in
    index e39100098..00a5d5c34 100644
    --- a/postfix/src/discard/Makefile.in
    +++ b/postfix/src/discard/Makefile.in
    @@ -67,6 +67,7 @@ discard.o: ../../include/dsn_util.h
     discard.o: ../../include/flush_clnt.h
     discard.o: ../../include/mail_queue.h
     discard.o: ../../include/mail_server.h
    +discard.o: ../../include/mail_version.h
     discard.o: ../../include/msg.h
     discard.o: ../../include/msg_stats.h
     discard.o: ../../include/recipient_list.h
    diff --git a/postfix/src/discard/discard.c b/postfix/src/discard/discard.c
    index 2e7b24b31..17bdeceee 100644
    --- a/postfix/src/discard/discard.c
    +++ b/postfix/src/discard/discard.c
    @@ -121,6 +121,7 @@
     #include 
     #include 
     #include 
    +#include 
     
     /* Single server skeleton. */
     
    @@ -225,10 +226,18 @@ static void pre_init(char *unused_name, char **unused_argv)
         flush_init();
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the single-threaded skeleton */
     
     int     main(int argc, char **argv)
     {
    +
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         single_server_main(argc, argv, discard_service,
     		       MAIL_SERVER_PRE_INIT, pre_init,
     		       0);
    diff --git a/postfix/src/error/Makefile.in b/postfix/src/error/Makefile.in
    index 8e1d097c5..a9453126f 100644
    --- a/postfix/src/error/Makefile.in
    +++ b/postfix/src/error/Makefile.in
    @@ -70,6 +70,7 @@ error.o: ../../include/iostuff.h
     error.o: ../../include/mail_proto.h
     error.o: ../../include/mail_queue.h
     error.o: ../../include/mail_server.h
    +error.o: ../../include/mail_version.h
     error.o: ../../include/msg.h
     error.o: ../../include/msg_stats.h
     error.o: ../../include/recipient_list.h
    diff --git a/postfix/src/error/error.c b/postfix/src/error/error.c
    index 6887ddd52..019900b2b 100644
    --- a/postfix/src/error/error.c
    +++ b/postfix/src/error/error.c
    @@ -126,6 +126,7 @@
     #include 
     #include 
     #include 
    +#include 
     
     /* Single server skeleton. */
     
    @@ -237,10 +238,18 @@ static void pre_init(char *unused_name, char **unused_argv)
         flush_init();
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the single-threaded skeleton */
     
     int     main(int argc, char **argv)
     {
    +
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         single_server_main(argc, argv, error_service,
     		       MAIL_SERVER_PRE_INIT, pre_init,
     		       0);
    diff --git a/postfix/src/flush/Makefile.in b/postfix/src/flush/Makefile.in
    index 8144eabbf..7578940f5 100644
    --- a/postfix/src/flush/Makefile.in
    +++ b/postfix/src/flush/Makefile.in
    @@ -72,6 +72,7 @@ flush.o: ../../include/mail_proto.h
     flush.o: ../../include/mail_queue.h
     flush.o: ../../include/mail_scan_dir.h
     flush.o: ../../include/mail_server.h
    +flush.o: ../../include/mail_version.h
     flush.o: ../../include/maps.h
     flush.o: ../../include/match_list.h
     flush.o: ../../include/match_ops.h
    diff --git a/postfix/src/flush/flush.c b/postfix/src/flush/flush.c
    index bfa4ca574..41ffafa87 100644
    --- a/postfix/src/flush/flush.c
    +++ b/postfix/src/flush/flush.c
    @@ -173,6 +173,7 @@
     /* Global library. */
     
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -387,7 +388,7 @@ static int flush_send_service(const char *site, int how)
     /* flush_one_file - move one queue file to incoming queue */
     
     static int flush_one_file(const char *queue_id, VSTRING *queue_file,
    -			            struct utimbuf * tbuf, int how)
    +			          struct utimbuf * tbuf, int how)
     {
         const char *myname = "flush_one_file";
         const char *queue_name;
    @@ -807,6 +808,8 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
     				     var_fflush_domains);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the single-threaded skeleton */
     
     int     main(int argc, char **argv)
    @@ -817,6 +820,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         single_server_main(argc, argv, flush_service,
     		       MAIL_SERVER_TIME_TABLE, time_table,
     		       MAIL_SERVER_PRE_INIT, pre_jail_init,
    diff --git a/postfix/src/fsstone/fsstone.c b/postfix/src/fsstone/fsstone.c
    index 26ff50c1e..026741231 100644
    --- a/postfix/src/fsstone/fsstone.c
    +++ b/postfix/src/fsstone/fsstone.c
    @@ -150,6 +150,8 @@ static void usage(char *myname)
         msg_fatal("usage: %s [-cr] [-s size] messages directory_entries", myname);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     int     main(int argc, char **argv)
     {
         int     op_count;
    @@ -161,6 +163,11 @@ int     main(int argc, char **argv)
         int     ch;
         int     size = 2;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         msg_vstream_init(argv[0], VSTREAM_ERR);
         while ((ch = GETOPT(argc, argv, "crs:")) != EOF) {
     	switch (ch) {
    diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in
    index 49e288d89..b6c602f0b 100644
    --- a/postfix/src/global/Makefile.in
    +++ b/postfix/src/global/Makefile.in
    @@ -890,10 +890,12 @@ input_transp.o: cleanup_user.h
     input_transp.o: input_transp.c
     input_transp.o: input_transp.h
     input_transp.o: mail_params.h
    +int_filt.o: ../../include/msg.h
     int_filt.o: ../../include/name_mask.h
     int_filt.o: ../../include/sys_defs.h
     int_filt.o: ../../include/vbuf.h
     int_filt.o: ../../include/vstring.h
    +int_filt.o: cleanup_user.h
     int_filt.o: int_filt.c
     int_filt.o: int_filt.h
     int_filt.o: mail_params.h
    @@ -1462,6 +1464,7 @@ post_mail.o: ../../include/vbuf.h
     post_mail.o: ../../include/vstream.h
     post_mail.o: ../../include/vstring.h
     post_mail.o: cleanup_user.h
    +post_mail.o: int_filt.h
     post_mail.o: mail_date.h
     post_mail.o: mail_params.h
     post_mail.o: mail_proto.h
    diff --git a/postfix/src/global/dict_ldap.c b/postfix/src/global/dict_ldap.c
    index efd8c3927..fd35579d2 100644
    --- a/postfix/src/global/dict_ldap.c
    +++ b/postfix/src/global/dict_ldap.c
    @@ -60,6 +60,14 @@
     /* .IP special_result_attribute
     /*	The attribute(s) of directory entries that can contain DNs or URLs.
     /*	If found, a recursive subsequent search is done using their values.
    +/* .IP leaf_result_attribute
    +/*	These are only returned for "leaf" LDAP entries, i.e. those that are
    +/*	not "terminal" and have no values for any of the "special" result
    +/*	attributes.
    +/* .IP terminal_result_attribute
    +/*	If found, the LDAP entry is considered a terminal LDAP object, not
    +/*	subject to further direct or recursive expansion. Only the terminal
    +/*	result attributes are returned.
     /* .IP scope
     /*	LDAP search scope: sub, base, or one.
     /* .IP bind
    @@ -228,7 +236,9 @@ typedef struct {
         int     scope;
         char   *search_base;
         ARGV   *result_attributes;
    -    int     num_attributes;		/* rest of list is DN's. */
    +    int     num_terminal;		/* Number of terminal attributes. */
    +    int     num_leaf;			/* Number of leaf attributes */
    +    int     num_attributes;		/* Combined # of non-special attrs */
         int     bind;
         char   *bind_dn;
         char   *bind_pw;
    @@ -256,7 +266,16 @@ typedef struct {
     
     #define DICT_LDAP_CONN(d) ((LDAP_CONN *)((d)->ht->value))
     
    -
    + /*
    +  * Bitrot: LDAP_API 3000 and up (OpenLDAP 2.2.x) deprecated ldap_unbind()
    +  */
    +#if LDAP_API_VERSION >= 3000
    +#define dict_ldap_unbind(ld)		ldap_unbind_ext((ld), 0, 0)
    +#define dict_ldap_abandon(ld, msg)	ldap_abandon_ext((ld), (msg), 0, 0)
    +#else
    +#define dict_ldap_unbind(ld)		ldap_unbind(ld)
    +#define dict_ldap_abandon(ld, msg)	ldap_abandon((ld), (msg))
    +#endif
     
     /*
      * Quoting rules.
    @@ -325,8 +344,7 @@ static void dict_ldap_timeout(int unused_sig)
     static void dict_ldap_logprint(LDAP_CONST char *data)
     {
         const char *myname = "dict_ldap_debug";
    -    char   *buf,
    -           *p;
    +    char   *buf, *p;
     
         buf = mystrdup(data);
         if (*buf) {
    @@ -338,7 +356,7 @@ static void dict_ldap_logprint(LDAP_CONST char *data)
         myfree(buf);
     }
     
    -static int dict_ldap_get_errno(LDAP * ld)
    +static int dict_ldap_get_errno(LDAP *ld)
     {
         int     rc;
     
    @@ -347,7 +365,7 @@ static int dict_ldap_get_errno(LDAP * ld)
         return rc;
     }
     
    -static int dict_ldap_set_errno(LDAP * ld, int rc)
    +static int dict_ldap_set_errno(LDAP *ld, int rc)
     {
         (void) ldap_set_option(ld, LDAP_OPT_ERROR_NUMBER, &rc);
         return rc;
    @@ -367,10 +385,9 @@ static int dict_ldap_result(LDAP *ld, int msgid, int timeout, LDAPMessage **res)
     	return (dict_ldap_get_errno(ld));
     
         if (dict_ldap_get_errno(ld) == LDAP_TIMEOUT) {
    -	(void) ldap_abandon_ext(ld, msgid, 0, 0);
    +	(void) dict_ldap_abandon(ld, msgid);
     	return (dict_ldap_set_errno(ld, LDAP_TIMEOUT));
         }
    -
         return LDAP_SUCCESS;
     }
     
    @@ -400,7 +417,7 @@ static int dict_ldap_bind_st(DICT_LDAP *dict_ldap)
     /* search_st - Synchronous search with timeout */
     
     static int search_st(LDAP *ld, char *base, int scope, char *query,
    -			    char **attrs, int timeout, LDAPMessage **res)
    +		             char **attrs, int timeout, LDAPMessage **res)
     {
         struct timeval mytimeval;
         int     msgid;
    @@ -411,7 +428,7 @@ static int search_st(LDAP *ld, char *base, int scope, char *query,
         mytimeval.tv_usec = 0;
     
     #define WANTVALS 0
    -#define USE_SIZE_LIM_OPT -1		/* Any negative value will do */
    +#define USE_SIZE_LIM_OPT -1			/* Any negative value will do */
     
         if ((rc = ldap_search_ext(ld, base, scope, query, attrs, WANTVALS, 0, 0,
     			      &mytimeval, USE_SIZE_LIM_OPT,
    @@ -506,7 +523,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
     #if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN)
         if (dict_ldap->debuglevel > 0 &&
     	ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN,
    -		     (LDAP_CONST void *) dict_ldap_logprint) != LBER_OPT_SUCCESS)
    +		(LDAP_CONST void *) dict_ldap_logprint) != LBER_OPT_SUCCESS)
     	msg_warn("%s: Unable to set ber logprint function.", myname);
     #if defined(LBER_OPT_DEBUG_LEVEL)
         if (ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL,
    @@ -752,8 +769,8 @@ static void dict_ldap_conn_find(DICT_LDAP *dict_ldap)
      * This and the rest of the handling of multiple attributes, DNs and URLs
      * are thanks to LaMont Jones.
      */
    -static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
    -				         VSTRING *result, const char* name)
    +static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res,
    +				         VSTRING *result, const char *name)
     {
         static int recursion = 0;
         static int expansion;
    @@ -768,6 +785,8 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
         int     valcount;
         LDAPURLDesc *url;
         const char *myname = "dict_ldap_get_values";
    +    int     is_leaf = 1;		/* No recursion via this entry */
    +    int     is_terminal = 0;		/* No expansion via this entry */
     
         if (++recursion == 1)
     	expansion = 0;
    @@ -792,10 +811,45 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
     		     dict_ldap->size_limit);
     	    dict_errno = DICT_ERR_RETRY;
     	}
    +
    +	/*
    +	 * Check for terminal attributes, these preclude expansion of all
    +	 * other attributes, and DN/URI recursion. Any terminal attributes
    +	 * are listed first in the attribute array.
    +	 */
    +	if (dict_ldap->num_terminal > 0) {
    +	    for (i = 0; i < dict_ldap->num_terminal; ++i) {
    +		attr = dict_ldap->result_attributes->argv[i];
    +		if (!(vals = ldap_get_values_len(dict_ldap->ld, entry, attr)))
    +		    continue;
    +		is_terminal = (ldap_count_values_len(vals) > 0);
    +		ldap_value_free_len(vals);
    +		if (is_terminal)
    +		    break;
    +	    }
    +	}
    +
    +	/*
    +	 * Check for special attributes, these preclude expansion of
    +	 * "leaf-only" attributes, and are at the end of the attribute array
    +	 * after the terminal, leaf and regular attributes.
    +	 */
    +	if (is_terminal == 0 && dict_ldap->num_leaf > 0) {
    +	    for (i = dict_ldap->num_attributes;
    +		 dict_ldap->result_attributes->argv[i]; ++i) {
    +		attr = dict_ldap->result_attributes->argv[i];
    +		if (!(vals = ldap_get_values_len(dict_ldap->ld, entry, attr)))
    +		    continue;
    +		is_leaf = (ldap_count_values_len(vals) == 0);
    +		ldap_value_free_len(vals);
    +		if (!is_leaf)
    +		    break;
    +	    }
    +	}
     	for (attr = ldap_first_attribute(dict_ldap->ld, entry, &ber);
    -	     attr != NULL;
    -	     ldap_memfree(attr), attr = ldap_next_attribute(dict_ldap->ld,
    -							    entry, ber)) {
    +	     attr != NULL; ldap_memfree(attr),
    +	     attr = ldap_next_attribute(dict_ldap->ld, entry, ber)) {
    +
     	    vals = ldap_get_values_len(dict_ldap->ld, entry, attr);
     	    if (vals == NULL) {
     		if (msg_verbose)
    @@ -803,7 +857,6 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
     			     myname, recursion, attr);
     		continue;
     	    }
    -
     	    valcount = ldap_count_values_len(vals);
     
     	    /*
    @@ -830,36 +883,47 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
     	     * We compute the attribute type (ordinary or special) from its
     	     * index on the "result_attributes" list.
     	     */
    -	    for (i = 0; dict_ldap->result_attributes->argv[i]; i++) {
    -		if (strcasecmp(dict_ldap->result_attributes->argv[i], attr) == 0)
    +	    for (i = 0; dict_ldap->result_attributes->argv[i]; i++)
    +		if (strcasecmp(dict_ldap->result_attributes->argv[i],
    +			       attr) == 0)
     		    break;
    -	    }
     
     	    /*
     	     * Append each returned address to the result list, possibly
    -	     * recursing (for dn or url attributes).
    +	     * recursing (for dn or url attributes of non-terminal entries)
     	     */
    -	    if (i < dict_ldap->num_attributes) {
    -		/* Ordinary result attribute */
    -		for (i = 0; i < valcount; i++) {
    -		    if (db_common_expand(dict_ldap->ctx,
    -					 dict_ldap->result_format,
    -					 vals[i]->bv_val,
    -					 name, result, 0)
    -			&& dict_ldap->expansion_limit > 0
    -			&& ++expansion > dict_ldap->expansion_limit) {
    -			msg_warn("%s[%d]: %s: Expansion limit exceeded for key: '%s'",
    -				 myname, recursion, dict_ldap->parser->name, name);
    -			dict_errno = DICT_ERR_RETRY;
    -			break;
    +	    if (i < dict_ldap->num_attributes || is_terminal) {
    +		if (is_terminal && i >= dict_ldap->num_terminal
    +		    || !is_leaf &&
    +		    i < dict_ldap->num_terminal + dict_ldap->num_leaf) {
    +		    if (msg_verbose)
    +			msg_info("%s[%d]: skipping %ld value(s) of %s "
    +				 "attribute %s", myname, recursion, i,
    +				 is_terminal ? "non-terminal" : "leaf-only",
    +				 attr);
    +		} else {
    +		    /* Ordinary result attribute */
    +		    for (i = 0; i < valcount; i++) {
    +			if (db_common_expand(dict_ldap->ctx,
    +					     dict_ldap->result_format,
    +					     vals[i]->bv_val,
    +					     name, result, 0)
    +			    && dict_ldap->expansion_limit > 0
    +			    && ++expansion > dict_ldap->expansion_limit) {
    +			    msg_warn("%s[%d]: %s: Expansion limit exceeded "
    +				     "for key: '%s'", myname, recursion,
    +				     dict_ldap->parser->name, name);
    +			    dict_errno = DICT_ERR_RETRY;
    +			    break;
    +			}
     		    }
    +		    if (dict_errno != 0)
    +			continue;
    +		    if (msg_verbose)
    +			msg_info("%s[%d]: search returned %ld value(s) for"
    +				 " requested result attribute %s",
    +				 myname, recursion, i, attr);
     		}
    -		if (dict_errno != 0)
    -		    continue;
    -		if (msg_verbose)
    -		    msg_info("%s[%d]: search returned %ld value(s) for"
    -			     " requested result attribute %s",
    -			     myname, recursion, i, attr);
     	    } else if (recursion < dict_ldap->recursion_limit
     		       && dict_ldap->result_attributes->argv[i]) {
     		/* Special result attribute */
    @@ -872,7 +936,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
     			if (rc == 0) {
     			    rc = search_st(dict_ldap->ld, url->lud_dn,
     					   url->lud_scope, url->lud_filter,
    -					   url->lud_attrs, dict_ldap->timeout,
    +					 url->lud_attrs, dict_ldap->timeout,
     					   &resloop);
     			    ldap_free_urldesc(url);
     			}
    @@ -973,7 +1037,6 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
     	    msg_info("%s: Skipping lookup of '%s'", myname, name);
     	return (0);
         }
    -
     #define INIT_VSTR(buf, len) do { \
     	if (buf == 0) \
     	    buf = vstring_alloc(len); \
    @@ -1026,28 +1089,27 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
     		 myname, dict_ldap->parser->name, dict_ldap->size_limit);
     
         /*
    -     * Expand the search base and query. Skip lookup when the
    -     * input key lacks sufficient domain components to satisfy
    -     * all the requested %-substitutions.
    -     *
    -     * When the search base is not static, LDAP_NO_SUCH_OBJECT is
    -     * expected and is therefore treated as a non-error: the lookup
    -     * returns no results rather than a soft error.
    +     * Expand the search base and query. Skip lookup when the input key lacks
    +     * sufficient domain components to satisfy all the requested
    +     * %-substitutions.
    +     * 
    +     * When the search base is not static, LDAP_NO_SUCH_OBJECT is expected and
    +     * is therefore treated as a non-error: the lookup returns no results
    +     * rather than a soft error.
          */
         if (!db_common_expand(dict_ldap->ctx, dict_ldap->search_base,
    -    			  name, 0, base, rfc2253_quote)) {
    -        if (msg_verbose > 1)
    +			  name, 0, base, rfc2253_quote)) {
    +	if (msg_verbose > 1)
     	    msg_info("%s: %s: Empty expansion for %s", myname,
     		     dict_ldap->parser->name, dict_ldap->search_base);
    -        return (0);
    +	return (0);
         }
    -
         if (!db_common_expand(dict_ldap->ctx, dict_ldap->query,
     			  name, 0, query, rfc2254_quote)) {
    -        if (msg_verbose > 1)
    +	if (msg_verbose > 1)
     	    msg_info("%s: %s: Empty expansion for %s", myname,
     		     dict_ldap->parser->name, dict_ldap->query);
    -        return (0);
    +	return (0);
         }
     
         /*
    @@ -1066,7 +1128,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
     	    msg_info("%s: Lost connection for LDAP source %s, reopening",
     		     myname, dict_ldap->parser->name);
     
    -	ldap_unbind_ext(dict_ldap->ld, 0, 0);
    +	dict_ldap_unbind(dict_ldap->ld);
     	dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
     	dict_ldap_connect(dict_ldap);
     
    @@ -1077,14 +1139,14 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
     	    return (0);
     
     	rc = search_st(dict_ldap->ld, vstring_str(base), dict_ldap->scope,
    -		       vstring_str(query), dict_ldap->result_attributes->argv,
    +		     vstring_str(query), dict_ldap->result_attributes->argv,
     		       dict_ldap->timeout, &res);
     
         }
    -
         switch (rc) {
     
         case LDAP_SUCCESS:
    +
     	/*
     	 * Search worked; extract the requested result_attribute.
     	 */
    @@ -1109,12 +1171,13 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
     	break;
     
         case LDAP_NO_SUCH_OBJECT:
    -        /*
    -	 * If the search base is input key dependent, then not finding it,
    -	 * is equivalent to not finding the input key. Sadly, we cannot
    -	 * detect misconfiguration in this case.
    +
    +	/*
    +	 * If the search base is input key dependent, then not finding it, is
    +	 * equivalent to not finding the input key. Sadly, we cannot detect
    +	 * misconfiguration in this case.
     	 */
    -    	if (dict_ldap->dynamic_base)
    +	if (dict_ldap->dynamic_base)
     	    break;
     
     	msg_warn("%s: %s: Search base '%s' not found: %d: %s",
    @@ -1124,6 +1187,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
     	break;
     
         default:
    +
     	/*
     	 * Rats. The search didn't work.
     	 */
    @@ -1134,7 +1198,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
     	 * Tear down the connection so it gets set up from scratch on the
     	 * next lookup.
     	 */
    -	ldap_unbind_ext(dict_ldap->ld, 0, 0);
    +	dict_ldap_unbind(dict_ldap->ld);
     	dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
     
     	/*
    @@ -1171,7 +1235,7 @@ static void dict_ldap_close(DICT *dict)
     	    if (msg_verbose)
     		msg_info("%s: Closed connection handle for LDAP source %s",
     			 myname, dict_ldap->parser->name);
    -	    ldap_unbind_ext(conn->conn_ld, 0, 0);
    +	    dict_ldap_unbind(conn->conn_ld);
     	}
     	binhash_delete(conn_hash, ht->key, ht->key_len, myfree);
         }
    @@ -1180,7 +1244,7 @@ static void dict_ldap_close(DICT *dict)
         myfree(dict_ldap->search_base);
         myfree(dict_ldap->query);
         if (dict_ldap->result_format)
    -        myfree(dict_ldap->result_format);
    +	myfree(dict_ldap->result_format);
         argv_free(dict_ldap->result_attributes);
         myfree(dict_ldap->bind_dn);
         myfree(dict_ldap->bind_pw);
    @@ -1282,11 +1346,11 @@ DICT   *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
     		dict_ldap->ldap_ssl = 1;
     	    ldap_free_urldesc(url_desc);
     	    if (VSTRING_LEN(url_list) > 0)
    -	    	VSTRING_ADDCH(url_list, ' ');
    +		VSTRING_ADDCH(url_list, ' ');
     	    vstring_strcat(url_list, h);
     	} else {
     	    if (VSTRING_LEN(url_list) > 0)
    -	    	VSTRING_ADDCH(url_list, ' ');
    +		VSTRING_ADDCH(url_list, ' ');
     	    if (strrchr(h, ':'))
     		vstring_sprintf_append(url_list, "ldap://%s", h);
     	    else
    @@ -1344,24 +1408,26 @@ DICT   *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
          */
         dict_ldap->timeout = cfg_get_int(dict_ldap->parser, "timeout", 10, 0, 0);
     
    -#if 0	/* No benefit from changing this to match the MySQL/PGSQL syntax */
    +#if 0						/* No benefit from changing
    +						 * this to match the
    +						 * MySQL/PGSQL syntax */
         if ((dict_ldap->query =
    -    	     cfg_get_str(dict_ldap->parser, "query", 0, 0, 0)) == 0)
    +	 cfg_get_str(dict_ldap->parser, "query", 0, 0, 0)) == 0)
     #endif
    -        dict_ldap->query =
    +	dict_ldap->query =
     	    cfg_get_str(dict_ldap->parser, "query_filter",
     			"(mailacceptinggeneralid=%s)", 0, 0);
     
         if ((dict_ldap->result_format =
    -        cfg_get_str(dict_ldap->parser, "result_format", 0, 0, 0)) == 0)
    -        dict_ldap->result_format =
    -                cfg_get_str(dict_ldap->parser, "result_filter", "%s", 1, 0);
    +	 cfg_get_str(dict_ldap->parser, "result_format", 0, 0, 0)) == 0)
    +	dict_ldap->result_format =
    +	    cfg_get_str(dict_ldap->parser, "result_filter", "%s", 1, 0);
     
         /*
    -     * Must parse all templates before we can use db_common_expand()
    -     * If data dependent substitutions are found in the search base,
    -     * treat NO_SUCH_OBJECT search errors as a non-matching key, rather
    -     * than a fatal run-time error.
    +     * Must parse all templates before we can use db_common_expand() If data
    +     * dependent substitutions are found in the search base, treat
    +     * NO_SUCH_OBJECT search errors as a non-matching key, rather than a
    +     * fatal run-time error.
          */
         dict_ldap->ctx = 0;
         dict_ldap->dynamic_base =
    @@ -1375,8 +1441,8 @@ DICT   *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
         db_common_parse_domain(dict_ldap->parser, dict_ldap->ctx);
     
         /*
    -     * Maps that use substring keys should only be used with the full
    -     * input key.
    +     * Maps that use substring keys should only be used with the full input
    +     * key.
          */
         if (db_common_dict_partial(dict_ldap->ctx))
     	dict_ldap->dict.flags |= DICT_FLAG_PATTERN;
    @@ -1385,14 +1451,29 @@ DICT   *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
         if (dict_flags & DICT_FLAG_FOLD_FIX)
     	dict_ldap->dict.fold_buf = vstring_alloc(10);
     
    -    attr = cfg_get_str(dict_ldap->parser, "result_attribute",
    -		       "maildrop", 0, 0);
    +    /* Order matters, first the terminal attributes: */
    +    attr = cfg_get_str(dict_ldap->parser, "terminal_result_attribute", "", 0, 0);
         dict_ldap->result_attributes = argv_split(attr, " ,\t\r\n");
    +    dict_ldap->num_terminal = dict_ldap->result_attributes->argc;
    +    myfree(attr);
    +
    +    /* Order matters, next the leaf-only attributes: */
    +    attr = cfg_get_str(dict_ldap->parser, "leaf_result_attribute", "", 0, 0);
    +    if (*attr)
    +	argv_split_append(dict_ldap->result_attributes, attr, " ,\t\r\n");
    +    dict_ldap->num_leaf =
    +	dict_ldap->result_attributes->argc - dict_ldap->num_terminal;
    +    myfree(attr);
    +
    +    /* Order matters, next the regular attributes: */
    +    attr = cfg_get_str(dict_ldap->parser, "result_attribute", "maildrop", 0, 0);
    +    if (*attr)
    +	argv_split_append(dict_ldap->result_attributes, attr, " ,\t\r\n");
         dict_ldap->num_attributes = dict_ldap->result_attributes->argc;
         myfree(attr);
     
    -    attr = cfg_get_str(dict_ldap->parser, "special_result_attribute",
    -		       "", 0, 0);
    +    /* Order matters, finally the special attributes: */
    +    attr = cfg_get_str(dict_ldap->parser, "special_result_attribute", "", 0, 0);
         if (*attr)
     	argv_split_append(dict_ldap->result_attributes, attr, " ,\t\r\n");
         myfree(attr);
    diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
    index cc2666ba6..652d50457 100644
    --- a/postfix/src/global/mail_version.h
    +++ b/postfix/src/global/mail_version.h
    @@ -20,8 +20,8 @@
       * Patches change both the patchlevel and the release date. Snapshots have no
       * patchlevel; they change the release date only.
       */
    -#define MAIL_RELEASE_DATE	"20070312"
    -#define MAIL_VERSION_NUMBER	"2.4.0-RC5"
    +#define MAIL_RELEASE_DATE	"20070317"
    +#define MAIL_VERSION_NUMBER	"2.4.0-RC6"
     
     #ifdef SNAPSHOT
     # define MAIL_VERSION_DATE	"-" MAIL_RELEASE_DATE
    @@ -47,6 +47,24 @@ extern char *var_mail_version;
     #define DEF_MAIL_RELEASE	MAIL_RELEASE_DATE
     extern char *var_mail_release;
     
    + /*
    +  * The following macros stamp executable files as well as core dumps. This
    +  * information helps to answer the following questions:
    +  * 
    +  * - What Postfix versions(s) are installed on this machine?
    +  * 
    +  * - Is this installation mixing multiple Postfix versions?
    +  * 
    +  * - What Postfix version generated this core dump?
    +  */
    +#include 
    +
    +#define MAIL_VERSION_STAMP_DECLARE \
    +    char *mail_version_stamp
    +
    +#define MAIL_VERSION_STAMP_ALLOCATE \
    +    mail_version_stamp = strdup(VAR_MAIL_VERSION "=" DEF_MAIL_VERSION)
    +
     /* LICENSE
     /* .ad
     /* .fi
    diff --git a/postfix/src/local/Makefile.in b/postfix/src/local/Makefile.in
    index bd9814b5f..f22a5646e 100644
    --- a/postfix/src/local/Makefile.in
    +++ b/postfix/src/local/Makefile.in
    @@ -353,6 +353,7 @@ local.o: ../../include/mail_addr.h
     local.o: ../../include/mail_conf.h
     local.o: ../../include/mail_params.h
     local.o: ../../include/mail_server.h
    +local.o: ../../include/mail_version.h
     local.o: ../../include/maps.h
     local.o: ../../include/mbox_conf.h
     local.o: ../../include/msg.h
    diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c
    index c24a55d55..557be6f4d 100644
    --- a/postfix/src/local/local.c
    +++ b/postfix/src/local/local.c
    @@ -595,6 +595,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -845,6 +846,8 @@ static void pre_init(char *unused_name, char **unused_argv)
         flush_init();
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the single-threaded skeleton */
     
     int     main(int argc, char **argv)
    @@ -896,6 +899,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         single_server_main(argc, argv, local_service,
     		       MAIL_SERVER_INT_TABLE, int_table,
     		       MAIL_SERVER_STR_TABLE, str_table,
    diff --git a/postfix/src/master/Makefile.in b/postfix/src/master/Makefile.in
    index 2138f0a48..d8230c1b7 100644
    --- a/postfix/src/master/Makefile.in
    +++ b/postfix/src/master/Makefile.in
    @@ -180,6 +180,7 @@ master_service.o: master.h
     master_service.o: master_service.c
     master_sig.o: ../../include/events.h
     master_sig.o: ../../include/iostuff.h
    +master_sig.o: ../../include/killme_after.h
     master_sig.o: ../../include/msg.h
     master_sig.o: ../../include/posix_signals.h
     master_sig.o: ../../include/sys_defs.h
    diff --git a/postfix/src/master/master.c b/postfix/src/master/master.c
    index c8b1e693d..ed9f94277 100644
    --- a/postfix/src/master/master.c
    +++ b/postfix/src/master/master.c
    @@ -209,6 +209,8 @@ static NORETURN usage(const char *me)
         msg_fatal("usage: %s [-c config_dir] [-D (debug)] [-d (don't detach from terminal)] [-e exit_time] [-t (test)] [-v]", me);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - main program */
     
     int     main(int argc, char **argv)
    @@ -225,6 +227,11 @@ int     main(int argc, char **argv)
         WATCHDOG *watchdog;
         ARGV   *import_env;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Initialize.
          */
    diff --git a/postfix/src/master/multi_server.c b/postfix/src/master/multi_server.c
    index b007986e6..ede015d8b 100644
    --- a/postfix/src/master/multi_server.c
    +++ b/postfix/src/master/multi_server.c
    @@ -626,6 +626,14 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
         if (redo_syslog_init)
     	msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
     
    +    /*
    +     * If not connected to stdin, stdin must not be a terminal.
    +     */
    +    if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
    +	msg_vstream_init(var_procname, VSTREAM_ERR);
    +	msg_fatal("do not run this command by hand");
    +    }
    +
         /*
          * Application-specific initialization.
          */
    @@ -694,14 +702,6 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
         if (user_name)
     	user_name = var_mail_owner;
     
    -    /*
    -     * If not connected to stdin, stdin must not be a terminal.
    -     */
    -    if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
    -	msg_vstream_init(var_procname, VSTREAM_ERR);
    -	msg_fatal("do not run this command by hand");
    -    }
    -
         /*
          * Can options be required?
          */
    diff --git a/postfix/src/master/single_server.c b/postfix/src/master/single_server.c
    index e22048f2b..244b6798f 100644
    --- a/postfix/src/master/single_server.c
    +++ b/postfix/src/master/single_server.c
    @@ -519,6 +519,14 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
         if (redo_syslog_init)
     	msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
     
    +    /*
    +     * If not connected to stdin, stdin must not be a terminal.
    +     */
    +    if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
    +	msg_vstream_init(var_procname, VSTREAM_ERR);
    +	msg_fatal("do not run this command by hand");
    +    }
    +
         /*
          * Application-specific initialization.
          */
    @@ -584,14 +592,6 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
         if (user_name)
     	user_name = var_mail_owner;
     
    -    /*
    -     * If not connected to stdin, stdin must not be a terminal.
    -     */
    -    if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
    -	msg_vstream_init(var_procname, VSTREAM_ERR);
    -	msg_fatal("do not run this command by hand");
    -    }
    -
         /*
          * Can options be required?
          */
    diff --git a/postfix/src/master/trigger_server.c b/postfix/src/master/trigger_server.c
    index 5db0fb8ee..e420d895e 100644
    --- a/postfix/src/master/trigger_server.c
    +++ b/postfix/src/master/trigger_server.c
    @@ -526,6 +526,14 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
         if (redo_syslog_init)
     	msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
     
    +    /*
    +     * If not connected to stdin, stdin must not be a terminal.
    +     */
    +    if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
    +	msg_vstream_init(var_procname, VSTREAM_ERR);
    +	msg_fatal("do not run this command by hand");
    +    }
    +
         /*
          * Application-specific initialization.
          */
    @@ -591,14 +599,6 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
         if (user_name)
     	user_name = var_mail_owner;
     
    -    /*
    -     * If not connected to stdin, stdin must not be a terminal.
    -     */
    -    if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
    -	msg_vstream_init(var_procname, VSTREAM_ERR);
    -	msg_fatal("do not run this command by hand");
    -    }
    -
         /*
          * Can options be required?
          * 
    diff --git a/postfix/src/milter/Makefile.in b/postfix/src/milter/Makefile.in
    index 4b10cda9b..ce66bd170 100644
    --- a/postfix/src/milter/Makefile.in
    +++ b/postfix/src/milter/Makefile.in
    @@ -100,6 +100,7 @@ milter8.o: ../../include/connect.h
     milter8.o: ../../include/header_opts.h
     milter8.o: ../../include/iostuff.h
     milter8.o: ../../include/is_header.h
    +milter8.o: ../../include/mail_params.h
     milter8.o: ../../include/mail_proto.h
     milter8.o: ../../include/mime_state.h
     milter8.o: ../../include/msg.h
    diff --git a/postfix/src/oqmgr/Makefile.in b/postfix/src/oqmgr/Makefile.in
    index 136bd72e6..7c6b21cce 100644
    --- a/postfix/src/oqmgr/Makefile.in
    +++ b/postfix/src/oqmgr/Makefile.in
    @@ -75,6 +75,7 @@ qmgr.o: ../../include/mail_params.h
     qmgr.o: ../../include/mail_proto.h
     qmgr.o: ../../include/mail_queue.h
     qmgr.o: ../../include/mail_server.h
    +qmgr.o: ../../include/mail_version.h
     qmgr.o: ../../include/master_proto.h
     qmgr.o: ../../include/msg.h
     qmgr.o: ../../include/recipient_list.h
    diff --git a/postfix/src/oqmgr/qmgr.c b/postfix/src/oqmgr/qmgr.c
    index 84baa7cac..6b7b037a3 100644
    --- a/postfix/src/oqmgr/qmgr.c
    +++ b/postfix/src/oqmgr/qmgr.c
    @@ -294,6 +294,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 			/* QMGR_SCAN constants */
     #include 
     #include 
    @@ -548,6 +549,8 @@ static void qmgr_post_init(char *unused_name, char **unused_argv)
         qmgr_deferred_run_event(0, (char *) 0);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - the main program */
     
     int     main(int argc, char **argv)
    @@ -584,6 +587,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Use the trigger service skeleton, because no-one else should be
          * monitoring our service port while this process runs, and because we do
    diff --git a/postfix/src/pickup/Makefile.in b/postfix/src/pickup/Makefile.in
    index f416e3cb1..07e39f2e1 100644
    --- a/postfix/src/pickup/Makefile.in
    +++ b/postfix/src/pickup/Makefile.in
    @@ -69,6 +69,7 @@ pickup.o: ../../include/mail_params.h
     pickup.o: ../../include/mail_proto.h
     pickup.o: ../../include/mail_queue.h
     pickup.o: ../../include/mail_server.h
    +pickup.o: ../../include/mail_version.h
     pickup.o: ../../include/msg.h
     pickup.o: ../../include/mymalloc.h
     pickup.o: ../../include/rec_attr_map.h
    diff --git a/postfix/src/pickup/pickup.c b/postfix/src/pickup/pickup.c
    index ca3d97c8d..153f36326 100644
    --- a/postfix/src/pickup/pickup.c
    +++ b/postfix/src/pickup/pickup.c
    @@ -141,6 +141,7 @@
     #include 
     #include 
     #include 
    +#include 
     
     /* Single-threaded server skeleton. */
     
    @@ -570,6 +571,8 @@ static void post_jail_init(char *unused_name, char **unused_argv)
     	input_transp_mask(VAR_INPUT_TRANSP, var_input_transp);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the multi-threaded server skeleton */
     
     int     main(int argc, char **argv)
    @@ -580,6 +583,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Use the multi-threaded skeleton, because no-one else should be
          * monitoring our service socket while this process runs.
    diff --git a/postfix/src/pipe/Makefile.in b/postfix/src/pipe/Makefile.in
    index f4e286670..c661d7420 100644
    --- a/postfix/src/pipe/Makefile.in
    +++ b/postfix/src/pipe/Makefile.in
    @@ -77,6 +77,7 @@ pipe.o: ../../include/mail_conf.h
     pipe.o: ../../include/mail_copy.h
     pipe.o: ../../include/mail_params.h
     pipe.o: ../../include/mail_server.h
    +pipe.o: ../../include/mail_version.h
     pipe.o: ../../include/msg.h
     pipe.o: ../../include/msg_stats.h
     pipe.o: ../../include/mymalloc.h
    diff --git a/postfix/src/pipe/pipe.c b/postfix/src/pipe/pipe.c
    index bf9bbf1aa..164896ca6 100644
    --- a/postfix/src/pipe/pipe.c
    +++ b/postfix/src/pipe/pipe.c
    @@ -400,6 +400,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -1196,6 +1197,8 @@ static void pre_init(char *unused_name, char **unused_argv)
         flush_init();
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the single-threaded skeleton */
     
     int     main(int argc, char **argv)
    @@ -1205,6 +1208,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         single_server_main(argc, argv, pipe_service,
     		       MAIL_SERVER_TIME_TABLE, time_table,
     		       MAIL_SERVER_PRE_INIT, pre_init,
    diff --git a/postfix/src/postalias/Makefile.in b/postfix/src/postalias/Makefile.in
    index 109dd6f71..2e748382e 100644
    --- a/postfix/src/postalias/Makefile.in
    +++ b/postfix/src/postalias/Makefile.in
    @@ -87,6 +87,7 @@ postalias.o: ../../include/mail_conf.h
     postalias.o: ../../include/mail_dict.h
     postalias.o: ../../include/mail_params.h
     postalias.o: ../../include/mail_task.h
    +postalias.o: ../../include/mail_version.h
     postalias.o: ../../include/mkmap.h
     postalias.o: ../../include/msg.h
     postalias.o: ../../include/msg_syslog.h
    diff --git a/postfix/src/postalias/postalias.c b/postfix/src/postalias/postalias.c
    index 3a6e5683a..955116b99 100644
    --- a/postfix/src/postalias/postalias.c
    +++ b/postfix/src/postalias/postalias.c
    @@ -236,6 +236,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 
     #include 
     
    @@ -598,6 +599,8 @@ static NORETURN usage(char *myname)
     	      myname);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     int     main(int argc, char **argv)
     {
         char   *path_name;
    @@ -613,6 +616,11 @@ int     main(int argc, char **argv)
         int     sequence = 0;
         int     found;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Be consistent with file permissions.
          */
    diff --git a/postfix/src/postcat/Makefile.in b/postfix/src/postcat/Makefile.in
    index e92b6b71f..237bf6092 100644
    --- a/postfix/src/postcat/Makefile.in
    +++ b/postfix/src/postcat/Makefile.in
    @@ -63,6 +63,7 @@ postcat.o: ../../include/mail_conf.h
     postcat.o: ../../include/mail_params.h
     postcat.o: ../../include/mail_proto.h
     postcat.o: ../../include/mail_queue.h
    +postcat.o: ../../include/mail_version.h
     postcat.o: ../../include/msg.h
     postcat.o: ../../include/msg_vstream.h
     postcat.o: ../../include/rec_type.h
    diff --git a/postfix/src/postcat/postcat.c b/postfix/src/postcat/postcat.c
    index 7f043f4c3..1db3d506b 100644
    --- a/postfix/src/postcat/postcat.c
    +++ b/postfix/src/postcat/postcat.c
    @@ -88,6 +88,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 
     
     /* Application-specific. */
    @@ -239,6 +240,8 @@ static NORETURN usage(char *myname)
     	      myname);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     int     main(int argc, char **argv)
     {
         VSTRING *buffer;
    @@ -258,6 +261,11 @@ int     main(int argc, char **argv)
         char  **cpp;
         int     tries;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * To minimize confusion, make sure that the standard file descriptors
          * are open before opening anything else. XXX Work around for 44BSD where
    diff --git a/postfix/src/postconf/extract.awk b/postfix/src/postconf/extract.awk
    index 25069f439..77cd7440f 100644
    --- a/postfix/src/postconf/extract.awk
    +++ b/postfix/src/postconf/extract.awk
    @@ -22,7 +22,7 @@
         }
     }
     /^(static| )*CONFIG_STR_TABLE .*\{/,/\};/ { 
    -    if ($1 ~ /VAR/) {
    +    if ($1 ~ /^VAR/) {
     	print "char *" substr($3,2,length($3)-2) ";" > "str_vars.h"
     	if (++stab[$1 $2 $4 $5 $6 $7 $8 $9] == 1) {
     	    print |"sed 's/[ 	][ 	]*/ /g' > str_table.h"
    @@ -30,7 +30,7 @@
         }
     }
     /^(static| )*CONFIG_RAW_TABLE .*\{/,/\};/ { 
    -    if ($1 ~ /VAR/) {
    +    if ($1 ~ /^VAR/) {
     	print "char *" substr($3,2,length($3)-2) ";" > "raw_vars.h"
     	if (++rtab[$1 $2 $4 $5 $6 $7 $8 $9] == 1) {
     	    print |"sed 's/[ 	][ 	]*/ /g' > raw_table.h"
    @@ -38,7 +38,7 @@
         }
     }
     /^(static| )*CONFIG_BOOL_TABLE .*\{/,/\};/ { 
    -    if ($1 ~ /VAR/) {
    +    if ($1 ~ /^VAR/) {
     	print "int " substr($3,2,length($3)-2) ";" > "bool_vars.h"
     	if (++btab[$1 $2 $4 $5 $6 $7 $8 $9] == 1) {
     	    print |"sed 's/[ 	][ 	]*/ /g' > bool_table.h"
    @@ -46,7 +46,7 @@
         }
     }
     /^(static| )*CONFIG_TIME_TABLE .*\{/,/\};/ { 
    -    if ($1 ~ /VAR/) {
    +    if ($1 ~ /^VAR/) {
     	print "int " substr($3,2,length($3)-2) ";" > "time_vars.h"
     	if (++ttab[$1 $2 $4 $5 $6 $7 $8 $9] == 1) {
     	    print |"sed 's/[ 	][ 	]*/ /g' > time_table.h" 
    diff --git a/postfix/src/postconf/postconf.c b/postfix/src/postconf/postconf.c
    index 376644fe9..dfa03612d 100644
    --- a/postfix/src/postconf/postconf.c
    +++ b/postfix/src/postconf/postconf.c
    @@ -960,6 +960,8 @@ static void show_parameters(int mode, char **names)
         }
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main */
     
     int     main(int argc, char **argv)
    @@ -970,6 +972,11 @@ int     main(int argc, char **argv)
         int     junk;
         ARGV   *ext_argv = 0;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Be consistent with file permissions.
          */
    diff --git a/postfix/src/postdrop/Makefile.in b/postfix/src/postdrop/Makefile.in
    index 178b14ba9..06afb8492 100644
    --- a/postfix/src/postdrop/Makefile.in
    +++ b/postfix/src/postdrop/Makefile.in
    @@ -68,6 +68,7 @@ postdrop.o: ../../include/mail_proto.h
     postdrop.o: ../../include/mail_queue.h
     postdrop.o: ../../include/mail_stream.h
     postdrop.o: ../../include/mail_task.h
    +postdrop.o: ../../include/mail_version.h
     postdrop.o: ../../include/msg.h
     postdrop.o: ../../include/msg_syslog.h
     postdrop.o: ../../include/msg_vstream.h
    diff --git a/postfix/src/postdrop/postdrop.c b/postfix/src/postdrop/postdrop.c
    index 537cdb260..7668df8da 100644
    --- a/postfix/src/postdrop/postdrop.c
    +++ b/postfix/src/postdrop/postdrop.c
    @@ -126,6 +126,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -206,6 +207,8 @@ static void postdrop_cleanup(void)
         postdrop_sig(0);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - the main program */
     
     int     main(int argc, char **argv)
    @@ -231,6 +234,11 @@ int     main(int argc, char **argv)
         struct timeval start;
         int     saved_errno;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Be consistent with file permissions.
          */
    diff --git a/postfix/src/postfix/Makefile.in b/postfix/src/postfix/Makefile.in
    index f61f6703d..ef7c63cac 100644
    --- a/postfix/src/postfix/Makefile.in
    +++ b/postfix/src/postfix/Makefile.in
    @@ -65,6 +65,7 @@ postfix.o: ../../include/argv.h
     postfix.o: ../../include/clean_env.h
     postfix.o: ../../include/mail_conf.h
     postfix.o: ../../include/mail_params.h
    +postfix.o: ../../include/mail_version.h
     postfix.o: ../../include/msg.h
     postfix.o: ../../include/msg_syslog.h
     postfix.o: ../../include/msg_vstream.h
    diff --git a/postfix/src/postfix/postfix.c b/postfix/src/postfix/postfix.c
    index 784526c47..d2bb01284 100644
    --- a/postfix/src/postfix/postfix.c
    +++ b/postfix/src/postfix/postfix.c
    @@ -291,6 +291,7 @@
     
     #include 
     #include 
    +#include 
     
     /* Additional installation parameters. */
     
    @@ -311,6 +312,8 @@ static void check_setenv(char *name, char *value)
     	msg_fatal("setenv: %m");
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - run administrative script from controlled environment */
     
     int     main(int argc, char **argv)
    @@ -332,6 +335,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Be consistent with file permissions.
          */
    diff --git a/postfix/src/postkick/Makefile.in b/postfix/src/postkick/Makefile.in
    index 527598be8..7271ed1d0 100644
    --- a/postfix/src/postkick/Makefile.in
    +++ b/postfix/src/postkick/Makefile.in
    @@ -63,6 +63,7 @@ postkick.o: ../../include/iostuff.h
     postkick.o: ../../include/mail_conf.h
     postkick.o: ../../include/mail_params.h
     postkick.o: ../../include/mail_proto.h
    +postkick.o: ../../include/mail_version.h
     postkick.o: ../../include/msg.h
     postkick.o: ../../include/msg_vstream.h
     postkick.o: ../../include/mymalloc.h
    diff --git a/postfix/src/postkick/postkick.c b/postfix/src/postkick/postkick.c
    index 8446f4069..93df8d0e3 100644
    --- a/postfix/src/postkick/postkick.c
    +++ b/postfix/src/postkick/postkick.c
    @@ -96,6 +96,7 @@
     
     #include 
     #include 
    +#include 
     #include 
     
     static NORETURN usage(char *myname)
    @@ -103,6 +104,8 @@ static NORETURN usage(char *myname)
         msg_fatal("usage: %s [-c config_dir] [-v] class service request", myname);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     int     main(int argc, char **argv)
     {
         char   *class;
    @@ -113,6 +116,11 @@ int     main(int argc, char **argv)
         char   *slash;
         int     c;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * To minimize confusion, make sure that the standard file descriptors
          * are open before opening anything else. XXX Work around for 44BSD where
    diff --git a/postfix/src/postlock/Makefile.in b/postfix/src/postlock/Makefile.in
    index b97c2b9d4..7024d7139 100644
    --- a/postfix/src/postlock/Makefile.in
    +++ b/postfix/src/postlock/Makefile.in
    @@ -66,6 +66,7 @@ postlock.o: ../../include/dsn_util.h
     postlock.o: ../../include/iostuff.h
     postlock.o: ../../include/mail_conf.h
     postlock.o: ../../include/mail_params.h
    +postlock.o: ../../include/mail_version.h
     postlock.o: ../../include/mbox_conf.h
     postlock.o: ../../include/mbox_open.h
     postlock.o: ../../include/msg.h
    diff --git a/postfix/src/postlock/postlock.c b/postfix/src/postlock/postlock.c
    index ab3a4ecf3..e2814bce3 100644
    --- a/postfix/src/postlock/postlock.c
    +++ b/postfix/src/postlock/postlock.c
    @@ -112,6 +112,7 @@
     /* Global library. */
     
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -136,6 +137,8 @@ static void fatal_exit(void)
         exit(EX_TEMPFAIL);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - go for it */
     
     int     main(int argc, char **argv)
    @@ -153,6 +156,11 @@ int     main(int argc, char **argv)
         char   *lock_style = 0;
         MBOX   *mp;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Be consistent with file permissions.
          */
    diff --git a/postfix/src/postlog/Makefile.in b/postfix/src/postlog/Makefile.in
    index d0e135930..5882fd33f 100644
    --- a/postfix/src/postlog/Makefile.in
    +++ b/postfix/src/postlog/Makefile.in
    @@ -64,6 +64,7 @@ depend: $(MAKES)
     postlog.o: ../../include/mail_conf.h
     postlog.o: ../../include/mail_params.h
     postlog.o: ../../include/mail_task.h
    +postlog.o: ../../include/mail_version.h
     postlog.o: ../../include/msg.h
     postlog.o: ../../include/msg_output.h
     postlog.o: ../../include/msg_syslog.h
    diff --git a/postfix/src/postlog/postlog.c b/postfix/src/postlog/postlog.c
    index ef6d37ea1..5ed28a152 100644
    --- a/postfix/src/postlog/postlog.c
    +++ b/postfix/src/postlog/postlog.c
    @@ -97,6 +97,7 @@
     /* Global library. */
     
     #include 		/* XXX right place for LOG_FACILITY? */
    +#include 
     #include 
     #include 
     
    @@ -160,6 +161,8 @@ static void log_stream(int level, VSTREAM *fp)
         vstring_free(buf);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - logger */
     
     int     main(int argc, char **argv)
    @@ -172,6 +175,11 @@ int     main(int argc, char **argv)
         int     log_flags = 0;
         int     level = MSG_INFO;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Be consistent with file permissions.
          */
    diff --git a/postfix/src/postmap/Makefile.in b/postfix/src/postmap/Makefile.in
    index a71a34f84..508fae4ec 100644
    --- a/postfix/src/postmap/Makefile.in
    +++ b/postfix/src/postmap/Makefile.in
    @@ -87,6 +87,7 @@ postmap.o: ../../include/mail_conf.h
     postmap.o: ../../include/mail_dict.h
     postmap.o: ../../include/mail_params.h
     postmap.o: ../../include/mail_task.h
    +postmap.o: ../../include/mail_version.h
     postmap.o: ../../include/mkmap.h
     postmap.o: ../../include/msg.h
     postmap.o: ../../include/msg_syslog.h
    diff --git a/postfix/src/postmap/postmap.c b/postfix/src/postmap/postmap.c
    index d2f15684a..5befc3e69 100644
    --- a/postfix/src/postmap/postmap.c
    +++ b/postfix/src/postmap/postmap.c
    @@ -42,7 +42,7 @@
     /*	The \fIkey\fR and \fIvalue\fR are processed as is, except that
     /*	surrounding white space is stripped off. Unlike with Postfix alias
     /*	databases, quotes cannot be used to protect lookup keys that contain
    -/*	special characters such as `#' or whitespace. 
    +/*	special characters such as `#' or whitespace.
     /*
     /*	By default the lookup key is mapped to lowercase to make
     /*	the lookups case insensitive; as of Postfix 2.3 this case
    @@ -245,6 +245,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 
     #include 
     
    @@ -427,7 +428,7 @@ static int postmap_queries(VSTREAM *in, char **maps, const int map_count,
     /* postmap_query - query a map and print the result to stdout */
     
     static int postmap_query(const char *map_type, const char *map_name,
    -			           const char *key, int dict_flags)
    +			         const char *key, int dict_flags)
     {
         DICT   *dict;
         const char *value;
    @@ -450,7 +451,7 @@ static int postmap_query(const char *map_type, const char *map_name,
     /* postmap_deletes - apply multiple requests from stdin */
     
     static int postmap_deletes(VSTREAM *in, char **maps, const int map_count,
    -			             int dict_flags)
    +			           int dict_flags)
     {
         int     found = 0;
         VSTRING *keybuf = vstring_alloc(100);
    @@ -495,7 +496,7 @@ static int postmap_deletes(VSTREAM *in, char **maps, const int map_count,
     /* postmap_delete - delete a (key, value) pair from a map */
     
     static int postmap_delete(const char *map_type, const char *map_name,
    -			            const char *key, int dict_flags)
    +			          const char *key, int dict_flags)
     {
         DICT   *dict;
         int     status;
    @@ -509,7 +510,7 @@ static int postmap_delete(const char *map_type, const char *map_name,
     /* postmap_seq - print all map entries to stdout */
     
     static void postmap_seq(const char *map_type, const char *map_name,
    -			          int dict_flags)
    +			        int dict_flags)
     {
         DICT   *dict;
         const char *key;
    @@ -543,6 +544,8 @@ static NORETURN usage(char *myname)
     	      myname);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     int     main(int argc, char **argv)
     {
         char   *path_name;
    @@ -558,6 +561,11 @@ int     main(int argc, char **argv)
         int     sequence = 0;
         int     found;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Be consistent with file permissions.
          */
    @@ -663,15 +671,15 @@ int     main(int argc, char **argv)
     	    usage(argv[0]);
     	if (strcmp(delkey, "-") == 0)
     	    exit(postmap_deletes(VSTREAM_IN, argv + optind, argc - optind,
    -				   dict_flags | DICT_FLAG_LOCK) == 0);
    +				 dict_flags | DICT_FLAG_LOCK) == 0);
     	found = 0;
     	while (optind < argc) {
     	    if ((path_name = split_at(argv[optind], ':')) != 0) {
     		found |= postmap_delete(argv[optind], path_name, delkey,
    -					  dict_flags | DICT_FLAG_LOCK);
    +					dict_flags | DICT_FLAG_LOCK);
     	    } else {
     		found |= postmap_delete(var_db_type, argv[optind], delkey,
    -					  dict_flags | DICT_FLAG_LOCK);
    +					dict_flags | DICT_FLAG_LOCK);
     	    }
     	    optind++;
     	}
    @@ -681,14 +689,14 @@ int     main(int argc, char **argv)
     	    usage(argv[0]);
     	if (strcmp(query, "-") == 0)
     	    exit(postmap_queries(VSTREAM_IN, argv + optind, argc - optind,
    -				   dict_flags | DICT_FLAG_LOCK) == 0);
    +				 dict_flags | DICT_FLAG_LOCK) == 0);
     	while (optind < argc) {
     	    if ((path_name = split_at(argv[optind], ':')) != 0) {
     		found = postmap_query(argv[optind], path_name, query,
    -					dict_flags | DICT_FLAG_LOCK);
    +				      dict_flags | DICT_FLAG_LOCK);
     	    } else {
     		found = postmap_query(var_db_type, argv[optind], query,
    -					dict_flags | DICT_FLAG_LOCK);
    +				      dict_flags | DICT_FLAG_LOCK);
     	    }
     	    if (found)
     		exit(0);
    @@ -699,10 +707,10 @@ int     main(int argc, char **argv)
     	while (optind < argc) {
     	    if ((path_name = split_at(argv[optind], ':')) != 0) {
     		postmap_seq(argv[optind], path_name,
    -			      dict_flags | DICT_FLAG_LOCK);
    +			    dict_flags | DICT_FLAG_LOCK);
     	    } else {
     		postmap_seq(var_db_type, argv[optind],
    -			      dict_flags | DICT_FLAG_LOCK);
    +			    dict_flags | DICT_FLAG_LOCK);
     	    }
     	    exit(0);
     	}
    diff --git a/postfix/src/postqueue/Makefile.in b/postfix/src/postqueue/Makefile.in
    index 7a0a39ca9..4e80a3c81 100644
    --- a/postfix/src/postqueue/Makefile.in
    +++ b/postfix/src/postqueue/Makefile.in
    @@ -71,6 +71,7 @@ postqueue.o: ../../include/mail_proto.h
     postqueue.o: ../../include/mail_queue.h
     postqueue.o: ../../include/mail_run.h
     postqueue.o: ../../include/mail_task.h
    +postqueue.o: ../../include/mail_version.h
     postqueue.o: ../../include/msg.h
     postqueue.o: ../../include/msg_syslog.h
     postqueue.o: ../../include/msg_vstream.h
    diff --git a/postfix/src/postqueue/postqueue.c b/postfix/src/postqueue/postqueue.c
    index 8013277be..dad7b592b 100644
    --- a/postfix/src/postqueue/postqueue.c
    +++ b/postfix/src/postqueue/postqueue.c
    @@ -192,6 +192,7 @@
     
     #include 
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -230,8 +231,8 @@
       * establish frequent proof of client liveliness with challenge/response, or
       * the client needs to restrict expensive requests to privileged users only.
       * 
    -  * We don't have this problem with queue listings. The showq server detects
    -  * an EPIPE error after reporting a few queue entries.
    +  * We don't have this problem with queue listings. The showq server detects an
    +  * EPIPE error after reporting a few queue entries.
       */
     #define PQ_MODE_DEFAULT		0	/* noop */
     #define PQ_MODE_MAILQ_LIST	1	/* list mail queue */
    @@ -429,6 +430,8 @@ static NORETURN usage(void)
         msg_fatal_status(EX_USAGE, "usage: postqueue -f | postqueue -i queueid | postqueue -p | postqueue -s site");
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - the main program */
     
     int     main(int argc, char **argv)
    @@ -443,6 +446,11 @@ int     main(int argc, char **argv)
         ARGV   *import_env;
         int     bad_site;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Be consistent with file permissions.
          */
    diff --git a/postfix/src/postsuper/Makefile.in b/postfix/src/postsuper/Makefile.in
    index b131fe88b..0df70b1ad 100644
    --- a/postfix/src/postsuper/Makefile.in
    +++ b/postfix/src/postsuper/Makefile.in
    @@ -63,6 +63,7 @@ postsuper.o: ../../include/mail_open_ok.h
     postsuper.o: ../../include/mail_params.h
     postsuper.o: ../../include/mail_queue.h
     postsuper.o: ../../include/mail_task.h
    +postsuper.o: ../../include/mail_version.h
     postsuper.o: ../../include/msg.h
     postsuper.o: ../../include/msg_syslog.h
     postsuper.o: ../../include/msg_vstream.h
    diff --git a/postfix/src/postsuper/postsuper.c b/postfix/src/postsuper/postsuper.c
    index a8bcedde8..47f67485c 100644
    --- a/postfix/src/postsuper/postsuper.c
    +++ b/postfix/src/postsuper/postsuper.c
    @@ -253,6 +253,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 
     #include 
     
    @@ -988,6 +989,8 @@ static void fatal_warning(void)
         interrupted(0);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     int     main(int argc, char **argv)
     {
         int     fd;
    @@ -1031,6 +1034,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Be consistent with file permissions.
          */
    diff --git a/postfix/src/proxymap/Makefile.in b/postfix/src/proxymap/Makefile.in
    index 565afbf6d..c4ccf673d 100644
    --- a/postfix/src/proxymap/Makefile.in
    +++ b/postfix/src/proxymap/Makefile.in
    @@ -67,6 +67,7 @@ proxymap.o: ../../include/mail_conf.h
     proxymap.o: ../../include/mail_params.h
     proxymap.o: ../../include/mail_proto.h
     proxymap.o: ../../include/mail_server.h
    +proxymap.o: ../../include/mail_version.h
     proxymap.o: ../../include/msg.h
     proxymap.o: ../../include/mymalloc.h
     proxymap.o: ../../include/stringops.h
    diff --git a/postfix/src/proxymap/proxymap.c b/postfix/src/proxymap/proxymap.c
    index 1e143d2dd..a9eb0c06b 100644
    --- a/postfix/src/proxymap/proxymap.c
    +++ b/postfix/src/proxymap/proxymap.c
    @@ -159,6 +159,7 @@
     
     #include 
     #include 
    +#include 
     #include 
     #include 
     
    @@ -429,6 +430,8 @@ static void pre_accept(char *unused_name, char **unused_argv)
         }
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the multi-threaded skeleton */
     
     int     main(int argc, char **argv)
    @@ -450,6 +453,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         multi_server_main(argc, argv, proxymap_service,
     		      MAIL_SERVER_STR_TABLE, str_table,
     		      MAIL_SERVER_POST_INIT, post_jail_init,
    diff --git a/postfix/src/qmgr/Makefile.in b/postfix/src/qmgr/Makefile.in
    index 75b86bf91..d7db1a073 100644
    --- a/postfix/src/qmgr/Makefile.in
    +++ b/postfix/src/qmgr/Makefile.in
    @@ -77,6 +77,7 @@ qmgr.o: ../../include/mail_params.h
     qmgr.o: ../../include/mail_proto.h
     qmgr.o: ../../include/mail_queue.h
     qmgr.o: ../../include/mail_server.h
    +qmgr.o: ../../include/mail_version.h
     qmgr.o: ../../include/master_proto.h
     qmgr.o: ../../include/msg.h
     qmgr.o: ../../include/recipient_list.h
    diff --git a/postfix/src/qmgr/qmgr.c b/postfix/src/qmgr/qmgr.c
    index 4ab22b02d..4cc999671 100644
    --- a/postfix/src/qmgr/qmgr.c
    +++ b/postfix/src/qmgr/qmgr.c
    @@ -346,6 +346,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 			/* QMGR_SCAN constants */
     #include 
     #include 
    @@ -615,6 +616,8 @@ static void qmgr_post_init(char *name, char **unused_argv)
         qmgr_deferred_run_event(0, (char *) 0);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - the main program */
     
     int     main(int argc, char **argv)
    @@ -659,6 +662,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Use the trigger service skeleton, because no-one else should be
          * monitoring our service port while this process runs, and because we do
    diff --git a/postfix/src/qmqpd/Makefile.in b/postfix/src/qmqpd/Makefile.in
    index 84c5523b8..ef50fda86 100644
    --- a/postfix/src/qmqpd/Makefile.in
    +++ b/postfix/src/qmqpd/Makefile.in
    @@ -72,6 +72,7 @@ qmqpd.o: ../../include/mail_params.h
     qmqpd.o: ../../include/mail_proto.h
     qmqpd.o: ../../include/mail_server.h
     qmqpd.o: ../../include/mail_stream.h
    +qmqpd.o: ../../include/mail_version.h
     qmqpd.o: ../../include/match_list.h
     qmqpd.o: ../../include/match_ops.h
     qmqpd.o: ../../include/match_parent_style.h
    diff --git a/postfix/src/qmqpd/qmqpd.c b/postfix/src/qmqpd/qmqpd.c
    index 19d804697..171ecae63 100644
    --- a/postfix/src/qmqpd/qmqpd.c
    +++ b/postfix/src/qmqpd/qmqpd.c
    @@ -165,6 +165,7 @@
     /* Global library. */
     
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -759,6 +760,8 @@ static void post_jail_init(char *unused_name, char **unused_argv)
         input_transp_mask(VAR_INPUT_TRANSP, var_input_transp);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - the main program */
     
     int     main(int argc, char **argv)
    @@ -775,6 +778,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Pass control to the single-threaded service skeleton.
          */
    diff --git a/postfix/src/scache/Makefile.in b/postfix/src/scache/Makefile.in
    index e5282e84f..c6ab06562 100644
    --- a/postfix/src/scache/Makefile.in
    +++ b/postfix/src/scache/Makefile.in
    @@ -65,6 +65,7 @@ scache.o: ../../include/mail_conf.h
     scache.o: ../../include/mail_params.h
     scache.o: ../../include/mail_proto.h
     scache.o: ../../include/mail_server.h
    +scache.o: ../../include/mail_version.h
     scache.o: ../../include/msg.h
     scache.o: ../../include/ring.h
     scache.o: ../../include/scache.h
    diff --git a/postfix/src/scache/scache.c b/postfix/src/scache/scache.c
    index 28de18c34..f75ec306a 100644
    --- a/postfix/src/scache/scache.c
    +++ b/postfix/src/scache/scache.c
    @@ -155,6 +155,7 @@
     /* Global library. */
     
     #include 
    +#include 
     #include 
     #include 
     
    @@ -532,6 +533,8 @@ static void post_jail_init(char *unused_name, char **unused_argv)
         scache_start_time = event_time();
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the multi-threaded skeleton */
     
     int     main(int argc, char **argv)
    @@ -542,6 +545,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         multi_server_main(argc, argv, scache_service,
     		      MAIL_SERVER_TIME_TABLE, time_table,
     		      MAIL_SERVER_POST_INIT, post_jail_init,
    diff --git a/postfix/src/sendmail/Makefile.in b/postfix/src/sendmail/Makefile.in
    index cf9dbeeaa..262b9b8f8 100644
    --- a/postfix/src/sendmail/Makefile.in
    +++ b/postfix/src/sendmail/Makefile.in
    @@ -76,6 +76,7 @@ sendmail.o: ../../include/mail_queue.h
     sendmail.o: ../../include/mail_run.h
     sendmail.o: ../../include/mail_stream.h
     sendmail.o: ../../include/mail_task.h
    +sendmail.o: ../../include/mail_version.h
     sendmail.o: ../../include/mime_state.h
     sendmail.o: ../../include/msg.h
     sendmail.o: ../../include/msg_stats.h
    diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c
    index 08cf0209c..30fef831e 100644
    --- a/postfix/src/sendmail/sendmail.c
    +++ b/postfix/src/sendmail/sendmail.c
    @@ -419,6 +419,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -897,6 +898,8 @@ static void tempfail(void)
         exit(EX_TEMPFAIL);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - the main program */
     
     int     main(int argc, char **argv)
    @@ -924,6 +927,11 @@ int     main(int argc, char **argv)
         const char *dsn_envid = 0;
         int     saved_optind;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Be consistent with file permissions.
          */
    @@ -1009,7 +1017,7 @@ int     main(int argc, char **argv)
         optind = saved_optind;
         mail_conf_read();
         if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0)
    -        msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY);
    +	msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY);
         get_mail_conf_str_table(str_table);
     
         if (chdir(var_queue_dir))
    diff --git a/postfix/src/showq/Makefile.in b/postfix/src/showq/Makefile.in
    index 2783e9700..d4cd349cb 100644
    --- a/postfix/src/showq/Makefile.in
    +++ b/postfix/src/showq/Makefile.in
    @@ -72,6 +72,7 @@ showq.o: ../../include/mail_proto.h
     showq.o: ../../include/mail_queue.h
     showq.o: ../../include/mail_scan_dir.h
     showq.o: ../../include/mail_server.h
    +showq.o: ../../include/mail_version.h
     showq.o: ../../include/msg.h
     showq.o: ../../include/mymalloc.h
     showq.o: ../../include/quote_822_local.h
    diff --git a/postfix/src/showq/showq.c b/postfix/src/showq/showq.c
    index 30ed5f9bb..8e1cc2d04 100644
    --- a/postfix/src/showq/showq.c
    +++ b/postfix/src/showq/showq.c
    @@ -122,6 +122,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -143,8 +144,8 @@ char   *var_empty_addr;
     #define SENDER_FORMAT	"%-11s %7ld %20.20s %s\n"
     #define DROP_FORMAT	"%-10s%c %7ld %20.20s (maildrop queue, sender UID %u)\n"
     
    -static void showq_reasons(VSTREAM *, BOUNCE_LOG *, RCPT_BUF *, DSN_BUF *, 
    -HTABLE *);
    +static void showq_reasons(VSTREAM *, BOUNCE_LOG *, RCPT_BUF *, DSN_BUF *,
    +			          HTABLE *);
     
     #define STR(x)	vstring_str(x)
     
    @@ -260,8 +261,8 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
     
     /* showq_reasons - show deferral reasons */
     
    -static void showq_reasons(VSTREAM *client, BOUNCE_LOG *bp, RCPT_BUF *rcpt_buf, 
    -DSN_BUF *dsn_buf, HTABLE *dup_filter)
    +static void showq_reasons(VSTREAM *client, BOUNCE_LOG *bp, RCPT_BUF *rcpt_buf,
    +			          DSN_BUF *dsn_buf, HTABLE *dup_filter)
     {
         char   *saved_reason = 0;
         int     padding;
    @@ -395,6 +396,8 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
         }
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the single-threaded server skeleton */
     
     int     main(int argc, char **argv)
    @@ -408,6 +411,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         single_server_main(argc, argv, showq_service,
     		       MAIL_SERVER_INT_TABLE, int_table,
     		       MAIL_SERVER_STR_TABLE, str_table,
    diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in
    index 94ef9d3c7..8e578347d 100644
    --- a/postfix/src/smtp/Makefile.in
    +++ b/postfix/src/smtp/Makefile.in
    @@ -99,6 +99,7 @@ smtp.o: ../../include/htable.h
     smtp.o: ../../include/mail_conf.h
     smtp.o: ../../include/mail_params.h
     smtp.o: ../../include/mail_server.h
    +smtp.o: ../../include/mail_version.h
     smtp.o: ../../include/maps.h
     smtp.o: ../../include/match_list.h
     smtp.o: ../../include/match_ops.h
    @@ -168,6 +169,7 @@ smtp_chat.o: ../../include/dsn.h
     smtp_chat.o: ../../include/dsn_buf.h
     smtp_chat.o: ../../include/dsn_util.h
     smtp_chat.o: ../../include/htable.h
    +smtp_chat.o: ../../include/int_filt.h
     smtp_chat.o: ../../include/line_wrap.h
     smtp_chat.o: ../../include/mail_addr.h
     smtp_chat.o: ../../include/mail_error.h
    diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c
    index 363b8132b..29c91d586 100644
    --- a/postfix/src/smtp/smtp.c
    +++ b/postfix/src/smtp/smtp.c
    @@ -602,6 +602,7 @@
     
     #include 
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -947,6 +948,8 @@ static void pre_accept(char *unused_name, char **unused_argv)
         }
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the single-threaded skeleton */
     
     int     main(int argc, char **argv)
    @@ -955,6 +958,11 @@ int     main(int argc, char **argv)
     #include "lmtp_params.c"
         int     smtp_mode;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * XXX At this point, var_procname etc. are not initialized.
          */
    diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c
    index 96d09ef94..601a1f538 100644
    --- a/postfix/src/smtpd/smtpd.c
    +++ b/postfix/src/smtpd/smtpd.c
    @@ -4401,6 +4401,8 @@ static void post_jail_init(char *unused_name, char **unused_argv)
     	anvil_clnt = anvil_clnt_create();
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - the main program */
     
     int     main(int argc, char **argv)
    @@ -4572,6 +4574,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Pass control to the single-threaded service skeleton.
          */
    diff --git a/postfix/src/smtpstone/Makefile.in b/postfix/src/smtpstone/Makefile.in
    index 6de57d175..3c0316e73 100644
    --- a/postfix/src/smtpstone/Makefile.in
    +++ b/postfix/src/smtpstone/Makefile.in
    @@ -82,6 +82,7 @@ qmqp-sink.o: ../../include/events.h
     qmqp-sink.o: ../../include/inet_proto.h
     qmqp-sink.o: ../../include/iostuff.h
     qmqp-sink.o: ../../include/listen.h
    +qmqp-sink.o: ../../include/mail_version.h
     qmqp-sink.o: ../../include/msg.h
     qmqp-sink.o: ../../include/msg_vstream.h
     qmqp-sink.o: ../../include/mymalloc.h
    @@ -99,6 +100,7 @@ qmqp-source.o: ../../include/host_port.h
     qmqp-source.o: ../../include/inet_proto.h
     qmqp-source.o: ../../include/iostuff.h
     qmqp-source.o: ../../include/mail_date.h
    +qmqp-source.o: ../../include/mail_version.h
     qmqp-source.o: ../../include/msg.h
     qmqp-source.o: ../../include/msg_vstream.h
     qmqp-source.o: ../../include/myaddrinfo.h
    @@ -114,14 +116,20 @@ qmqp-source.o: ../../include/vbuf.h
     qmqp-source.o: ../../include/vstream.h
     qmqp-source.o: ../../include/vstring.h
     qmqp-source.o: qmqp-source.c
    +smtp-sink.o: ../../include/chroot_uid.h
     smtp-sink.o: ../../include/events.h
     smtp-sink.o: ../../include/get_hostname.h
     smtp-sink.o: ../../include/inet_proto.h
     smtp-sink.o: ../../include/iostuff.h
     smtp-sink.o: ../../include/listen.h
    +smtp-sink.o: ../../include/mail_date.h
    +smtp-sink.o: ../../include/mail_version.h
    +smtp-sink.o: ../../include/make_dirs.h
     smtp-sink.o: ../../include/msg.h
     smtp-sink.o: ../../include/msg_vstream.h
    +smtp-sink.o: ../../include/myaddrinfo.h
     smtp-sink.o: ../../include/mymalloc.h
    +smtp-sink.o: ../../include/myrand.h
     smtp-sink.o: ../../include/sane_accept.h
     smtp-sink.o: ../../include/smtp_stream.h
     smtp-sink.o: ../../include/stringops.h
    @@ -138,6 +146,7 @@ smtp-source.o: ../../include/host_port.h
     smtp-source.o: ../../include/inet_proto.h
     smtp-source.o: ../../include/iostuff.h
     smtp-source.o: ../../include/mail_date.h
    +smtp-source.o: ../../include/mail_version.h
     smtp-source.o: ../../include/msg.h
     smtp-source.o: ../../include/msg_vstream.h
     smtp-source.o: ../../include/myaddrinfo.h
    diff --git a/postfix/src/smtpstone/qmqp-sink.c b/postfix/src/smtpstone/qmqp-sink.c
    index 30390e627..f89cd194f 100644
    --- a/postfix/src/smtpstone/qmqp-sink.c
    +++ b/postfix/src/smtpstone/qmqp-sink.c
    @@ -79,6 +79,7 @@
     /* Global library. */
     
     #include 
    +#include 
     
     /* Application-specific. */
     
    @@ -239,6 +240,8 @@ static void usage(char *myname)
         msg_fatal("usage: %s [-cv] [-x time] [host]:port backlog", myname);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     int     main(int argc, char **argv)
     {
         int     sock;
    @@ -248,6 +251,11 @@ int     main(int argc, char **argv)
         const char *protocols = INET_PROTO_NAME_ALL;
         INET_PROTO_INFO *proto_info;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Fix 20051207.
          */
    diff --git a/postfix/src/smtpstone/qmqp-source.c b/postfix/src/smtpstone/qmqp-source.c
    index 2606e6e11..33282ac40 100644
    --- a/postfix/src/smtpstone/qmqp-source.c
    +++ b/postfix/src/smtpstone/qmqp-source.c
    @@ -110,6 +110,7 @@
     
     #include 
     #include 
    +#include 
     
     /* Application-specific. */
     
    @@ -442,6 +443,8 @@ static void usage(char *myname)
         msg_fatal("usage: %s -cv -s sess -l msglen -m msgs -C count -M myhostname -f from -t to -R delay -w delay host[:port]", myname);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - parse JCL and start the machine */
     
     int     main(int argc, char **argv)
    @@ -463,6 +466,11 @@ int     main(int argc, char **argv)
         const char *protocols = INET_PROTO_NAME_ALL;
         INET_PROTO_INFO *proto_info;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         signal(SIGPIPE, SIG_IGN);
         msg_vstream_init(argv[0], VSTREAM_ERR);
     
    diff --git a/postfix/src/smtpstone/smtp-sink.c b/postfix/src/smtpstone/smtp-sink.c
    index b18278fa9..d5b0bcd7e 100644
    --- a/postfix/src/smtpstone/smtp-sink.c
    +++ b/postfix/src/smtpstone/smtp-sink.c
    @@ -266,6 +266,7 @@
     
     #include 
     #include 
    +#include 
     
     /* Application-specific. */
     
    @@ -1249,6 +1250,8 @@ static void usage(char *myname)
         msg_fatal("usage: %s [-468acCeEFLpPv] [-A abort_delay] [-f commands] [-h hostname] [-m max_concurrency] [-n quit_count] [-q commands] [-r commands] [-s commands] [-w delay] [-d dump-template] [-D dump-template] [-R root-dir] [-S start-string] [-u user_privs] [host]:port backlog", myname);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     int     main(int argc, char **argv)
     {
         int     backlog;
    @@ -1258,6 +1261,11 @@ int     main(int argc, char **argv)
         const char *root_dir = 0;
         const char *user_privs = 0;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Fix 20051207.
          */
    diff --git a/postfix/src/smtpstone/smtp-source.c b/postfix/src/smtpstone/smtp-source.c
    index 9a736e14a..52306cf8c 100644
    --- a/postfix/src/smtpstone/smtp-source.c
    +++ b/postfix/src/smtpstone/smtp-source.c
    @@ -137,6 +137,7 @@
     
     #include 
     #include 
    +#include 
     
     /* Application-specific. */
     
    @@ -794,6 +795,8 @@ static void usage(char *myname)
         msg_fatal("usage: %s -cdLNov -s sess -l msglen -m msgs -C count -M myhostname -f from -t to -r rcptcount -R delay -w delay host[:port]", myname);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - parse JCL and start the machine */
     
     int     main(int argc, char **argv)
    @@ -813,6 +816,11 @@ int     main(int argc, char **argv)
         const char *protocols = INET_PROTO_NAME_ALL;
         INET_PROTO_INFO *proto_info;
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         signal(SIGPIPE, SIG_IGN);
         msg_vstream_init(argv[0], VSTREAM_ERR);
     
    diff --git a/postfix/src/spawn/Makefile.in b/postfix/src/spawn/Makefile.in
    index 24d2cc2fe..1a89937db 100644
    --- a/postfix/src/spawn/Makefile.in
    +++ b/postfix/src/spawn/Makefile.in
    @@ -62,6 +62,7 @@ spawn.o: ../../include/dict.h
     spawn.o: ../../include/mail_conf.h
     spawn.o: ../../include/mail_params.h
     spawn.o: ../../include/mail_server.h
    +spawn.o: ../../include/mail_version.h
     spawn.o: ../../include/msg.h
     spawn.o: ../../include/mymalloc.h
     spawn.o: ../../include/set_eugid.h
    diff --git a/postfix/src/spawn/spawn.c b/postfix/src/spawn/spawn.c
    index 9fa0eb9ec..90fe7987b 100644
    --- a/postfix/src/spawn/spawn.c
    +++ b/postfix/src/spawn/spawn.c
    @@ -70,7 +70,7 @@
     /*	The amount of time the command is allowed to run before it is
     /*	terminated.
     /*
    -/*	Postfix 2.4 and later support a suffix that specifies the 
    +/*	Postfix 2.4 and later support a suffix that specifies the
     /*	time unit: s (seconds), m (minutes), h (hours), d (days),
     /*	w (weeks). The default time unit is seconds.
     /* MISCELLANEOUS
    @@ -148,6 +148,10 @@
     #include 
     #include 
     
    +/* Global library. */
    +
    +#include 
    +
     /* Single server skeleton. */
     
     #include 
    @@ -322,7 +326,7 @@ static void spawn_service(VSTREAM *client_stream, char *service, char **argv)
     static void pre_accept(char *unused_name, char **unused_argv)
     {
         const char *table;
    - 
    +
         if ((table = dict_changed_name()) != 0) {
     	msg_info("table %s has changed -- restarting", table);
     	exit(0);
    @@ -336,6 +340,8 @@ static void drop_privileges(char *unused_name, char **unused_argv)
         set_eugid(var_owner_uid, var_owner_gid);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the single-threaded skeleton */
     
     int     main(int argc, char **argv)
    @@ -345,6 +351,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         single_server_main(argc, argv, spawn_service,
     		       MAIL_SERVER_TIME_TABLE, time_table,
     		       MAIL_SERVER_POST_INIT, drop_privileges,
    diff --git a/postfix/src/tlsmgr/Makefile.in b/postfix/src/tlsmgr/Makefile.in
    index 05301e47b..a25208427 100644
    --- a/postfix/src/tlsmgr/Makefile.in
    +++ b/postfix/src/tlsmgr/Makefile.in
    @@ -68,6 +68,7 @@ tlsmgr.o: ../../include/mail_conf.h
     tlsmgr.o: ../../include/mail_params.h
     tlsmgr.o: ../../include/mail_proto.h
     tlsmgr.o: ../../include/mail_server.h
    +tlsmgr.o: ../../include/mail_version.h
     tlsmgr.o: ../../include/master_proto.h
     tlsmgr.o: ../../include/msg.h
     tlsmgr.o: ../../include/mymalloc.h
    diff --git a/postfix/src/tlsmgr/tlsmgr.c b/postfix/src/tlsmgr/tlsmgr.c
    index ed1018ec1..e4630193d 100644
    --- a/postfix/src/tlsmgr/tlsmgr.c
    +++ b/postfix/src/tlsmgr/tlsmgr.c
    @@ -192,6 +192,7 @@
     
     #include 
     #include 
    +#include 
     #include 
     #include 
     
    @@ -876,6 +877,8 @@ static void tlsmgr_before_exit(char *unused_service_name, char **unused_argv)
     	tls_prng_exch_update(rand_exch);
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - the main program */
     
     int     main(int argc, char **argv)
    @@ -904,6 +907,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         /*
          * Use the multi service skeleton, and require that no-one else is
          * monitoring our service port while this process runs.
    diff --git a/postfix/src/trivial-rewrite/Makefile.in b/postfix/src/trivial-rewrite/Makefile.in
    index eadb385c0..6b3ae51a3 100644
    --- a/postfix/src/trivial-rewrite/Makefile.in
    +++ b/postfix/src/trivial-rewrite/Makefile.in
    @@ -146,6 +146,7 @@ trivial-rewrite.o: ../../include/mail_conf.h
     trivial-rewrite.o: ../../include/mail_params.h
     trivial-rewrite.o: ../../include/mail_proto.h
     trivial-rewrite.o: ../../include/mail_server.h
    +trivial-rewrite.o: ../../include/mail_version.h
     trivial-rewrite.o: ../../include/maps.h
     trivial-rewrite.o: ../../include/msg.h
     trivial-rewrite.o: ../../include/resolve_clnt.h
    diff --git a/postfix/src/trivial-rewrite/trivial-rewrite.c b/postfix/src/trivial-rewrite/trivial-rewrite.c
    index 233d740a4..d539a5d2a 100644
    --- a/postfix/src/trivial-rewrite/trivial-rewrite.c
    +++ b/postfix/src/trivial-rewrite/trivial-rewrite.c
    @@ -272,6 +272,7 @@
     /* Global library. */
     
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -530,6 +531,8 @@ static void post_jail_init(char *unused_name, char **unused_argv)
         var_idle_limit = 1;
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the multi-threaded skeleton code */
     
     int     main(int argc, char **argv)
    @@ -569,6 +572,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         multi_server_main(argc, argv, rewrite_service,
     		      MAIL_SERVER_STR_TABLE, str_table,
     		      MAIL_SERVER_BOOL_TABLE, bool_table,
    diff --git a/postfix/src/verify/Makefile.in b/postfix/src/verify/Makefile.in
    index f9671f8da..0bb5c159d 100644
    --- a/postfix/src/verify/Makefile.in
    +++ b/postfix/src/verify/Makefile.in
    @@ -65,11 +65,13 @@ verify.o: ../../include/dict.h
     verify.o: ../../include/dict_ht.h
     verify.o: ../../include/dsn.h
     verify.o: ../../include/htable.h
    +verify.o: ../../include/int_filt.h
     verify.o: ../../include/iostuff.h
     verify.o: ../../include/mail_conf.h
     verify.o: ../../include/mail_params.h
     verify.o: ../../include/mail_proto.h
     verify.o: ../../include/mail_server.h
    +verify.o: ../../include/mail_version.h
     verify.o: ../../include/msg.h
     verify.o: ../../include/msg_stats.h
     verify.o: ../../include/mymalloc.h
    diff --git a/postfix/src/verify/verify.c b/postfix/src/verify/verify.c
    index c1771fa56..13db73fd8 100644
    --- a/postfix/src/verify/verify.c
    +++ b/postfix/src/verify/verify.c
    @@ -186,6 +186,7 @@
     
     #include 
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -562,6 +563,8 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
         setsid();
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the multi-threaded skeleton */
     
     int     main(int argc, char **argv)
    @@ -579,6 +582,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         multi_server_main(argc, argv, verify_service,
     		      MAIL_SERVER_STR_TABLE, str_table,
     		      MAIL_SERVER_TIME_TABLE, time_table,
    diff --git a/postfix/src/virtual/Makefile.in b/postfix/src/virtual/Makefile.in
    index 51360fe43..9aed39f41 100644
    --- a/postfix/src/virtual/Makefile.in
    +++ b/postfix/src/virtual/Makefile.in
    @@ -187,6 +187,7 @@ virtual.o: ../../include/mail_conf.h
     virtual.o: ../../include/mail_params.h
     virtual.o: ../../include/mail_queue.h
     virtual.o: ../../include/mail_server.h
    +virtual.o: ../../include/mail_version.h
     virtual.o: ../../include/maps.h
     virtual.o: ../../include/mbox_conf.h
     virtual.o: ../../include/msg.h
    diff --git a/postfix/src/virtual/virtual.c b/postfix/src/virtual/virtual.c
    index 1ccbcc67d..c52227874 100644
    --- a/postfix/src/virtual/virtual.c
    +++ b/postfix/src/virtual/virtual.c
    @@ -303,6 +303,7 @@
     #include 
     #include 
     #include 
    +#include 
     #include 
     #include 
     #include 
    @@ -482,6 +483,8 @@ static void pre_init(char *unused_name, char **unused_argv)
         flush_init();
     }
     
    +MAIL_VERSION_STAMP_DECLARE;
    +
     /* main - pass control to the single-threaded skeleton */
     
     int     main(int argc, char **argv)
    @@ -501,6 +504,11 @@ int     main(int argc, char **argv)
     	0,
         };
     
    +    /*
    +     * Fingerprint executables and core dumps.
    +     */
    +    MAIL_VERSION_STAMP_ALLOCATE;
    +
         single_server_main(argc, argv, local_service,
     		       MAIL_SERVER_INT_TABLE, int_table,
     		       MAIL_SERVER_STR_TABLE, str_table,