mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-31 14:17:41 +00:00
postfix-2.3-20050308
This commit is contained in:
committed by
Viktor Dukhovni
parent
9bf2b1e43e
commit
9228cc5a29
@@ -10341,6 +10341,13 @@ Apologies for any names omitted.
|
||||
Cleanup: documented the myorigin/mydomain address rewriting
|
||||
in canonical, generic and virtual alias maps.
|
||||
|
||||
Feature: updated LDAP and *SQL query interfaces using a
|
||||
common infrastructure so that all have the same feature set
|
||||
where possible. Victor Duchovni and many others. This code
|
||||
was tested separately and was merged into the main stream
|
||||
20050308. Files: global/db_common.[hc], global/dict_ldap.c,
|
||||
global/dict_mysql.c, global/dict_pgsql.c, plus documentation.
|
||||
|
||||
20050210
|
||||
|
||||
Bugfix: spurious fallback_relay warnings after 20050202.
|
||||
@@ -10445,6 +10452,11 @@ Apologies for any names omitted.
|
||||
webpage. As proof of authenticity the new PGP key is signed
|
||||
with Wietse's old PGP key.
|
||||
|
||||
Cleanup: check_mumble_{ns,mx}_access no longer attempt to
|
||||
do MX or NS lookups for address literals. An address literal
|
||||
is treated as its own MX host; there is no meaningful
|
||||
equivalent for NS access control. File: smtpd/smtpd_check.c.
|
||||
|
||||
Open problems:
|
||||
|
||||
Med: disable header address rewriting after XCLIENT?
|
||||
|
@@ -129,58 +129,59 @@ this document for the first time, skip forward to "Address rewriting when mail
|
||||
is received". Once you've finished reading the remainder of this document, the
|
||||
table will help you to quickly find what you need.
|
||||
|
||||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
|AAddddrreessss |SSccooppee |DDaaeemmoonn |GGlloobbaall ttuurrnn--oonn |SSeelleeccttiivvee ttuurrnn--ooffff |
|
||||
|mmaanniippuullaattiioonn| | |ccoonnttrrooll |ccoonnttrrooll |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Rewrite | |trivial-|append_at_myorigin, | |
|
||||
|addresses to|all mail|rewrite |append_dot_mydomain,|none |
|
||||
|standard | |(8) |swap_bangpath, | |
|
||||
|form | | |allow_percent_hack | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Canonical | |cleanup | | |
|
||||
|address |all mail|(8) |canonical_maps |receive_override_options|
|
||||
|mapping | | | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Address |all mail|cleanup |masquerade_domains |receive_override_options|
|
||||
|masquerading| |(8) | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Automatic | |cleanup |always_bcc, | |
|
||||
|BCC |new mail|(8) |sender_bcc_maps, |receive_override_options|
|
||||
|recipients | | |recipient_bcc_maps | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Virtual |all mail|cleanup |virtual_alias_maps |receive_override_options|
|
||||
|aliasing | |(8) | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Resolve | |trivial-| | |
|
||||
|address to |all mail|rewrite |none |none |
|
||||
|destination | |(8) | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Mail | |trivial-| | |
|
||||
|transport |all mail|rewrite |transport_maps |none |
|
||||
|switch | |(8) | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Relocated | |trivial-| | |
|
||||
|users table |all mail|rewrite |relocated_maps |none |
|
||||
| | |(8) | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Generic |outgoing| | | |
|
||||
|mapping |SMTP |smtp(8) |smtp_generic_maps |none |
|
||||
|table |mail | | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Local alias |local | | | |
|
||||
|database |mail |local(8)|alias_maps |none |
|
||||
| |only | | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Local per- |local | | | |
|
||||
|user |mail |local(8)|forward_path |none |
|
||||
|.forward |only | | | |
|
||||
|files | | | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Local catch-|local | | | |
|
||||
|all address |mail |local(8)|luser_relay |none |
|
||||
| |only | | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
|AAddddrreessss |SSccooppee |DDaaeemmoonn |GGlloobbaall ttuurrnn--oonn |SSeelleeccttiivvee ttuurrnn--ooffff ccoonnttrrooll |
|
||||
|mmaanniippuullaattiioonn| | |ccoonnttrrooll | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Rewrite | |trivial-|append_at_myorigin, | |
|
||||
|addresses to|all mail|rewrite |append_dot_mydomain,|local_header_rewrite_clients,|
|
||||
|standard | |(8) |swap_bangpath, |remote_header_rewrite_domain |
|
||||
|form | | |allow_percent_hack | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Canonical | |cleanup | |receive_override_options, |
|
||||
|address |all mail|(8) |canonical_maps |local_header_rewrite_clients,|
|
||||
|mapping | | | |remote_header_rewrite_domain |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Address | |cleanup | |receive_override_options, |
|
||||
|masquerading|all mail|(8) |masquerade_domains |local_header_rewrite_clients,|
|
||||
| | | | |remote_header_rewrite_domain |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Automatic | |cleanup |always_bcc, | |
|
||||
|BCC |new mail|(8) |sender_bcc_maps, |receive_override_options |
|
||||
|recipients | | |recipient_bcc_maps | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Virtual |all mail|cleanup |virtual_alias_maps |receive_override_options |
|
||||
|aliasing | |(8) | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Resolve | |trivial-| | |
|
||||
|address to |all mail|rewrite |none |none |
|
||||
|destination | |(8) | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Mail | |trivial-| | |
|
||||
|transport |all mail|rewrite |transport_maps |none |
|
||||
|switch | |(8) | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Relocated | |trivial-| | |
|
||||
|users table |all mail|rewrite |relocated_maps |none |
|
||||
| | |(8) | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Generic |outgoing| | | |
|
||||
|mapping |SMTP |smtp(8) |smtp_generic_maps |none |
|
||||
|table |mail | | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Local alias |local | | | |
|
||||
|database |mail |local(8)|alias_maps |none |
|
||||
| |only | | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Local per- |local | | | |
|
||||
|user |mail |local(8)|forward_path |none |
|
||||
|.forward |only | | | |
|
||||
|files | | | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|Local catch-|local | | | |
|
||||
|all address |mail |local(8)|luser_relay |none |
|
||||
| |only | | | |
|
||||
|_ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
|
||||
|
||||
AAddddrreessss rreewwrriittiinngg wwhheenn mmaaiill iiss rreecceeiivveedd
|
||||
|
||||
@@ -213,11 +214,11 @@ table, it first rewrites the address to the standard
|
||||
rewrite(8) daemon. The purpose of rewriting to standard form is to reduce the
|
||||
number of entries needed in lookup tables.
|
||||
|
||||
Postfix versions 2.2 and later do not rewrite message headers from remote SMTP
|
||||
clients at all, unless a non-empty domain name is specified with the
|
||||
remote_header_rewrite_domain configuration parameter. The
|
||||
local_header_rewrite_clients parameter controls what SMTP clients Postfix
|
||||
considers local.
|
||||
NOTE: Postfix versions 2.2 and later rewrite message headers from remote SMTP
|
||||
clients only if the client matches the local_header_rewrite_clients parameter,
|
||||
or if the remote_header_rewrite_domain configuration parameter specifies a non-
|
||||
empty value. To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all".
|
||||
|
||||
The Postfix trivial-rewrite(8) daemon implements the following hard-coded
|
||||
address manipulations:
|
||||
@@ -246,10 +247,13 @@ address manipulations:
|
||||
of Postfix components expect that all addresses have the form
|
||||
"user@domain".
|
||||
|
||||
Postfix versions 2.2 and later either do not rewrite message headers
|
||||
from remote SMTP clients at all, or they append the domain name
|
||||
specified with the remote_header_rewrite_domain configuration
|
||||
parameter.
|
||||
NOTE: Postfix versions 2.2 and later rewrite message headers from
|
||||
remote SMTP clients only if the client matches the
|
||||
local_header_rewrite_clients parameter; otherwise they append the
|
||||
domain name specified with the remote_header_rewrite_domain
|
||||
configuration parameter, if one is specified. To get the behavior
|
||||
before Postfix 2.2, specify "local_header_rewrite_clients = static:
|
||||
all".
|
||||
|
||||
If your machine is not the main machine for $myorigin and you wish to
|
||||
have some users delivered locally without going via that main machine,
|
||||
@@ -262,9 +266,13 @@ address manipulations:
|
||||
(default: yes). The purpose is to get consistent treatment of different
|
||||
forms of the same hostname.
|
||||
|
||||
Postfix versions 2.2 and later either do not rewrite message headers
|
||||
from remote clients at all, or they append the domain name specified
|
||||
with the remote_header_rewrite_domain configuration parameter.
|
||||
NOTE: Postfix versions 2.2 and later rewrite message headers from
|
||||
remote SMTP clients only if the client matches the
|
||||
local_header_rewrite_clients parameter; otherwise they append the
|
||||
domain name specified with the remote_header_rewrite_domain
|
||||
configuration parameter, if one is specified. To get the behavior
|
||||
before Postfix 2.2, specify "local_header_rewrite_clients = static:
|
||||
all".
|
||||
|
||||
Some will argue that rewriting "host" to "host.domain" is bad. That is
|
||||
why it can be turned off. Others like the convenience of having
|
||||
@@ -281,11 +289,11 @@ message envelopes and in message headers. By default all header and envelope
|
||||
addresses are rewritten; this is controlled with the canonical_classes
|
||||
configuration parameter.
|
||||
|
||||
Postfix versions 2.2 and later do not rewrite message headers from remote
|
||||
clients at all, unless a non-empty domain name is specified with the
|
||||
remote_header_rewrite_domain configuration parameter. The
|
||||
local_header_rewrite_clients parameter controls what SMTP clients Postfix
|
||||
considers local.
|
||||
NOTE: Postfix versions 2.2 and later rewrite message headers from remote SMTP
|
||||
clients only if the client matches the local_header_rewrite_clients parameter,
|
||||
or if the remote_header_rewrite_domain configuration parameter specifies a non-
|
||||
empty value. To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all".
|
||||
|
||||
Address rewriting is done for local and remote addresses. The mapping is useful
|
||||
to replace login names by "Firstname.Lastname" style addresses, or to clean up
|
||||
@@ -345,11 +353,11 @@ Address masquerading is a method to hide hosts inside a domain behind their
|
||||
mail gateway, and to make it appear as if the mail comes from the gateway
|
||||
itself, instead of from individual machines.
|
||||
|
||||
Postfix versions 2.2 and later do not rewrite message headers from remote SMTP
|
||||
clients at all, unless a non-empty domain name is specified with the
|
||||
remote_header_rewrite_domain configuration parameter. The
|
||||
local_header_rewrite_clients parameter controls what SMTP clients Postfix
|
||||
considers local.
|
||||
NOTE: Postfix versions 2.2 and later rewrite message headers from remote SMTP
|
||||
clients only if the client matches the local_header_rewrite_clients parameter,
|
||||
or if the remote_header_rewrite_domain configuration parameter specifies a non-
|
||||
empty value. To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all".
|
||||
|
||||
Address masquerading is disabled by default, and is implemented by the cleanup
|
||||
(8) server. To enable, edit the masquerade_domains parameter in the main.cf
|
||||
|
@@ -180,7 +180,7 @@ NNootteess aanndd tthhiinnggss ttoo tthhiinnkk aabboouu
|
||||
* If you use an LDAP map for lookups other than aliases, you may have to make
|
||||
sure the lookup makes sense. In the case of virtual lookups, maildrops
|
||||
other than mail addresses are pretty useless, because Postfix can't know
|
||||
how to set the ownership for program or file delivery. Your query_filter
|
||||
how to set the ownership for program or file delivery. Your qquueerryy__ffiilltteerr
|
||||
should probably look something like this:
|
||||
|
||||
query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")
|
||||
@@ -196,7 +196,7 @@ NNootteess aanndd tthhiinnggss ttoo tthhiinnkk aabboouu
|
||||
some thought on your part to implement safely, considering the
|
||||
ramifications of this type of delivery. You may decide it's not worth the
|
||||
bother to allow any of that nonsense in LDAP lookups, ban it in the
|
||||
query_filter, and keep things like majordomo lists in local alias
|
||||
qquueerryy__ffiilltteerr, and keep things like majordomo lists in local alias
|
||||
databases.
|
||||
|
||||
query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")
|
||||
@@ -236,12 +236,17 @@ CCrreeddiittss
|
||||
the work on RFC 2254 escaping in queries. Spotted a bug in binding.
|
||||
* Sami Haahtinen: Referral chasing and v3 support.
|
||||
* Victor Duchovni: ldap_bind() timeout. With fixes from LaMont Jones:
|
||||
OpenLDAP cache deprecation. Limits on recursion, expansion and query
|
||||
OpenLDAP cache deprecation. Limits on recursion, expansion and search
|
||||
results size. LDAP connection sharing for maps differing only in the query
|
||||
parameters.
|
||||
* Liviu Daia: Support for SSL/STARTTLS. Support for storing map definitions
|
||||
in 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
|
||||
configuration feature.
|
||||
* Liviu Daia with further refinements from Jose Luis Tallon and Victor
|
||||
Duchovni developed the common query, result_format, domain and
|
||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.
|
||||
|
||||
And of course Wietse.
|
||||
|
||||
|
@@ -62,22 +62,16 @@ password = some_password
|
||||
# The database name on the servers.
|
||||
dbname = customer_database
|
||||
|
||||
# The table name.
|
||||
table = mxaliases
|
||||
# For Postfix 2.2 and later The SQL query template.
|
||||
# See mysql_table(5) for details.
|
||||
query = SELECT forw_addr FROM mxaliases WHERE alias='%s' AND status='paid'
|
||||
|
||||
# Query components, see below.
|
||||
# For Postfix releases prior to 2.2. See mysql_table(5) for details.
|
||||
select_field = forw_addr
|
||||
table = mxaliases
|
||||
where_field = alias
|
||||
|
||||
# You may specify additional_conditions or leave this empty.
|
||||
additional_conditions = and status = 'paid'
|
||||
|
||||
# The above variables will result in a query of the form:
|
||||
#
|
||||
# select forw_addr from mxaliases where alias = '$lookup' and status = 'paid'
|
||||
#
|
||||
# ($lookup is escaped so if it contains single quotes or other odd
|
||||
# characters, it will not cause trouble).
|
||||
# Don't forget the leading "AND"!
|
||||
additional_conditions = AND status = 'paid'
|
||||
|
||||
AAddddiittiioonnaall nnootteess
|
||||
|
||||
@@ -100,4 +94,7 @@ CCrreeddiittss
|
||||
Group, Inc.
|
||||
* Liviu Daia revised the configuration interface and added the main.cf
|
||||
configuration feature.
|
||||
* Liviu Daia with further refinements from Jose Luis Tallon and Victor
|
||||
Duchovni developed the common query, result_format, domain and
|
||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.
|
||||
|
||||
|
@@ -63,25 +63,15 @@ password = some_password
|
||||
# The database name on the servers.
|
||||
dbname = customer_database
|
||||
|
||||
# The table name.
|
||||
table = mxaliases
|
||||
# Postfix 2.2 and later The SQL query template. See pgsql_table(5).
|
||||
query = SELECT forw_addr FROM mxaliases WHERE alias='%s' AND status='paid'
|
||||
|
||||
# Query components, see below.
|
||||
# For Postfix releases prior to 2.2. See pgsql_table(5) for details.
|
||||
select_field = forw_addr
|
||||
table = mxaliases
|
||||
where_field = alias
|
||||
|
||||
# You may specify additional_conditions or leave this empty.
|
||||
additional_conditions = and status = 'paid'
|
||||
|
||||
# The above variables will result in a query of the form:
|
||||
#
|
||||
# select forw_addr from mxaliases where alias = '$lookup' and status = 'paid'
|
||||
#
|
||||
# ($lookup is escaped so if it contains single quotes or other odd
|
||||
# characters, it will not cause problems).
|
||||
#
|
||||
# You may also override the built-in SELECT template. See pgsql_table(5)
|
||||
# for details.
|
||||
# Don't forget the leading "AND"!
|
||||
additional_conditions = AND status = 'paid'
|
||||
|
||||
UUssiinngg mmiirrrroorreedd ddaattaabbaasseess
|
||||
|
||||
@@ -107,4 +97,9 @@ CCrreeddiittss
|
||||
* LaMont Jones was the initial Postfix pgsql maintainer.
|
||||
* Liviu Daia revised the configuration interface and added the main.cf
|
||||
configuration feature.
|
||||
* Liviu Daia revised the configuration interface and added the main.cf
|
||||
configuration feature.
|
||||
* Liviu Daia with further refinements from Jose Luis Tallon and Victor
|
||||
Duchovni developed the common query, result_format, domain and
|
||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.
|
||||
|
||||
|
@@ -20,13 +20,17 @@ the following sections of this document.
|
||||
- TLS and IPv6 support are now built into Postfix, based on code
|
||||
from third-party patches.
|
||||
|
||||
- Extended query interface for LDAP, MySQL and PostgreSQL with free
|
||||
form SQL queries, and domain filters to reduce unnecessary lookups.
|
||||
|
||||
- SMTP client-side connection reuse. This can dramatically speed
|
||||
up deliveries to high-volume destinations that have some servers
|
||||
that respond, and some non-responding mail servers.
|
||||
|
||||
- By default, message header address rewriting is now disabled for
|
||||
SMTP mail from other systems. Thus, spam from poorly written
|
||||
software no longer looks like it came from a local user.
|
||||
SMTP mail from other systems (including masquerading and canonical
|
||||
mapping). Thus, spam from poorly written software no longer looks
|
||||
like it came from a local user.
|
||||
|
||||
- When your machine does not have its own domain name, Postfix can
|
||||
now replace your "home network" email address by your ISP account
|
||||
@@ -273,6 +277,12 @@ it does not turn off the actual features in the SMTP server.
|
||||
Major changes - database support
|
||||
--------------------------------
|
||||
|
||||
[Feature 20050209] Extended LDAP, MySQL and PgSQL query interface
|
||||
with free form SQL queries, the domain filter optimization that was
|
||||
already available with LDAP and more. This code was worked on by
|
||||
many people but Victor Duchovni took the lead. See the respective
|
||||
{LDAP,MYSQL,PGSQL}_README and {ldap,mysql,pgsql}_table documents.
|
||||
|
||||
[Feature 20041210] You can now dump an entire database with the new
|
||||
postmap/postalias "-s" option. This works only for database types
|
||||
with Postfix sequence operator support: hash, btree, dbm, and sdbm.
|
||||
|
@@ -1,242 +0,0 @@
|
||||
#!/bin/sh
|
||||
# postfinger - captures Postfix configuration for reporting errors
|
||||
#
|
||||
# Inspired by comments on the postfix-users mailing list.
|
||||
# Copyright (C) 2003 Simon J. Mudd (sjmudd@pobox.com)
|
||||
# With help from:
|
||||
# Matthias Andree <ma@dt.e-technik.uni-dortmund.de>
|
||||
# Victor Duchovni <Victor.Duchovni@morganstanley.com>
|
||||
# Sasa Babic <sasab@hygia.pharmacy.bg.ac.yu>
|
||||
# I<>aki Arenaza <iarenaza@escomposlinux.org>
|
||||
# Jorge Gordoy <gordoy@g2ctech.com>
|
||||
# $Revision: 1.29 $
|
||||
#
|
||||
# License:
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You may have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
# USA.
|
||||
#
|
||||
# An on-line copy of the GNU General Public License can be found
|
||||
# http://www.fsf.org/copyleft/gpl.html.
|
||||
|
||||
version_number=1.29 # don't use rcs version here
|
||||
version="version: ${version_number}"
|
||||
BACKUP_IFS=$IFS
|
||||
usage="postfinger ${version}: a Postfix configuration extraction utility
|
||||
Usage: postfinger [options]
|
||||
|
||||
Options can be any of:
|
||||
--all Show all configuration information
|
||||
--system Show basic system environment (os/kernel/...) [default]
|
||||
--package Show packaging information [default]
|
||||
--locking Show mailbox locking methods
|
||||
--tables Show supported lookup tables
|
||||
--main Show main.cf non-default configuration values [default]
|
||||
--defaultsinmain Show main.cf defined values which are identical to defaults
|
||||
--master Show master.cf configuration [default]
|
||||
--permissions Show some of the spool_directory permissions
|
||||
--libraries Show the Postfix libraries dependencies
|
||||
|
||||
--nosystem Do not show basic system environment (os/kernel/...)
|
||||
--nomain Do not show main.cf non-default configuration values
|
||||
--nomaster Do not show master.cf configuration
|
||||
--nowarn Do not warn about private information being leaked to
|
||||
outsiders
|
||||
--version print the version of postfinger being used and exit
|
||||
|
||||
Mail bug reports and suggestions to <postfinger@WL0.org>".
|
||||
|
||||
system=1; package=1; locking=; tables=; main=1; master=1; permissions=; libraries=;warn=1;defaultsinmain=
|
||||
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
--version) echo "postfinger ${version}"; exit 0;;
|
||||
--all) system=1; package=1; locking=1; tables=1; main=1; master=1; permissions=1; libraries=1; warn=1;;
|
||||
--system) system=1;;
|
||||
--package) package=1;;
|
||||
--locking) locking=1;;
|
||||
--tables) tables=1;;
|
||||
--main) main=1;;
|
||||
--defaultsinmain) defaultsinmain=1;;
|
||||
--master) master=1;;
|
||||
--permissions) permissions=1;;
|
||||
--libraries) libraries=1;;
|
||||
--nosystem) system=;;
|
||||
--nomain) main=;;
|
||||
--nomaster) master=;;
|
||||
--nowarn) warn=;;
|
||||
--help) echo "${usage}"; exit 0;;
|
||||
*) echo "Error: ${usage}" 1>&2; exit 1;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
echo "postfinger - postfix configuration on `LANG=C date`"
|
||||
echo ${version}
|
||||
echo ''
|
||||
|
||||
[ "${warn}" = 1 ] && {
|
||||
cat <<END
|
||||
Warning: postfinger output may show private configuration information,
|
||||
such as ip addresses and/or domain names which you do not want to show
|
||||
to the public. If this is the case it is your responsibility to modify
|
||||
the output to hide this private information. [Remove this warning with
|
||||
the --nowarn option.]
|
||||
|
||||
END
|
||||
}
|
||||
|
||||
# Look for postconf, using environment variable if given
|
||||
[ -n "${POSTCONF}" ] && [ ! -x "${POSTCONF}" ] && POSTCONF=
|
||||
[ -z "${POSTCONF}" ] && [ -x /usr/sbin/postconf ] && POSTCONF=/usr/sbin/postconf
|
||||
[ -z "${POSTCONF}" ] && [ -x /usr/local/sbin/postconf ] && POSTCONF=/usr/local/sbin/postconf
|
||||
[ -z "${POSTCONF}" ] && {
|
||||
echo "$0: can not find postconf"
|
||||
echo "set POSTCONF to postconf's location and try again"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Look for smtpd, using environment variable if given
|
||||
[ -z "${SMTPD}" ] && {
|
||||
SMTPD=`${POSTCONF} -h daemon_directory`/smtpd
|
||||
[ -d "${SMTPD}" -o ! -x "${SMTPD}" ] && SMTPD=
|
||||
}
|
||||
[ -z "${SMTPD}" ] && {
|
||||
echo "$0: can not find smtpd"
|
||||
echo "set SMTPD to smtpd's location and try again"
|
||||
exit 1
|
||||
}
|
||||
|
||||
[ "${system}" = 1 ] && {
|
||||
echo '--System Parameters--'
|
||||
${POSTCONF} -d mail_version
|
||||
echo "hostname = `hostname`"
|
||||
echo "uname = `uname -a`"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# check for different packaging systems and try to identify if this postfix
|
||||
# (smtpd) comes from a package.
|
||||
# I would appreciate help in adapting this part to include other packaging
|
||||
# systems.
|
||||
[ "${package}" = 1 ] && {
|
||||
echo "--Packaging information--"
|
||||
|
||||
DPKG=
|
||||
[ -x /usr/bin/dpkg ] && DPKG=/usr/bin/dpkg
|
||||
[ -z "${DPKG}" ] && [ -x /usr/local/bin/dpkg ] && DPKG=/usr/local/bin/dpkg
|
||||
[ -n "${DPKG}" ] && {
|
||||
${DPKG} -S ${SMTPD} >/dev/null 2>/dev/null && {
|
||||
package=`${DPKG} -S ${SMTPD} | awk -F: '{print $1}' | head -n 1`
|
||||
package_ver=`COLUMNS=132 ${DPKG} -l ${package} | grep ii | grep -v "documentation" | awk '{print $3}'`
|
||||
echo "looks like this postfix comes from deb package: ${package}-${package_ver}"
|
||||
}
|
||||
}
|
||||
|
||||
RPM=
|
||||
[ -x /bin/rpm ] && RPM=/bin/rpm
|
||||
[ -z "${RPM}" ] && [ -x /usr/local/bin/rpm ] && RPM=/usr/local/bin/rpm
|
||||
[ -n "${RPM}" ] && {
|
||||
${RPM} -qf ${SMTPD} >/dev/null 2>/dev/null && \
|
||||
echo "looks like this postfix comes from RPM package: `${RPM} -qf ${SMTPD}`"
|
||||
}
|
||||
|
||||
BSDPKG=
|
||||
[ -x /usr/sbin/pkg_info ] && BSDPKG=/usr/sbin/pkg_info
|
||||
[ -n "${BSDPKG}" ] && {
|
||||
${BSDPKG} -q -W ${SMTPD} >/dev/null 2>/dev/null && \
|
||||
echo "looks like this postfix comes from BSD package: `${BSDPKG} -q -W ${SMTPD}`"
|
||||
}
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
IFS="
|
||||
"
|
||||
[ "${locking}" = 1 ] && {
|
||||
echo "--Mailbox locking methods--"
|
||||
locking_methods=`${POSTCONF} -l`
|
||||
echo $locking_methods
|
||||
echo ""
|
||||
}
|
||||
|
||||
[ "${tables}" = 1 ] && {
|
||||
echo "--Supported Lookup tables--"
|
||||
lookup_tables=`${POSTCONF} -m`
|
||||
echo $lookup_tables
|
||||
echo ""
|
||||
}
|
||||
|
||||
[ "${main}" = 1 -o "${defaultsinmain}" = 1 ] && {
|
||||
if [ "x`find . -prune \( -perm 020 -o -perm 002 \) -print`" != "x" ]
|
||||
then
|
||||
echo 2>&2 "Do not run this in a public- or group-writable directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f postfinger.$$.d postfinger.$$.n
|
||||
${POSTCONF} -d | tr -s [:blank:] | sort > postfinger.$$.d
|
||||
${POSTCONF} -n | tr -s [:blank:] | sort > postfinger.$$.n
|
||||
|
||||
[ "$main" = 1 ] && {
|
||||
echo "--main.cf non-default parameters--"
|
||||
comm -13 postfinger.$$.d postfinger.$$.n
|
||||
echo ""
|
||||
}
|
||||
|
||||
[ "${defaultsinmain}" = 1 ] && {
|
||||
echo "--main.cf parameters defined as per defaults--"
|
||||
comm -12 postfinger.$$.d postfinger.$$.n
|
||||
echo ""
|
||||
}
|
||||
|
||||
rm -f postfinger.$$.d postfinger.$$.n
|
||||
}
|
||||
|
||||
[ "${master}" = 1 ] && {
|
||||
echo "--master.cf--"
|
||||
# Remove blank and commented lines to reduce the output
|
||||
# Note: the second grep contains a space followed by a tab character
|
||||
cat `${POSTCONF} -h config_directory`/master.cf | \
|
||||
grep -v '^#' | \
|
||||
grep -v '^[ ]*$'
|
||||
echo ""
|
||||
}
|
||||
|
||||
[ "${permissions}" = 1 ] && {
|
||||
echo "--Specific file and directory permissions--"
|
||||
ls -ld `${POSTCONF} -h queue_directory`/maildrop
|
||||
ls -ld `${POSTCONF} -h queue_directory`/public
|
||||
ls -l `${POSTCONF} -h queue_directory`/public 2>/dev/null || {
|
||||
echo 'WARNING: No access to $queue_directory/public'
|
||||
echo ' Try running postfinger as user root or postfix'
|
||||
}
|
||||
ls -ld `${POSTCONF} -h queue_directory`/private
|
||||
ls -l `${POSTCONF} -h queue_directory`/private 2>/dev/null || {
|
||||
echo 'WARNING: No access to $queue_directory/private'
|
||||
echo ' Try running postfinger as user root or postfix'
|
||||
}
|
||||
ls -l `${POSTCONF} -h command_directory`/postdrop
|
||||
ls -l `${POSTCONF} -h command_directory`/postqueue
|
||||
echo ""
|
||||
}
|
||||
|
||||
[ "${libraries}" = 1 ] && {
|
||||
echo "--Library dependencies--"
|
||||
echo "${SMTPD}:"
|
||||
ldd ${SMTPD} || echo "WARNING: Can not find ldd. Check you have it installed and in your path"
|
||||
}
|
||||
|
||||
echo "-- end of postfinger output --"
|
@@ -594,7 +594,7 @@ EOF
|
||||
if [ -z "$has_lrm" -a -z "$has_lrjc" ]
|
||||
then
|
||||
echo SAFETY: editing main.cf, setting $unknown_local=450.
|
||||
echo See the RELEASE_NOTES and LOCAL_RECIPIENT_README files for details.
|
||||
echo See the LOCAL_RECIPIENT_README file for details.
|
||||
$POSTCONF -e "$unknown_local = 450" || exit 1
|
||||
fi
|
||||
|
||||
|
@@ -317,15 +317,18 @@ turn-off control </th> </tr>
|
||||
<tr> <td> <a href="#standard"> Rewrite addresses to standard form</a>
|
||||
</td> <td nowrap> all mail </td> <td> <a href="trivial-rewrite.8.html">trivial-<br>rewrite(8)</a> </td>
|
||||
<td> <a href="postconf.5.html#append_at_myorigin">append_at_myorigin</a>, <a href="postconf.5.html#append_dot_mydomain">append_dot_mydomain</a>, <a href="postconf.5.html#swap_bangpath">swap_bangpath</a>,
|
||||
<a href="postconf.5.html#allow_percent_hack">allow_percent_hack</a> </td> <td> none </td> </tr>
|
||||
<a href="postconf.5.html#allow_percent_hack">allow_percent_hack</a> </td> <td> <a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a>,
|
||||
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> </td> </tr>
|
||||
|
||||
<tr> <td> <a href="#canonical"> Canonical address mapping </a>
|
||||
</td> <td nowrap> all mail </td> <td> <a href="cleanup.8.html">cleanup(8)</a> </td> <td>
|
||||
<a href="postconf.5.html#canonical_maps">canonical_maps</a> </td> <td> <a href="postconf.5.html#receive_override_options">receive_override_options</a> </td> </tr>
|
||||
<tr> <td> <a href="#canonical"> Canonical address mapping </a> </td>
|
||||
<td nowrap> all mail </td> <td> <a href="cleanup.8.html">cleanup(8)</a> </td> <td> <a href="postconf.5.html#canonical_maps">canonical_maps</a>
|
||||
</td> <td> <a href="postconf.5.html#receive_override_options">receive_override_options</a>, <a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a>,
|
||||
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> </td> </tr>
|
||||
|
||||
<tr> <td> <a href="#canonical"> Address masquerading </a> </td>
|
||||
<td nowrap> all mail </td> <td> <a href="cleanup.8.html">cleanup(8)</a> </td> <td> <a href="postconf.5.html#masquerade_domains">masquerade_domains</a>
|
||||
</td> <td> <a href="postconf.5.html#receive_override_options">receive_override_options</a> </td> </tr>
|
||||
<tr> <td> <a href="#masquerade"> Address masquerading </a> </td> <td
|
||||
nowrap> all mail </td> <td> <a href="cleanup.8.html">cleanup(8)</a> </td> <td> <a href="postconf.5.html#masquerade_domains">masquerade_domains</a>
|
||||
</td> <td> <a href="postconf.5.html#receive_override_options">receive_override_options</a>, <a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a>,
|
||||
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> </td> </tr>
|
||||
|
||||
<tr> <td> <a href="#auto_bcc"> Automatic BCC recipients </a> </td>
|
||||
<td nowrap> new mail </td> <td> <a href="cleanup.8.html">cleanup(8)</a> </td> <td> <a href="postconf.5.html#always_bcc">always_bcc</a>,
|
||||
@@ -411,11 +414,12 @@ mapping lookup table, it first rewrites the address to the standard
|
||||
form is to reduce the number of entries needed in lookup tables.
|
||||
</p>
|
||||
|
||||
<p> Postfix versions 2.2 and later do not rewrite message headers
|
||||
from remote SMTP clients at all, unless a non-empty domain name is
|
||||
specified with the <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> configuration
|
||||
parameter. The <a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> parameter controls
|
||||
what SMTP clients Postfix considers local. </p>
|
||||
<p> NOTE: Postfix versions 2.2 and later rewrite message headers
|
||||
from remote SMTP clients only if the client matches the
|
||||
<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> parameter, or if the
|
||||
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> configuration parameter specifies a
|
||||
non-empty value. To get the behavior before Postfix 2.2, specify
|
||||
"<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = static:all". </p>
|
||||
|
||||
<p> The Postfix <a href="trivial-rewrite.8.html">trivial-rewrite(8)</a> daemon implements the following
|
||||
hard-coded address manipulations: </p>
|
||||
@@ -455,10 +459,13 @@ parameter (default: yes). You should never turn off this feature,
|
||||
because a lot of Postfix components expect that all addresses have
|
||||
the form "user@domain". </p>
|
||||
|
||||
<p> Postfix versions 2.2 and later either do not rewrite message
|
||||
headers from remote SMTP clients at all, or they append the domain
|
||||
name specified with the <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> configuration
|
||||
parameter. </p>
|
||||
<p> NOTE: Postfix versions 2.2 and later rewrite message headers
|
||||
from remote SMTP clients only if the client matches the
|
||||
<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> parameter; otherwise they append the
|
||||
domain name specified with the <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a>
|
||||
configuration parameter, if one is specified. To get the behavior
|
||||
before Postfix 2.2, specify "<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> =
|
||||
static:all". </p>
|
||||
|
||||
<p> If your machine is not the main machine for $<a href="postconf.5.html#myorigin">myorigin</a> and you
|
||||
wish to have some users delivered locally without going via that
|
||||
@@ -476,10 +483,13 @@ Rewrite "user@host" to "user@host.$<a href="postconf.5.html#mydomain">mydomain</
|
||||
parameter (default: yes). The purpose is to get consistent treatment
|
||||
of different forms of the same hostname. </p>
|
||||
|
||||
<p> Postfix versions 2.2 and later either do not rewrite message
|
||||
headers from remote clients at all, or they append the domain name
|
||||
specified with the <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> configuration
|
||||
parameter. </p>
|
||||
<p> NOTE: Postfix versions 2.2 and later rewrite message headers
|
||||
from remote SMTP clients only if the client matches the
|
||||
<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> parameter; otherwise they append the
|
||||
domain name specified with the <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a>
|
||||
configuration parameter, if one is specified. To get the behavior
|
||||
before Postfix 2.2, specify "<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> =
|
||||
static:all". </p>
|
||||
|
||||
<p> Some will argue that rewriting "host" to "host.domain"
|
||||
is bad. That is why it can be turned off. Others like the convenience
|
||||
@@ -502,11 +512,12 @@ addresses in message envelopes and in message headers. By default
|
||||
all header and envelope addresses are rewritten; this is controlled
|
||||
with the <a href="postconf.5.html#canonical_classes">canonical_classes</a> configuration parameter. </p>
|
||||
|
||||
<p> Postfix versions 2.2 and later do not rewrite message headers
|
||||
from remote clients at all, unless a non-empty domain name is
|
||||
specified with the <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> configuration
|
||||
parameter. The <a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> parameter controls
|
||||
what SMTP clients Postfix considers local. </p>
|
||||
<p> NOTE: Postfix versions 2.2 and later rewrite message headers
|
||||
from remote SMTP clients only if the client matches the
|
||||
<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> parameter, or if the
|
||||
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> configuration parameter specifies a
|
||||
non-empty value. To get the behavior before Postfix 2.2, specify
|
||||
"<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = static:all". </p>
|
||||
|
||||
<p> Address rewriting is
|
||||
done for local and remote addresses. The mapping is useful to
|
||||
@@ -585,11 +596,12 @@ behind their mail gateway, and to make it appear as if the mail
|
||||
comes from the gateway itself, instead of from individual machines.
|
||||
</p>
|
||||
|
||||
<p> Postfix versions 2.2 and later do not rewrite message headers
|
||||
from remote SMTP clients at all, unless a non-empty domain name is
|
||||
specified with the <a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> configuration
|
||||
parameter. The <a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> parameter controls
|
||||
what SMTP clients Postfix considers local. </p>
|
||||
<p> NOTE: Postfix versions 2.2 and later rewrite message headers
|
||||
from remote SMTP clients only if the client matches the
|
||||
<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> parameter, or if the
|
||||
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> configuration parameter specifies a
|
||||
non-empty value. To get the behavior before Postfix 2.2, specify
|
||||
"<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = static:all". </p>
|
||||
|
||||
<p> Address masquerading is disabled by default, and is implemented
|
||||
by the <a href="cleanup.8.html">cleanup(8)</a> server. To enable, edit the <a href="postconf.5.html#masquerade_domains">masquerade_domains</a>
|
||||
|
@@ -257,7 +257,7 @@ maildrop: this, that, theother
|
||||
make sure the lookup makes sense. In the case of virtual lookups,
|
||||
maildrops other than mail addresses are pretty useless, because
|
||||
Postfix can't know how to set the ownership for program or file
|
||||
delivery. Your query_filter should probably look something like this: </p>
|
||||
delivery. Your <b>query_filter</b> should probably look something like this: </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
@@ -276,7 +276,7 @@ query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")(maildrop="*
|
||||
require some thought on your part to implement safely, considering the
|
||||
ramifications of this type of delivery. You may decide it's not worth
|
||||
the bother to allow any of that nonsense in LDAP lookups, ban it in
|
||||
the query_filter, and keep things like majordomo lists in local alias
|
||||
the <b>query_filter</b>, and keep things like majordomo lists in local alias
|
||||
databases. </p>
|
||||
|
||||
<blockquote>
|
||||
@@ -334,13 +334,20 @@ contents, please include the applicable bits of some directory entries. </p>
|
||||
|
||||
<li>Victor Duchovni: ldap_bind() timeout. With fixes from LaMont Jones:
|
||||
OpenLDAP cache deprecation. Limits on recursion, expansion
|
||||
and query results size. LDAP connection sharing for maps
|
||||
and search results size. LDAP connection sharing for maps
|
||||
differing only in the query parameters.
|
||||
|
||||
<li>Liviu Daia: Support for SSL/STARTTLS. Support for storing map definitions in
|
||||
external files (<a href="ldap_table.5.html">ldap</a>:/path/ldap.cf) needed to securely store
|
||||
passwords for plain auth.
|
||||
|
||||
<li>Liviu Daia revised the configuration interface and added the main.cf
|
||||
configuration feature.</li>
|
||||
|
||||
<li>Liviu Daia with further refinements from Jose Luis Tallon and
|
||||
Victor Duchovni developed the common query, result_format, domain and
|
||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
And of course Wietse.
|
||||
|
@@ -89,22 +89,16 @@ password = some_password
|
||||
# The database name on the servers.
|
||||
dbname = customer_database
|
||||
|
||||
# The table name.
|
||||
table = mxaliases
|
||||
# For Postfix 2.2 and later The SQL query template.
|
||||
# See <a href="mysql_table.5.html">mysql_table(5)</a> for details.
|
||||
query = SELECT forw_addr FROM mxaliases WHERE alias='%s' AND status='paid'
|
||||
|
||||
# Query components, see below.
|
||||
# For Postfix releases prior to 2.2. See <a href="mysql_table.5.html">mysql_table(5)</a> for details.
|
||||
select_field = forw_addr
|
||||
table = mxaliases
|
||||
where_field = alias
|
||||
|
||||
# You may specify additional_conditions or leave this empty.
|
||||
additional_conditions = and status = 'paid'
|
||||
|
||||
# The above variables will result in a query of the form:
|
||||
#
|
||||
# select forw_addr from mxaliases where alias = '$lookup' and status = 'paid'
|
||||
#
|
||||
# ($lookup is escaped so if it contains single quotes or other odd
|
||||
# characters, it will not cause trouble).
|
||||
# Don't forget the leading "AND"!
|
||||
additional_conditions = AND status = 'paid'
|
||||
</pre>
|
||||
|
||||
<h2>Additional notes</h2>
|
||||
@@ -129,10 +123,14 @@ will be deferred until at least one of those hosts is reachable.
|
||||
<ul>
|
||||
|
||||
<li> The initial version was contributed by Scott Cotton and Joshua
|
||||
Marcus, IC Group, Inc.
|
||||
Marcus, IC Group, Inc.</li>
|
||||
|
||||
<li>Liviu Daia revised the configuration interface and added the
|
||||
main.cf configuration feature.
|
||||
<li> Liviu Daia revised the configuration interface and added the
|
||||
main.cf configuration feature.</li>
|
||||
|
||||
<li> Liviu Daia with further refinements from Jose Luis Tallon and
|
||||
Victor Duchovni developed the common query, result_format, domain and
|
||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
@@ -88,25 +88,15 @@ password = some_password
|
||||
# The database name on the servers.
|
||||
dbname = customer_database
|
||||
|
||||
# The table name.
|
||||
table = mxaliases
|
||||
# Postfix 2.2 and later The SQL query template. See <a href="pgsql_table.5.html">pgsql_table(5)</a>.
|
||||
query = SELECT forw_addr FROM mxaliases WHERE alias='%s' AND status='paid'
|
||||
|
||||
# Query components, see below.
|
||||
# For Postfix releases prior to 2.2. See <a href="pgsql_table.5.html">pgsql_table(5)</a> for details.
|
||||
select_field = forw_addr
|
||||
table = mxaliases
|
||||
where_field = alias
|
||||
|
||||
# You may specify additional_conditions or leave this empty.
|
||||
additional_conditions = and status = 'paid'
|
||||
|
||||
# The above variables will result in a query of the form:
|
||||
#
|
||||
# select forw_addr from mxaliases where alias = '$lookup' and status = 'paid'
|
||||
#
|
||||
# ($lookup is escaped so if it contains single quotes or other odd
|
||||
# characters, it will not cause problems).
|
||||
#
|
||||
# You may also override the built-in SELECT template. See <a href="pgsql_table.5.html">pgsql_table(5)</a>
|
||||
# for details.
|
||||
# Don't forget the leading "AND"!
|
||||
additional_conditions = AND status = 'paid'
|
||||
</pre>
|
||||
|
||||
<h2>Using mirrored databases</h2>
|
||||
@@ -130,17 +120,24 @@ those hosts is reachable. </p>
|
||||
<ul>
|
||||
|
||||
<li> This code is based upon the Postfix mysql map by Scott Cotton
|
||||
and Joshua Marcus, IC Group, Inc.
|
||||
and Joshua Marcus, IC Group, Inc.</li>
|
||||
|
||||
<li> The PostgreSQL changes were done by Aaron Sethman.
|
||||
<li> The PostgreSQL changes were done by Aaron Sethman.</li>
|
||||
|
||||
<li> Updates for Postfix 1.1.x and PostgreSQL 7.1+ and support for
|
||||
calling stored procedures were added by Philip Warner.
|
||||
calling stored procedures were added by Philip Warner.</li>
|
||||
|
||||
<li> LaMont Jones was the initial Postfix pgsql maintainer.
|
||||
<li> LaMont Jones was the initial Postfix pgsql maintainer.</li>
|
||||
|
||||
<li> Liviu Daia revised the configuration interface and added the
|
||||
main.cf configuration feature.
|
||||
main.cf configuration feature.</li>
|
||||
|
||||
<li> Liviu Daia revised the configuration interface and added the main.cf
|
||||
configuration feature.</li>
|
||||
|
||||
<li> Liviu Daia with further refinements from Jose Luis Tallon and
|
||||
Victor Duchovni developed the common query, result_format, domain and
|
||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
@@ -54,6 +54,20 @@ LDAP_TABLE(5) LDAP_TABLE(5)
|
||||
Support for this form will be removed in a future Postfix
|
||||
version.
|
||||
|
||||
Postfix 2.2 has enhanced query interfaces for MySQL and
|
||||
PostgreSQL, these now include features previously avail-
|
||||
able only in the Postfix LDAP client. This work also cre-
|
||||
ated an opportunity for improvements in the LDAP inter-
|
||||
face. The primary compatibility issue is that <b>result_fil-</b>
|
||||
<b>ter</b> (a name that has caused some confusion as to its mean-
|
||||
ing in the past) has been renamed to <b>result_format</b>. For
|
||||
backwards compatibility with the pre 2.2 LDAP client,
|
||||
<b>result_filter</b> can for now be used instead of <b>result_for-</b>
|
||||
<b>mat</b>, when the latter parameter is not also set. The new
|
||||
name better reflects the function of the parameter. This
|
||||
compatibility interface may be removed in a future
|
||||
release.
|
||||
|
||||
<b>LIST MEMBERSHIP</b>
|
||||
When using LDAP to store lists such as $<a href="postconf.5.html#mynetworks">mynetworks</a>,
|
||||
$<a href="postconf.5.html#mydestination">mydestination</a>, $<a href="postconf.5.html#relay_domains">relay_domains</a>, $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a>,
|
||||
@@ -114,15 +128,57 @@ LDAP_TABLE(5) LDAP_TABLE(5)
|
||||
The port the LDAP server listens on, e.g.
|
||||
server_port = 778
|
||||
|
||||
<b>timeout (default: 10 seconds)</b>
|
||||
The number of seconds a search can take before tim-
|
||||
ing out, e.g.
|
||||
timeout = 5
|
||||
|
||||
<b>search_base (No default; you must configure this)</b>
|
||||
The <a href="http://www.faqs.org/rfcs/rfc2253.html">RFC2253</a> base DN at which to conduct the search,
|
||||
e.g.
|
||||
search_base = dc=your, dc=com
|
||||
|
||||
<b>timeout (default: 10 seconds)</b>
|
||||
The number of seconds a search can take before tim-
|
||||
ing out, e.g.
|
||||
timeout = 5
|
||||
With Postfix 2.2 and later this parameter supports
|
||||
the following '%' expansions:
|
||||
|
||||
<b>%%</b> This is replaced by a literal '%' character.
|
||||
|
||||
<b>%s</b> This is replaced by the input key. <a href="http://www.faqs.org/rfcs/rfc2253.html">RFC 2253</a>
|
||||
quoting is used to make sure that the input
|
||||
key does not add unexpected metacharacters.
|
||||
|
||||
<b>%u</b> When the input key is an address of the form
|
||||
user@domain, <b>%u</b> is replaced by the (RFC
|
||||
2253) quoted local part of the address.
|
||||
Otherwise, <b>%u</b> is replaced by the entire
|
||||
search string. If the localpart is empty,
|
||||
the search is suppressed and returns no
|
||||
results.
|
||||
|
||||
<b>%d</b> When the input key is an address of the form
|
||||
user@domain, <b>%d</b> is replaced by the (RFC
|
||||
2253) quoted domain part of the address.
|
||||
Otherwise, the search is suppressed and
|
||||
returns no results.
|
||||
|
||||
<b>%[SUD]</b> For the <b>search_base</b> parameter, the upper-
|
||||
case equivalents of the above expansions
|
||||
behave identically to their lower-case
|
||||
counter-parts. With the <b>result_format</b> param-
|
||||
eter (previously called <b>result_filter</b> see
|
||||
the COMPATIBILITY section and below), they
|
||||
expand to the corresponding components of
|
||||
input key rather than the result value.
|
||||
|
||||
<b>%[1-9]</b> The patterns %1, %2, ... %9 are replaced by
|
||||
the corresponding most significant component
|
||||
of the input key's domain. If the input key
|
||||
is <i>user@mail.example.com</i>, then %1 is <b>com</b>, %2
|
||||
is <b>example</b> and %3 is <b>mail</b>. If the input key
|
||||
is unqualified or does not have enough
|
||||
domain components to satisfy all the speci-
|
||||
fied patterns, the search is suppressed and
|
||||
returns no results.
|
||||
|
||||
<b>query_filter (default: mailacceptinggeneralid=%s)</b>
|
||||
The <a href="http://www.faqs.org/rfcs/rfc2254.html">RFC2254</a> filter used to search the directory,
|
||||
@@ -133,21 +189,51 @@ LDAP_TABLE(5) LDAP_TABLE(5)
|
||||
This parameter supports the following '%' expan-
|
||||
sions:
|
||||
|
||||
<b>%s</b> This is replaced by the input key. <a href="http://www.faqs.org/rfcs/rfc2254.html">RFC 2254</a>
|
||||
quoting is used to make sure that the input
|
||||
key does not add unexpected metacharacters.
|
||||
<b>%%</b> This is replaced by a literal '%' character.
|
||||
(Postfix 2.2 and later).
|
||||
|
||||
<b>%s</b> This is replaced by the input key. <a href="http://www.faqs.org/rfcs/rfc2254.html">RFC 2254</a>
|
||||
quoting is used to make sure that the input
|
||||
key does not add unexpected metacharacters.
|
||||
|
||||
<b>%u</b> When the input key is an address of the form
|
||||
user@domain, <b>%u</b> is replaced by the (RFC
|
||||
2254) quoted local part of the address. Oth-
|
||||
erwise, <b>%u</b> is replaced by the entire search
|
||||
string.
|
||||
user@domain, <b>%u</b> is replaced by the (RFC
|
||||
2254) quoted local part of the address.
|
||||
Otherwise, <b>%u</b> is replaced by the entire
|
||||
search string. If the localpart is empty,
|
||||
the search is suppressed and returns no
|
||||
results.
|
||||
|
||||
<b>%d</b> When the input key is an address of the form
|
||||
user@domain, <b>%d</b> is replaced by the (RFC
|
||||
2254) quoted domain part of the address.
|
||||
Otherwise, <b>%d</b> is replaced by the entire
|
||||
search string.
|
||||
user@domain, <b>%d</b> is replaced by the (RFC
|
||||
2254) quoted domain part of the address.
|
||||
Otherwise, the search is suppressed and
|
||||
returns no results.
|
||||
|
||||
<b>%[SUD]</b> The upper-case equivalents of the above
|
||||
expansions behave in the <b>query_filter</b> param-
|
||||
eter identically to their lower-case
|
||||
counter-parts. With the <b>result_format</b> param-
|
||||
eter (previously called <b>result_filter</b> see
|
||||
the COMPATIBILITY section and below), they
|
||||
expand to the corresponding components of
|
||||
input key rather than the result value.
|
||||
|
||||
The above %S, %U and %D expansions are
|
||||
available with Postfix 2.2 and later.
|
||||
|
||||
<b>%[1-9]</b> The patterns %1, %2, ... %9 are replaced by
|
||||
the corresponding most significant component
|
||||
of the input key's domain. If the input key
|
||||
is <i>user@mail.example.com</i>, then %1 is <b>com</b>, %2
|
||||
is <b>example</b> and %3 is <b>mail</b>. If the input key
|
||||
is unqualified or does not have enough
|
||||
domain components to satisfy all the speci-
|
||||
fied patterns, the saerch is suppressed and
|
||||
returns no results.
|
||||
|
||||
The above %1, ..., %9 expansions are avail-
|
||||
able with Postfix 2.2 and later.
|
||||
|
||||
The "domain" parameter described below limits the
|
||||
input keys to addresses in matching domains. When
|
||||
@@ -156,34 +242,53 @@ LDAP_TABLE(5) LDAP_TABLE(5)
|
||||
matching domains are suppressed and return no
|
||||
results.
|
||||
|
||||
NOTE: DO NOT put quotes around the query filter.
|
||||
NOTE: DO NOT put quotes around the <b>query_filter</b>
|
||||
parameter.
|
||||
|
||||
<b>result_filter (default: %s</b>)
|
||||
Format template applied to result attributes. Sup-
|
||||
ports the same expansions as the query_filter, and
|
||||
can be easily used to append (or prepend) text.
|
||||
This parameter supports the following '%' expan-
|
||||
sions:
|
||||
<b>result_format (default: %s</b>)
|
||||
Called <b>result_filter</b> in Postfix releases prior to
|
||||
2.2. Format template applied to result attributes.
|
||||
Most commonly used to append (or prepend) text to
|
||||
the result. This parameter supports the following
|
||||
'%' expansions:
|
||||
|
||||
<b>%%</b> This is replaced by a literal '%' character.
|
||||
(Postfix 2.2 and later).
|
||||
|
||||
<b>%s</b> This is replaced by the value of the result
|
||||
attribute.
|
||||
attribute. When result is empty it is
|
||||
skipped.
|
||||
|
||||
<b>%u</b> When the result attribute value is an
|
||||
<b>%u</b> When the result attribute value is an
|
||||
address of the form user@domain, <b>%u</b> is
|
||||
replaced by the local part of the address.
|
||||
Otherwise, <b>%u</b> is replaced by the entire
|
||||
attribute value.
|
||||
replaced by the local part of the address.
|
||||
When the result has an empty localpart it is
|
||||
skipped.
|
||||
|
||||
<b>%d</b> When a result attribute value is an address
|
||||
of the form user@domain, <b>%d</b> is replaced by
|
||||
the domain part of the attribute value.
|
||||
Otherwise, <b>%d</b> is replaced by the entire
|
||||
attribute value.
|
||||
<b>%d</b> When a result attribute value is an address
|
||||
of the form user@domain, <b>%d</b> is replaced by
|
||||
the domain part of the attribute value. When
|
||||
the result is unqualified it is skipped.
|
||||
|
||||
For example, using "result_filter = <a href="smtp.8.html">smtp</a>:[%s]"
|
||||
<b>%[SUD1-9]</b>
|
||||
The upper-case and decimal digit expansions
|
||||
interpolate the parts of the input key
|
||||
rather than the result. Their behaviour is
|
||||
identical to that described with <b>query_fil-</b>
|
||||
<b>ter</b>, and in fact because the input key is
|
||||
known in advance, lookups whose key does not
|
||||
contain all the information specified in the
|
||||
result template are suppressed and return no
|
||||
results.
|
||||
|
||||
The above %S, %U, %D and %1, ..., %9 expan-
|
||||
sions are available with Postfix 2.2 and
|
||||
later.
|
||||
|
||||
For example, using "result_format = <a href="smtp.8.html">smtp</a>:[%s]"
|
||||
allows one to use a mailHost attribute as the basis
|
||||
of a <a href="transport.5.html">transport(5)</a> table. After applying the result
|
||||
filter, multiple values are concatenated as comma
|
||||
format, multiple values are concatenated as comma
|
||||
separated strings. The expansion_limit and
|
||||
size_limit parameters explained below allow one to
|
||||
restrict the number of values in the result, which
|
||||
@@ -193,77 +298,84 @@ LDAP_TABLE(5) LDAP_TABLE(5)
|
||||
The default value <b>%s</b> specifies that each attribute
|
||||
value should be used as is.
|
||||
|
||||
NOTE: DO NOT put quotes around the result filter!
|
||||
This parameter was called <b>result_filter</b> in Postfix
|
||||
releases prior to 2.2. If no "result_format" is
|
||||
specified, the value of "result_filter" will be
|
||||
used instead before resorting to the default value.
|
||||
This provides compatibility with old configuration
|
||||
files.
|
||||
|
||||
NOTE: DO NOT put quotes around the result format!
|
||||
|
||||
<b>domain (default: no domain list)</b>
|
||||
This is a list of domain names, paths to files, or
|
||||
dictionaries. When specified, only fully qualified
|
||||
search 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
|
||||
This is a list of domain names, paths to files, or
|
||||
dictionaries. When specified, only fully qualified
|
||||
search 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.
|
||||
domain = postfix.org, hash:/etc/postfix/search-
|
||||
domains
|
||||
|
||||
It is best not to use LDAP to store the domains
|
||||
It is best not to use LDAP to store the domains
|
||||
eligible for LDAP lookups.
|
||||
|
||||
NOTE: DO NOT define this parameter for <a href="local.8.html">local(8)</a>
|
||||
NOTE: DO NOT define this parameter for <a href="local.8.html">local(8)</a>
|
||||
aliases.
|
||||
|
||||
<b>result_attribute (default: maildrop)</b>
|
||||
The attribute(s) Postfix will read from any direc-
|
||||
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
|
||||
result_attribute = mailbox, maildrop
|
||||
|
||||
<b>special_result_attribute (No default)</b>
|
||||
The attribute(s) of directory entries that can con-
|
||||
tain DNs or URLs. If found, a recursive subsequent
|
||||
tain DNs or URLs. If found, a recursive subsequent
|
||||
search is done using their values.
|
||||
special_result_attribute = member
|
||||
|
||||
DN recursion retrieves the same result_attributes
|
||||
DN recursion retrieves the same result_attributes
|
||||
as the main query, including the special attributes
|
||||
for further recursion. URI processing retrieves
|
||||
only those attributes 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
|
||||
for further recursion. URI processing retrieves
|
||||
only those attributes 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.
|
||||
|
||||
<b>scope (default: sub)</b>
|
||||
The LDAP search scope: <b>sub</b>, <b>base</b>, or <b>one</b>. These
|
||||
The LDAP search scope: <b>sub</b>, <b>base</b>, or <b>one</b>. These
|
||||
translate into LDAP_SCOPE_SUBTREE, LDAP_SCOPE_BASE,
|
||||
and LDAP_SCOPE_ONELEVEL.
|
||||
|
||||
<b>bind (default: yes)</b>
|
||||
Whether or not to bind to the LDAP server. Newer
|
||||
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-
|
||||
uring Postfix to connect to the local machine on a
|
||||
port that's an SSL tunnel to your LDAP server. If
|
||||
your LDAP server doesn't natively support SSL, put
|
||||
If you do need to bind, you might consider config-
|
||||
uring Postfix to connect to the local machine on a
|
||||
port that's an SSL tunnel to your LDAP server. If
|
||||
your LDAP server doesn't natively support SSL, put
|
||||
a tunnel (wrapper, proxy, whatever you want to call
|
||||
it) on that system too. This should prevent the
|
||||
password from traversing the network in the clear.
|
||||
it) on that system too. This should prevent the
|
||||
password from traversing the network in the clear.
|
||||
|
||||
<b>bind_dn (default: empty)</b>
|
||||
If you do have to bind, do it with this distin-
|
||||
If you do have to bind, do it with this distin-
|
||||
guished name. Example:
|
||||
bind_dn = uid=postfix, dc=your, dc=com
|
||||
|
||||
<b>bind_pw (default: empty)</b>
|
||||
The password for the distinguished name above. If
|
||||
The password for the distinguished name above. If
|
||||
you have to use this, you probably want to make the
|
||||
map configuration file readable only by the Postfix
|
||||
user. When using the obsolete <a href="ldap_table.5.html">ldap</a>:ldapsource syn-
|
||||
user. When using the obsolete <a href="ldap_table.5.html">ldap</a>:ldapsource syn-
|
||||
tax, with map parameters in main.cf, it is not pos-
|
||||
sible to securely store the bind password. This is
|
||||
sible 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 com-
|
||||
mand. Example:
|
||||
@@ -274,43 +386,43 @@ LDAP_TABLE(5) LDAP_TABLE(5)
|
||||
<b>cache_expiry (IGNORED with a warning)</b>
|
||||
|
||||
<b>cache_size (IGNORED with a warning)</b>
|
||||
The above parameters are NO LONGER SUPPORTED by
|
||||
The above parameters are NO LONGER SUPPORTED by
|
||||
Postfix. Cache support has been dropped from
|
||||
OpenLDAP as of release 2.1.13.
|
||||
|
||||
<b>recursion_limit (default: 1000)</b>
|
||||
A limit on the nesting depth of DN and URL special
|
||||
result attribute evaluation. The limit must be a
|
||||
A limit on the nesting depth of DN and URL special
|
||||
result attribute evaluation. The limit must be a
|
||||
non-zero positive number.
|
||||
|
||||
<b>expansion_limit (default: 0)</b>
|
||||
A limit on the total number of result elements
|
||||
returned (as a comma separated list) by a lookup
|
||||
against the map. A setting of zero disables the
|
||||
limit. Lookups fail with a temporary error if the
|
||||
limit is exceeded. Setting the limit to 1 ensures
|
||||
A limit on the total number of result elements
|
||||
returned (as a comma separated list) by a lookup
|
||||
against the map. A setting of zero disables the
|
||||
limit. Lookups fail with a temporary error if the
|
||||
limit is exceeded. Setting the limit to 1 ensures
|
||||
that lookups do not return multiple values.
|
||||
|
||||
<b>size_limit (default: $expansion_limit)</b>
|
||||
A limit on the number of LDAP entries returned by
|
||||
any single LDAP query performed as part of the
|
||||
lookup. A setting of 0 disables the limit. Expan-
|
||||
sion of DN and URL references involves nested LDAP
|
||||
queries, each of which is separately subjected to
|
||||
A limit on the number of LDAP entries returned by
|
||||
any single LDAP search performed as part of the
|
||||
lookup. A setting of 0 disables the limit. Expan-
|
||||
sion of DN and URL references involves nested LDAP
|
||||
queries, each of which is separately subjected to
|
||||
this limit.
|
||||
|
||||
Note: even a single LDAP entry can generate multi-
|
||||
ple lookup results, via multiple result attributes
|
||||
and/or multi-valued result attributes. This limit
|
||||
caps the per query resource utilization on the LDAP
|
||||
server, not the final multiplicity of the lookup
|
||||
result. It is analogous to the "-z" option of
|
||||
"ldapsearch".
|
||||
Note: even a single LDAP entry can generate multi-
|
||||
ple lookup results, via multiple result attributes
|
||||
and/or multi-valued result attributes. This limit
|
||||
caps the per search resource utilization on the
|
||||
LDAP server, not the final multiplicity of the
|
||||
lookup result. It is analogous to the "-z" option
|
||||
of "ldapsearch".
|
||||
|
||||
<b>dereference (default: 0)</b>
|
||||
When to dereference LDAP aliases. (Note that this
|
||||
When to dereference LDAP aliases. (Note that this
|
||||
has nothing do with Postfix aliases.) The permitted
|
||||
values are those legal for the OpenLDAP/UM LDAP
|
||||
values are those legal for the OpenLDAP/UM LDAP
|
||||
implementations:
|
||||
|
||||
0 never
|
||||
@@ -322,99 +434,99 @@ LDAP_TABLE(5) LDAP_TABLE(5)
|
||||
3 always
|
||||
|
||||
See ldap.h or the ldap_open(3) or ldapsearch(1) man
|
||||
pages for more information. And if you're using an
|
||||
pages for more information. And if you're using an
|
||||
LDAP package that has other possible values, please
|
||||
bring it to the attention of the postfix-
|
||||
bring it to the attention of the postfix-
|
||||
users@postfix.org mailing list.
|
||||
|
||||
<b>chase_referrals (default: 0)</b>
|
||||
Sets (or clears) LDAP_OPT_REFERRALS (requires LDAP
|
||||
Sets (or clears) LDAP_OPT_REFERRALS (requires LDAP
|
||||
version 3 support).
|
||||
|
||||
<b>version (default: 2)</b>
|
||||
Specifies the LDAP protocol version to use.
|
||||
|
||||
<b>debuglevel (default: 0)</b>
|
||||
What level to set for debugging in the OpenLDAP
|
||||
What level to set for debugging in the OpenLDAP
|
||||
libraries.
|
||||
|
||||
<b>LDAP SSL AND STARTTLS PARAMETERS</b>
|
||||
If you're using the OpenLDAP libraries compiled with SSL
|
||||
support, Postfix can connect to LDAP SSL servers and can
|
||||
If you're using the OpenLDAP libraries compiled with SSL
|
||||
support, Postfix can connect to LDAP SSL servers and can
|
||||
issue the STARTTLS command.
|
||||
|
||||
LDAP SSL service can be requested by using a LDAP SSL URL
|
||||
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
|
||||
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-
|
||||
ured in master.cf to run chrooted, all the certificates
|
||||
ured in master.cf to run chrooted, all the certificates
|
||||
and keys involved have to be copied to the chroot jail. Of
|
||||
course, the private keys should only be readable by the
|
||||
course, the private keys should only be readable by the
|
||||
user "postfix".
|
||||
|
||||
The following parameters are relevant to LDAP SSL and
|
||||
The following parameters are relevant to LDAP SSL and
|
||||
STARTTLS:
|
||||
|
||||
<b>start_tls (default: no)</b>
|
||||
Whether or not to issue STARTTLS upon connection to
|
||||
the server. Don't set this with LDAP SSL (the SSL
|
||||
the server. Don't set this with LDAP SSL (the SSL
|
||||
session is setup automatically when the TCP connec-
|
||||
tion is opened).
|
||||
|
||||
<b>tls_ca_cert_dir (No default; set either this or</b>
|
||||
<b>tls_ca_cert_dir (No default; set either this or</b>
|
||||
<b>tls_ca_cert_file)</b>
|
||||
Directory containing X509 Certificate Authority
|
||||
certificates in PEM format which are to be recog-
|
||||
nized by the client in SSL/TLS connections. The
|
||||
files each contain one CA certificate. The files
|
||||
are looked up by the CA subject name hash value,
|
||||
which must hence be available. If more than one CA
|
||||
certificate with the same name hash value exist,
|
||||
the extension must be different (e.g. 9d66eef0.0,
|
||||
9d66eef0.1 etc). The search is performed in the
|
||||
ordering of the extension number, regardless of
|
||||
certificates in PEM format which are to be recog-
|
||||
nized by the client in SSL/TLS connections. The
|
||||
files each contain one CA certificate. The files
|
||||
are looked up by the CA subject name hash value,
|
||||
which must hence be available. If more than one CA
|
||||
certificate with the same name hash value exist,
|
||||
the extension must be different (e.g. 9d66eef0.0,
|
||||
9d66eef0.1 etc). The search is performed in the
|
||||
ordering of the extension number, regardless of
|
||||
other properties of the certificates. Use the
|
||||
c_rehash utility (from the OpenSSL distribution) to
|
||||
create the necessary links.
|
||||
|
||||
<b>tls_ca_cert_file (No default; set either this or</b>
|
||||
<b>tls_ca_cert_file (No default; set either this or</b>
|
||||
<b>tls_ca_cert_dir)</b>
|
||||
File containing the X509 Certificate Authority cer-
|
||||
tificates in PEM format which are to be recognized
|
||||
by the client in SSL/TLS connections. This setting
|
||||
tificates in PEM format which are to be recognized
|
||||
by the client in SSL/TLS connections. This setting
|
||||
takes precedence over tls_ca_cert_dir.
|
||||
|
||||
<b>tls_cert (No default; you must set this)</b>
|
||||
File containing client's X509 certificate to be
|
||||
File containing client's X509 certificate to be
|
||||
used by the client in SSL/ TLS connections.
|
||||
|
||||
<b>tls_key (No default; you must set this)</b>
|
||||
File containing the private key corresponding to
|
||||
File containing the private key corresponding to
|
||||
the above tls_cert.
|
||||
|
||||
<b>tls_require_cert (default: no)</b>
|
||||
Whether or not to request server's X509 certificate
|
||||
and check its validity when establishing SSL/TLS
|
||||
and check its validity when establishing SSL/TLS
|
||||
connections.
|
||||
|
||||
<b>tls_random_file (No default)</b>
|
||||
Path of a file to obtain random bits from when
|
||||
/dev/[u]random is not available, to be used by the
|
||||
Path of a file to obtain random bits from when
|
||||
/dev/[u]random is not available, to be used by the
|
||||
client in SSL/TLS connections.
|
||||
|
||||
<b>tls_cipher_suite (No default)</b>
|
||||
Cipher suite to use in SSL/TLS negotiations.
|
||||
|
||||
<b>EXAMPLE</b>
|
||||
Here's a basic example for using LDAP to look up <a href="local.8.html">local(8)</a>
|
||||
Here's a basic example for using LDAP to look up <a href="local.8.html">local(8)</a>
|
||||
aliases. Assume that in main.cf, you have:
|
||||
<a href="postconf.5.html#alias_maps">alias_maps</a> = hash:/etc/aliases,
|
||||
<a href="ldap_table.5.html">ldap</a>:/etc/postfix/ldap-aliases.cf
|
||||
@@ -423,14 +535,14 @@ LDAP_TABLE(5) LDAP_TABLE(5)
|
||||
server_host = ldap.my.com
|
||||
search_base = dc=my, 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 <a href="http://www.faqs.org/rfcs/rfc822.html">RFC822</a> addresses to which the message will be
|
||||
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 <a href="http://www.faqs.org/rfcs/rfc822.html">RFC822</a> addresses to which the message will be
|
||||
delivered.
|
||||
|
||||
<b>SEE ALSO</b>
|
||||
@@ -444,13 +556,13 @@ LDAP_TABLE(5) LDAP_TABLE(5)
|
||||
<a href="LDAP_README.html">LDAP_README</a>, Postfix LDAP client guide
|
||||
|
||||
<b>LICENSE</b>
|
||||
The Secure Mailer license must be distributed with this
|
||||
The Secure Mailer license must be distributed with this
|
||||
software.
|
||||
|
||||
<b>AUTHOR(S)</b>
|
||||
Carsten Hoeger, Hery Rakotoarisoa, John Hensley, Keith
|
||||
Stevenson, LaMont Jones, Liviu Daia, Manuel Guesdon, Mike
|
||||
Mattice, Prabhat K Singh, Sami Haahtinen, Samuel Tardieu,
|
||||
Carsten Hoeger, Hery Rakotoarisoa, John Hensley, Keith
|
||||
Stevenson, LaMont Jones, Liviu Daia, Manuel Guesdon, Mike
|
||||
Mattice, Prabhat K Singh, Sami Haahtinen, Samuel Tardieu,
|
||||
Victor Duchovni, and many others.
|
||||
|
||||
LDAP_TABLE(5)
|
||||
|
@@ -28,7 +28,7 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
||||
as the Postfix main.cf file, and can specify the parame-
|
||||
ters described below.
|
||||
|
||||
<b>ALTERNATIVE CONFIGURATION</b>
|
||||
<b>BACKWARDS COMPATIBILITY</b>
|
||||
For compatibility with other Postfix lookup tables, MySQL
|
||||
parameters can also be defined in main.cf. In order to do
|
||||
that, specify as MySQL source a name that doesn't begin
|
||||
@@ -44,6 +44,27 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
||||
Support for this form will be removed in a future Postfix
|
||||
version.
|
||||
|
||||
Postfix 2.2 has enhanced query interfaces for MySQL and
|
||||
PostreSQL, these include features previously available
|
||||
only in the Postfix LDAP client. In the new interface the
|
||||
SQL query is specified via a single <b>query</b> parameter
|
||||
(described in more detail below). When the new <b>query</b>
|
||||
parameter is not specified in the map definition, Postfix
|
||||
reverts to the old interface, with the SQL query con-
|
||||
structed from the <b>select_field</b>, <b>table</b>, <b>where_field</b> and
|
||||
<b>additional_conditions</b> parameters. The old interface will
|
||||
be gradually phased out. To migrate to the new interface
|
||||
set:
|
||||
|
||||
<b>query</b> = SELECT [<i>select</i><b>_</b><i>field</i>]
|
||||
FROM [<i>table</i>]
|
||||
WHERE [<i>where</i><b>_</b><i>field</i>] = '%s'
|
||||
[<i>additional</i><b>_</b><i>conditions</i>]
|
||||
|
||||
Insert the value, not the name, of each legacy parameter.
|
||||
Note that the <b>additional_conditions</b> parameter is optional
|
||||
and if not empty, will always start with <b>AND</b>.
|
||||
|
||||
<b>LIST MEMBERSHIP</b>
|
||||
When using SQL to store lists such as $<a href="postconf.5.html#mynetworks">mynetworks</a>, $<a href="postconf.5.html#mydestination">mydes</a>-
|
||||
<a href="postconf.5.html#mydestination">tination</a>, $<a href="postconf.5.html#relay_domains">relay_domains</a>, $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a>, etc., it
|
||||
@@ -91,29 +112,189 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
||||
<b>dbname</b> The database name on the servers. Example:
|
||||
dbname = customer_database
|
||||
|
||||
The following parameters are used to fill in a SELECT
|
||||
query template of the form:
|
||||
select [<b>select_field</b>] from [<b>table</b>] where
|
||||
[<b>where_field</b>] = '$lookup' [<b>additional_conditions</b>]
|
||||
<b>query</b> The SQL query template used to search the database,
|
||||
where <b>%s</b> is a substitute for the address Postfix is
|
||||
trying to resolve, e.g.
|
||||
query = SELECT replacement FROM aliases WHERE
|
||||
mailbox = '%s'
|
||||
|
||||
$lookup contains the search string, and is escaped so if
|
||||
it contains single quotes or other odd characters, it will
|
||||
not cause a parse error, or worse, a security problem.
|
||||
This parameter supports the following '%' expan-
|
||||
sions:
|
||||
|
||||
<b>%%</b> This is replaced by a literal '%' character.
|
||||
|
||||
<b>%s</b> This is replaced by the input key. SQL
|
||||
quoting is used to make sure that the input
|
||||
key does not add unexpected metacharacters.
|
||||
|
||||
<b>%u</b> When the input key is an address of the form
|
||||
user@domain, <b>%u</b> is replaced by the SQL
|
||||
quoted local part of the address. Other-
|
||||
wise, <b>%u</b> is replaced by the entire search
|
||||
string. If the localpart is empty, the
|
||||
query is suppressed and returns no results.
|
||||
|
||||
<b>%d</b> When the input key is an address of the form
|
||||
user@domain, <b>%d</b> is replaced by the SQL
|
||||
quoted domain part of the address. Other-
|
||||
wise, the query is suppressed and returns no
|
||||
results.
|
||||
|
||||
<b>%[SUD]</b> The upper-case equivalents of the above
|
||||
expansions behave in the <b>query</b> parameter
|
||||
identically to their lower-case counter-
|
||||
parts. With the <b>result_format</b> parameter
|
||||
(see below), they expand the input key
|
||||
rather than the result value.
|
||||
|
||||
<b>%[1-9]</b> The patterns %1, %2, ... %9 are replaced by
|
||||
the corresponding most significant component
|
||||
of the input key's domain. If the input key
|
||||
is <i>user@mail.example.com</i>, then %1 is <b>com</b>, %2
|
||||
is <b>example</b> and %3 is <b>mail</b>. If the input key
|
||||
is unqualified or does not have enough
|
||||
domain components to satisfy all the speci-
|
||||
fied patterns, the query is suppressed and
|
||||
returns no results.
|
||||
|
||||
The <b>domain</b> parameter described below limits the
|
||||
input keys to addresses in matching domains. When
|
||||
the <b>domain</b> parameter is non-empty, SQL queries for
|
||||
unqualified addresses or addresses in non-matching
|
||||
domains are suppressed and return no results.
|
||||
|
||||
This parameter is available with Postfix 2.2. In
|
||||
prior releases the SQL query was built from the
|
||||
separate parameters: <b>select_field</b>, <b>table</b>,
|
||||
<b>where_field</b> and <b>additional_conditions</b>. The mapping
|
||||
from the old parameters to the equivalent query is:
|
||||
|
||||
SELECT [<b>select_field</b>]
|
||||
FROM [<b>table</b>]
|
||||
WHERE [<b>where_field</b>] = '%s'
|
||||
[<b>additional_conditions</b>]
|
||||
|
||||
The '%s' in the <b>WHERE</b> clause expands to the escaped
|
||||
search string. With Postfix 2.2 these legacy
|
||||
parameters are used if the <b>query</b> parameter is not
|
||||
specified.
|
||||
|
||||
NOTE: DO NOT put quotes around the query parameter.
|
||||
|
||||
<b>result_format (default: %s</b>)
|
||||
Format template applied to result attributes. Most
|
||||
commonly used to append (or prepend) text to the
|
||||
result. This parameter supports the following '%'
|
||||
expansions:
|
||||
|
||||
<b>%%</b> This is replaced by a literal '%' character.
|
||||
|
||||
<b>%s</b> This is replaced by the value of the result
|
||||
attribute. When result is empty it is
|
||||
skipped.
|
||||
|
||||
<b>%u</b> When the result attribute value is an
|
||||
address of the form user@domain, <b>%u</b> is
|
||||
replaced by the local part of the address.
|
||||
When the result has an empty localpart it is
|
||||
skipped.
|
||||
|
||||
<b>%d</b> When a result attribute value is an address
|
||||
of the form user@domain, <b>%d</b> is replaced by
|
||||
the domain part of the attribute value. When
|
||||
the result is unqualified it is skipped.
|
||||
|
||||
<b>%[SUD1-9]</b>
|
||||
The upper-case and decimal digit expansions
|
||||
interpolate the parts of the input key
|
||||
rather than the result. Their behaviour is
|
||||
identical to that described with <b>query</b>, and
|
||||
in fact because the input key is known in
|
||||
advance, queries whose key does not contain
|
||||
all the information specified in the result
|
||||
template are suppressed and return no
|
||||
results.
|
||||
|
||||
For example, using "result_format = <a href="smtp.8.html">smtp</a>:[%s]"
|
||||
allows one to use a mailHost attribute as the basis
|
||||
of a <a href="transport.5.html">transport(5)</a> table. After applying the result
|
||||
format, multiple values are concatenated as comma
|
||||
separated strings. The expansion_limit and parame-
|
||||
ter explained below allows one to restrict the num-
|
||||
ber of values in the result, which is especially
|
||||
useful for maps that must return at most one value.
|
||||
|
||||
The default value <b>%s</b> specifies that each result
|
||||
value should be used as is.
|
||||
|
||||
This parameter is available with Postfix 2.2 and
|
||||
later.
|
||||
|
||||
NOTE: DO NOT put quotes around the result format!
|
||||
|
||||
<b>domain (default: no domain list)</b>
|
||||
This is a list of domain names, paths to files, or
|
||||
dictionaries. When specified, only fully qualified
|
||||
search 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 MySQL server.
|
||||
domain = postfix.org, hash:/etc/postfix/search-
|
||||
domains
|
||||
|
||||
It is best not to use SQL to store the domains eli-
|
||||
gible for SQL lookups.
|
||||
|
||||
This parameter is available with Postfix 2.2 and
|
||||
later.
|
||||
|
||||
NOTE: DO NOT define this parameter for <a href="local.8.html">local(8)</a>
|
||||
aliases, because the input keys are always unquali-
|
||||
fied.
|
||||
|
||||
<b>expansion_limit (default: 0)</b>
|
||||
A limit on the total number of result elements
|
||||
returned (as a comma separated list) by a lookup
|
||||
against the map. A setting of zero disables the
|
||||
limit. Lookups fail with a temporary error if the
|
||||
limit is exceeded. Setting the limit to 1 ensures
|
||||
that lookups do not return multiple values.
|
||||
|
||||
The following parameters can be used to fill in a SELECT
|
||||
template statement of the form:
|
||||
|
||||
SELECT [<b>select_field</b>]
|
||||
FROM [<b>table</b>]
|
||||
WHERE [<b>where_field</b>] = '%s'
|
||||
[<b>additional_conditions</b>]
|
||||
|
||||
The specifier %s is replaced by the search string, and is
|
||||
escaped so if it contains single quotes or other odd char-
|
||||
acters, it will not cause a parse error, or worse, a secu-
|
||||
rity problem.
|
||||
|
||||
As of Postfix 2.2 this interface is obsolete, it is
|
||||
replaced by the more general <b>query</b> interface described
|
||||
above. If the <b>query</b> parameter is defined, the legacy
|
||||
parameters are ignored. Please migrate to the new inter-
|
||||
face as the legacy interface may be removed in a future
|
||||
release.
|
||||
|
||||
<b>select_field</b>
|
||||
The SQL "select" parameter. Example:
|
||||
select_field = forw_addr
|
||||
<b>select_field</b> = forw_addr
|
||||
|
||||
<b>table</b> The SQL "select .. from" table name. Example:
|
||||
table = mxaliases
|
||||
<b>table</b> = mxaliases
|
||||
|
||||
<b>where_field</b>
|
||||
The SQL "select .. where" parameter. Example:
|
||||
where_field = alias
|
||||
<b>where_field</b> = alias
|
||||
|
||||
<b>additional_conditions</b>
|
||||
Additional conditions to the SQL query. Example:
|
||||
additional_conditions = and status = 'paid'
|
||||
<b>additional_conditions</b> = AND status = 'paid'
|
||||
|
||||
<b>SEE ALSO</b>
|
||||
<a href="postmap.1.html">postmap(1)</a>, Postfix lookup table maintenance
|
||||
@@ -126,7 +307,7 @@ MYSQL_TABLE(5) MYSQL_TABLE(5)
|
||||
<a href="MYSQL_README.html">MYSQL_README</a>, Postfix MYSQL client guide
|
||||
|
||||
<b>LICENSE</b>
|
||||
The Secure Mailer license must be distributed with this
|
||||
The Secure Mailer license must be distributed with this
|
||||
software.
|
||||
|
||||
<b>HISTORY</b>
|
||||
|
@@ -29,7 +29,7 @@ PGSQL_TABLE(5) PGSQL_TABLE(5)
|
||||
as the Postfix main.cf file, and can specify the parame-
|
||||
ters described below.
|
||||
|
||||
<b>ALTERNATIVE CONFIGURATION</b>
|
||||
<b>BACKWARDS COMPATIBILITY</b>
|
||||
For compatibility with other Postfix lookup tables, Post-
|
||||
greSQL parameters can also be defined in main.cf. In
|
||||
order to do that, specify as PostgreSQL source a name that
|
||||
@@ -45,44 +45,72 @@ PGSQL_TABLE(5) PGSQL_TABLE(5)
|
||||
readable. Support for this form will be removed in a
|
||||
future Postfix version.
|
||||
|
||||
Postfix 2.2 has enhanced query interfaces for MySQL and
|
||||
PostgreSQL, these include features previously available
|
||||
only in the Postfix LDAP client. In the new interface the
|
||||
SQL query is specified via a single <b>query</b> parameter
|
||||
(described in more detail below). In Postfix 2.1 the
|
||||
parameter precedence was, from highest to lowest,
|
||||
<b>select_function</b>, <b>query</b> and finally <b>select_field</b>, ...
|
||||
|
||||
With Postfix 2.2 the <b>query</b> parameter has highest prece-
|
||||
dence, and is used in preference to the still supported,
|
||||
but slated to be phased out, <b>select_function</b>,
|
||||
<b>select_field</b>, <b>table</b>, <b>where_field</b> and <b>additional_conditions</b>
|
||||
parameters. To migrate to the new interface set:
|
||||
|
||||
<b>query</b> = SELECT <i>select</i><b>_</b><i>function</i>('%s')
|
||||
|
||||
or in the absense of <b>selection_function</b>, the lower prece-
|
||||
dence:
|
||||
|
||||
<b>query</b> = SELECT <i>select</i><b>_</b><i>field</i>
|
||||
FROM <i>table</i>
|
||||
WHERE <i>where</i><b>_</b><i>field</i> = '%s'
|
||||
<i>additional</i><b>_</b><i>conditions</i>
|
||||
|
||||
Use the value, not the name, of each legacy parameter.
|
||||
Note that the <b>additional_conditions</b> parameter is optional
|
||||
and if not empty, will always start with <b>AND</b>.
|
||||
|
||||
<b>LIST MEMBERSHIP</b>
|
||||
When using SQL to store lists such as $<a href="postconf.5.html#mynetworks">mynetworks</a>, $<a href="postconf.5.html#mydestination">mydes</a>-
|
||||
<a href="postconf.5.html#mydestination">tination</a>, $<a href="postconf.5.html#relay_domains">relay_domains</a>, $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a>, etc., it
|
||||
is important to understand that the table must store each
|
||||
list member as a separate key. The table lookup verifies
|
||||
the *existence* of the key. See "Postfix lists versus
|
||||
tables" in the <a href="DATABASE_README.html">DATABASE_README</a> document for a discussion.
|
||||
<a href="postconf.5.html#mydestination">tination</a>, $<a href="postconf.5.html#relay_domains">relay_domains</a>, $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a>, etc., it
|
||||
is important to understand that the table must store each
|
||||
list member as a separate key. The table lookup verifies
|
||||
the *existence* of the key. See "Postfix lists versus
|
||||
tables" in the <a href="DATABASE_README.html">DATABASE_README</a> document for a discussion.
|
||||
|
||||
Do NOT create tables that return the full list of domains
|
||||
in $<a href="postconf.5.html#mydestination">mydestination</a> or $<a href="postconf.5.html#relay_domains">relay_domains</a> etc., or IP addresses
|
||||
Do NOT create tables that return the full list of domains
|
||||
in $<a href="postconf.5.html#mydestination">mydestination</a> or $<a href="postconf.5.html#relay_domains">relay_domains</a> etc., or IP addresses
|
||||
in $<a href="postconf.5.html#mynetworks">mynetworks</a>.
|
||||
|
||||
DO create tables with each matching item as a key and with
|
||||
an arbitrary value. With SQL databases it is not uncommon
|
||||
an arbitrary value. With SQL databases it is not uncommon
|
||||
to return the key itself or a constant value.
|
||||
|
||||
<b>PGSQL PARAMETERS</b>
|
||||
<b>hosts</b> The hosts that Postfix will try to connect to and
|
||||
<b>hosts</b> The hosts that Postfix will try to connect to and
|
||||
query from. Specify <i>unix:</i> for UNIX-domain sockets,
|
||||
<i>inet:</i> for TCP connections (default). Example:
|
||||
hosts = host1.some.domain host2.some.domain
|
||||
hosts = unix:/file/name
|
||||
|
||||
The hosts are tried in random order, with all con-
|
||||
The hosts are tried in random order, with all con-
|
||||
nections over UNIX domain sockets being tried
|
||||
before those over TCP. The connections are auto-
|
||||
matically closed after being idle for about 1
|
||||
before those over TCP. The connections are auto-
|
||||
matically closed after being idle for about 1
|
||||
minute, and are re-opened as necessary.
|
||||
|
||||
NOTE: the <i>unix:</i> and <i>inet:</i> prefixes are accepted for
|
||||
backwards compatibility reasons, but are actually
|
||||
backwards compatibility reasons, but are actually
|
||||
ignored. The PostgreSQL client library will always
|
||||
try to connect to an UNIX socket if the name starts
|
||||
with a slash, and will try a TCP connection other-
|
||||
with a slash, and will try a TCP connection other-
|
||||
wise.
|
||||
|
||||
<b>user, password</b>
|
||||
The user name and password to log into the pgsql
|
||||
The user name and password to log into the pgsql
|
||||
server. Example:
|
||||
user = someone
|
||||
password = some_password
|
||||
@@ -90,58 +118,155 @@ PGSQL_TABLE(5) PGSQL_TABLE(5)
|
||||
<b>dbname</b> The database name on the servers. Example:
|
||||
dbname = customer_database
|
||||
|
||||
The following parameters can be used to fill in a SELECT
|
||||
template statement of the form:
|
||||
select [<b>select_field</b>] from [<b>table</b>] where
|
||||
[<b>where_field</b>] = '$lookup' [<b>additional_conditions</b>]
|
||||
<b>query</b> The SQL query template used to search the database,
|
||||
where <b>%s</b> is a substitute for the address Postfix is
|
||||
trying to resolve, e.g.
|
||||
query = SELECT replacement FROM aliases WHERE
|
||||
mailbox = '%s'
|
||||
|
||||
$lookup contains the search string, and is escaped so if
|
||||
it contains single quotes or other odd characters, it will
|
||||
not cause a parse error, or worse, a security problem.
|
||||
|
||||
<b>select_field</b>
|
||||
The SQL "select" parameter. Example:
|
||||
select_field = forw_addr
|
||||
|
||||
<b>table</b> The SQL "select .. from" table name. Example:
|
||||
table = mxaliases
|
||||
|
||||
<b>where_field</b>
|
||||
The SQL "select .. where" parameter. Example:
|
||||
where_field = alias
|
||||
|
||||
<b>additional_conditions</b>
|
||||
Additional conditions to the SQL query. Example:
|
||||
additional_conditions = and status = 'paid'
|
||||
|
||||
The following parameters provide ways to override the
|
||||
default SELECT statement. Setting them will instruct
|
||||
Postfix to ignore the above <b>table</b>, <b>select_field</b>,
|
||||
<b>where_field</b> and <b>additional_conditions</b> parameters:
|
||||
|
||||
<b>query</b> This parameter specifies a complete SQL query.
|
||||
Example:
|
||||
query = select forw_addr from mxaliases where
|
||||
alias = '%s' and status = 'paid'
|
||||
|
||||
This parameter supports the following '%' expan-
|
||||
This parameter supports the following '%' expan-
|
||||
sions:
|
||||
|
||||
<b>%s</b> This is replaced by the input key. Quoting
|
||||
is used to make sure that the input key does
|
||||
not add unexpected metacharacters.
|
||||
<b>%%</b> This is replaced by a literal '%' character.
|
||||
(Postfix 2.2 and later)
|
||||
|
||||
<b>%s</b> This is replaced by the input key. SQL
|
||||
quoting is used to make sure that the input
|
||||
key does not add unexpected metacharacters.
|
||||
|
||||
<b>%u</b> When the input key is an address of the form
|
||||
user@domain, <b>%u</b> is replaced by the quoted
|
||||
local part of the address. If no domain is
|
||||
specified, <b>%u</b> is replaced by the entire
|
||||
search string.
|
||||
user@domain, <b>%u</b> is replaced by the SQL
|
||||
quoted local part of the address. Other-
|
||||
wise, <b>%u</b> is replaced by the entire search
|
||||
string. If the localpart is empty, the
|
||||
query is suppressed and returns no results.
|
||||
|
||||
<b>%d</b> When the input key is an address of the form
|
||||
user@domain, <b>%d</b> is replaced by the quoted
|
||||
domain part of the address. When the input
|
||||
key has no domain qualifier, <b>%d</b> is replaced
|
||||
by the entire search string.
|
||||
user@domain, <b>%d</b> is replaced by the SQL
|
||||
quoted domain part of the address. Other-
|
||||
wise, the query is suppressed and returns no
|
||||
results.
|
||||
|
||||
<b>%[SUD]</b> The upper-case equivalents of the above
|
||||
expansions behave in the <b>query</b> parameter
|
||||
identically to their lower-case counter-
|
||||
parts. With the <b>result_format</b> parameter
|
||||
(see below), they expand the input key
|
||||
rather than the result value.
|
||||
|
||||
The above %S, %U and %D expansions are
|
||||
available with Postfix 2.2 and later
|
||||
|
||||
<b>%[1-9]</b> The patterns %1, %2, ... %9 are replaced by
|
||||
the corresponding most significant component
|
||||
of the input key's domain. If the input key
|
||||
is <i>user@mail.example.com</i>, then %1 is <b>com</b>, %2
|
||||
is <b>example</b> and %3 is <b>mail</b>. If the input key
|
||||
is unqualified or does not have enough
|
||||
domain components to satisfy all the speci-
|
||||
fied patterns, the query is suppressed and
|
||||
returns no results.
|
||||
|
||||
The above %1, ... %9 expansions are avail-
|
||||
able with Postfix 2.2 and later
|
||||
|
||||
The <b>domain</b> parameter described below limits the
|
||||
input keys to addresses in matching domains. When
|
||||
the <b>domain</b> parameter is non-empty, SQL queries for
|
||||
unqualified addresses or addresses in non-matching
|
||||
domains are suppressed and return no results.
|
||||
|
||||
The precedence of this parameter has changed with
|
||||
Postfix 2.2, in prior releases the precedence was,
|
||||
from highest to lowest, <b>select_function</b>, <b>query</b>,
|
||||
<b>select_field</b>, ...
|
||||
|
||||
With Postfix 2.2 the <b>query</b> parameter has highest
|
||||
precedence, see COMPATIBILITY above.
|
||||
|
||||
NOTE: DO NOT put quotes around the <b>query</b> parameter.
|
||||
|
||||
<b>result_format (default: %s</b>)
|
||||
Format template applied to result attributes. Most
|
||||
commonly used to append (or prepend) text to the
|
||||
result. This parameter supports the following '%'
|
||||
expansions:
|
||||
|
||||
<b>%%</b> This is replaced by a literal '%' character.
|
||||
|
||||
<b>%s</b> This is replaced by the value of the result
|
||||
attribute. When result is empty it is
|
||||
skipped.
|
||||
|
||||
<b>%u</b> When the result attribute value is an
|
||||
address of the form user@domain, <b>%u</b> is
|
||||
replaced by the local part of the address.
|
||||
When the result has an empty localpart it is
|
||||
skipped.
|
||||
|
||||
<b>%d</b> When a result attribute value is an address
|
||||
of the form user@domain, <b>%d</b> is replaced by
|
||||
the domain part of the attribute value. When
|
||||
the result is unqualified it is skipped.
|
||||
|
||||
<b>%[SUD1-9]</b>
|
||||
The upper-case and decimal digit expansions
|
||||
interpolate the parts of the input key
|
||||
rather than the result. Their behaviour is
|
||||
identical to that described with <b>query</b>, and
|
||||
in fact because the input key is known in
|
||||
advance, queries whose key does not contain
|
||||
all the information specified in the result
|
||||
template are suppressed and return no
|
||||
results.
|
||||
|
||||
For example, using "result_format = <a href="smtp.8.html">smtp</a>:[%s]"
|
||||
allows one to use a mailHost attribute as the basis
|
||||
of a <a href="transport.5.html">transport(5)</a> table. After applying the result
|
||||
format, multiple values are concatenated as comma
|
||||
separated strings. The expansion_limit and parame-
|
||||
ter explained below allows one to restrict the num-
|
||||
ber of values in the result, which is especially
|
||||
useful for maps that must return at most one value.
|
||||
|
||||
The default value <b>%s</b> specifies that each result
|
||||
value should be used as is.
|
||||
|
||||
This parameter is available with Postfix 2.2 and
|
||||
later.
|
||||
|
||||
NOTE: DO NOT put quotes around the result format!
|
||||
|
||||
<b>domain (default: no domain list)</b>
|
||||
This is a list of domain names, paths to files, or
|
||||
dictionaries. When specified, only fully qualified
|
||||
search 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 PostgreSQL server.
|
||||
domain = postfix.org, hash:/etc/postfix/search-
|
||||
domains
|
||||
|
||||
It is best not to use SQL to store the domains eli-
|
||||
gible for SQL lookups.
|
||||
|
||||
This parameter is available with Postfix 2.2 and
|
||||
later.
|
||||
|
||||
NOTE: DO NOT define this parameter for <a href="local.8.html">local(8)</a>
|
||||
aliases, because the input keys are always unquali-
|
||||
fied.
|
||||
|
||||
<b>expansion_limit (default: 0)</b>
|
||||
A limit on the total number of result elements
|
||||
returned (as a comma separated list) by a lookup
|
||||
against the map. A setting of zero disables the
|
||||
limit. Lookups fail with a temporary error if the
|
||||
limit is exceeded. Setting the limit to 1 ensures
|
||||
that lookups do not return multiple values.
|
||||
|
||||
Pre-Postfix 2.2 legacy interfaces:
|
||||
|
||||
<b>select_function</b>
|
||||
This parameter specifies a database function name.
|
||||
@@ -149,18 +274,51 @@ PGSQL_TABLE(5) PGSQL_TABLE(5)
|
||||
select_function = my_lookup_user_alias
|
||||
|
||||
This is equivalent to:
|
||||
query = select my_lookup_user_alias('%s')
|
||||
query = SELECT my_lookup_user_alias('%s')
|
||||
|
||||
and overrides both the <b>query</b> parameter and the ta-
|
||||
ble-related fields above.
|
||||
This parameter overrides the legacy table-related
|
||||
fields (described below). With Postfix versions
|
||||
prior to 2.2, it also overrides the <b>query</b> parame-
|
||||
ter. Starting with Postfix 2.2, the <b>query</b> parameter
|
||||
has highest precedence, and this parameter is dep-
|
||||
recated. Please migrate to the new <b>query</b> interface
|
||||
as this interface is slated to be phased out.
|
||||
|
||||
As of June 2002, if the function returns a single
|
||||
row and a single column AND that value is NULL,
|
||||
then the result will be treated as if the key was
|
||||
not in the dictionary.
|
||||
The following parameters (with lower precedence than the
|
||||
<b>select_function</b> interface described above) can be used to
|
||||
build the SQL select statement as follows:
|
||||
|
||||
Future versions will allow functions to return
|
||||
result sets.
|
||||
SELECT [<b>select_field</b>]
|
||||
FROM [<b>table</b>]
|
||||
WHERE [<b>where_field</b>] = '%s'
|
||||
[<b>additional_conditions</b>]
|
||||
|
||||
The specifier %s is replaced with each lookup by the
|
||||
lookup key and is escaped so if it contains single quotes
|
||||
or other odd characters, it will not cause a parse error,
|
||||
or worse, a security problem.
|
||||
|
||||
Starting with Postfix 2.2, this interface is obsoleted by
|
||||
the more general <b>query</b> interface described above. If
|
||||
higher precedence the <b>query</b> or <b>select_function</b> parameters
|
||||
described above are defined, these parameters are ignored.
|
||||
Please migrate to the new <b>query</b> interface as this inter-
|
||||
face is slated to be phased out.
|
||||
|
||||
<b>select_field</b>
|
||||
The SQL "select" parameter. Example:
|
||||
<b>select_field</b> = forw_addr
|
||||
|
||||
<b>table</b> The SQL "select .. from" table name. Example:
|
||||
<b>table</b> = mxaliases
|
||||
|
||||
<b>where_field</b>
|
||||
The SQL "select .. where" parameter. Example:
|
||||
<b>where_field</b> = alias
|
||||
|
||||
<b>additional_conditions</b>
|
||||
Additional conditions to the SQL query. Example:
|
||||
<b>additional_conditions</b> = AND status = 'paid'
|
||||
|
||||
<b>SEE ALSO</b>
|
||||
<a href="postmap.1.html">postmap(1)</a>, Postfix lookup table manager
|
||||
@@ -173,7 +331,7 @@ PGSQL_TABLE(5) PGSQL_TABLE(5)
|
||||
<a href="PGSQL_README.html">PGSQL_README</a>, Postfix PostgreSQL client guide
|
||||
|
||||
<b>LICENSE</b>
|
||||
The Secure Mailer license must be distributed with this
|
||||
The Secure Mailer license must be distributed with this
|
||||
software.
|
||||
|
||||
<b>HISTORY</b>
|
||||
|
@@ -559,6 +559,24 @@ Enable the rewriting of the form "user%domain" to "user@domain".
|
||||
This is enabled by default.
|
||||
</p>
|
||||
|
||||
<p> Note: With Postfix version 2.2, message header address rewriting
|
||||
happens only when one of the following conditions is true: </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The message is received with the Postfix <a href="sendmail.1.html">sendmail(1)</a> command,
|
||||
|
||||
<li> The message is received from a network client that matches
|
||||
$<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a>,
|
||||
|
||||
<li> The message is received from the network, and the
|
||||
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> parameter specifies a non-empty value.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> To get the behavior before Postfix 2.2, specify
|
||||
"<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = static:all". </p>
|
||||
|
||||
<p>
|
||||
Example:
|
||||
</p>
|
||||
@@ -689,10 +707,28 @@ append the string "@$<a href="postconf.5.html#remote_header_rewrite_domain">remo
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This feature is enabled by default and must not be turned off.
|
||||
Note 1: This feature is enabled by default and must not be turned off.
|
||||
Postfix does not support domain-less addresses.
|
||||
</p>
|
||||
|
||||
<p> Note 2: With Postfix version 2.2, message header address rewriting
|
||||
happens only when one of the following conditions is true: </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The message is received with the Postfix <a href="sendmail.1.html">sendmail(1)</a> command,
|
||||
|
||||
<li> The message is received from a network client that matches
|
||||
$<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a>,
|
||||
|
||||
<li> The message is received from the network, and the
|
||||
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> parameter specifies a non-empty value.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> To get the behavior before Postfix 2.2, specify
|
||||
"<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = static:all". </p>
|
||||
|
||||
|
||||
</DD>
|
||||
|
||||
@@ -707,11 +743,29 @@ instead.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This feature is enabled by default. If disabled, users will not be
|
||||
Note 1: This feature is enabled by default. If disabled, users will not be
|
||||
able to send mail to "user@partialdomainname" but will have to
|
||||
specify full domain names instead.
|
||||
</p>
|
||||
|
||||
<p> Note 2: With Postfix version 2.2, message header address rewriting
|
||||
happens only when one of the following conditions is true: </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The message is received with the Postfix <a href="sendmail.1.html">sendmail(1)</a> command,
|
||||
|
||||
<li> The message is received from a network client that matches
|
||||
$<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a>,
|
||||
|
||||
<li> The message is received from the network, and the
|
||||
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> parameter specifies a non-empty value.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> To get the behavior before Postfix 2.2, specify
|
||||
"<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = static:all". </p>
|
||||
|
||||
|
||||
</DD>
|
||||
|
||||
@@ -1105,6 +1159,24 @@ will become visible after a minute or so. Use "<b>postfix reload</b>"
|
||||
to eliminate the delay.
|
||||
</p>
|
||||
|
||||
<p> Note: with Postfix version 2.2, message header address mapping
|
||||
happens only when message header address rewriting is enabled: </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The message is received with the Postfix <a href="sendmail.1.html">sendmail(1)</a> command,
|
||||
|
||||
<li> The message is received from a network client that matches
|
||||
$<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a>,
|
||||
|
||||
<li> The message is received from the network, and the
|
||||
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> parameter specifies a non-empty value.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> To get the behavior before Postfix 2.2, specify
|
||||
"<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = static:all". </p>
|
||||
|
||||
<p>
|
||||
Examples:
|
||||
</p>
|
||||
@@ -2659,7 +2731,8 @@ Examples:
|
||||
<p> The Internet protocols Postfix will attempt to use when making
|
||||
or accepting connections. Specify one or more of "ipv4"
|
||||
or "ipv6", separated by whitespace or commas. The form
|
||||
"all" is equivalent to "ipv4, ipv6". </p>
|
||||
"all" is equivalent to "ipv4, ipv6" or "ipv4", depending
|
||||
on whether the operating system implements IPv6. </p>
|
||||
|
||||
<p> This feature is available in Postfix version 2.2 and later. </p>
|
||||
|
||||
@@ -3881,6 +3954,24 @@ does not change "user@any.thing.foo.example.com" or "user@foo.example.com",
|
||||
but strips "user@any.thing.else.example.com" to "user@example.com".
|
||||
</p>
|
||||
|
||||
<p> Note: with Postfix version 2.2, message header address masquerading
|
||||
happens only when message header address rewriting is enabled: </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The message is received with the Postfix <a href="sendmail.1.html">sendmail(1)</a> command,
|
||||
|
||||
<li> The message is received from a network client that matches
|
||||
$<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a>,
|
||||
|
||||
<li> The message is received from the network, and the
|
||||
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> parameter specifies a non-empty value.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> To get the behavior before Postfix 2.2, specify
|
||||
"<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = static:all". </p>
|
||||
|
||||
<p>
|
||||
Example:
|
||||
</p>
|
||||
@@ -9044,6 +9135,24 @@ necessary if your machine is connected to UUCP networks. It is
|
||||
enabled by default.
|
||||
</p>
|
||||
|
||||
<p> Note: With Postfix version 2.2, message header address rewriting
|
||||
happens only when one of the following conditions is true: </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The message is received with the Postfix <a href="sendmail.1.html">sendmail(1)</a> command,
|
||||
|
||||
<li> The message is received from a network client that matches
|
||||
$<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a>,
|
||||
|
||||
<li> The message is received from the network, and the
|
||||
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> parameter specifies a non-empty value.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> To get the behavior before Postfix 2.2, specify
|
||||
"<a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> = static:all". </p>
|
||||
|
||||
<p>
|
||||
Example:
|
||||
</p>
|
||||
|
@@ -53,6 +53,18 @@ parameter below would be defined in main.cf as
|
||||
Note: with this form, the passwords for the LDAP sources are
|
||||
written in main.cf, which is normally world-readable. Support
|
||||
for this form will be removed in a future Postfix version.
|
||||
|
||||
Postfix 2.2 has enhanced query interfaces for MySQL and PostgreSQL,
|
||||
these now include features previously available only in the
|
||||
Postfix LDAP client. This work also created an opportunity for
|
||||
improvements in the LDAP interface. The primary compatibility
|
||||
issue is that \fBresult_filter\fR (a name that has caused some
|
||||
confusion as to its meaning in the past) has been renamed to
|
||||
\fBresult_format\fR. For backwards compatibility with the pre
|
||||
2.2 LDAP client, \fBresult_filter\fR can for now be used instead
|
||||
of \fBresult_format\fR, when the latter parameter is not also set.
|
||||
The new name better reflects the function of the parameter. This
|
||||
compatibility interface may be removed in a future release.
|
||||
.SH "LIST MEMBERSHIP"
|
||||
.na
|
||||
.nf
|
||||
@@ -128,14 +140,50 @@ server_host = ldapi://%2Fsome%2Fpath
|
||||
The port the LDAP server listens on, e.g.
|
||||
.ti +4
|
||||
server_port = 778
|
||||
.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 "\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
|
||||
With Postfix 2.2 and later this parameter supports the
|
||||
following '%' expansions:
|
||||
.RS
|
||||
.IP "\fB\fB%%\fR\fR"
|
||||
This is replaced by a literal '%' character.
|
||||
.IP "\fB\fB%s\fR\fR"
|
||||
This is replaced by the input key.
|
||||
RFC 2253 quoting is used to make sure that the input key
|
||||
does not add unexpected metacharacters.
|
||||
.IP "\fB\fB%u\fR\fR"
|
||||
When the input key is an address of the form user@domain, \fB%u\fR
|
||||
is replaced by the (RFC 2253) quoted local part of the address.
|
||||
Otherwise, \fB%u\fR is replaced by the entire search string.
|
||||
If the localpart is empty, the search is suppressed and returns
|
||||
no results.
|
||||
.IP "\fB\fB%d\fR\fR"
|
||||
When the input key is an address of the form user@domain, \fB%d\fR
|
||||
is replaced by the (RFC 2253) quoted domain part of the address.
|
||||
Otherwise, the search is suppressed and returns no results.
|
||||
.IP "\fB\fB%[SUD]\fR\fR"
|
||||
For the \fBsearch_base\fR parameter, the upper-case equivalents
|
||||
of the above expansions behave identically to their lower-case
|
||||
counter-parts. With the \fBresult_format\fR parameter (previously
|
||||
called \fBresult_filter\fR see the COMPATIBILITY section and below),
|
||||
they expand to the corresponding components of input key rather
|
||||
than the result value.
|
||||
.IP "\fB\fB%[1-9]\fR\fR"
|
||||
The patterns %1, %2, ... %9 are replaced by the corresponding
|
||||
most significant component of the input key's domain. If the
|
||||
input key is \fIuser@mail.example.com\fR, then %1 is \fBcom\fR,
|
||||
%2 is \fBexample\fR and %3 is \fBmail\fR. If the input key is
|
||||
unqualified or does not have enough domain components to satisfy
|
||||
all the specified patterns, the search is suppressed and returns
|
||||
no results.
|
||||
.RE
|
||||
.IP "\fBquery_filter (default: mailacceptinggeneralid=%s)\fR"
|
||||
The RFC2254 filter used to search the directory, where \fB%s\fR
|
||||
is a substitute for the address Postfix is trying to resolve,
|
||||
@@ -145,20 +193,43 @@ query_filter = (&(mail=%s)(paid_up=true))
|
||||
|
||||
This parameter supports the following '%' expansions:
|
||||
.RS
|
||||
.IP "\fB\fB%%\fR\fR"
|
||||
This is replaced by a literal '%' character. (Postfix 2.2 and later).
|
||||
.IP "\fB\fB%s\fR\fR"
|
||||
This is replaced by the input key. RFC 2254 quoting is used
|
||||
to make sure that the input key does not add unexpected
|
||||
metacharacters.
|
||||
This is replaced by the input key.
|
||||
RFC 2254 quoting is used to make sure that the input key
|
||||
does not add unexpected metacharacters.
|
||||
.IP "\fB\fB%u\fR\fR"
|
||||
When the input key is an address of the form user@domain,
|
||||
\fB%u\fR is replaced by the (RFC 2254) quoted local part of the
|
||||
address. Otherwise, \fB%u\fR is replaced by the entire
|
||||
search string.
|
||||
When the input key is an address of the form user@domain, \fB%u\fR
|
||||
is replaced by the (RFC 2254) quoted local part of the address.
|
||||
Otherwise, \fB%u\fR is replaced by the entire search string.
|
||||
If the localpart is empty, the search is suppressed and returns
|
||||
no results.
|
||||
.IP "\fB\fB%d\fR\fR"
|
||||
When the input key is an address of the form user@domain,
|
||||
\fB%d\fR is replaced by the (RFC 2254) quoted domain part of the
|
||||
address. Otherwise, \fB%d\fR is replaced by the entire
|
||||
search string.
|
||||
When the input key is an address of the form user@domain, \fB%d\fR
|
||||
is replaced by the (RFC 2254) quoted domain part of the address.
|
||||
Otherwise, the search is suppressed and returns no results.
|
||||
.IP "\fB\fB%[SUD]\fR\fR"
|
||||
The upper-case equivalents of the above expansions behave in the
|
||||
\fBquery_filter\fR parameter identically to their lower-case
|
||||
counter-parts. With the \fBresult_format\fR parameter (previously
|
||||
called \fBresult_filter\fR see the COMPATIBILITY section and below),
|
||||
they expand to the corresponding components of input key rather
|
||||
than the result value.
|
||||
.IP
|
||||
The above %S, %U and %D expansions are available with Postfix 2.2
|
||||
and later.
|
||||
.IP "\fB\fB%[1-9]\fR\fR"
|
||||
The patterns %1, %2, ... %9 are replaced by the corresponding
|
||||
most significant component of the input key's domain. If the
|
||||
input key is \fIuser@mail.example.com\fR, then %1 is \fBcom\fR,
|
||||
%2 is \fBexample\fR and %3 is \fBmail\fR. If the input key is
|
||||
unqualified or does not have enough domain components to satisfy
|
||||
all the specified patterns, the saerch is suppressed and returns
|
||||
no results.
|
||||
.IP
|
||||
The above %1, ..., %9 expansions are available with Postfix 2.2
|
||||
and later.
|
||||
.RE
|
||||
.IP
|
||||
The "domain" parameter described below limits the input
|
||||
@@ -167,30 +238,42 @@ parameter is non-empty, LDAP queries for unqualified
|
||||
addresses or addresses in non-matching domains are suppressed
|
||||
and return no results.
|
||||
|
||||
NOTE: DO NOT put quotes around the query filter.
|
||||
.IP "\fBresult_filter (default: \fB%s\fR)\fR"
|
||||
Format template applied to result attributes. Supports the
|
||||
same expansions as the query_filter, and can be easily used
|
||||
to append (or prepend) text. This parameter supports the
|
||||
following '%' expansions:
|
||||
NOTE: DO NOT put quotes around the \fBquery_filter\fR parameter.
|
||||
.IP "\fBresult_format (default: \fB%s\fR)\fR"
|
||||
Called \fBresult_filter\fR in Postfix releases prior to 2.2.
|
||||
Format template applied to result attributes. Most commonly used
|
||||
to append (or prepend) text to the result. This parameter supports
|
||||
the following '%' expansions:
|
||||
.RS
|
||||
.IP "\fB\fB%%\fR\fR"
|
||||
This is replaced by a literal '%' character. (Postfix 2.2 and later).
|
||||
.IP "\fB\fB%s\fR\fR"
|
||||
This is replaced by the value of the result attribute.
|
||||
This is replaced by the value of the result attribute. When
|
||||
result is empty it is skipped.
|
||||
.IP "\fB%u\fR
|
||||
When the result attribute value is an address of the form
|
||||
user@domain, \fB%u\fR is replaced by the local part of the
|
||||
address. Otherwise, \fB%u\fR is replaced by the entire
|
||||
attribute value.
|
||||
address. When the result has an empty localpart it is skipped.
|
||||
.IP "\fB\fB%d\fR\fR"
|
||||
When a result attribute value is an address of the form
|
||||
user@domain, \fB%d\fR is replaced by the domain part of
|
||||
the attribute value. Otherwise, \fB%d\fR is replaced by
|
||||
the entire attribute value.
|
||||
the attribute value. When the result is unqualified it
|
||||
is skipped.
|
||||
.IP "\fB\fB%[SUD1-9]\fR\fB"
|
||||
The upper-case and decimal digit expansions interpolate
|
||||
the parts of the input key rather than the result. Their
|
||||
behaviour is identical to that described with \fBquery_filter\fR,
|
||||
and in fact because the input key is known in advance, lookups
|
||||
whose key does not contain all the information specified in
|
||||
the result template are suppressed and return no results.
|
||||
.IP
|
||||
The above %S, %U, %D and %1, ..., %9 expansions are available with
|
||||
Postfix 2.2 and later.
|
||||
.RE
|
||||
.IP
|
||||
For example, using "result_filter = smtp:[%s]" allows one
|
||||
For example, using "result_format = smtp:[%s]" allows one
|
||||
to use a mailHost attribute as the basis of a transport(5)
|
||||
table. After applying the result filter, multiple values
|
||||
table. After applying the result format, multiple values
|
||||
are concatenated as comma separated strings. The expansion_limit
|
||||
and size_limit parameters explained below allow one to
|
||||
restrict the number of values in the result, which is
|
||||
@@ -200,7 +283,13 @@ value.
|
||||
The default value \fB%s\fR specifies that each
|
||||
attribute value should be used as is.
|
||||
|
||||
NOTE: DO NOT put quotes around the result filter!
|
||||
This parameter was called \fBresult_filter\fR in Postfix
|
||||
releases prior to 2.2. If no "result_format" is specified,
|
||||
the value of "result_filter" will be used instead before
|
||||
resorting to the default value. This provides compatibility
|
||||
with old configuration files.
|
||||
|
||||
NOTE: DO NOT put quotes around the result format!
|
||||
.IP "\fBdomain (default: no domain list)\fR"
|
||||
This is a list of domain names, paths to files, or
|
||||
dictionaries. When specified, only fully qualified search
|
||||
@@ -220,7 +309,7 @@ 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
|
||||
result_attribute = mailbox, maildrop
|
||||
.IP "\fBspecial_result_attribute (No default)\fR"
|
||||
The attribute(s) of directory entries that can contain DNs
|
||||
or URLs. If found, a recursive subsequent search is done
|
||||
@@ -287,14 +376,14 @@ limit to 1 ensures that lookups do not return multiple
|
||||
values.
|
||||
.IP "\fBsize_limit (default: $expansion_limit)\fR"
|
||||
A limit on the number of LDAP entries returned by any single
|
||||
LDAP query performed as part of the lookup. A setting of
|
||||
LDAP search performed as part of the lookup. A setting of
|
||||
0 disables the limit. Expansion of DN and URL references
|
||||
involves nested LDAP queries, each of which is separately
|
||||
subjected to this limit.
|
||||
|
||||
Note: even a single LDAP entry can generate multiple lookup
|
||||
results, via multiple result attributes and/or multi-valued
|
||||
result attributes. This limit caps the per query resource
|
||||
result attributes. This limit caps the per search resource
|
||||
utilization on the LDAP server, not the final multiplicity
|
||||
of the lookup result. It is analogous to the "-z" option
|
||||
of "ldapsearch".
|
||||
|
@@ -27,7 +27,7 @@ alias_maps = mysql:/etc/mysql-aliases.cf
|
||||
The file /etc/postfix/mysql-aliases.cf has the same format as
|
||||
the Postfix main.cf file, and can specify the parameters
|
||||
described below.
|
||||
.SH "ALTERNATIVE CONFIGURATION"
|
||||
.SH "BACKWARDS COMPATIBILITY"
|
||||
.na
|
||||
.nf
|
||||
.ad
|
||||
@@ -44,6 +44,30 @@ below would be defined in main.cf as "\fImysqlname\fR_hosts".
|
||||
Note: with this form, the passwords for the MySQL sources are
|
||||
written in main.cf, which is normally world-readable. Support
|
||||
for this form will be removed in a future Postfix version.
|
||||
|
||||
Postfix 2.2 has enhanced query interfaces for MySQL and PostreSQL,
|
||||
these include features previously available only in the Postfix
|
||||
LDAP client. In the new interface the SQL query is specified via
|
||||
a single \fBquery\fR parameter (described in more detail below).
|
||||
When the new \fBquery\fR parameter is not specified in the map
|
||||
definition, Postfix reverts to the old interface, with the SQL
|
||||
query constructed from the \fBselect_field\fR, \fBtable\fR,
|
||||
\fBwhere_field\fR and \fBadditional_conditions\fR parameters.
|
||||
The old interface will be gradually phased out. To migrate to
|
||||
the new interface set:
|
||||
|
||||
.ti +4
|
||||
\fBquery\fR = SELECT [\fIselect_field\fR]
|
||||
.ti +8
|
||||
FROM [\fItable\fR]
|
||||
.ti +8
|
||||
WHERE [\fIwhere_field\fR] = '%s'
|
||||
.ti +12
|
||||
[\fIadditional_conditions\fR]
|
||||
|
||||
Insert the value, not the name, of each legacy parameter. Note
|
||||
that the \fBadditional_conditions\fR parameter is optional
|
||||
and if not empty, will always start with \fBAND\fR.
|
||||
.SH "LIST MEMBERSHIP"
|
||||
.na
|
||||
.nf
|
||||
@@ -102,33 +126,176 @@ password = some_password
|
||||
The database name on the servers. Example:
|
||||
.ti +4
|
||||
dbname = customer_database
|
||||
.PP
|
||||
The following parameters are used to fill in a SELECT
|
||||
query template of the form:
|
||||
.IP "\fBquery\fR"
|
||||
The SQL query template used to search the database, where \fB%s\fR
|
||||
is a substitute for the address Postfix is trying to resolve,
|
||||
e.g.
|
||||
.ti +4
|
||||
select [\fBselect_field\fR] from [\fBtable\fR] where
|
||||
.ti +8
|
||||
[\fBwhere_field\fR] = '$lookup' [\fBadditional_conditions\fR]
|
||||
query = SELECT replacement FROM aliases WHERE mailbox = '%s'
|
||||
|
||||
$lookup contains the search string, and is escaped so if
|
||||
it contains single quotes or other odd characters, it will
|
||||
not cause a parse error, or worse, a security problem.
|
||||
This parameter supports the following '%' expansions:
|
||||
.RS
|
||||
.IP "\fB\fB%%\fR\fR"
|
||||
This is replaced by a literal '%' character.
|
||||
.IP "\fB\fB%s\fR\fR"
|
||||
This is replaced by the input key.
|
||||
SQL quoting is used to make sure that the input key does not
|
||||
add unexpected metacharacters.
|
||||
.IP "\fB\fB%u\fR\fR"
|
||||
When the input key is an address of the form user@domain, \fB%u\fR
|
||||
is replaced by the SQL quoted local part of the address.
|
||||
Otherwise, \fB%u\fR is replaced by the entire search string.
|
||||
If the localpart is empty, the query is suppressed and returns
|
||||
no results.
|
||||
.IP "\fB\fB%d\fR\fR"
|
||||
When the input key is an address of the form user@domain, \fB%d\fR
|
||||
is replaced by the SQL quoted domain part of the address.
|
||||
Otherwise, the query is suppressed and returns no results.
|
||||
.IP "\fB\fB%[SUD]\fR\fR"
|
||||
The upper-case equivalents of the above expansions behave in the
|
||||
\fBquery\fR parameter identically to their lower-case counter-parts.
|
||||
With the \fBresult_format\fR parameter (see below), they expand the
|
||||
input key rather than the result value.
|
||||
.IP "\fB\fB%[1-9]\fR\fR"
|
||||
The patterns %1, %2, ... %9 are replaced by the corresponding
|
||||
most significant component of the input key's domain. If the
|
||||
input key is \fIuser@mail.example.com\fR, then %1 is \fBcom\fR,
|
||||
%2 is \fBexample\fR and %3 is \fBmail\fR. If the input key is
|
||||
unqualified or does not have enough domain components to satisfy
|
||||
all the specified patterns, the query is suppressed and returns
|
||||
no results.
|
||||
.RE
|
||||
.IP
|
||||
The \fBdomain\fR parameter described below limits the input
|
||||
keys to addresses in matching domains. When the \fBdomain\fR
|
||||
parameter is non-empty, SQL queries for unqualified addresses
|
||||
or addresses in non-matching domains are suppressed
|
||||
and return no results.
|
||||
|
||||
This parameter is available with Postfix 2.2. In prior releases
|
||||
the SQL query was built from the separate parameters:
|
||||
\fBselect_field\fR, \fBtable\fR, \fBwhere_field\fR and
|
||||
\fBadditional_conditions\fR. The mapping from the old parameters
|
||||
to the equivalent query is:
|
||||
|
||||
.ti +4
|
||||
SELECT [\fBselect_field\fR]
|
||||
.ti +4
|
||||
FROM [\fBtable\fR]
|
||||
.ti +4
|
||||
WHERE [\fBwhere_field\fR] = '%s'
|
||||
.ti +10
|
||||
[\fBadditional_conditions\fR]
|
||||
|
||||
The '%s' in the \fBWHERE\fR clause expands to the escaped search string.
|
||||
With Postfix 2.2 these legacy parameters are used if the \fBquery\fR
|
||||
parameter is not specified.
|
||||
|
||||
NOTE: DO NOT put quotes around the query parameter.
|
||||
.IP "\fBresult_format (default: \fB%s\fR)\fR"
|
||||
Format template applied to result attributes. Most commonly used
|
||||
to append (or prepend) text to the result. This parameter supports
|
||||
the following '%' expansions:
|
||||
.RS
|
||||
.IP "\fB\fB%%\fR\fR"
|
||||
This is replaced by a literal '%' character.
|
||||
.IP "\fB\fB%s\fR\fR"
|
||||
This is replaced by the value of the result attribute. When
|
||||
result is empty it is skipped.
|
||||
.IP "\fB%u\fR
|
||||
When the result attribute value is an address of the form
|
||||
user@domain, \fB%u\fR is replaced by the local part of the
|
||||
address. When the result has an empty localpart it is skipped.
|
||||
.IP "\fB\fB%d\fR\fR"
|
||||
When a result attribute value is an address of the form
|
||||
user@domain, \fB%d\fR is replaced by the domain part of
|
||||
the attribute value. When the result is unqualified it
|
||||
is skipped.
|
||||
.IP "\fB\fB%[SUD1-9]\fR\fB"
|
||||
The upper-case and decimal digit expansions interpolate
|
||||
the parts of the input key rather than the result. Their
|
||||
behaviour is identical to that described with \fBquery\fR,
|
||||
and in fact because the input key is known in advance, queries
|
||||
whose key does not contain all the information specified in
|
||||
the result template are suppressed and return no results.
|
||||
.RE
|
||||
.IP
|
||||
For example, using "result_format = smtp:[%s]" allows one
|
||||
to use a mailHost attribute as the basis of a transport(5)
|
||||
table. After applying the result format, multiple values
|
||||
are concatenated as comma separated strings. The expansion_limit
|
||||
and parameter explained below allows one to restrict the number
|
||||
of values in the result, which is especially useful for maps that
|
||||
must return at most one value.
|
||||
|
||||
The default value \fB%s\fR specifies that each result value should
|
||||
be used as is.
|
||||
|
||||
This parameter is available with Postfix 2.2 and later.
|
||||
|
||||
NOTE: DO NOT put quotes around the result format!
|
||||
.IP "\fBdomain (default: no domain list)\fR"
|
||||
This is a list of domain names, paths to files, or
|
||||
dictionaries. When specified, only fully qualified search
|
||||
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 MySQL server.
|
||||
.ti +4
|
||||
domain = postfix.org, hash:/etc/postfix/searchdomains
|
||||
|
||||
It is best not to use SQL to store the domains eligible
|
||||
for SQL lookups.
|
||||
|
||||
This parameter is available with Postfix 2.2 and later.
|
||||
|
||||
NOTE: DO NOT define this parameter for local(8) aliases,
|
||||
because the input keys are always unqualified.
|
||||
.IP "\fBexpansion_limit (default: 0)\fR"
|
||||
A limit on the total number of result elements returned
|
||||
(as a comma separated list) by a lookup against the map.
|
||||
A setting of zero disables the limit. Lookups fail with a
|
||||
temporary error if the limit is exceeded. Setting the
|
||||
limit to 1 ensures that lookups do not return multiple
|
||||
values.
|
||||
.PP
|
||||
The following parameters can be used to fill in a
|
||||
SELECT template statement of the form:
|
||||
|
||||
.ti +4
|
||||
SELECT [\fBselect_field\fR]
|
||||
.ti +4
|
||||
FROM [\fBtable\fR]
|
||||
.ti +4
|
||||
WHERE [\fBwhere_field\fR] = '%s'
|
||||
.ti +10
|
||||
[\fBadditional_conditions\fR]
|
||||
|
||||
The specifier %s is replaced by the search string, and is
|
||||
escaped so if it contains single quotes or other odd characters,
|
||||
it will not cause a parse error, or worse, a security problem.
|
||||
|
||||
As of Postfix 2.2 this interface is obsolete, it is replaced
|
||||
by the more general \fBquery\fR interface described above.
|
||||
If the \fBquery\fR parameter is defined, the legacy parameters
|
||||
are ignored. Please migrate to the new interface as the legacy
|
||||
interface may be removed in a future release.
|
||||
.IP "\fBselect_field\fR"
|
||||
The SQL "select" parameter. Example:
|
||||
.ti +4
|
||||
select_field = forw_addr
|
||||
\fBselect_field\fR = forw_addr
|
||||
.IP "\fBtable\fR"
|
||||
The SQL "select .. from" table name. Example:
|
||||
.ti +4
|
||||
table = mxaliases
|
||||
\fBtable\fR = mxaliases
|
||||
.IP "\fBwhere_field\fR
|
||||
The SQL "select .. where" parameter. Example:
|
||||
.ti +4
|
||||
where_field = alias
|
||||
\fBwhere_field\fR = alias
|
||||
.IP "\fBadditional_conditions\fR
|
||||
Additional conditions to the SQL query. Example:
|
||||
.ti +4
|
||||
additional_conditions = and status = 'paid'
|
||||
\fBadditional_conditions\fR = AND status = 'paid'
|
||||
.SH "SEE ALSO"
|
||||
.na
|
||||
.nf
|
||||
|
@@ -27,7 +27,7 @@ alias_maps = pgsql:/etc/pgsql-aliases.cf
|
||||
The file /etc/postfix/pgsql-aliases.cf has the same format as
|
||||
the Postfix main.cf file, and can specify the parameters
|
||||
described below.
|
||||
.SH "ALTERNATIVE CONFIGURATION"
|
||||
.SH "BACKWARDS COMPATIBILITY"
|
||||
.na
|
||||
.nf
|
||||
.ad
|
||||
@@ -46,6 +46,37 @@ Note: with this form, the passwords for the PostgreSQL sources
|
||||
are written in main.cf, which is normally world-readable.
|
||||
Support for this form will be removed in a future Postfix
|
||||
version.
|
||||
|
||||
Postfix 2.2 has enhanced query interfaces for MySQL and PostgreSQL,
|
||||
these include features previously available only in the Postfix
|
||||
LDAP client. In the new interface the SQL query is specified via
|
||||
a single \fBquery\fR parameter (described in more detail below).
|
||||
In Postfix 2.1 the parameter precedence was, from highest to lowest,
|
||||
\fBselect_function\fR, \fBquery\fR and finally \fBselect_field\fR, ...
|
||||
|
||||
With Postfix 2.2 the \fBquery\fR parameter has highest precedence,
|
||||
and is used in preference to the still supported, but slated to be
|
||||
phased out, \fBselect_function\fR, \fBselect_field\fR, \fBtable\fR,
|
||||
\fBwhere_field\fR and \fBadditional_conditions\fR parameters. To
|
||||
migrate to the new interface set:
|
||||
|
||||
.ti +4
|
||||
\fBquery\fR = SELECT \fIselect_function\fR('%s')
|
||||
|
||||
or in the absense of \fBselection_function\fR, the lower precedence:
|
||||
|
||||
.ti +4
|
||||
\fBquery\fR = SELECT \fIselect_field\fR
|
||||
.ti +8
|
||||
FROM \fItable\fR
|
||||
.ti +8
|
||||
WHERE \fIwhere_field\fR = '%s'
|
||||
.ti +12
|
||||
\fIadditional_conditions\fR
|
||||
|
||||
Use the value, not the name, of each legacy parameter. Note
|
||||
that the \fBadditional_conditions\fR parameter is optional
|
||||
and if not empty, will always start with \fBAND\fR.
|
||||
.SH "LIST MEMBERSHIP"
|
||||
.na
|
||||
.nf
|
||||
@@ -102,61 +133,134 @@ password = some_password
|
||||
The database name on the servers. Example:
|
||||
.ti +4
|
||||
dbname = customer_database
|
||||
.PP
|
||||
The following parameters can be used to fill in a SELECT
|
||||
template statement of the form:
|
||||
.ti +4
|
||||
select [\fBselect_field\fR] from [\fBtable\fR] where
|
||||
.ti +8
|
||||
[\fBwhere_field\fR] = '$lookup' [\fBadditional_conditions\fR]
|
||||
|
||||
$lookup contains the search string, and is escaped so if
|
||||
it contains single quotes or other odd characters, it will
|
||||
not cause a parse error, or worse, a security problem.
|
||||
.IP "\fBselect_field\fR"
|
||||
The SQL "select" parameter. Example:
|
||||
.ti +4
|
||||
select_field = forw_addr
|
||||
.IP "\fBtable\fR"
|
||||
The SQL "select .. from" table name. Example:
|
||||
.ti +4
|
||||
table = mxaliases
|
||||
.IP "\fBwhere_field\fR
|
||||
The SQL "select .. where" parameter. Example:
|
||||
.ti +4
|
||||
where_field = alias
|
||||
.IP "\fBadditional_conditions\fR
|
||||
Additional conditions to the SQL query. Example:
|
||||
.ti +4
|
||||
additional_conditions = and status = 'paid'
|
||||
.PP
|
||||
The following parameters provide ways to override the default
|
||||
SELECT statement. Setting them will instruct Postfix to ignore
|
||||
the above \fBtable\fR, \fBselect_field\fR, \fBwhere_field\fR and
|
||||
\fBadditional_conditions\fR parameters:
|
||||
.IP "\fBquery\fR"
|
||||
This parameter specifies a complete SQL query. Example:
|
||||
The SQL query template used to search the database, where \fB%s\fR
|
||||
is a substitute for the address Postfix is trying to resolve,
|
||||
e.g.
|
||||
.ti +4
|
||||
query = select forw_addr from mxaliases where
|
||||
.ti +8
|
||||
alias = '%s' and status = 'paid'
|
||||
query = SELECT replacement FROM aliases WHERE mailbox = '%s'
|
||||
|
||||
This parameter supports the following '%' expansions:
|
||||
.RS
|
||||
.IP "\fB\fB%%\fR\fR"
|
||||
This is replaced by a literal '%' character. (Postfix 2.2 and later)
|
||||
.IP "\fB\fB%s\fR\fR"
|
||||
This is replaced by the input key. Quoting is used to make sure
|
||||
that the input key does not add unexpected metacharacters.
|
||||
This is replaced by the input key.
|
||||
SQL quoting is used to make sure that the input key does not
|
||||
add unexpected metacharacters.
|
||||
.IP "\fB\fB%u\fR\fR"
|
||||
When the input key is an address of the form user@domain,
|
||||
\fB%u\fR is replaced by the quoted local part of the address.
|
||||
If no domain is specified, \fB%u\fR is replaced by the entire
|
||||
search string.
|
||||
When the input key is an address of the form user@domain, \fB%u\fR
|
||||
is replaced by the SQL quoted local part of the address.
|
||||
Otherwise, \fB%u\fR is replaced by the entire search string.
|
||||
If the localpart is empty, the query is suppressed and returns
|
||||
no results.
|
||||
.IP "\fB\fB%d\fR\fR"
|
||||
When the input key is an address of the form user@domain,
|
||||
\fB%d\fR is replaced by the quoted domain part of the address.
|
||||
When the input key has no domain qualifier, \fB%d\fR is replaced
|
||||
by the entire search string.
|
||||
When the input key is an address of the form user@domain, \fB%d\fR
|
||||
is replaced by the SQL quoted domain part of the address.
|
||||
Otherwise, the query is suppressed and returns no results.
|
||||
.IP "\fB\fB%[SUD]\fR\fR"
|
||||
The upper-case equivalents of the above expansions behave in the
|
||||
\fBquery\fR parameter identically to their lower-case counter-parts.
|
||||
With the \fBresult_format\fR parameter (see below), they expand the
|
||||
input key rather than the result value.
|
||||
.IP
|
||||
The above %S, %U and %D expansions are available with Postfix 2.2
|
||||
and later
|
||||
.IP "\fB\fB%[1-9]\fR\fR"
|
||||
The patterns %1, %2, ... %9 are replaced by the corresponding
|
||||
most significant component of the input key's domain. If the
|
||||
input key is \fIuser@mail.example.com\fR, then %1 is \fBcom\fR,
|
||||
%2 is \fBexample\fR and %3 is \fBmail\fR. If the input key is
|
||||
unqualified or does not have enough domain components to satisfy
|
||||
all the specified patterns, the query is suppressed and returns
|
||||
no results.
|
||||
.IP
|
||||
The above %1, ... %9 expansions are available with Postfix 2.2
|
||||
and later
|
||||
.RE
|
||||
.IP
|
||||
The \fBdomain\fR parameter described below limits the input
|
||||
keys to addresses in matching domains. When the \fBdomain\fR
|
||||
parameter is non-empty, SQL queries for unqualified addresses
|
||||
or addresses in non-matching domains are suppressed
|
||||
and return no results.
|
||||
|
||||
The precedence of this parameter has changed with Postfix 2.2,
|
||||
in prior releases the precedence was, from highest to lowest,
|
||||
\fBselect_function\fR, \fBquery\fR, \fBselect_field\fR, ...
|
||||
|
||||
With Postfix 2.2 the \fBquery\fR parameter has highest precedence,
|
||||
see COMPATIBILITY above.
|
||||
|
||||
NOTE: DO NOT put quotes around the \fBquery\fR parameter.
|
||||
.IP "\fBresult_format (default: \fB%s\fR)\fR"
|
||||
Format template applied to result attributes. Most commonly used
|
||||
to append (or prepend) text to the result. This parameter supports
|
||||
the following '%' expansions:
|
||||
.RS
|
||||
.IP "\fB\fB%%\fR\fR"
|
||||
This is replaced by a literal '%' character.
|
||||
.IP "\fB\fB%s\fR\fR"
|
||||
This is replaced by the value of the result attribute. When
|
||||
result is empty it is skipped.
|
||||
.IP "\fB%u\fR
|
||||
When the result attribute value is an address of the form
|
||||
user@domain, \fB%u\fR is replaced by the local part of the
|
||||
address. When the result has an empty localpart it is skipped.
|
||||
.IP "\fB\fB%d\fR\fR"
|
||||
When a result attribute value is an address of the form
|
||||
user@domain, \fB%d\fR is replaced by the domain part of
|
||||
the attribute value. When the result is unqualified it
|
||||
is skipped.
|
||||
.IP "\fB\fB%[SUD1-9]\fR\fB"
|
||||
The upper-case and decimal digit expansions interpolate
|
||||
the parts of the input key rather than the result. Their
|
||||
behaviour is identical to that described with \fBquery\fR,
|
||||
and in fact because the input key is known in advance, queries
|
||||
whose key does not contain all the information specified in
|
||||
the result template are suppressed and return no results.
|
||||
.RE
|
||||
.IP
|
||||
For example, using "result_format = smtp:[%s]" allows one
|
||||
to use a mailHost attribute as the basis of a transport(5)
|
||||
table. After applying the result format, multiple values
|
||||
are concatenated as comma separated strings. The expansion_limit
|
||||
and parameter explained below allows one to restrict the number
|
||||
of values in the result, which is especially useful for maps that
|
||||
must return at most one value.
|
||||
|
||||
The default value \fB%s\fR specifies that each result value should
|
||||
be used as is.
|
||||
|
||||
This parameter is available with Postfix 2.2 and later.
|
||||
|
||||
NOTE: DO NOT put quotes around the result format!
|
||||
.IP "\fBdomain (default: no domain list)\fR"
|
||||
This is a list of domain names, paths to files, or
|
||||
dictionaries. When specified, only fully qualified search
|
||||
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 PostgreSQL server.
|
||||
.ti +4
|
||||
domain = postfix.org, hash:/etc/postfix/searchdomains
|
||||
|
||||
It is best not to use SQL to store the domains eligible
|
||||
for SQL lookups.
|
||||
|
||||
This parameter is available with Postfix 2.2 and later.
|
||||
|
||||
NOTE: DO NOT define this parameter for local(8) aliases,
|
||||
because the input keys are always unqualified.
|
||||
.IP "\fBexpansion_limit (default: 0)\fR"
|
||||
A limit on the total number of result elements returned
|
||||
(as a comma separated list) by a lookup against the map.
|
||||
A setting of zero disables the limit. Lookups fail with a
|
||||
temporary error if the limit is exceeded. Setting the
|
||||
limit to 1 ensures that lookups do not return multiple
|
||||
values.
|
||||
.PP
|
||||
Pre-Postfix 2.2 legacy interfaces:
|
||||
.IP "\fBselect_function\fR"
|
||||
This parameter specifies a database function name. Example:
|
||||
.ti +4
|
||||
@@ -164,16 +268,54 @@ select_function = my_lookup_user_alias
|
||||
|
||||
This is equivalent to:
|
||||
.ti +4
|
||||
query = select my_lookup_user_alias('%s')
|
||||
query = SELECT my_lookup_user_alias('%s')
|
||||
|
||||
and overrides both the \fBquery\fR parameter and the table-related
|
||||
fields above.
|
||||
This parameter overrides the legacy table-related fields (described
|
||||
below). With Postfix versions prior to 2.2, it also overrides the
|
||||
\fBquery\fR parameter. Starting with Postfix 2.2, the \fBquery\fR
|
||||
parameter has highest precedence, and this parameter is deprecated.
|
||||
Please migrate to the new \fBquery\fR interface as this interface
|
||||
is slated to be phased out.
|
||||
.PP
|
||||
The following parameters (with lower precedence than the
|
||||
\fBselect_function\fR interface described above) can be used to
|
||||
build the SQL select statement as follows:
|
||||
|
||||
As of June 2002, if the function returns a single row and
|
||||
a single column AND that value is NULL, then the result
|
||||
will be treated as if the key was not in the dictionary.
|
||||
.ti +4
|
||||
SELECT [\fBselect_field\fR]
|
||||
.ti +4
|
||||
FROM [\fBtable\fR]
|
||||
.ti +4
|
||||
WHERE [\fBwhere_field\fR] = '%s'
|
||||
.ti +10
|
||||
[\fBadditional_conditions\fR]
|
||||
|
||||
Future versions will allow functions to return result sets.
|
||||
The specifier %s is replaced with each lookup by the lookup key
|
||||
and is escaped so if it contains single quotes or other odd
|
||||
characters, it will not cause a parse error, or worse, a security
|
||||
problem.
|
||||
|
||||
Starting with Postfix 2.2, this interface is obsoleted by the more
|
||||
general \fBquery\fR interface described above. If higher precedence
|
||||
the \fBquery\fR or \fBselect_function\fR parameters described above
|
||||
are defined, these parameters are ignored. Please migrate to the new
|
||||
\fBquery\fR interface as this interface is slated to be phased out.
|
||||
.IP "\fBselect_field\fR"
|
||||
The SQL "select" parameter. Example:
|
||||
.ti +4
|
||||
\fBselect_field\fR = forw_addr
|
||||
.IP "\fBtable\fR"
|
||||
The SQL "select .. from" table name. Example:
|
||||
.ti +4
|
||||
\fBtable\fR = mxaliases
|
||||
.IP "\fBwhere_field\fR
|
||||
The SQL "select .. where" parameter. Example:
|
||||
.ti +4
|
||||
\fBwhere_field\fR = alias
|
||||
.IP "\fBadditional_conditions\fR
|
||||
Additional conditions to the SQL query. Example:
|
||||
.ti +4
|
||||
\fBadditional_conditions\fR = AND status = 'paid'
|
||||
.SH "SEE ALSO"
|
||||
.na
|
||||
.nf
|
||||
|
@@ -306,6 +306,20 @@ difficult to enforce consistently and globally.
|
||||
Enable the rewriting of the form "user%domain" to "user@domain".
|
||||
This is enabled by default.
|
||||
.PP
|
||||
Note: With Postfix version 2.2, message header address rewriting
|
||||
happens only when one of the following conditions is true:
|
||||
.IP \(bu
|
||||
The message is received with the Postfix \fBsendmail\fR(1) command,
|
||||
.IP \(bu
|
||||
The message is received from a network client that matches
|
||||
$local_header_rewrite_clients,
|
||||
.IP \(bu
|
||||
The message is received from the network, and the
|
||||
remote_header_rewrite_domain parameter specifies a non-empty value.
|
||||
.PP
|
||||
To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all".
|
||||
.PP
|
||||
Example:
|
||||
.PP
|
||||
.nf
|
||||
@@ -371,17 +385,45 @@ With locally submitted mail, append the string "@$myorigin" to mail
|
||||
addresses without domain information. With remotely submitted mail,
|
||||
append the string "@$remote_header_rewrite_domain" instead.
|
||||
.PP
|
||||
This feature is enabled by default and must not be turned off.
|
||||
Note 1: This feature is enabled by default and must not be turned off.
|
||||
Postfix does not support domain-less addresses.
|
||||
.PP
|
||||
Note 2: With Postfix version 2.2, message header address rewriting
|
||||
happens only when one of the following conditions is true:
|
||||
.IP \(bu
|
||||
The message is received with the Postfix \fBsendmail\fR(1) command,
|
||||
.IP \(bu
|
||||
The message is received from a network client that matches
|
||||
$local_header_rewrite_clients,
|
||||
.IP \(bu
|
||||
The message is received from the network, and the
|
||||
remote_header_rewrite_domain parameter specifies a non-empty value.
|
||||
.PP
|
||||
To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all".
|
||||
.SH append_dot_mydomain (default: yes)
|
||||
With locally submitted mail, append the string ".$mydomain" to
|
||||
addresses that have no ".domain" information. With remotely submitted
|
||||
mail, append the string ".$remote_header_rewrite_domain"
|
||||
instead.
|
||||
.PP
|
||||
This feature is enabled by default. If disabled, users will not be
|
||||
Note 1: This feature is enabled by default. If disabled, users will not be
|
||||
able to send mail to "user@partialdomainname" but will have to
|
||||
specify full domain names instead.
|
||||
.PP
|
||||
Note 2: With Postfix version 2.2, message header address rewriting
|
||||
happens only when one of the following conditions is true:
|
||||
.IP \(bu
|
||||
The message is received with the Postfix \fBsendmail\fR(1) command,
|
||||
.IP \(bu
|
||||
The message is received from a network client that matches
|
||||
$local_header_rewrite_clients,
|
||||
.IP \(bu
|
||||
The message is received from the network, and the
|
||||
remote_header_rewrite_domain parameter specifies a non-empty value.
|
||||
.PP
|
||||
To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all".
|
||||
.SH application_event_drain_time (default: 100s)
|
||||
How long the \fBpostkick\fR(1) command waits for a request to enter the
|
||||
server's input buffer before giving up.
|
||||
@@ -590,6 +632,20 @@ build the necessary DBM or DB file after every change. The changes
|
||||
will become visible after a minute or so. Use "\fBpostfix reload\fR"
|
||||
to eliminate the delay.
|
||||
.PP
|
||||
Note: with Postfix version 2.2, message header address mapping
|
||||
happens only when message header address rewriting is enabled:
|
||||
.IP \(bu
|
||||
The message is received with the Postfix \fBsendmail\fR(1) command,
|
||||
.IP \(bu
|
||||
The message is received from a network client that matches
|
||||
$local_header_rewrite_clients,
|
||||
.IP \(bu
|
||||
The message is received from the network, and the
|
||||
remote_header_rewrite_domain parameter specifies a non-empty value.
|
||||
.PP
|
||||
To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all".
|
||||
.PP
|
||||
Examples:
|
||||
.PP
|
||||
.nf
|
||||
@@ -1382,7 +1438,8 @@ inet_interfaces = 192.168.1.2, 127.0.0.1
|
||||
The Internet protocols Postfix will attempt to use when making
|
||||
or accepting connections. Specify one or more of "ipv4"
|
||||
or "ipv6", separated by whitespace or commas. The form
|
||||
"all" is equivalent to "ipv4, ipv6".
|
||||
"all" is equivalent to "ipv4, ipv6" or "ipv4", depending
|
||||
on whether the operating system implements IPv6.
|
||||
.PP
|
||||
This feature is available in Postfix version 2.2 and later.
|
||||
.PP
|
||||
@@ -2077,6 +2134,20 @@ or its subdomains. Thus,
|
||||
does not change "user@any.thing.foo.example.com" or "user@foo.example.com",
|
||||
but strips "user@any.thing.else.example.com" to "user@example.com".
|
||||
.PP
|
||||
Note: with Postfix version 2.2, message header address masquerading
|
||||
happens only when message header address rewriting is enabled:
|
||||
.IP \(bu
|
||||
The message is received with the Postfix \fBsendmail\fR(1) command,
|
||||
.IP \(bu
|
||||
The message is received from a network client that matches
|
||||
$local_header_rewrite_clients,
|
||||
.IP \(bu
|
||||
The message is received from the network, and the
|
||||
remote_header_rewrite_domain parameter specifies a non-empty value.
|
||||
.PP
|
||||
To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all".
|
||||
.PP
|
||||
Example:
|
||||
.PP
|
||||
.nf
|
||||
@@ -5205,6 +5276,20 @@ Enable the rewriting of "site!user" into "user@site". This is
|
||||
necessary if your machine is connected to UUCP networks. It is
|
||||
enabled by default.
|
||||
.PP
|
||||
Note: With Postfix version 2.2, message header address rewriting
|
||||
happens only when one of the following conditions is true:
|
||||
.IP \(bu
|
||||
The message is received with the Postfix \fBsendmail\fR(1) command,
|
||||
.IP \(bu
|
||||
The message is received from a network client that matches
|
||||
$local_header_rewrite_clients,
|
||||
.IP \(bu
|
||||
The message is received from the network, and the
|
||||
remote_header_rewrite_domain parameter specifies a non-empty value.
|
||||
.PP
|
||||
To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all".
|
||||
.PP
|
||||
Example:
|
||||
.PP
|
||||
.nf
|
||||
|
@@ -317,15 +317,18 @@ turn-off control </th> </tr>
|
||||
<tr> <td> <a href="#standard"> Rewrite addresses to standard form</a>
|
||||
</td> <td nowrap> all mail </td> <td> trivial-<br>rewrite(8) </td>
|
||||
<td> append_at_myorigin, append_dot_mydomain, swap_bangpath,
|
||||
allow_percent_hack </td> <td> none </td> </tr>
|
||||
allow_percent_hack </td> <td> local_header_rewrite_clients,
|
||||
remote_header_rewrite_domain </td> </tr>
|
||||
|
||||
<tr> <td> <a href="#canonical"> Canonical address mapping </a>
|
||||
</td> <td nowrap> all mail </td> <td> cleanup(8) </td> <td>
|
||||
canonical_maps </td> <td> receive_override_options </td> </tr>
|
||||
<tr> <td> <a href="#canonical"> Canonical address mapping </a> </td>
|
||||
<td nowrap> all mail </td> <td> cleanup(8) </td> <td> canonical_maps
|
||||
</td> <td> receive_override_options, local_header_rewrite_clients,
|
||||
remote_header_rewrite_domain </td> </tr>
|
||||
|
||||
<tr> <td> <a href="#canonical"> Address masquerading </a> </td>
|
||||
<td nowrap> all mail </td> <td> cleanup(8) </td> <td> masquerade_domains
|
||||
</td> <td> receive_override_options </td> </tr>
|
||||
<tr> <td> <a href="#masquerade"> Address masquerading </a> </td> <td
|
||||
nowrap> all mail </td> <td> cleanup(8) </td> <td> masquerade_domains
|
||||
</td> <td> receive_override_options, local_header_rewrite_clients,
|
||||
remote_header_rewrite_domain </td> </tr>
|
||||
|
||||
<tr> <td> <a href="#auto_bcc"> Automatic BCC recipients </a> </td>
|
||||
<td nowrap> new mail </td> <td> cleanup(8) </td> <td> always_bcc,
|
||||
@@ -411,11 +414,12 @@ trivial-rewrite(8) daemon. The purpose of rewriting to standard
|
||||
form is to reduce the number of entries needed in lookup tables.
|
||||
</p>
|
||||
|
||||
<p> Postfix versions 2.2 and later do not rewrite message headers
|
||||
from remote SMTP clients at all, unless a non-empty domain name is
|
||||
specified with the remote_header_rewrite_domain configuration
|
||||
parameter. The local_header_rewrite_clients parameter controls
|
||||
what SMTP clients Postfix considers local. </p>
|
||||
<p> NOTE: Postfix versions 2.2 and later rewrite message headers
|
||||
from remote SMTP clients only if the client matches the
|
||||
local_header_rewrite_clients parameter, or if the
|
||||
remote_header_rewrite_domain configuration parameter specifies a
|
||||
non-empty value. To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all". </p>
|
||||
|
||||
<p> The Postfix trivial-rewrite(8) daemon implements the following
|
||||
hard-coded address manipulations: </p>
|
||||
@@ -455,10 +459,13 @@ parameter (default: yes). You should never turn off this feature,
|
||||
because a lot of Postfix components expect that all addresses have
|
||||
the form "user@domain". </p>
|
||||
|
||||
<p> Postfix versions 2.2 and later either do not rewrite message
|
||||
headers from remote SMTP clients at all, or they append the domain
|
||||
name specified with the remote_header_rewrite_domain configuration
|
||||
parameter. </p>
|
||||
<p> NOTE: Postfix versions 2.2 and later rewrite message headers
|
||||
from remote SMTP clients only if the client matches the
|
||||
local_header_rewrite_clients parameter; otherwise they append the
|
||||
domain name specified with the remote_header_rewrite_domain
|
||||
configuration parameter, if one is specified. To get the behavior
|
||||
before Postfix 2.2, specify "local_header_rewrite_clients =
|
||||
static:all". </p>
|
||||
|
||||
<p> If your machine is not the main machine for $myorigin and you
|
||||
wish to have some users delivered locally without going via that
|
||||
@@ -476,10 +483,13 @@ Rewrite "user@host" to "user@host.$mydomain" </dt>
|
||||
parameter (default: yes). The purpose is to get consistent treatment
|
||||
of different forms of the same hostname. </p>
|
||||
|
||||
<p> Postfix versions 2.2 and later either do not rewrite message
|
||||
headers from remote clients at all, or they append the domain name
|
||||
specified with the remote_header_rewrite_domain configuration
|
||||
parameter. </p>
|
||||
<p> NOTE: Postfix versions 2.2 and later rewrite message headers
|
||||
from remote SMTP clients only if the client matches the
|
||||
local_header_rewrite_clients parameter; otherwise they append the
|
||||
domain name specified with the remote_header_rewrite_domain
|
||||
configuration parameter, if one is specified. To get the behavior
|
||||
before Postfix 2.2, specify "local_header_rewrite_clients =
|
||||
static:all". </p>
|
||||
|
||||
<p> Some will argue that rewriting "host" to "host.domain"
|
||||
is bad. That is why it can be turned off. Others like the convenience
|
||||
@@ -502,11 +512,12 @@ addresses in message envelopes and in message headers. By default
|
||||
all header and envelope addresses are rewritten; this is controlled
|
||||
with the canonical_classes configuration parameter. </p>
|
||||
|
||||
<p> Postfix versions 2.2 and later do not rewrite message headers
|
||||
from remote clients at all, unless a non-empty domain name is
|
||||
specified with the remote_header_rewrite_domain configuration
|
||||
parameter. The local_header_rewrite_clients parameter controls
|
||||
what SMTP clients Postfix considers local. </p>
|
||||
<p> NOTE: Postfix versions 2.2 and later rewrite message headers
|
||||
from remote SMTP clients only if the client matches the
|
||||
local_header_rewrite_clients parameter, or if the
|
||||
remote_header_rewrite_domain configuration parameter specifies a
|
||||
non-empty value. To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all". </p>
|
||||
|
||||
<p> Address rewriting is
|
||||
done for local and remote addresses. The mapping is useful to
|
||||
@@ -585,11 +596,12 @@ behind their mail gateway, and to make it appear as if the mail
|
||||
comes from the gateway itself, instead of from individual machines.
|
||||
</p>
|
||||
|
||||
<p> Postfix versions 2.2 and later do not rewrite message headers
|
||||
from remote SMTP clients at all, unless a non-empty domain name is
|
||||
specified with the remote_header_rewrite_domain configuration
|
||||
parameter. The local_header_rewrite_clients parameter controls
|
||||
what SMTP clients Postfix considers local. </p>
|
||||
<p> NOTE: Postfix versions 2.2 and later rewrite message headers
|
||||
from remote SMTP clients only if the client matches the
|
||||
local_header_rewrite_clients parameter, or if the
|
||||
remote_header_rewrite_domain configuration parameter specifies a
|
||||
non-empty value. To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all". </p>
|
||||
|
||||
<p> Address masquerading is disabled by default, and is implemented
|
||||
by the cleanup(8) server. To enable, edit the masquerade_domains
|
||||
|
@@ -257,7 +257,7 @@ maildrop: this, that, theother
|
||||
make sure the lookup makes sense. In the case of virtual lookups,
|
||||
maildrops other than mail addresses are pretty useless, because
|
||||
Postfix can't know how to set the ownership for program or file
|
||||
delivery. Your query_filter should probably look something like this: </p>
|
||||
delivery. Your <b>query_filter</b> should probably look something like this: </p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
@@ -276,7 +276,7 @@ query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")(maildrop="*
|
||||
require some thought on your part to implement safely, considering the
|
||||
ramifications of this type of delivery. You may decide it's not worth
|
||||
the bother to allow any of that nonsense in LDAP lookups, ban it in
|
||||
the query_filter, and keep things like majordomo lists in local alias
|
||||
the <b>query_filter</b>, and keep things like majordomo lists in local alias
|
||||
databases. </p>
|
||||
|
||||
<blockquote>
|
||||
@@ -334,13 +334,20 @@ contents, please include the applicable bits of some directory entries. </p>
|
||||
|
||||
<li>Victor Duchovni: ldap_bind() timeout. With fixes from LaMont Jones:
|
||||
OpenLDAP cache deprecation. Limits on recursion, expansion
|
||||
and query results size. LDAP connection sharing for maps
|
||||
and search results size. LDAP connection sharing for maps
|
||||
differing only in the query parameters.
|
||||
|
||||
<li>Liviu Daia: Support for SSL/STARTTLS. Support for storing map definitions in
|
||||
external files (ldap:/path/ldap.cf) needed to securely store
|
||||
passwords for plain auth.
|
||||
|
||||
<li>Liviu Daia revised the configuration interface and added the main.cf
|
||||
configuration feature.</li>
|
||||
|
||||
<li>Liviu Daia with further refinements from Jose Luis Tallon and
|
||||
Victor Duchovni developed the common query, result_format, domain and
|
||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
And of course Wietse.
|
||||
|
@@ -89,22 +89,16 @@ password = some_password
|
||||
# The database name on the servers.
|
||||
dbname = customer_database
|
||||
|
||||
# The table name.
|
||||
table = mxaliases
|
||||
# For Postfix 2.2 and later The SQL query template.
|
||||
# See mysql_table(5) for details.
|
||||
query = SELECT forw_addr FROM mxaliases WHERE alias='%s' AND status='paid'
|
||||
|
||||
# Query components, see below.
|
||||
# For Postfix releases prior to 2.2. See mysql_table(5) for details.
|
||||
select_field = forw_addr
|
||||
table = mxaliases
|
||||
where_field = alias
|
||||
|
||||
# You may specify additional_conditions or leave this empty.
|
||||
additional_conditions = and status = 'paid'
|
||||
|
||||
# The above variables will result in a query of the form:
|
||||
#
|
||||
# select forw_addr from mxaliases where alias = '$lookup' and status = 'paid'
|
||||
#
|
||||
# ($lookup is escaped so if it contains single quotes or other odd
|
||||
# characters, it will not cause trouble).
|
||||
# Don't forget the leading "AND"!
|
||||
additional_conditions = AND status = 'paid'
|
||||
</pre>
|
||||
|
||||
<h2>Additional notes</h2>
|
||||
@@ -129,10 +123,14 @@ will be deferred until at least one of those hosts is reachable.
|
||||
<ul>
|
||||
|
||||
<li> The initial version was contributed by Scott Cotton and Joshua
|
||||
Marcus, IC Group, Inc.
|
||||
Marcus, IC Group, Inc.</li>
|
||||
|
||||
<li>Liviu Daia revised the configuration interface and added the
|
||||
main.cf configuration feature.
|
||||
<li> Liviu Daia revised the configuration interface and added the
|
||||
main.cf configuration feature.</li>
|
||||
|
||||
<li> Liviu Daia with further refinements from Jose Luis Tallon and
|
||||
Victor Duchovni developed the common query, result_format, domain and
|
||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
@@ -88,25 +88,15 @@ password = some_password
|
||||
# The database name on the servers.
|
||||
dbname = customer_database
|
||||
|
||||
# The table name.
|
||||
table = mxaliases
|
||||
# Postfix 2.2 and later The SQL query template. See pgsql_table(5).
|
||||
query = SELECT forw_addr FROM mxaliases WHERE alias='%s' AND status='paid'
|
||||
|
||||
# Query components, see below.
|
||||
# For Postfix releases prior to 2.2. See pgsql_table(5) for details.
|
||||
select_field = forw_addr
|
||||
table = mxaliases
|
||||
where_field = alias
|
||||
|
||||
# You may specify additional_conditions or leave this empty.
|
||||
additional_conditions = and status = 'paid'
|
||||
|
||||
# The above variables will result in a query of the form:
|
||||
#
|
||||
# select forw_addr from mxaliases where alias = '$lookup' and status = 'paid'
|
||||
#
|
||||
# ($lookup is escaped so if it contains single quotes or other odd
|
||||
# characters, it will not cause problems).
|
||||
#
|
||||
# You may also override the built-in SELECT template. See pgsql_table(5)
|
||||
# for details.
|
||||
# Don't forget the leading "AND"!
|
||||
additional_conditions = AND status = 'paid'
|
||||
</pre>
|
||||
|
||||
<h2>Using mirrored databases</h2>
|
||||
@@ -130,17 +120,24 @@ those hosts is reachable. </p>
|
||||
<ul>
|
||||
|
||||
<li> This code is based upon the Postfix mysql map by Scott Cotton
|
||||
and Joshua Marcus, IC Group, Inc.
|
||||
and Joshua Marcus, IC Group, Inc.</li>
|
||||
|
||||
<li> The PostgreSQL changes were done by Aaron Sethman.
|
||||
<li> The PostgreSQL changes were done by Aaron Sethman.</li>
|
||||
|
||||
<li> Updates for Postfix 1.1.x and PostgreSQL 7.1+ and support for
|
||||
calling stored procedures were added by Philip Warner.
|
||||
calling stored procedures were added by Philip Warner.</li>
|
||||
|
||||
<li> LaMont Jones was the initial Postfix pgsql maintainer.
|
||||
<li> LaMont Jones was the initial Postfix pgsql maintainer.</li>
|
||||
|
||||
<li> Liviu Daia revised the configuration interface and added the
|
||||
main.cf configuration feature.
|
||||
main.cf configuration feature.</li>
|
||||
|
||||
<li> Liviu Daia revised the configuration interface and added the main.cf
|
||||
configuration feature.</li>
|
||||
|
||||
<li> Liviu Daia with further refinements from Jose Luis Tallon and
|
||||
Victor Duchovni developed the common query, result_format, domain and
|
||||
expansion_limit interface for LDAP, MySQL and PosgreSQL.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
@@ -45,6 +45,18 @@
|
||||
# Note: with this form, the passwords for the LDAP sources are
|
||||
# written in main.cf, which is normally world-readable. Support
|
||||
# for this form will be removed in a future Postfix version.
|
||||
#
|
||||
# Postfix 2.2 has enhanced query interfaces for MySQL and PostgreSQL,
|
||||
# these now include features previously available only in the
|
||||
# Postfix LDAP client. This work also created an opportunity for
|
||||
# improvements in the LDAP interface. The primary compatibility
|
||||
# issue is that \fBresult_filter\fR (a name that has caused some
|
||||
# confusion as to its meaning in the past) has been renamed to
|
||||
# \fBresult_format\fR. For backwards compatibility with the pre
|
||||
# 2.2 LDAP client, \fBresult_filter\fR can for now be used instead
|
||||
# of \fBresult_format\fR, when the latter parameter is not also set.
|
||||
# The new name better reflects the function of the parameter. This
|
||||
# compatibility interface may be removed in a future release.
|
||||
# LIST MEMBERSHIP
|
||||
# .ad
|
||||
# .fi
|
||||
@@ -116,14 +128,50 @@
|
||||
# The port the LDAP server listens on, e.g.
|
||||
# .ti +4
|
||||
# server_port = 778
|
||||
# .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 "\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
|
||||
# With Postfix 2.2 and later this parameter supports the
|
||||
# following '%' expansions:
|
||||
# .RS
|
||||
# .IP "\fB\fB%%\fR\fR"
|
||||
# This is replaced by a literal '%' character.
|
||||
# .IP "\fB\fB%s\fR\fR"
|
||||
# This is replaced by the input key.
|
||||
# RFC 2253 quoting is used to make sure that the input key
|
||||
# does not add unexpected metacharacters.
|
||||
# .IP "\fB\fB%u\fR\fR"
|
||||
# When the input key is an address of the form user@domain, \fB%u\fR
|
||||
# is replaced by the (RFC 2253) quoted local part of the address.
|
||||
# Otherwise, \fB%u\fR is replaced by the entire search string.
|
||||
# If the localpart is empty, the search is suppressed and returns
|
||||
# no results.
|
||||
# .IP "\fB\fB%d\fR\fR"
|
||||
# When the input key is an address of the form user@domain, \fB%d\fR
|
||||
# is replaced by the (RFC 2253) quoted domain part of the address.
|
||||
# Otherwise, the search is suppressed and returns no results.
|
||||
# .IP "\fB\fB%[SUD]\fR\fR"
|
||||
# For the \fBsearch_base\fR parameter, the upper-case equivalents
|
||||
# of the above expansions behave identically to their lower-case
|
||||
# counter-parts. With the \fBresult_format\fR parameter (previously
|
||||
# called \fBresult_filter\fR see the COMPATIBILITY section and below),
|
||||
# they expand to the corresponding components of input key rather
|
||||
# than the result value.
|
||||
# .IP "\fB\fB%[1-9]\fR\fR"
|
||||
# The patterns %1, %2, ... %9 are replaced by the corresponding
|
||||
# most significant component of the input key's domain. If the
|
||||
# input key is \fIuser@mail.example.com\fR, then %1 is \fBcom\fR,
|
||||
# %2 is \fBexample\fR and %3 is \fBmail\fR. If the input key is
|
||||
# unqualified or does not have enough domain components to satisfy
|
||||
# all the specified patterns, the search is suppressed and returns
|
||||
# no results.
|
||||
# .RE
|
||||
# .IP "\fBquery_filter (default: mailacceptinggeneralid=%s)\fR"
|
||||
# The RFC2254 filter used to search the directory, where \fB%s\fR
|
||||
# is a substitute for the address Postfix is trying to resolve,
|
||||
@@ -133,20 +181,43 @@
|
||||
#
|
||||
# This parameter supports the following '%' expansions:
|
||||
# .RS
|
||||
# .IP "\fB\fB%%\fR\fR"
|
||||
# This is replaced by a literal '%' character. (Postfix 2.2 and later).
|
||||
# .IP "\fB\fB%s\fR\fR"
|
||||
# This is replaced by the input key. RFC 2254 quoting is used
|
||||
# to make sure that the input key does not add unexpected
|
||||
# metacharacters.
|
||||
# This is replaced by the input key.
|
||||
# RFC 2254 quoting is used to make sure that the input key
|
||||
# does not add unexpected metacharacters.
|
||||
# .IP "\fB\fB%u\fR\fR"
|
||||
# When the input key is an address of the form user@domain,
|
||||
# \fB%u\fR is replaced by the (RFC 2254) quoted local part of the
|
||||
# address. Otherwise, \fB%u\fR is replaced by the entire
|
||||
# search string.
|
||||
# When the input key is an address of the form user@domain, \fB%u\fR
|
||||
# is replaced by the (RFC 2254) quoted local part of the address.
|
||||
# Otherwise, \fB%u\fR is replaced by the entire search string.
|
||||
# If the localpart is empty, the search is suppressed and returns
|
||||
# no results.
|
||||
# .IP "\fB\fB%d\fR\fR"
|
||||
# When the input key is an address of the form user@domain,
|
||||
# \fB%d\fR is replaced by the (RFC 2254) quoted domain part of the
|
||||
# address. Otherwise, \fB%d\fR is replaced by the entire
|
||||
# search string.
|
||||
# When the input key is an address of the form user@domain, \fB%d\fR
|
||||
# is replaced by the (RFC 2254) quoted domain part of the address.
|
||||
# Otherwise, the search is suppressed and returns no results.
|
||||
# .IP "\fB\fB%[SUD]\fR\fR"
|
||||
# The upper-case equivalents of the above expansions behave in the
|
||||
# \fBquery_filter\fR parameter identically to their lower-case
|
||||
# counter-parts. With the \fBresult_format\fR parameter (previously
|
||||
# called \fBresult_filter\fR see the COMPATIBILITY section and below),
|
||||
# they expand to the corresponding components of input key rather
|
||||
# than the result value.
|
||||
# .IP
|
||||
# The above %S, %U and %D expansions are available with Postfix 2.2
|
||||
# and later.
|
||||
# .IP "\fB\fB%[1-9]\fR\fR"
|
||||
# The patterns %1, %2, ... %9 are replaced by the corresponding
|
||||
# most significant component of the input key's domain. If the
|
||||
# input key is \fIuser@mail.example.com\fR, then %1 is \fBcom\fR,
|
||||
# %2 is \fBexample\fR and %3 is \fBmail\fR. If the input key is
|
||||
# unqualified or does not have enough domain components to satisfy
|
||||
# all the specified patterns, the saerch is suppressed and returns
|
||||
# no results.
|
||||
# .IP
|
||||
# The above %1, ..., %9 expansions are available with Postfix 2.2
|
||||
# and later.
|
||||
# .RE
|
||||
# .IP
|
||||
# The "domain" parameter described below limits the input
|
||||
@@ -155,30 +226,42 @@
|
||||
# addresses or addresses in non-matching domains are suppressed
|
||||
# and return no results.
|
||||
#
|
||||
# NOTE: DO NOT put quotes around the query filter.
|
||||
# .IP "\fBresult_filter (default: \fB%s\fR)\fR"
|
||||
# Format template applied to result attributes. Supports the
|
||||
# same expansions as the query_filter, and can be easily used
|
||||
# to append (or prepend) text. This parameter supports the
|
||||
# following '%' expansions:
|
||||
# NOTE: DO NOT put quotes around the \fBquery_filter\fR parameter.
|
||||
# .IP "\fBresult_format (default: \fB%s\fR)\fR"
|
||||
# Called \fBresult_filter\fR in Postfix releases prior to 2.2.
|
||||
# Format template applied to result attributes. Most commonly used
|
||||
# to append (or prepend) text to the result. This parameter supports
|
||||
# the following '%' expansions:
|
||||
# .RS
|
||||
# .IP "\fB\fB%%\fR\fR"
|
||||
# This is replaced by a literal '%' character. (Postfix 2.2 and later).
|
||||
# .IP "\fB\fB%s\fR\fR"
|
||||
# This is replaced by the value of the result attribute.
|
||||
# This is replaced by the value of the result attribute. When
|
||||
# result is empty it is skipped.
|
||||
# .IP "\fB%u\fR
|
||||
# When the result attribute value is an address of the form
|
||||
# user@domain, \fB%u\fR is replaced by the local part of the
|
||||
# address. Otherwise, \fB%u\fR is replaced by the entire
|
||||
# attribute value.
|
||||
# address. When the result has an empty localpart it is skipped.
|
||||
# .IP "\fB\fB%d\fR\fR"
|
||||
# When a result attribute value is an address of the form
|
||||
# user@domain, \fB%d\fR is replaced by the domain part of
|
||||
# the attribute value. Otherwise, \fB%d\fR is replaced by
|
||||
# the entire attribute value.
|
||||
# the attribute value. When the result is unqualified it
|
||||
# is skipped.
|
||||
# .IP "\fB\fB%[SUD1-9]\fR\fB"
|
||||
# The upper-case and decimal digit expansions interpolate
|
||||
# the parts of the input key rather than the result. Their
|
||||
# behaviour is identical to that described with \fBquery_filter\fR,
|
||||
# and in fact because the input key is known in advance, lookups
|
||||
# whose key does not contain all the information specified in
|
||||
# the result template are suppressed and return no results.
|
||||
# .IP
|
||||
# The above %S, %U, %D and %1, ..., %9 expansions are available with
|
||||
# Postfix 2.2 and later.
|
||||
# .RE
|
||||
# .IP
|
||||
# For example, using "result_filter = smtp:[%s]" allows one
|
||||
# For example, using "result_format = smtp:[%s]" allows one
|
||||
# to use a mailHost attribute as the basis of a transport(5)
|
||||
# table. After applying the result filter, multiple values
|
||||
# table. After applying the result format, multiple values
|
||||
# are concatenated as comma separated strings. The expansion_limit
|
||||
# and size_limit parameters explained below allow one to
|
||||
# restrict the number of values in the result, which is
|
||||
@@ -188,7 +271,13 @@
|
||||
# The default value \fB%s\fR specifies that each
|
||||
# attribute value should be used as is.
|
||||
#
|
||||
# NOTE: DO NOT put quotes around the result filter!
|
||||
# This parameter was called \fBresult_filter\fR in Postfix
|
||||
# releases prior to 2.2. If no "result_format" is specified,
|
||||
# the value of "result_filter" will be used instead before
|
||||
# resorting to the default value. This provides compatibility
|
||||
# with old configuration files.
|
||||
#
|
||||
# NOTE: DO NOT put quotes around the result format!
|
||||
# .IP "\fBdomain (default: no domain list)\fR"
|
||||
# This is a list of domain names, paths to files, or
|
||||
# dictionaries. When specified, only fully qualified search
|
||||
@@ -208,7 +297,7 @@
|
||||
# entries returned by the lookup, to be resolved to an email
|
||||
# address.
|
||||
# .ti +4
|
||||
# result_attribute = mailbox,maildrop
|
||||
# result_attribute = mailbox, maildrop
|
||||
# .IP "\fBspecial_result_attribute (No default)\fR"
|
||||
# The attribute(s) of directory entries that can contain DNs
|
||||
# or URLs. If found, a recursive subsequent search is done
|
||||
@@ -275,14 +364,14 @@
|
||||
# values.
|
||||
# .IP "\fBsize_limit (default: $expansion_limit)\fR"
|
||||
# A limit on the number of LDAP entries returned by any single
|
||||
# LDAP query performed as part of the lookup. A setting of
|
||||
# LDAP search performed as part of the lookup. A setting of
|
||||
# 0 disables the limit. Expansion of DN and URL references
|
||||
# involves nested LDAP queries, each of which is separately
|
||||
# subjected to this limit.
|
||||
#
|
||||
# Note: even a single LDAP entry can generate multiple lookup
|
||||
# results, via multiple result attributes and/or multi-valued
|
||||
# result attributes. This limit caps the per query resource
|
||||
# result attributes. This limit caps the per search resource
|
||||
# utilization on the LDAP server, not the final multiplicity
|
||||
# of the lookup result. It is analogous to the "-z" option
|
||||
# of "ldapsearch".
|
||||
|
@@ -21,7 +21,7 @@
|
||||
# The file /etc/postfix/mysql-aliases.cf has the same format as
|
||||
# the Postfix main.cf file, and can specify the parameters
|
||||
# described below.
|
||||
# ALTERNATIVE CONFIGURATION
|
||||
# BACKWARDS COMPATIBILITY
|
||||
# .ad
|
||||
# .fi
|
||||
# For compatibility with other Postfix lookup tables, MySQL
|
||||
@@ -36,6 +36,30 @@
|
||||
# Note: with this form, the passwords for the MySQL sources are
|
||||
# written in main.cf, which is normally world-readable. Support
|
||||
# for this form will be removed in a future Postfix version.
|
||||
#
|
||||
# Postfix 2.2 has enhanced query interfaces for MySQL and PostreSQL,
|
||||
# these include features previously available only in the Postfix
|
||||
# LDAP client. In the new interface the SQL query is specified via
|
||||
# a single \fBquery\fR parameter (described in more detail below).
|
||||
# When the new \fBquery\fR parameter is not specified in the map
|
||||
# definition, Postfix reverts to the old interface, with the SQL
|
||||
# query constructed from the \fBselect_field\fR, \fBtable\fR,
|
||||
# \fBwhere_field\fR and \fBadditional_conditions\fR parameters.
|
||||
# The old interface will be gradually phased out. To migrate to
|
||||
# the new interface set:
|
||||
#
|
||||
# .ti +4
|
||||
# \fBquery\fR = SELECT [\fIselect_field\fR]
|
||||
# .ti +8
|
||||
# FROM [\fItable\fR]
|
||||
# .ti +8
|
||||
# WHERE [\fIwhere_field\fR] = '%s'
|
||||
# .ti +12
|
||||
# [\fIadditional_conditions\fR]
|
||||
#
|
||||
# Insert the value, not the name, of each legacy parameter. Note
|
||||
# that the \fBadditional_conditions\fR parameter is optional
|
||||
# and if not empty, will always start with \fBAND\fR.
|
||||
# LIST MEMBERSHIP
|
||||
# .ad
|
||||
# .fi
|
||||
@@ -90,33 +114,176 @@
|
||||
# The database name on the servers. Example:
|
||||
# .ti +4
|
||||
# dbname = customer_database
|
||||
# .PP
|
||||
# The following parameters are used to fill in a SELECT
|
||||
# query template of the form:
|
||||
# .IP "\fBquery\fR"
|
||||
# The SQL query template used to search the database, where \fB%s\fR
|
||||
# is a substitute for the address Postfix is trying to resolve,
|
||||
# e.g.
|
||||
# .ti +4
|
||||
# select [\fBselect_field\fR] from [\fBtable\fR] where
|
||||
# .ti +8
|
||||
# [\fBwhere_field\fR] = '$lookup' [\fBadditional_conditions\fR]
|
||||
# query = SELECT replacement FROM aliases WHERE mailbox = '%s'
|
||||
#
|
||||
# $lookup contains the search string, and is escaped so if
|
||||
# it contains single quotes or other odd characters, it will
|
||||
# not cause a parse error, or worse, a security problem.
|
||||
# This parameter supports the following '%' expansions:
|
||||
# .RS
|
||||
# .IP "\fB\fB%%\fR\fR"
|
||||
# This is replaced by a literal '%' character.
|
||||
# .IP "\fB\fB%s\fR\fR"
|
||||
# This is replaced by the input key.
|
||||
# SQL quoting is used to make sure that the input key does not
|
||||
# add unexpected metacharacters.
|
||||
# .IP "\fB\fB%u\fR\fR"
|
||||
# When the input key is an address of the form user@domain, \fB%u\fR
|
||||
# is replaced by the SQL quoted local part of the address.
|
||||
# Otherwise, \fB%u\fR is replaced by the entire search string.
|
||||
# If the localpart is empty, the query is suppressed and returns
|
||||
# no results.
|
||||
# .IP "\fB\fB%d\fR\fR"
|
||||
# When the input key is an address of the form user@domain, \fB%d\fR
|
||||
# is replaced by the SQL quoted domain part of the address.
|
||||
# Otherwise, the query is suppressed and returns no results.
|
||||
# .IP "\fB\fB%[SUD]\fR\fR"
|
||||
# The upper-case equivalents of the above expansions behave in the
|
||||
# \fBquery\fR parameter identically to their lower-case counter-parts.
|
||||
# With the \fBresult_format\fR parameter (see below), they expand the
|
||||
# input key rather than the result value.
|
||||
# .IP "\fB\fB%[1-9]\fR\fR"
|
||||
# The patterns %1, %2, ... %9 are replaced by the corresponding
|
||||
# most significant component of the input key's domain. If the
|
||||
# input key is \fIuser@mail.example.com\fR, then %1 is \fBcom\fR,
|
||||
# %2 is \fBexample\fR and %3 is \fBmail\fR. If the input key is
|
||||
# unqualified or does not have enough domain components to satisfy
|
||||
# all the specified patterns, the query is suppressed and returns
|
||||
# no results.
|
||||
# .RE
|
||||
# .IP
|
||||
# The \fBdomain\fR parameter described below limits the input
|
||||
# keys to addresses in matching domains. When the \fBdomain\fR
|
||||
# parameter is non-empty, SQL queries for unqualified addresses
|
||||
# or addresses in non-matching domains are suppressed
|
||||
# and return no results.
|
||||
#
|
||||
# This parameter is available with Postfix 2.2. In prior releases
|
||||
# the SQL query was built from the separate parameters:
|
||||
# \fBselect_field\fR, \fBtable\fR, \fBwhere_field\fR and
|
||||
# \fBadditional_conditions\fR. The mapping from the old parameters
|
||||
# to the equivalent query is:
|
||||
#
|
||||
# .ti +4
|
||||
# SELECT [\fBselect_field\fR]
|
||||
# .ti +4
|
||||
# FROM [\fBtable\fR]
|
||||
# .ti +4
|
||||
# WHERE [\fBwhere_field\fR] = '%s'
|
||||
# .ti +10
|
||||
# [\fBadditional_conditions\fR]
|
||||
#
|
||||
# The '%s' in the \fBWHERE\fR clause expands to the escaped search string.
|
||||
# With Postfix 2.2 these legacy parameters are used if the \fBquery\fR
|
||||
# parameter is not specified.
|
||||
#
|
||||
# NOTE: DO NOT put quotes around the query parameter.
|
||||
# .IP "\fBresult_format (default: \fB%s\fR)\fR"
|
||||
# Format template applied to result attributes. Most commonly used
|
||||
# to append (or prepend) text to the result. This parameter supports
|
||||
# the following '%' expansions:
|
||||
# .RS
|
||||
# .IP "\fB\fB%%\fR\fR"
|
||||
# This is replaced by a literal '%' character.
|
||||
# .IP "\fB\fB%s\fR\fR"
|
||||
# This is replaced by the value of the result attribute. When
|
||||
# result is empty it is skipped.
|
||||
# .IP "\fB%u\fR
|
||||
# When the result attribute value is an address of the form
|
||||
# user@domain, \fB%u\fR is replaced by the local part of the
|
||||
# address. When the result has an empty localpart it is skipped.
|
||||
# .IP "\fB\fB%d\fR\fR"
|
||||
# When a result attribute value is an address of the form
|
||||
# user@domain, \fB%d\fR is replaced by the domain part of
|
||||
# the attribute value. When the result is unqualified it
|
||||
# is skipped.
|
||||
# .IP "\fB\fB%[SUD1-9]\fR\fB"
|
||||
# The upper-case and decimal digit expansions interpolate
|
||||
# the parts of the input key rather than the result. Their
|
||||
# behaviour is identical to that described with \fBquery\fR,
|
||||
# and in fact because the input key is known in advance, queries
|
||||
# whose key does not contain all the information specified in
|
||||
# the result template are suppressed and return no results.
|
||||
# .RE
|
||||
# .IP
|
||||
# For example, using "result_format = smtp:[%s]" allows one
|
||||
# to use a mailHost attribute as the basis of a transport(5)
|
||||
# table. After applying the result format, multiple values
|
||||
# are concatenated as comma separated strings. The expansion_limit
|
||||
# and parameter explained below allows one to restrict the number
|
||||
# of values in the result, which is especially useful for maps that
|
||||
# must return at most one value.
|
||||
#
|
||||
# The default value \fB%s\fR specifies that each result value should
|
||||
# be used as is.
|
||||
#
|
||||
# This parameter is available with Postfix 2.2 and later.
|
||||
#
|
||||
# NOTE: DO NOT put quotes around the result format!
|
||||
# .IP "\fBdomain (default: no domain list)\fR"
|
||||
# This is a list of domain names, paths to files, or
|
||||
# dictionaries. When specified, only fully qualified search
|
||||
# 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 MySQL server.
|
||||
# .ti +4
|
||||
# domain = postfix.org, hash:/etc/postfix/searchdomains
|
||||
#
|
||||
# It is best not to use SQL to store the domains eligible
|
||||
# for SQL lookups.
|
||||
#
|
||||
# This parameter is available with Postfix 2.2 and later.
|
||||
#
|
||||
# NOTE: DO NOT define this parameter for local(8) aliases,
|
||||
# because the input keys are always unqualified.
|
||||
# .IP "\fBexpansion_limit (default: 0)\fR"
|
||||
# A limit on the total number of result elements returned
|
||||
# (as a comma separated list) by a lookup against the map.
|
||||
# A setting of zero disables the limit. Lookups fail with a
|
||||
# temporary error if the limit is exceeded. Setting the
|
||||
# limit to 1 ensures that lookups do not return multiple
|
||||
# values.
|
||||
# .PP
|
||||
# The following parameters can be used to fill in a
|
||||
# SELECT template statement of the form:
|
||||
#
|
||||
# .ti +4
|
||||
# SELECT [\fBselect_field\fR]
|
||||
# .ti +4
|
||||
# FROM [\fBtable\fR]
|
||||
# .ti +4
|
||||
# WHERE [\fBwhere_field\fR] = '%s'
|
||||
# .ti +10
|
||||
# [\fBadditional_conditions\fR]
|
||||
#
|
||||
# The specifier %s is replaced by the search string, and is
|
||||
# escaped so if it contains single quotes or other odd characters,
|
||||
# it will not cause a parse error, or worse, a security problem.
|
||||
#
|
||||
# As of Postfix 2.2 this interface is obsolete, it is replaced
|
||||
# by the more general \fBquery\fR interface described above.
|
||||
# If the \fBquery\fR parameter is defined, the legacy parameters
|
||||
# are ignored. Please migrate to the new interface as the legacy
|
||||
# interface may be removed in a future release.
|
||||
# .IP "\fBselect_field\fR"
|
||||
# The SQL "select" parameter. Example:
|
||||
# .ti +4
|
||||
# select_field = forw_addr
|
||||
# \fBselect_field\fR = forw_addr
|
||||
# .IP "\fBtable\fR"
|
||||
# The SQL "select .. from" table name. Example:
|
||||
# .ti +4
|
||||
# table = mxaliases
|
||||
# \fBtable\fR = mxaliases
|
||||
# .IP "\fBwhere_field\fR
|
||||
# The SQL "select .. where" parameter. Example:
|
||||
# .ti +4
|
||||
# where_field = alias
|
||||
# \fBwhere_field\fR = alias
|
||||
# .IP "\fBadditional_conditions\fR
|
||||
# Additional conditions to the SQL query. Example:
|
||||
# .ti +4
|
||||
# additional_conditions = and status = 'paid'
|
||||
# \fBadditional_conditions\fR = AND status = 'paid'
|
||||
# SEE ALSO
|
||||
# postmap(1), Postfix lookup table maintenance
|
||||
# postconf(5), configuration parameters
|
||||
|
@@ -21,7 +21,7 @@
|
||||
# The file /etc/postfix/pgsql-aliases.cf has the same format as
|
||||
# the Postfix main.cf file, and can specify the parameters
|
||||
# described below.
|
||||
# ALTERNATIVE CONFIGURATION
|
||||
# BACKWARDS COMPATIBILITY
|
||||
# .ad
|
||||
# .fi
|
||||
# For compatibility with other Postfix lookup tables, PostgreSQL
|
||||
@@ -38,6 +38,37 @@
|
||||
# are written in main.cf, which is normally world-readable.
|
||||
# Support for this form will be removed in a future Postfix
|
||||
# version.
|
||||
#
|
||||
# Postfix 2.2 has enhanced query interfaces for MySQL and PostgreSQL,
|
||||
# these include features previously available only in the Postfix
|
||||
# LDAP client. In the new interface the SQL query is specified via
|
||||
# a single \fBquery\fR parameter (described in more detail below).
|
||||
# In Postfix 2.1 the parameter precedence was, from highest to lowest,
|
||||
# \fBselect_function\fR, \fBquery\fR and finally \fBselect_field\fR, ...
|
||||
#
|
||||
# With Postfix 2.2 the \fBquery\fR parameter has highest precedence,
|
||||
# and is used in preference to the still supported, but slated to be
|
||||
# phased out, \fBselect_function\fR, \fBselect_field\fR, \fBtable\fR,
|
||||
# \fBwhere_field\fR and \fBadditional_conditions\fR parameters. To
|
||||
# migrate to the new interface set:
|
||||
#
|
||||
# .ti +4
|
||||
# \fBquery\fR = SELECT \fIselect_function\fR('%s')
|
||||
#
|
||||
# or in the absense of \fBselection_function\fR, the lower precedence:
|
||||
#
|
||||
# .ti +4
|
||||
# \fBquery\fR = SELECT \fIselect_field\fR
|
||||
# .ti +8
|
||||
# FROM \fItable\fR
|
||||
# .ti +8
|
||||
# WHERE \fIwhere_field\fR = '%s'
|
||||
# .ti +12
|
||||
# \fIadditional_conditions\fR
|
||||
#
|
||||
# Use the value, not the name, of each legacy parameter. Note
|
||||
# that the \fBadditional_conditions\fR parameter is optional
|
||||
# and if not empty, will always start with \fBAND\fR.
|
||||
# LIST MEMBERSHIP
|
||||
# .ad
|
||||
# .fi
|
||||
@@ -90,61 +121,134 @@
|
||||
# The database name on the servers. Example:
|
||||
# .ti +4
|
||||
# dbname = customer_database
|
||||
# .PP
|
||||
# The following parameters can be used to fill in a SELECT
|
||||
# template statement of the form:
|
||||
# .ti +4
|
||||
# select [\fBselect_field\fR] from [\fBtable\fR] where
|
||||
# .ti +8
|
||||
# [\fBwhere_field\fR] = '$lookup' [\fBadditional_conditions\fR]
|
||||
#
|
||||
# $lookup contains the search string, and is escaped so if
|
||||
# it contains single quotes or other odd characters, it will
|
||||
# not cause a parse error, or worse, a security problem.
|
||||
# .IP "\fBselect_field\fR"
|
||||
# The SQL "select" parameter. Example:
|
||||
# .ti +4
|
||||
# select_field = forw_addr
|
||||
# .IP "\fBtable\fR"
|
||||
# The SQL "select .. from" table name. Example:
|
||||
# .ti +4
|
||||
# table = mxaliases
|
||||
# .IP "\fBwhere_field\fR
|
||||
# The SQL "select .. where" parameter. Example:
|
||||
# .ti +4
|
||||
# where_field = alias
|
||||
# .IP "\fBadditional_conditions\fR
|
||||
# Additional conditions to the SQL query. Example:
|
||||
# .ti +4
|
||||
# additional_conditions = and status = 'paid'
|
||||
# .PP
|
||||
# The following parameters provide ways to override the default
|
||||
# SELECT statement. Setting them will instruct Postfix to ignore
|
||||
# the above \fBtable\fR, \fBselect_field\fR, \fBwhere_field\fR and
|
||||
# \fBadditional_conditions\fR parameters:
|
||||
# .IP "\fBquery\fR"
|
||||
# This parameter specifies a complete SQL query. Example:
|
||||
# The SQL query template used to search the database, where \fB%s\fR
|
||||
# is a substitute for the address Postfix is trying to resolve,
|
||||
# e.g.
|
||||
# .ti +4
|
||||
# query = select forw_addr from mxaliases where
|
||||
# .ti +8
|
||||
# alias = '%s' and status = 'paid'
|
||||
# query = SELECT replacement FROM aliases WHERE mailbox = '%s'
|
||||
#
|
||||
# This parameter supports the following '%' expansions:
|
||||
# .RS
|
||||
# .IP "\fB\fB%%\fR\fR"
|
||||
# This is replaced by a literal '%' character. (Postfix 2.2 and later)
|
||||
# .IP "\fB\fB%s\fR\fR"
|
||||
# This is replaced by the input key. Quoting is used to make sure
|
||||
# that the input key does not add unexpected metacharacters.
|
||||
# This is replaced by the input key.
|
||||
# SQL quoting is used to make sure that the input key does not
|
||||
# add unexpected metacharacters.
|
||||
# .IP "\fB\fB%u\fR\fR"
|
||||
# When the input key is an address of the form user@domain,
|
||||
# \fB%u\fR is replaced by the quoted local part of the address.
|
||||
# If no domain is specified, \fB%u\fR is replaced by the entire
|
||||
# search string.
|
||||
# When the input key is an address of the form user@domain, \fB%u\fR
|
||||
# is replaced by the SQL quoted local part of the address.
|
||||
# Otherwise, \fB%u\fR is replaced by the entire search string.
|
||||
# If the localpart is empty, the query is suppressed and returns
|
||||
# no results.
|
||||
# .IP "\fB\fB%d\fR\fR"
|
||||
# When the input key is an address of the form user@domain,
|
||||
# \fB%d\fR is replaced by the quoted domain part of the address.
|
||||
# When the input key has no domain qualifier, \fB%d\fR is replaced
|
||||
# by the entire search string.
|
||||
# When the input key is an address of the form user@domain, \fB%d\fR
|
||||
# is replaced by the SQL quoted domain part of the address.
|
||||
# Otherwise, the query is suppressed and returns no results.
|
||||
# .IP "\fB\fB%[SUD]\fR\fR"
|
||||
# The upper-case equivalents of the above expansions behave in the
|
||||
# \fBquery\fR parameter identically to their lower-case counter-parts.
|
||||
# With the \fBresult_format\fR parameter (see below), they expand the
|
||||
# input key rather than the result value.
|
||||
# .IP
|
||||
# The above %S, %U and %D expansions are available with Postfix 2.2
|
||||
# and later
|
||||
# .IP "\fB\fB%[1-9]\fR\fR"
|
||||
# The patterns %1, %2, ... %9 are replaced by the corresponding
|
||||
# most significant component of the input key's domain. If the
|
||||
# input key is \fIuser@mail.example.com\fR, then %1 is \fBcom\fR,
|
||||
# %2 is \fBexample\fR and %3 is \fBmail\fR. If the input key is
|
||||
# unqualified or does not have enough domain components to satisfy
|
||||
# all the specified patterns, the query is suppressed and returns
|
||||
# no results.
|
||||
# .IP
|
||||
# The above %1, ... %9 expansions are available with Postfix 2.2
|
||||
# and later
|
||||
# .RE
|
||||
# .IP
|
||||
# The \fBdomain\fR parameter described below limits the input
|
||||
# keys to addresses in matching domains. When the \fBdomain\fR
|
||||
# parameter is non-empty, SQL queries for unqualified addresses
|
||||
# or addresses in non-matching domains are suppressed
|
||||
# and return no results.
|
||||
#
|
||||
# The precedence of this parameter has changed with Postfix 2.2,
|
||||
# in prior releases the precedence was, from highest to lowest,
|
||||
# \fBselect_function\fR, \fBquery\fR, \fBselect_field\fR, ...
|
||||
#
|
||||
# With Postfix 2.2 the \fBquery\fR parameter has highest precedence,
|
||||
# see COMPATIBILITY above.
|
||||
#
|
||||
# NOTE: DO NOT put quotes around the \fBquery\fR parameter.
|
||||
# .IP "\fBresult_format (default: \fB%s\fR)\fR"
|
||||
# Format template applied to result attributes. Most commonly used
|
||||
# to append (or prepend) text to the result. This parameter supports
|
||||
# the following '%' expansions:
|
||||
# .RS
|
||||
# .IP "\fB\fB%%\fR\fR"
|
||||
# This is replaced by a literal '%' character.
|
||||
# .IP "\fB\fB%s\fR\fR"
|
||||
# This is replaced by the value of the result attribute. When
|
||||
# result is empty it is skipped.
|
||||
# .IP "\fB%u\fR
|
||||
# When the result attribute value is an address of the form
|
||||
# user@domain, \fB%u\fR is replaced by the local part of the
|
||||
# address. When the result has an empty localpart it is skipped.
|
||||
# .IP "\fB\fB%d\fR\fR"
|
||||
# When a result attribute value is an address of the form
|
||||
# user@domain, \fB%d\fR is replaced by the domain part of
|
||||
# the attribute value. When the result is unqualified it
|
||||
# is skipped.
|
||||
# .IP "\fB\fB%[SUD1-9]\fR\fB"
|
||||
# The upper-case and decimal digit expansions interpolate
|
||||
# the parts of the input key rather than the result. Their
|
||||
# behaviour is identical to that described with \fBquery\fR,
|
||||
# and in fact because the input key is known in advance, queries
|
||||
# whose key does not contain all the information specified in
|
||||
# the result template are suppressed and return no results.
|
||||
# .RE
|
||||
# .IP
|
||||
# For example, using "result_format = smtp:[%s]" allows one
|
||||
# to use a mailHost attribute as the basis of a transport(5)
|
||||
# table. After applying the result format, multiple values
|
||||
# are concatenated as comma separated strings. The expansion_limit
|
||||
# and parameter explained below allows one to restrict the number
|
||||
# of values in the result, which is especially useful for maps that
|
||||
# must return at most one value.
|
||||
#
|
||||
# The default value \fB%s\fR specifies that each result value should
|
||||
# be used as is.
|
||||
#
|
||||
# This parameter is available with Postfix 2.2 and later.
|
||||
#
|
||||
# NOTE: DO NOT put quotes around the result format!
|
||||
# .IP "\fBdomain (default: no domain list)\fR"
|
||||
# This is a list of domain names, paths to files, or
|
||||
# dictionaries. When specified, only fully qualified search
|
||||
# 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 PostgreSQL server.
|
||||
# .ti +4
|
||||
# domain = postfix.org, hash:/etc/postfix/searchdomains
|
||||
#
|
||||
# It is best not to use SQL to store the domains eligible
|
||||
# for SQL lookups.
|
||||
#
|
||||
# This parameter is available with Postfix 2.2 and later.
|
||||
#
|
||||
# NOTE: DO NOT define this parameter for local(8) aliases,
|
||||
# because the input keys are always unqualified.
|
||||
# .IP "\fBexpansion_limit (default: 0)\fR"
|
||||
# A limit on the total number of result elements returned
|
||||
# (as a comma separated list) by a lookup against the map.
|
||||
# A setting of zero disables the limit. Lookups fail with a
|
||||
# temporary error if the limit is exceeded. Setting the
|
||||
# limit to 1 ensures that lookups do not return multiple
|
||||
# values.
|
||||
# .PP
|
||||
# Pre-Postfix 2.2 legacy interfaces:
|
||||
# .IP "\fBselect_function\fR"
|
||||
# This parameter specifies a database function name. Example:
|
||||
# .ti +4
|
||||
@@ -152,16 +256,54 @@
|
||||
#
|
||||
# This is equivalent to:
|
||||
# .ti +4
|
||||
# query = select my_lookup_user_alias('%s')
|
||||
# query = SELECT my_lookup_user_alias('%s')
|
||||
#
|
||||
# and overrides both the \fBquery\fR parameter and the table-related
|
||||
# fields above.
|
||||
# This parameter overrides the legacy table-related fields (described
|
||||
# below). With Postfix versions prior to 2.2, it also overrides the
|
||||
# \fBquery\fR parameter. Starting with Postfix 2.2, the \fBquery\fR
|
||||
# parameter has highest precedence, and this parameter is deprecated.
|
||||
# Please migrate to the new \fBquery\fR interface as this interface
|
||||
# is slated to be phased out.
|
||||
# .PP
|
||||
# The following parameters (with lower precedence than the
|
||||
# \fBselect_function\fR interface described above) can be used to
|
||||
# build the SQL select statement as follows:
|
||||
#
|
||||
# As of June 2002, if the function returns a single row and
|
||||
# a single column AND that value is NULL, then the result
|
||||
# will be treated as if the key was not in the dictionary.
|
||||
# .ti +4
|
||||
# SELECT [\fBselect_field\fR]
|
||||
# .ti +4
|
||||
# FROM [\fBtable\fR]
|
||||
# .ti +4
|
||||
# WHERE [\fBwhere_field\fR] = '%s'
|
||||
# .ti +10
|
||||
# [\fBadditional_conditions\fR]
|
||||
#
|
||||
# Future versions will allow functions to return result sets.
|
||||
# The specifier %s is replaced with each lookup by the lookup key
|
||||
# and is escaped so if it contains single quotes or other odd
|
||||
# characters, it will not cause a parse error, or worse, a security
|
||||
# problem.
|
||||
#
|
||||
# Starting with Postfix 2.2, this interface is obsoleted by the more
|
||||
# general \fBquery\fR interface described above. If higher precedence
|
||||
# the \fBquery\fR or \fBselect_function\fR parameters described above
|
||||
# are defined, these parameters are ignored. Please migrate to the new
|
||||
# \fBquery\fR interface as this interface is slated to be phased out.
|
||||
# .IP "\fBselect_field\fR"
|
||||
# The SQL "select" parameter. Example:
|
||||
# .ti +4
|
||||
# \fBselect_field\fR = forw_addr
|
||||
# .IP "\fBtable\fR"
|
||||
# The SQL "select .. from" table name. Example:
|
||||
# .ti +4
|
||||
# \fBtable\fR = mxaliases
|
||||
# .IP "\fBwhere_field\fR
|
||||
# The SQL "select .. where" parameter. Example:
|
||||
# .ti +4
|
||||
# \fBwhere_field\fR = alias
|
||||
# .IP "\fBadditional_conditions\fR
|
||||
# Additional conditions to the SQL query. Example:
|
||||
# .ti +4
|
||||
# \fBadditional_conditions\fR = AND status = 'paid'
|
||||
# SEE ALSO
|
||||
# postmap(1), Postfix lookup table manager
|
||||
# postconf(5), configuration parameters
|
||||
|
@@ -511,6 +511,24 @@ Enable the rewriting of the form "user%domain" to "user@domain".
|
||||
This is enabled by default.
|
||||
</p>
|
||||
|
||||
<p> Note: With Postfix version 2.2, message header address rewriting
|
||||
happens only when one of the following conditions is true: </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The message is received with the Postfix sendmail(1) command,
|
||||
|
||||
<li> The message is received from a network client that matches
|
||||
$local_header_rewrite_clients,
|
||||
|
||||
<li> The message is received from the network, and the
|
||||
remote_header_rewrite_domain parameter specifies a non-empty value.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all". </p>
|
||||
|
||||
<p>
|
||||
Example:
|
||||
</p>
|
||||
@@ -685,6 +703,24 @@ will become visible after a minute or so. Use "<b>postfix reload</b>"
|
||||
to eliminate the delay.
|
||||
</p>
|
||||
|
||||
<p> Note: with Postfix version 2.2, message header address mapping
|
||||
happens only when message header address rewriting is enabled: </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The message is received with the Postfix sendmail(1) command,
|
||||
|
||||
<li> The message is received from a network client that matches
|
||||
$local_header_rewrite_clients,
|
||||
|
||||
<li> The message is received from the network, and the
|
||||
remote_header_rewrite_domain parameter specifies a non-empty value.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all". </p>
|
||||
|
||||
<p>
|
||||
Examples:
|
||||
</p>
|
||||
@@ -1638,7 +1674,8 @@ inet_interfaces = 192.168.1.2, 127.0.0.1
|
||||
<p> The Internet protocols Postfix will attempt to use when making
|
||||
or accepting connections. Specify one or more of "ipv4"
|
||||
or "ipv6", separated by whitespace or commas. The form
|
||||
"all" is equivalent to "ipv4, ipv6". </p>
|
||||
"all" is equivalent to "ipv4, ipv6" or "ipv4", depending
|
||||
on whether the operating system implements IPv6. </p>
|
||||
|
||||
<p> This feature is available in Postfix version 2.2 and later. </p>
|
||||
|
||||
@@ -2385,6 +2422,25 @@ does not change "user@any.thing.foo.example.com" or "user@foo.example.com",
|
||||
but strips "user@any.thing.else.example.com" to "user@example.com".
|
||||
</p>
|
||||
|
||||
<p> Note: with Postfix version 2.2, message header address masquerading
|
||||
happens only when message header address rewriting is enabled: </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The message is received with the Postfix sendmail(1) command,
|
||||
|
||||
<li> The message is received from a network client that matches
|
||||
$local_header_rewrite_clients,
|
||||
|
||||
<li> The message is received from the network, and the
|
||||
remote_header_rewrite_domain parameter specifies a non-empty value.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all". </p>
|
||||
|
||||
|
||||
<p>
|
||||
Example:
|
||||
</p>
|
||||
@@ -5478,6 +5534,24 @@ necessary if your machine is connected to UUCP networks. It is
|
||||
enabled by default.
|
||||
</p>
|
||||
|
||||
<p> Note: With Postfix version 2.2, message header address rewriting
|
||||
happens only when one of the following conditions is true: </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The message is received with the Postfix sendmail(1) command,
|
||||
|
||||
<li> The message is received from a network client that matches
|
||||
$local_header_rewrite_clients,
|
||||
|
||||
<li> The message is received from the network, and the
|
||||
remote_header_rewrite_domain parameter specifies a non-empty value.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all". </p>
|
||||
|
||||
<p>
|
||||
Example:
|
||||
</p>
|
||||
@@ -5834,10 +5908,28 @@ append the string "@$remote_header_rewrite_domain" instead.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This feature is enabled by default and must not be turned off.
|
||||
Note 1: This feature is enabled by default and must not be turned off.
|
||||
Postfix does not support domain-less addresses.
|
||||
</p>
|
||||
|
||||
<p> Note 2: With Postfix version 2.2, message header address rewriting
|
||||
happens only when one of the following conditions is true: </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The message is received with the Postfix sendmail(1) command,
|
||||
|
||||
<li> The message is received from a network client that matches
|
||||
$local_header_rewrite_clients,
|
||||
|
||||
<li> The message is received from the network, and the
|
||||
remote_header_rewrite_domain parameter specifies a non-empty value.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all". </p>
|
||||
|
||||
%PARAM append_dot_mydomain yes
|
||||
|
||||
<p>
|
||||
@@ -5848,11 +5940,29 @@ instead.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This feature is enabled by default. If disabled, users will not be
|
||||
Note 1: This feature is enabled by default. If disabled, users will not be
|
||||
able to send mail to "user@partialdomainname" but will have to
|
||||
specify full domain names instead.
|
||||
</p>
|
||||
|
||||
<p> Note 2: With Postfix version 2.2, message header address rewriting
|
||||
happens only when one of the following conditions is true: </p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li> The message is received with the Postfix sendmail(1) command,
|
||||
|
||||
<li> The message is received from a network client that matches
|
||||
$local_header_rewrite_clients,
|
||||
|
||||
<li> The message is received from the network, and the
|
||||
remote_header_rewrite_domain parameter specifies a non-empty value.
|
||||
|
||||
</ul>
|
||||
|
||||
<p> To get the behavior before Postfix 2.2, specify
|
||||
"local_header_rewrite_clients = static:all". </p>
|
||||
|
||||
%PARAM application_event_drain_time 100s
|
||||
|
||||
<p>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
SHELL = /bin/sh
|
||||
SRCS = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \
|
||||
canon_addr.c cfg_parser.c cleanup_strerror.c cleanup_strflags.c \
|
||||
clnt_stream.c debug_peer.c debug_process.c defer.c \
|
||||
clnt_stream.c debug_peer.c debug_process.c defer.c db_common.c \
|
||||
deliver_completed.c deliver_flock.c deliver_pass.c deliver_request.c \
|
||||
dict_ldap.c dict_mysql.c dict_pgsql.c dict_proxy.c domain_list.c \
|
||||
dot_lockfile.c dot_lockfile_as.c ext_prop.c file_id.c flush_clnt.c \
|
||||
@@ -28,7 +28,7 @@ SRCS = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \
|
||||
wildcard_inet_addr.c valid_mailhost_addr.c
|
||||
OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
|
||||
canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
|
||||
clnt_stream.o debug_peer.o debug_process.o defer.o \
|
||||
clnt_stream.o debug_peer.o debug_process.o defer.o db_common.o \
|
||||
deliver_completed.o deliver_flock.o deliver_pass.o deliver_request.o \
|
||||
dict_ldap.o dict_mysql.o dict_pgsql.o dict_proxy.o domain_list.o \
|
||||
dot_lockfile.o dot_lockfile_as.o ext_prop.o file_id.o flush_clnt.o \
|
||||
@@ -73,7 +73,7 @@ HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
|
||||
resolve_local.h rewrite_clnt.h sent.h smtp_stream.h split_addr.h \
|
||||
string_list.h strip_addr.h sys_exits.h timed_ipc.h tok822.h \
|
||||
trace.h verify.h verify_clnt.h verp_sender.h virtual8_maps.h \
|
||||
xtext.h scache.h user_acl.h ehlo_mask.h \
|
||||
xtext.h scache.h user_acl.h ehlo_mask.h db_common.h \
|
||||
wildcard_inet_addr.h valid_mailhost_addr.h
|
||||
TESTSRC = rec2stream.c stream2rec.c recdump.c
|
||||
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
|
||||
@@ -520,6 +520,20 @@ clnt_stream.o: mail_proto.h
|
||||
clnt_stream.o: ../../include/attr.h
|
||||
clnt_stream.o: mail_params.h
|
||||
clnt_stream.o: clnt_stream.h
|
||||
db_common.o: db_common.c
|
||||
db_common.o: ../../include/sys_defs.h
|
||||
db_common.o: cfg_parser.h
|
||||
db_common.o: ../../include/mymalloc.h
|
||||
db_common.o: ../../include/vstring.h
|
||||
db_common.o: ../../include/vbuf.h
|
||||
db_common.o: ../../include/msg.h
|
||||
db_common.o: ../../include/dict.h
|
||||
db_common.o: ../../include/vstream.h
|
||||
db_common.o: ../../include/argv.h
|
||||
db_common.o: db_common.h
|
||||
db_common.o: string_list.h
|
||||
db_common.o: ../../include/match_list.h
|
||||
db_common.o: ../../include/match_ops.h
|
||||
debug_peer.o: debug_peer.c
|
||||
debug_peer.o: ../../include/sys_defs.h
|
||||
debug_peer.o: ../../include/msg.h
|
||||
@@ -603,10 +617,59 @@ deliver_request.o: recipient_list.h
|
||||
deliver_request.o: deliver_request.h
|
||||
dict_ldap.o: dict_ldap.c
|
||||
dict_ldap.o: ../../include/sys_defs.h
|
||||
dict_ldap.o: ../../include/msg.h
|
||||
dict_ldap.o: ../../include/mymalloc.h
|
||||
dict_ldap.o: ../../include/vstring.h
|
||||
dict_ldap.o: ../../include/vbuf.h
|
||||
dict_ldap.o: ../../include/dict.h
|
||||
dict_ldap.o: ../../include/vstream.h
|
||||
dict_ldap.o: ../../include/argv.h
|
||||
dict_ldap.o: ../../include/stringops.h
|
||||
dict_ldap.o: ../../include/binhash.h
|
||||
dict_ldap.o: cfg_parser.h
|
||||
dict_ldap.o: db_common.h
|
||||
dict_ldap.o: string_list.h
|
||||
dict_ldap.o: ../../include/match_list.h
|
||||
dict_ldap.o: ../../include/match_ops.h
|
||||
dict_ldap.o: dict_ldap.h
|
||||
dict_mysql.o: dict_mysql.c
|
||||
dict_mysql.o: ../../include/sys_defs.h
|
||||
dict_mysql.o: ../../include/dict.h
|
||||
dict_mysql.o: ../../include/vstream.h
|
||||
dict_mysql.o: ../../include/vbuf.h
|
||||
dict_mysql.o: ../../include/argv.h
|
||||
dict_mysql.o: ../../include/msg.h
|
||||
dict_mysql.o: ../../include/mymalloc.h
|
||||
dict_mysql.o: ../../include/vstring.h
|
||||
dict_mysql.o: ../../include/split_at.h
|
||||
dict_mysql.o: ../../include/find_inet.h
|
||||
dict_mysql.o: ../../include/myrand.h
|
||||
dict_mysql.o: ../../include/events.h
|
||||
dict_mysql.o: cfg_parser.h
|
||||
dict_mysql.o: db_common.h
|
||||
dict_mysql.o: string_list.h
|
||||
dict_mysql.o: ../../include/match_list.h
|
||||
dict_mysql.o: ../../include/match_ops.h
|
||||
dict_mysql.o: dict_mysql.h
|
||||
dict_pgsql.o: dict_pgsql.c
|
||||
dict_pgsql.o: ../../include/sys_defs.h
|
||||
dict_pgsql.o: ../../include/dict.h
|
||||
dict_pgsql.o: ../../include/vstream.h
|
||||
dict_pgsql.o: ../../include/vbuf.h
|
||||
dict_pgsql.o: ../../include/argv.h
|
||||
dict_pgsql.o: ../../include/msg.h
|
||||
dict_pgsql.o: ../../include/mymalloc.h
|
||||
dict_pgsql.o: ../../include/vstring.h
|
||||
dict_pgsql.o: ../../include/split_at.h
|
||||
dict_pgsql.o: ../../include/find_inet.h
|
||||
dict_pgsql.o: ../../include/myrand.h
|
||||
dict_pgsql.o: ../../include/events.h
|
||||
dict_pgsql.o: cfg_parser.h
|
||||
dict_pgsql.o: db_common.h
|
||||
dict_pgsql.o: string_list.h
|
||||
dict_pgsql.o: ../../include/match_list.h
|
||||
dict_pgsql.o: ../../include/match_ops.h
|
||||
dict_pgsql.o: dict_pgsql.h
|
||||
dict_proxy.o: dict_proxy.c
|
||||
dict_proxy.o: ../../include/sys_defs.h
|
||||
dict_proxy.o: ../../include/msg.h
|
||||
|
448
postfix/src/global/db_common.c
Normal file
448
postfix/src/global/db_common.c
Normal file
@@ -0,0 +1,448 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* db_common 3
|
||||
/* SUMMARY
|
||||
/* utilities common to network based dictionaries
|
||||
/* SYNOPSIS
|
||||
/* #include "db_common.h"
|
||||
/*
|
||||
/* int db_common_parse(dict, ctx, format, query)
|
||||
/* DICT *dict;
|
||||
/* void **ctx;
|
||||
/* const char *format;
|
||||
/* int query;
|
||||
/*
|
||||
/* void db_common_free_context(ctx)
|
||||
/* void *ctx;
|
||||
/*
|
||||
/* int db_common_expand(ctx, format, value, key, buf, quote_func);
|
||||
/* void *ctx;
|
||||
/* const char *format;
|
||||
/* const char *value;
|
||||
/* const char *key;
|
||||
/* VSTRING *buf;
|
||||
/* void (*quote_func)(DICT *, const char *, VSTRING *);
|
||||
/*
|
||||
/* int db_common_check_domain(domain_list, addr);
|
||||
/* STRING_LIST *domain_list;
|
||||
/* const char *addr;
|
||||
/*
|
||||
/* void db_common_sql_build_query(query,parser);
|
||||
/* VSTRING *query;
|
||||
/* CFG_PARSER *parser;
|
||||
/*
|
||||
/* DESCRIPTION
|
||||
/* This module implements utilities common to network based dictionaries.
|
||||
/*
|
||||
/* \fIdb_common_parse\fR parses query and result substitution templates.
|
||||
/* It must be called for each template before any calls to
|
||||
/* \fIdb_common_expand\fR. The \fIctx\fB argument must be initialized to
|
||||
/* a reference to a (void *)0 before the first template is parsed, this
|
||||
/* causes memory for the context to be allocated and the new pointer is
|
||||
/* stored in *ctx. When the dictionary is closed, this memory must be
|
||||
/* freed with a final call to \fBdb_common_free_context\fR.
|
||||
/*
|
||||
/* Calls for additional templates associated with the same map must use the
|
||||
/* same ctx argument. The context accumulates run-time lookup key and result
|
||||
/* validation information (inapplicable keys or results are skipped) and is
|
||||
/* needed later in each call of \fIdb_common_expand\fR. A non-zero return
|
||||
/* value indicates that data-depedent '%' expansions were found in the input
|
||||
/* template.
|
||||
/*
|
||||
/* \fIdb_common_expand\fR expands the specifiers in \fIformat\fR.
|
||||
/* When the input data lacks all fields needed for the expansion, zero
|
||||
/* is returned and the query or result should be skipped. Otherwise
|
||||
/* the expansion is appended to the result buffer (after a comma if the
|
||||
/* the result buffer is not empty).
|
||||
/*
|
||||
/* If not NULL, the \fBquote_func\fR callback performs database-specific
|
||||
/* quoting of each variable before expansion.
|
||||
/* \fBvalue\fR is the lookup key for query expansion and result for result
|
||||
/* expansion. \fBkey\fR is NULL for query expansion and the lookup key for
|
||||
/* result expansion.
|
||||
/* .PP
|
||||
/* The following '%' expansions are performed on \fBvalue\fR:
|
||||
/* .IP %%
|
||||
/* A literal percent character.
|
||||
/* .IP %s
|
||||
/* The entire lookup key \fIaddr\fR.
|
||||
/* .IP %u
|
||||
/* If \fBaddr\fR is a fully qualified address, the local part of the
|
||||
/* address. Otherwise \fIaddr\fR.
|
||||
/* .IP %d
|
||||
/* If \fIaddr\fR is a fully qualified address, the domain part of the
|
||||
/* address. Otherwise the query against the database is suppressed and
|
||||
/* the lookup returns no results.
|
||||
/*
|
||||
/* The following '%' expansions are performed on the lookup \fBkey\fR:
|
||||
/* .IP %S
|
||||
/* The entire lookup key \fIkey\fR.
|
||||
/* .IP %U
|
||||
/* If \fBkey\fR is a fully qualified address, the local part of the
|
||||
/* address. Otherwise \fIkey\fR.
|
||||
/* .IP %D
|
||||
/* If \fIkey\fR is a fully qualified address, the domain part of the
|
||||
/* address. Otherwise the query against the database is suppressed and
|
||||
/* the lookup returns no results.
|
||||
/*
|
||||
/* .PP
|
||||
/* \fIdb_common_check_domain\fR checks domain list so that query optimization
|
||||
/* can be performed
|
||||
/*
|
||||
/* .PP
|
||||
/* \fIdb_common_sql_build_query\fR builds the "default"(backwards compatible)
|
||||
/* query from the 'table', 'select_field', 'where_field' and
|
||||
/* 'additional_conditions' parameters, checking for errors.
|
||||
/*
|
||||
/* DIAGNOSTICS
|
||||
/* Fatal errors: invalid substitution format, invalid string_list pattern,
|
||||
/* insufficient parameters.
|
||||
/* SEE ALSO
|
||||
/* dict(3) dictionary manager
|
||||
/* string_list(3) string list pattern matching
|
||||
/* match_ops(3) simple string or host pattern matching
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Liviu Daia
|
||||
/* Institute of Mathematics of the Romanian Academy
|
||||
/* P.O. BOX 1-764
|
||||
/* RO-014700 Bucharest, ROMANIA
|
||||
/*
|
||||
/* Jose Luis Tallon
|
||||
/* G4 J.E. - F.I. - U.P.M.
|
||||
/* Campus de Montegancedo, S/N
|
||||
/* E-28660 Madrid, SPAIN
|
||||
/*
|
||||
/* Victor Duchovni
|
||||
/* Morgan Stanley
|
||||
/*--*/
|
||||
|
||||
/*
|
||||
* System library.
|
||||
*/
|
||||
#include "sys_defs.h"
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Global library.
|
||||
*/
|
||||
#include "cfg_parser.h"
|
||||
|
||||
/*
|
||||
* Utility library.
|
||||
*/
|
||||
#include <mymalloc.h>
|
||||
#include <vstring.h>
|
||||
#include <msg.h>
|
||||
#include <dict.h>
|
||||
|
||||
/*
|
||||
* Application specific
|
||||
*/
|
||||
#include "db_common.h"
|
||||
|
||||
#define DB_COMMON_KEY_DOMAIN (1 << 0) /* Need lookup key domain */
|
||||
#define DB_COMMON_KEY_USER (1 << 1) /* Need lookup key localpart */
|
||||
#define DB_COMMON_VALUE_DOMAIN (1 << 2) /* Need result domain */
|
||||
#define DB_COMMON_VALUE_USER (1 << 3) /* Need result localpart */
|
||||
|
||||
typedef struct {
|
||||
DICT *dict;
|
||||
int flags;
|
||||
int nparts;
|
||||
} DB_COMMON_CTX;
|
||||
|
||||
/* db_common_parse - validate query or result template */
|
||||
|
||||
int db_common_parse(DICT *dict, void **ctxPtr, const char *format, int query)
|
||||
{
|
||||
DB_COMMON_CTX *ctx = (DB_COMMON_CTX *)*ctxPtr;
|
||||
const char *cp;
|
||||
int dynamic = 0;
|
||||
|
||||
if (ctx == 0) {
|
||||
ctx = (DB_COMMON_CTX *)(*ctxPtr = mymalloc(sizeof *ctx));
|
||||
ctx->dict = dict;
|
||||
ctx->flags = 0;
|
||||
ctx->nparts = 0;
|
||||
}
|
||||
|
||||
for (cp = format; *cp; ++cp)
|
||||
if (*cp == '%')
|
||||
switch (*++cp) {
|
||||
case '%':
|
||||
break;
|
||||
case 'u':
|
||||
ctx->flags |=
|
||||
query ? DB_COMMON_KEY_USER : DB_COMMON_VALUE_USER;
|
||||
dynamic = 1;
|
||||
break;
|
||||
case 'd':
|
||||
ctx->flags |=
|
||||
query ? DB_COMMON_KEY_DOMAIN : DB_COMMON_VALUE_DOMAIN;
|
||||
dynamic = 1;
|
||||
break;
|
||||
case 's': case 'S':
|
||||
dynamic = 1;
|
||||
break;
|
||||
case 'U':
|
||||
ctx->flags |= DB_COMMON_KEY_USER;
|
||||
dynamic = 1;
|
||||
break;
|
||||
case '1': case '2': case '3': case '4': case '5':
|
||||
case '6': case '7': case '8': case '9':
|
||||
if (ctx->nparts < *cp - '0')
|
||||
ctx->nparts = *cp - '0';
|
||||
/* FALLTHROUGH */
|
||||
case 'D':
|
||||
ctx->flags |= DB_COMMON_KEY_DOMAIN;
|
||||
dynamic = 1;
|
||||
break;
|
||||
default:
|
||||
msg_fatal("db_common_parse: %s: Invalid %s template: %s",
|
||||
dict->name, query ? "query" : "result", format);
|
||||
}
|
||||
return dynamic;
|
||||
}
|
||||
|
||||
/* db_common_free_ctx - free parse context */
|
||||
|
||||
void db_common_free_ctx(void *ctxPtr)
|
||||
{
|
||||
myfree((char *)ctxPtr);
|
||||
}
|
||||
|
||||
/* db_common_expand - expand query and result templates */
|
||||
|
||||
int db_common_expand(void *ctxArg, const char *format, const char *value,
|
||||
const char *key, VSTRING *result,
|
||||
db_quote_callback_t quote_func)
|
||||
{
|
||||
char *myname = "db_common_expand";
|
||||
DB_COMMON_CTX *ctx = (DB_COMMON_CTX *)ctxArg;
|
||||
const char *vdomain = 0;
|
||||
const char *kdomain = 0;
|
||||
char *vuser = 0;
|
||||
char *kuser = 0;
|
||||
ARGV *parts = 0;
|
||||
int i;
|
||||
const char *cp;
|
||||
|
||||
/* Skip NULL or empty values */
|
||||
if (value == 0 || *value == 0)
|
||||
return (0);
|
||||
|
||||
if (key) {
|
||||
/* This is a result template and the input value is the result */
|
||||
if (ctx->flags & (DB_COMMON_VALUE_DOMAIN | DB_COMMON_VALUE_USER))
|
||||
if ((vdomain = strrchr(value, '@')) != 0)
|
||||
++vdomain;
|
||||
|
||||
if ((!vdomain || !*vdomain) && (ctx->flags&DB_COMMON_VALUE_DOMAIN) != 0
|
||||
|| vdomain == value + 1 && (ctx->flags&DB_COMMON_VALUE_USER) != 0)
|
||||
return (0);
|
||||
|
||||
/* The result format may use the local or domain part of the key */
|
||||
if (ctx->flags & (DB_COMMON_KEY_DOMAIN | DB_COMMON_KEY_USER))
|
||||
if ((kdomain = strrchr(key, '@')) != 0)
|
||||
++kdomain;
|
||||
|
||||
/*
|
||||
* The key should already be checked before the query. No harm if
|
||||
* the query did not get optimized out, so we just issue a warning.
|
||||
*/
|
||||
if ((!kdomain || !*kdomain) && (ctx->flags&DB_COMMON_KEY_DOMAIN) != 0
|
||||
|| kdomain == key + 1 && (ctx->flags & DB_COMMON_KEY_USER) != 0) {
|
||||
msg_warn("%s: %s: lookup key '%s' skipped after query", myname,
|
||||
ctx->dict->name, value);
|
||||
return (0);
|
||||
}
|
||||
} else {
|
||||
/* This is a query template and the input value is the lookup key */
|
||||
if (ctx->flags & (DB_COMMON_KEY_DOMAIN | DB_COMMON_KEY_USER))
|
||||
if ((vdomain = strrchr(value, '@')) != 0)
|
||||
++vdomain;
|
||||
|
||||
if ((!vdomain || !*vdomain) && (ctx->flags&DB_COMMON_KEY_DOMAIN) != 0
|
||||
|| vdomain == value + 1 && (ctx->flags & DB_COMMON_KEY_USER) != 0)
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (ctx->nparts > 0) {
|
||||
parts = argv_split(key ? kdomain : vdomain, ".");
|
||||
/*
|
||||
* Skip domains that lack enough labels to fill-in the template.
|
||||
*/
|
||||
if (parts->argc < ctx->nparts) {
|
||||
argv_free(parts);
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* Skip domains with leading, consecutive or trailing '.'
|
||||
* separators among the required labels.
|
||||
*/
|
||||
for (i = 0; i < ctx->nparts; i++)
|
||||
if (*parts->argv[parts->argc-i-1] == 0) {
|
||||
argv_free(parts);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (VSTRING_LEN(result) > 0)
|
||||
VSTRING_ADDCH(result, ',');
|
||||
|
||||
#define QUOTE_VAL(d, q, v, buf) \
|
||||
(q ? q(d, v, buf) : vstring_strcat(buf, v))
|
||||
|
||||
/*
|
||||
* Replace all instances of %s with the address to look up. Replace
|
||||
* %u with the user portion, and %d with the domain portion. "%%"
|
||||
* expands to "%". lowercase -> addr, uppercase -> key
|
||||
*/
|
||||
for (cp = format; *cp; cp++) {
|
||||
if (*cp == '%') {
|
||||
switch (*++cp) {
|
||||
|
||||
case '%':
|
||||
VSTRING_ADDCH(result, '%');
|
||||
break;
|
||||
|
||||
case 's':
|
||||
QUOTE_VAL(ctx->dict, quote_func, value, result);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
if (vdomain) {
|
||||
if (vuser == 0)
|
||||
vuser = mystrndup(value, vdomain - value - 1);
|
||||
QUOTE_VAL(ctx->dict, quote_func, vuser, result);
|
||||
}
|
||||
else
|
||||
QUOTE_VAL(ctx->dict, quote_func, value, result);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
QUOTE_VAL(ctx->dict, quote_func, vdomain, result);
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
if (key)
|
||||
QUOTE_VAL(ctx->dict, quote_func, key, result);
|
||||
else
|
||||
QUOTE_VAL(ctx->dict, quote_func, value, result);
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
if (key) {
|
||||
if (kdomain) {
|
||||
if (kuser == 0)
|
||||
kuser = mystrndup(key, kdomain - key - 1);
|
||||
QUOTE_VAL(ctx->dict, quote_func, kuser, result);
|
||||
}
|
||||
else
|
||||
QUOTE_VAL(ctx->dict, quote_func, key, result);
|
||||
} else {
|
||||
if (vdomain) {
|
||||
if (vuser == 0)
|
||||
vuser = mystrndup(value, vdomain - value - 1);
|
||||
QUOTE_VAL(ctx->dict, quote_func, vuser, result);
|
||||
}
|
||||
else
|
||||
QUOTE_VAL(ctx->dict, quote_func, value, result);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
if (key)
|
||||
QUOTE_VAL(ctx->dict, quote_func, kdomain, result);
|
||||
else
|
||||
QUOTE_VAL(ctx->dict, quote_func, vdomain, result);
|
||||
break;
|
||||
|
||||
case '1': case '2': case '3': case '4': case '5':
|
||||
case '6': case '7': case '8': case '9':
|
||||
QUOTE_VAL(ctx->dict, quote_func,
|
||||
parts->argv[parts->argc-(*cp-'0')], result);
|
||||
break;
|
||||
|
||||
default:
|
||||
msg_fatal("%s: %s: invalid %s template '%s'", myname,
|
||||
ctx->dict->name, key ? "result" : "query",
|
||||
format);
|
||||
}
|
||||
} else
|
||||
VSTRING_ADDCH(result, *cp);
|
||||
}
|
||||
VSTRING_TERMINATE(result);
|
||||
|
||||
if (vuser)
|
||||
myfree(vuser);
|
||||
if (kuser)
|
||||
myfree(kuser);
|
||||
if (parts)
|
||||
argv_free(parts);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
/* db_common_check_domain - check domain list */
|
||||
|
||||
int db_common_check_domain(STRING_LIST *domain_list, const char *addr)
|
||||
{
|
||||
char *domain;
|
||||
|
||||
if (domain_list) {
|
||||
if ((domain = strrchr(addr, '@')) != NULL)
|
||||
++domain;
|
||||
if (domain == NULL || domain == addr + 1)
|
||||
return (0);
|
||||
if (match_list_match(domain_list, domain) == 0)
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* db_common_sql_build_query -- build query for SQL maptypes */
|
||||
|
||||
void db_common_sql_build_query(VSTRING *query, CFG_PARSER *parser)
|
||||
{
|
||||
char *myname = "db_common_sql_build_query";
|
||||
char *table;
|
||||
char *select_field;
|
||||
char *where_field;
|
||||
char *additional_conditions;
|
||||
|
||||
/*
|
||||
* Build "old style" query: "select %s from %s where %s"
|
||||
*/
|
||||
if ((table = cfg_get_str(parser, "table", NULL, 1, 0)) == 0)
|
||||
msg_fatal("%s: 'table' parameter not defined", myname);
|
||||
|
||||
if ((select_field = cfg_get_str(parser, "select_field", NULL, 1, 0)) == 0)
|
||||
msg_fatal("%s: 'select_field' parameter not defined", myname);
|
||||
|
||||
if ((where_field = cfg_get_str(parser, "where_field", NULL, 1, 0)) == 0)
|
||||
msg_fatal("%s: 'where_field' parameter not defined", myname);
|
||||
|
||||
additional_conditions = cfg_get_str(parser, "additional_conditions",
|
||||
"", 0, 0);
|
||||
|
||||
vstring_sprintf(query, "SELECT %s FROM %s WHERE %s='%%s' %s",
|
||||
select_field, table, where_field,
|
||||
additional_conditions);
|
||||
|
||||
myfree(table);
|
||||
myfree(select_field);
|
||||
myfree(where_field);
|
||||
myfree(additional_conditions);
|
||||
}
|
55
postfix/src/global/db_common.h
Normal file
55
postfix/src/global/db_common.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef _DB_COMMON_H_INCLUDED_
|
||||
#define _DB_COMMON_H_INCLUDED_
|
||||
|
||||
/*++
|
||||
/* NAME
|
||||
/* db_common 3h
|
||||
/* SUMMARY
|
||||
/* utilities common to network based dictionaries
|
||||
/* SYNOPSIS
|
||||
/* #include "db_common.h"
|
||||
/* DESCRIPTION
|
||||
/* .nf
|
||||
*/
|
||||
|
||||
/*
|
||||
* External interface.
|
||||
*/
|
||||
#include "dict.h"
|
||||
#include "string_list.h"
|
||||
|
||||
typedef void (*db_quote_callback_t)(DICT *, const char *, VSTRING *);
|
||||
|
||||
extern int db_common_parse(DICT *, void **, const char *, int);
|
||||
extern void db_common_free_ctx(void *);
|
||||
extern int db_common_expand(void *, const char *, const char *,
|
||||
const char *, VSTRING *, db_quote_callback_t);
|
||||
extern int db_common_check_domain(STRING_LIST *, const char *);
|
||||
extern void db_common_sql_build_query(VSTRING *query, CFG_PARSER *parser);
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Liviu Daia
|
||||
/* Institute of Mathematics of the Romanian Academy
|
||||
/* P.O. BOX 1-764
|
||||
/* RO-014700 Bucharest, ROMANIA
|
||||
/*
|
||||
/* Jose Luis Tallon
|
||||
/* G4 J.E. - F.I. - U.P.M.
|
||||
/* Campus de Montegancedo, S/N
|
||||
/* E-28660 Madrid, SPAIN
|
||||
/*
|
||||
/* Victor Duchovni
|
||||
/* Morgan Stanley
|
||||
/*--*/
|
||||
|
||||
#endif
|
||||
|
@@ -7,7 +7,7 @@
|
||||
/* #include <dict_ldap.h>
|
||||
/*
|
||||
/* DICT *dict_ldap_open(attribute, dummy, dict_flags)
|
||||
/* const char *attribute;
|
||||
/* const char *ldapsource;
|
||||
/* int dummy;
|
||||
/* int dict_flags;
|
||||
/* DESCRIPTION
|
||||
@@ -47,11 +47,13 @@
|
||||
/* .IP timeout
|
||||
/* Deadline for LDAP open() and LDAP search() .
|
||||
/* .IP query_filter
|
||||
/* The filter used to search for directory entries, for example
|
||||
/* \fI(mailacceptinggeneralid=%s)\fR.
|
||||
/* .IP result_filter
|
||||
/* The filter used to expand results from queries. Default is
|
||||
/* \fI%s\fR.
|
||||
/* The search filter template used to search for directory entries,
|
||||
/* for example \fI(mailacceptinggeneralid=%s)\fR. See ldap_table(5)
|
||||
/* for details.
|
||||
/* .IP result_format
|
||||
/* The result template used to expand results from queries. Default
|
||||
/* is \fI%s\fR. See ldap_table(5) for details. Also supported under
|
||||
/* the name \fIresult_filter\fR for compatibility with older releases.
|
||||
/* .IP result_attribute
|
||||
/* The attribute(s) returned by the search, in which to find
|
||||
/* RFC822 addresses, for example \fImaildrop\fR.
|
||||
@@ -184,8 +186,6 @@
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include "match_list.h"
|
||||
#include "match_ops.h"
|
||||
#include "msg.h"
|
||||
#include "mymalloc.h"
|
||||
#include "vstring.h"
|
||||
@@ -196,6 +196,7 @@
|
||||
/* Global library. */
|
||||
|
||||
#include "cfg_parser.h"
|
||||
#include "db_common.h"
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@@ -212,15 +213,17 @@ typedef struct {
|
||||
*/
|
||||
typedef struct {
|
||||
DICT dict; /* generic member */
|
||||
CFG_PARSER *parser;
|
||||
char *ldapsource;
|
||||
CFG_PARSER *parser; /* common parameter parser */
|
||||
char *query; /* db_common_expand() query */
|
||||
char *result_format; /* db_common_expand() result_format */
|
||||
STRING_LIST *domain; /* restrict queries to these domains */
|
||||
void *ctx; /* db_common_parse() context */
|
||||
int dynamic_base; /* Search base has substitutions? */
|
||||
int expansion_limit;
|
||||
char *server_host;
|
||||
int server_port;
|
||||
int scope;
|
||||
char *search_base;
|
||||
MATCH_LIST *domain;
|
||||
char *query_filter;
|
||||
char *result_filter;
|
||||
ARGV *result_attributes;
|
||||
int num_attributes; /* rest of list is DN's. */
|
||||
int bind;
|
||||
@@ -229,7 +232,6 @@ typedef struct {
|
||||
int timeout;
|
||||
int dereference;
|
||||
long recursion_limit;
|
||||
long expansion_limit;
|
||||
long size_limit;
|
||||
int chase_referrals;
|
||||
int debuglevel;
|
||||
@@ -251,6 +253,55 @@ typedef struct {
|
||||
|
||||
#define DICT_LDAP_CONN(d) ((LDAP_CONN *)((d)->ht->value))
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Quoting rules.
|
||||
*/
|
||||
|
||||
/* rfc2253_quote - Quote input key for safe inclusion in the search base */
|
||||
|
||||
static void rfc2253_quote(DICT *unused, const char *name, VSTRING *result)
|
||||
{
|
||||
unsigned char *sub = (unsigned char *)name;
|
||||
size_t len;
|
||||
|
||||
/*
|
||||
* The RFC only requires quoting of a leading or trailing space,
|
||||
* but it is harmless to quote whitespace everywhere. Similarly,
|
||||
* we quote all '#' characters, even though only the leading '#'
|
||||
* character requires quoting per the RFC.
|
||||
*/
|
||||
while (*sub)
|
||||
if ((len = strcspn(sub, " \t\"#+,;<>\\")) > 0) {
|
||||
vstring_strncat(result, sub, len);
|
||||
sub += len;
|
||||
} else
|
||||
vstring_sprintf_append(result, "\\%02X", *(sub++));
|
||||
}
|
||||
|
||||
/* rfc2254_quote - Quote input key for safe inclusion in the query filter */
|
||||
|
||||
static void rfc2254_quote(DICT *unused, const char *name, VSTRING *result)
|
||||
{
|
||||
unsigned char *sub = (unsigned char *)name;
|
||||
size_t len;
|
||||
|
||||
/*
|
||||
* If any characters in the supplied address should be escaped per RFC
|
||||
* 2254, do so. Thanks to Keith Stevenson and Wietse. And thanks to
|
||||
* Samuel Tardieu for spotting that wildcard searches were being done in
|
||||
* the first place, which prompted the ill-conceived lookup_wildcards
|
||||
* parameter and then this more comprehensive mechanism.
|
||||
*/
|
||||
while (*sub)
|
||||
if ((len = strcspn(sub, "*()\\")) > 0) {
|
||||
vstring_strncat(result, sub, len);
|
||||
sub += len;
|
||||
} else
|
||||
vstring_sprintf_append(result, "\\%02X", *(sub++));
|
||||
}
|
||||
|
||||
static BINHASH *conn_hash = 0;
|
||||
|
||||
#if defined(LDAP_API_FEATURE_X_OPENLDAP) || !defined(LDAP_OPT_NETWORK_TIMEOUT)
|
||||
@@ -404,7 +455,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 *) 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,
|
||||
@@ -497,7 +548,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
|
||||
if (ldap_set_option(dict_ldap->ld, LDAP_OPT_SIZELIMIT,
|
||||
&dict_ldap->size_limit) != LDAP_OPT_SUCCESS)
|
||||
msg_warn("%s: %s: Unable to set query result size limit to %ld.",
|
||||
myname, dict_ldap->ldapsource, dict_ldap->size_limit);
|
||||
myname, dict_ldap->parser->name, dict_ldap->size_limit);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -582,7 +633,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Cached connection handle for LDAP source %s",
|
||||
myname, dict_ldap->ldapsource);
|
||||
myname, dict_ldap->parser->name);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -643,59 +694,6 @@ static void dict_ldap_conn_find(DICT_LDAP *dict_ldap)
|
||||
vstring_free(keybuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* expand a filter (lookup or result)
|
||||
*/
|
||||
static void dict_ldap_expand_filter(char *ldapsource, char *filter,
|
||||
char *value, VSTRING *out)
|
||||
{
|
||||
char *myname = "dict_ldap_expand_filter";
|
||||
char *sub,
|
||||
*end;
|
||||
|
||||
/*
|
||||
* Yes, replace all instances of %s with the address to look up. Replace
|
||||
* %u with the user portion, and %d with the domain portion.
|
||||
*/
|
||||
sub = filter;
|
||||
end = sub + strlen(filter);
|
||||
while (sub < end) {
|
||||
|
||||
/*
|
||||
* Make sure it's %[sud] and not something else. For backward
|
||||
* compatibilty, treat anything other than %u or %d as %s, with a
|
||||
* warning.
|
||||
*/
|
||||
if (*(sub) == '%') {
|
||||
char *u = value;
|
||||
char *p = strrchr(u, '@');
|
||||
|
||||
switch (*(sub + 1)) {
|
||||
case 'd':
|
||||
if (p)
|
||||
vstring_strcat(out, p + 1);
|
||||
break;
|
||||
case 'u':
|
||||
if (p)
|
||||
vstring_strncat(out, u, p - u);
|
||||
else
|
||||
vstring_strcat(out, u);
|
||||
break;
|
||||
default:
|
||||
msg_warn("%s: %s: Invalid filter substitution format '%%%c'!",
|
||||
myname, ldapsource, *(sub + 1));
|
||||
/* fall through */
|
||||
case 's':
|
||||
vstring_strcat(out, u);
|
||||
break;
|
||||
}
|
||||
sub++;
|
||||
} else
|
||||
vstring_strncat(out, sub, 1);
|
||||
sub++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dict_ldap_get_values: for each entry returned by a search, get the values
|
||||
* of all its attributes. Recurses to resolve any DN or URL values found.
|
||||
@@ -704,7 +702,7 @@ static void dict_ldap_expand_filter(char *ldapsource, char *filter,
|
||||
* are thanks to LaMont Jones.
|
||||
*/
|
||||
static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
VSTRING *result)
|
||||
VSTRING *result, const char* name)
|
||||
{
|
||||
static int recursion = 0;
|
||||
static int expansion;
|
||||
@@ -738,10 +736,12 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
* LDAP should not, but may produce more than the requested maximum
|
||||
* number of entries.
|
||||
*/
|
||||
if (dict_errno == 0 && ++entries > dict_ldap->size_limit
|
||||
&& dict_ldap->size_limit) {
|
||||
msg_warn("%s[%d]: %s: Query size limit (%ld) exceeded", myname,
|
||||
recursion, dict_ldap->ldapsource, dict_ldap->size_limit);
|
||||
if (dict_errno == 0
|
||||
&& dict_ldap->size_limit
|
||||
&& ++entries > dict_ldap->size_limit) {
|
||||
msg_warn("%s[%d]: %s: Query size limit (%ld) exceeded",
|
||||
myname, recursion, dict_ldap->parser->name,
|
||||
dict_ldap->size_limit);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
}
|
||||
for (attr = ldap_first_attribute(dict_ldap->ld, entry, &ber);
|
||||
@@ -792,22 +792,16 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
if (i < dict_ldap->num_attributes) {
|
||||
/* Ordinary result attribute */
|
||||
for (i = 0; vals[i] != NULL; i++) {
|
||||
if (++expansion > dict_ldap->expansion_limit &&
|
||||
dict_ldap->expansion_limit) {
|
||||
msg_warn("%s[%d]: %s: Expansion limit exceeded at"
|
||||
" result attribute %s=%s", myname, recursion,
|
||||
dict_ldap->ldapsource, attr, vals[i]);
|
||||
if (db_common_expand(dict_ldap->ctx,
|
||||
dict_ldap->result_format, vals[i],
|
||||
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 (VSTRING_LEN(result) > 0)
|
||||
vstring_strcat(result, ",");
|
||||
if (dict_ldap->result_filter == NULL)
|
||||
vstring_strcat(result, vals[i]);
|
||||
else
|
||||
dict_ldap_expand_filter(dict_ldap->ldapsource,
|
||||
dict_ldap->result_filter,
|
||||
vals[i], result);
|
||||
}
|
||||
if (dict_errno != 0)
|
||||
continue;
|
||||
@@ -842,7 +836,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
}
|
||||
switch (rc) {
|
||||
case LDAP_SUCCESS:
|
||||
dict_ldap_get_values(dict_ldap, resloop, result);
|
||||
dict_ldap_get_values(dict_ldap, resloop, result, name);
|
||||
break;
|
||||
case LDAP_NO_SUCH_OBJECT:
|
||||
|
||||
@@ -875,8 +869,8 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
|
||||
} else if (recursion >= dict_ldap->recursion_limit
|
||||
&& dict_ldap->result_attributes->argv[i]) {
|
||||
msg_warn("%s[%d]: %s: Recursion limit exceeded"
|
||||
" for special attribute %s=%s",
|
||||
myname, recursion, dict_ldap->ldapsource, attr, vals[0]);
|
||||
" for special attribute %s=%s", myname, recursion,
|
||||
dict_ldap->parser->name, attr, vals[0]);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
}
|
||||
ldap_value_free(vals);
|
||||
@@ -897,14 +891,12 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
char *myname = "dict_ldap_lookup";
|
||||
DICT_LDAP *dict_ldap = (DICT_LDAP *) dict;
|
||||
LDAPMessage *res = 0;
|
||||
static VSTRING *base;
|
||||
static VSTRING *query;
|
||||
static VSTRING *result;
|
||||
struct timeval tv;
|
||||
VSTRING *escaped_name = 0,
|
||||
*filter_buf = 0;
|
||||
int rc = 0;
|
||||
int sizelimit;
|
||||
char *sub,
|
||||
*end;
|
||||
|
||||
dict_errno = 0;
|
||||
|
||||
@@ -916,24 +908,22 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
* addresses in domains on the list. This can significantly reduce the
|
||||
* load on the LDAP server.
|
||||
*/
|
||||
if (dict_ldap->domain) {
|
||||
const char *p = strrchr(name, '@');
|
||||
|
||||
if (p == 0 || p == name ||
|
||||
match_list_match(dict_ldap->domain, ++p) == 0) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: domain of %s not found in domain list", myname,
|
||||
name);
|
||||
return (0);
|
||||
}
|
||||
if (db_common_check_domain(dict_ldap->domain, name) == 0) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Skipping lookup of '%s'", myname, name);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the result holder.
|
||||
*/
|
||||
if (result == 0)
|
||||
result = vstring_alloc(2);
|
||||
vstring_strcpy(result, "");
|
||||
#define INIT_VSTR(buf, len) do { \
|
||||
if (buf == 0) \
|
||||
buf = vstring_alloc(len); \
|
||||
VSTRING_RESET(buf); \
|
||||
VSTRING_TERMINATE(buf); \
|
||||
} while (0)
|
||||
|
||||
INIT_VSTR(base, 10);
|
||||
INIT_VSTR(query, 10);
|
||||
INIT_VSTR(result, 10);
|
||||
|
||||
/*
|
||||
* Because the connection may be shared and invalidated via queries for
|
||||
@@ -949,7 +939,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
if (msg_verbose)
|
||||
msg_info
|
||||
("%s: No existing connection for LDAP source %s, reopening",
|
||||
myname, dict_ldap->ldapsource);
|
||||
myname, dict_ldap->parser->name);
|
||||
|
||||
dict_ldap_connect(dict_ldap);
|
||||
|
||||
@@ -960,7 +950,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
return (0);
|
||||
} else if (msg_verbose)
|
||||
msg_info("%s: Using existing connection for LDAP source %s",
|
||||
myname, dict_ldap->ldapsource);
|
||||
myname, dict_ldap->parser->name);
|
||||
|
||||
/*
|
||||
* Connection caching, means that the connection handle may have the
|
||||
@@ -973,89 +963,55 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
if (ldap_set_option(dict_ldap->ld, LDAP_OPT_SIZELIMIT, &sizelimit)
|
||||
!= LDAP_OPT_SUCCESS)
|
||||
msg_warn("%s: %s: Unable to set query result size limit to %ld.",
|
||||
myname, dict_ldap->ldapsource, dict_ldap->size_limit);
|
||||
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.
|
||||
*/
|
||||
if (!db_common_expand(dict_ldap->ctx, dict_ldap->search_base,
|
||||
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);
|
||||
}
|
||||
|
||||
if (!db_common_expand(dict_ldap->ctx, dict_ldap->query,
|
||||
name, 0, query, rfc2254_quote)) {
|
||||
if (msg_verbose > 1)
|
||||
msg_info("%s: %s: Empty expansion for %s", myname,
|
||||
dict_ldap->parser->name, dict_ldap->query);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare the query.
|
||||
*/
|
||||
tv.tv_sec = dict_ldap->timeout;
|
||||
tv.tv_usec = 0;
|
||||
escaped_name = vstring_alloc(20);
|
||||
filter_buf = vstring_alloc(30);
|
||||
|
||||
/*
|
||||
* If any characters in the supplied address should be escaped per RFC
|
||||
* 2254, do so. Thanks to Keith Stevenson and Wietse. And thanks to
|
||||
* Samuel Tardieu for spotting that wildcard searches were being done in
|
||||
* the first place, which prompted the ill-conceived lookup_wildcards
|
||||
* parameter and then this more comprehensive mechanism.
|
||||
*/
|
||||
end = (char *) name + strlen((char *) name);
|
||||
sub = (char *) strpbrk((char *) name, "*()\\\0");
|
||||
if (sub && sub != end) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Found character(s) in %s that must be escaped",
|
||||
myname, name);
|
||||
for (sub = (char *) name; sub != end; sub++) {
|
||||
switch (*sub) {
|
||||
case '*':
|
||||
vstring_strcat(escaped_name, "\\2a");
|
||||
break;
|
||||
case '(':
|
||||
vstring_strcat(escaped_name, "\\28");
|
||||
break;
|
||||
case ')':
|
||||
vstring_strcat(escaped_name, "\\29");
|
||||
break;
|
||||
case '\\':
|
||||
vstring_strcat(escaped_name, "\\5c");
|
||||
break;
|
||||
case '\0':
|
||||
vstring_strcat(escaped_name, "\\00");
|
||||
break;
|
||||
default:
|
||||
vstring_strncat(escaped_name, sub, 1);
|
||||
}
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: After escaping, it's %s", myname,
|
||||
vstring_str(escaped_name));
|
||||
} else
|
||||
vstring_strcpy(escaped_name, (char *) name);
|
||||
|
||||
/*
|
||||
* Does the supplied query_filter even include a substitution?
|
||||
*/
|
||||
if ((char *) strchr(dict_ldap->query_filter, '%') == NULL) {
|
||||
|
||||
/*
|
||||
* No, log the fact and continue.
|
||||
*/
|
||||
msg_warn("%s: %s: Fixed query_filter %s is probably useless",
|
||||
myname, dict_ldap->ldapsource, dict_ldap->query_filter);
|
||||
vstring_strcpy(filter_buf, dict_ldap->query_filter);
|
||||
} else {
|
||||
dict_ldap_expand_filter(dict_ldap->ldapsource, dict_ldap->query_filter,
|
||||
vstring_str(escaped_name), filter_buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* On to the search.
|
||||
*/
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Searching with filter %s", myname,
|
||||
vstring_str(filter_buf));
|
||||
msg_info("%s: %s: Searching with filter %s", myname,
|
||||
dict_ldap->parser->name, vstring_str(query));
|
||||
|
||||
rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base,
|
||||
dict_ldap->scope,
|
||||
vstring_str(filter_buf),
|
||||
rc = ldap_search_st(dict_ldap->ld, vstring_str(base),
|
||||
dict_ldap->scope, vstring_str(query),
|
||||
dict_ldap->result_attributes->argv,
|
||||
0, &tv, &res);
|
||||
|
||||
if (rc == LDAP_SERVER_DOWN) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Lost connection for LDAP source %s, reopening",
|
||||
myname, dict_ldap->ldapsource);
|
||||
myname, dict_ldap->parser->name);
|
||||
|
||||
ldap_unbind(dict_ldap->ld);
|
||||
dict_ldap->ld = DICT_LDAP_CONN(dict_ldap)->conn_ld = 0;
|
||||
@@ -1067,20 +1023,21 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
if (dict_errno)
|
||||
return (0);
|
||||
|
||||
rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base,
|
||||
dict_ldap->scope,
|
||||
vstring_str(filter_buf),
|
||||
rc = ldap_search_st(dict_ldap->ld, vstring_str(base),
|
||||
dict_ldap->scope, vstring_str(query),
|
||||
dict_ldap->result_attributes->argv,
|
||||
0, &tv, &res);
|
||||
|
||||
}
|
||||
if (rc == LDAP_SUCCESS) {
|
||||
|
||||
switch (rc) {
|
||||
|
||||
case LDAP_SUCCESS:
|
||||
/*
|
||||
* Search worked; extract the requested result_attribute.
|
||||
*/
|
||||
|
||||
dict_ldap_get_values(dict_ldap, res, result);
|
||||
dict_ldap_get_values(dict_ldap, res, result, name);
|
||||
|
||||
/*
|
||||
* OpenLDAP's ldap_next_attribute returns a bogus
|
||||
@@ -1097,8 +1054,24 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
msg_info("%s: Search returned %s", myname,
|
||||
VSTRING_LEN(result) >
|
||||
0 ? vstring_str(result) : "nothing");
|
||||
} else {
|
||||
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 (dict_ldap->dynamic_base)
|
||||
break;
|
||||
|
||||
msg_warn("%s: %s: Search base '%s' not found: %d: %s",
|
||||
myname, dict_ldap->parser->name,
|
||||
vstring_str(base), rc, ldap_err2string(rc));
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* Rats. The search didn't work.
|
||||
*/
|
||||
@@ -1116,6 +1089,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
* And tell the caller to try again later.
|
||||
*/
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1123,10 +1097,6 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
*/
|
||||
if (res != 0)
|
||||
ldap_msgfree(res);
|
||||
if (filter_buf != 0)
|
||||
vstring_free(filter_buf);
|
||||
if (escaped_name != 0)
|
||||
vstring_free(escaped_name);
|
||||
|
||||
/*
|
||||
* If we had an error, return nothing, Otherwise, return the result, if
|
||||
@@ -1148,23 +1118,24 @@ static void dict_ldap_close(DICT *dict)
|
||||
if (conn->conn_ld) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Closed connection handle for LDAP source %s",
|
||||
myname, dict_ldap->ldapsource);
|
||||
myname, dict_ldap->parser->name);
|
||||
ldap_unbind(conn->conn_ld);
|
||||
}
|
||||
binhash_delete(conn_hash, ht->key, ht->key_len, myfree);
|
||||
}
|
||||
cfg_parser_free(dict_ldap->parser);
|
||||
myfree(dict_ldap->ldapsource);
|
||||
myfree(dict_ldap->server_host);
|
||||
myfree(dict_ldap->search_base);
|
||||
if (dict_ldap->domain)
|
||||
match_list_free(dict_ldap->domain);
|
||||
myfree(dict_ldap->query_filter);
|
||||
if (dict_ldap->result_filter)
|
||||
myfree(dict_ldap->result_filter);
|
||||
string_list_free(dict_ldap->domain);
|
||||
myfree(dict_ldap->query);
|
||||
if (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);
|
||||
if (dict_ldap->ctx)
|
||||
db_common_free_ctx(dict_ldap->ctx);
|
||||
#ifdef LDAP_API_FEATURE_X_OPENLDAP
|
||||
myfree(dict_ldap->tls_ca_cert_file);
|
||||
myfree(dict_ldap->tls_ca_cert_dir);
|
||||
@@ -1202,7 +1173,6 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
|
||||
|
||||
dict_ldap->ld = NULL;
|
||||
dict_ldap->parser = cfg_parser_alloc(ldapsource);
|
||||
dict_ldap->ldapsource = mystrdup(ldapsource);
|
||||
|
||||
server_host = cfg_get_str(dict_ldap->parser, "server_host",
|
||||
"localhost", 1, 0);
|
||||
@@ -1260,20 +1230,26 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
|
||||
if (strcasecmp(url_desc->lud_scheme, "ldaps") == 0)
|
||||
dict_ldap->ldap_ssl = 1;
|
||||
ldap_free_urldesc(url_desc);
|
||||
vstring_sprintf_append(url_list, " %s", h);
|
||||
if (VSTRING_LEN(url_list) > 0)
|
||||
VSTRING_ADDCH(url_list, ' ');
|
||||
vstring_strcat(url_list, h);
|
||||
} else {
|
||||
if (VSTRING_LEN(url_list) > 0)
|
||||
VSTRING_ADDCH(url_list, ' ');
|
||||
if (strrchr(h, ':'))
|
||||
vstring_sprintf_append(url_list, " ldap://%s", h);
|
||||
vstring_sprintf_append(url_list, "ldap://%s", h);
|
||||
else
|
||||
vstring_sprintf_append(url_list, " ldap://%s:%d", h,
|
||||
vstring_sprintf_append(url_list, "ldap://%s:%d", h,
|
||||
dict_ldap->server_port);
|
||||
}
|
||||
#else
|
||||
vstring_sprintf_append(url_list, " %s", h);
|
||||
if (VSTRING_LEN(url_list) > 0)
|
||||
VSTRING_ADDCH(url_list, ' ');
|
||||
vstring_strcat(url_list, h);
|
||||
#endif
|
||||
}
|
||||
dict_ldap->server_host =
|
||||
mystrdup(VSTRING_LEN(url_list) > 0 ? vstring_str(url_list) + 1 : "");
|
||||
VSTRING_TERMINATE(url_list);
|
||||
dict_ldap->server_host = vstring_export(url_list);
|
||||
|
||||
#if defined(LDAP_API_FEATURE_X_OPENLDAP)
|
||||
|
||||
@@ -1286,7 +1262,6 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
|
||||
dict_ldap->server_host);
|
||||
#endif
|
||||
myfree(server_host);
|
||||
vstring_free(url_list);
|
||||
|
||||
/*
|
||||
* Scope handling thanks to Carsten Hoeger of SuSE.
|
||||
@@ -1312,18 +1287,15 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
|
||||
|
||||
domainlist = cfg_get_str(dict_ldap->parser, "domain", "", 0, 0);
|
||||
if (*domainlist) {
|
||||
#ifdef MATCH_FLAG_NONE
|
||||
dict_ldap->domain = match_list_init(MATCH_FLAG_NONE,
|
||||
domainlist, 1, match_string);
|
||||
#else
|
||||
dict_ldap->domain = match_list_init(domainlist, 1, match_string);
|
||||
#endif
|
||||
dict_ldap->domain = string_list_init(MATCH_FLAG_NONE, domainlist);
|
||||
if (dict_ldap->domain == NULL)
|
||||
msg_warn("%s: domain match list creation using \"%s\" failed, will continue without it",
|
||||
myname, domainlist);
|
||||
if (msg_verbose)
|
||||
msg_info("%s: domain list created using \"%s\"", myname,
|
||||
domainlist);
|
||||
/*
|
||||
* The "domain" optimization skips input keys that may in fact
|
||||
* have unwanted matches in the database, so failure to create
|
||||
* the match list is fatal.
|
||||
*/
|
||||
msg_fatal("%s: %s: domain match list creation using '%s' failed",
|
||||
myname, ldapsource, domainlist);
|
||||
} else {
|
||||
dict_ldap->domain = NULL;
|
||||
}
|
||||
@@ -1335,20 +1307,37 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
|
||||
* Thanks to Manuel Guesdon for spotting that this wasn't really getting
|
||||
* set.
|
||||
*/
|
||||
dict_ldap->timeout = cfg_get_int(dict_ldap->parser, "timeout",
|
||||
10, 0, 0);
|
||||
dict_ldap->timeout = cfg_get_int(dict_ldap->parser, "timeout", 10, 0, 0);
|
||||
|
||||
dict_ldap->query_filter =
|
||||
cfg_get_str(dict_ldap->parser, "query_filter",
|
||||
"(mailacceptinggeneralid=%s)", 0, 0);
|
||||
#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)
|
||||
#endif
|
||||
dict_ldap->query =
|
||||
cfg_get_str(dict_ldap->parser, "query_filter",
|
||||
"(mailacceptinggeneralid=%s)", 0, 0);
|
||||
|
||||
dict_ldap->result_filter =
|
||||
cfg_get_str(dict_ldap->parser, "result_filter", "%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);
|
||||
|
||||
if (strcmp(dict_ldap->result_filter, "%s") == 0) {
|
||||
myfree(dict_ldap->result_filter);
|
||||
dict_ldap->result_filter = NULL;
|
||||
/*
|
||||
* 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 =
|
||||
db_common_parse(&dict_ldap->dict, &dict_ldap->ctx,
|
||||
dict_ldap->search_base, 1);
|
||||
if (!db_common_parse(0, &dict_ldap->ctx, dict_ldap->query, 1)) {
|
||||
msg_warn("%s: %s: Fixed query_filter %s is probably useless",
|
||||
myname, ldapsource, dict_ldap->query);
|
||||
}
|
||||
(void) db_common_parse(0, &dict_ldap->ctx, dict_ldap->result_format, 0);
|
||||
|
||||
attr = cfg_get_str(dict_ldap->parser, "result_attribute",
|
||||
"maildrop", 0, 0);
|
||||
dict_ldap->result_attributes = argv_split(attr, " ,\t\r\n");
|
||||
@@ -1357,9 +1346,8 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
|
||||
|
||||
attr = cfg_get_str(dict_ldap->parser, "special_result_attribute",
|
||||
"", 0, 0);
|
||||
if (*attr) {
|
||||
if (*attr)
|
||||
argv_split_append(dict_ldap->result_attributes, attr, " ,\t\r\n");
|
||||
}
|
||||
myfree(attr);
|
||||
|
||||
/*
|
||||
@@ -1378,44 +1366,32 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
|
||||
dict_ldap->bind_pw = cfg_get_str(dict_ldap->parser, "bind_pw", "", 0, 0);
|
||||
|
||||
/*
|
||||
* get configured value of "cache"; default to false
|
||||
* LDAP message caching never worked and is no longer supported.
|
||||
*/
|
||||
tmp = cfg_get_bool(dict_ldap->parser, "cache", 0);
|
||||
if (tmp)
|
||||
msg_warn("%s: %s ignoring cache", myname, ldapsource);
|
||||
|
||||
/*
|
||||
* get configured value of "cache_expiry"; default to 30 seconds
|
||||
*/
|
||||
tmp = cfg_get_int(dict_ldap->parser, "cache_expiry", -1, 0, 0);
|
||||
if (tmp >= 0)
|
||||
msg_warn("%s: %s ignoring cache_expiry", myname, ldapsource);
|
||||
|
||||
/*
|
||||
* get configured value of "cache_size"; default to 32k
|
||||
*/
|
||||
tmp = cfg_get_int(dict_ldap->parser, "cache_size", -1, 0, 0);
|
||||
if (tmp >= 0)
|
||||
msg_warn("%s: %s ignoring cache_size", myname, ldapsource);
|
||||
|
||||
/*
|
||||
* get configured value of "recursion_limit"; default to 1000
|
||||
*/
|
||||
dict_ldap->recursion_limit = cfg_get_int(dict_ldap->parser,
|
||||
"recursion_limit", 1000, 1, 0);
|
||||
|
||||
/*
|
||||
* get configured value of "expansion_limit"; default to 0
|
||||
* XXX: The default should be non-zero for safety, but that is not
|
||||
* backwards compatible.
|
||||
*/
|
||||
dict_ldap->expansion_limit = cfg_get_int(dict_ldap->parser,
|
||||
"expansion_limit", 0, 0, 0);
|
||||
|
||||
/*
|
||||
* get configured value of "size_limit"; default to expansion_limit
|
||||
*/
|
||||
dict_ldap->size_limit = cfg_get_int(dict_ldap->parser, "size_limit",
|
||||
dict_ldap->expansion_limit,
|
||||
0, 0);
|
||||
dict_ldap->expansion_limit, 0, 0);
|
||||
|
||||
/*
|
||||
* Alias dereferencing suggested by Mike Mattice.
|
||||
|
@@ -57,14 +57,69 @@
|
||||
/* Password for the above.
|
||||
/* .IP \fIdbname\fR
|
||||
/* Name of the database.
|
||||
/* .IP \fIdomain\fR
|
||||
/* List of domains the queries should be restricted to. If
|
||||
/* specified, only FQDN addresses whose domain parts matching this
|
||||
/* list will be queried against the SQL database. Lookups for
|
||||
/* partial addresses are also supressed. This can significantly
|
||||
/* reduce the query load on the server.
|
||||
/* .IP \fIquery\fR
|
||||
/* Query template, before the query is actually issued, variable
|
||||
/* substitutions are performed. See mysql_table(5) for details. If
|
||||
/* No query is specified, the legacy variables \fItable\fR,
|
||||
/* \fIselect_field\fR, \fIwhere_field\fR and \fIadditional_conditions\fR
|
||||
/* are used to construct the query template.
|
||||
/* .IP \fIresult_format\fR
|
||||
/* The format used to expand results from queries. Substitutions
|
||||
/* are performed as described in mysql_table(5). Defaults to returning
|
||||
/* the lookup result unchanged.
|
||||
/* .IP expansion_limit
|
||||
/* Limit (if any) on the total number of lookup result values. Lookups which
|
||||
/* exceed the limit fail with dict_errno=DICT_ERR_RETRY. Note that each
|
||||
/* non-empty (and non-NULL) column of a multi-column result row counts as
|
||||
/* one result.
|
||||
/* .IP \fItable\fR
|
||||
/* Name of the table.
|
||||
/* When \fIquery\fR is not set, name of the table used to construct the
|
||||
/* query string. This provides compatibility with older releases.
|
||||
/* .IP \fIselect_field\fR
|
||||
/* Name of the result field.
|
||||
/* When \fIquery\fR is not set, name of the result field used to
|
||||
/* construct the query string. This provides compatibility with older
|
||||
/* releases.
|
||||
/* .IP \fIwhere_field\fR
|
||||
/* Field used in the WHERE clause.
|
||||
/* When \fIquery\fR is not set, name of the where clause field used to
|
||||
/* construct the query string. This provides compatibility with older
|
||||
/* releases.
|
||||
/* .IP \fIadditional_conditions\fR
|
||||
/* Additional conditions to the WHERE clause.
|
||||
/* When \fIquery\fR is not set, additional where clause conditions used
|
||||
/* to construct the query string. This provides compatibility with older
|
||||
/* releases.
|
||||
/* .IP \fIhosts\fR
|
||||
/* List of hosts to connect to.
|
||||
/* .PP
|
||||
/* For example, if you want the map to reference databases of
|
||||
/* the name "your_db" and execute a query like this: select
|
||||
/* forw_addr from aliases where alias like '<some username>'
|
||||
/* against any database called "vmailer_info" located on hosts
|
||||
/* host1.some.domain and host2.some.domain, logging in as user
|
||||
/* "vmailer" and password "passwd" then the configuration file
|
||||
/* should read:
|
||||
/* .PP
|
||||
/* \fIuser\fR = \fBvmailer\fR
|
||||
/* .br
|
||||
/* \fIpassword\fR = \fBpasswd\fR
|
||||
/* .br
|
||||
/* \fIdbname\fR = \fBvmailer_info\fR
|
||||
/* .br
|
||||
/* \fItable\fR = \fBaliases\fR
|
||||
/* .br
|
||||
/* \fIselect_field\fR = \fBforw_addr\fR
|
||||
/* .br
|
||||
/* \fIwhere_field\fR = \fBalias\fR
|
||||
/* .br
|
||||
/* \fIhosts\fR = \fBhost1.some.domain\fR \fBhost2.some.domain\fR
|
||||
/* .IP \fIadditional_conditions\fR
|
||||
/* Backward compatibility when \fIquery\fR is not set, additional
|
||||
/* conditions to the WHERE clause.
|
||||
/* .IP \fIhosts\fR
|
||||
/* List of hosts to connect to.
|
||||
/* .PP
|
||||
@@ -132,6 +187,7 @@
|
||||
/* Global library. */
|
||||
|
||||
#include "cfg_parser.h"
|
||||
#include "db_common.h"
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@@ -156,22 +212,18 @@ typedef struct {
|
||||
} PLMYSQL;
|
||||
|
||||
typedef struct {
|
||||
DICT dict;
|
||||
CFG_PARSER *parser;
|
||||
char *query;
|
||||
char *result_format;
|
||||
STRING_LIST *domain;
|
||||
void *ctx;
|
||||
int expansion_limit;
|
||||
char *username;
|
||||
char *password;
|
||||
char *dbname;
|
||||
char *table;
|
||||
char *select_field;
|
||||
char *where_field;
|
||||
char *additional_conditions;
|
||||
char **hostnames;
|
||||
int len_hosts;
|
||||
} MYSQL_NAME;
|
||||
|
||||
typedef struct {
|
||||
DICT dict;
|
||||
ARGV *hosts;
|
||||
PLMYSQL *pldb;
|
||||
MYSQL_NAME *name;
|
||||
} DICT_MYSQL;
|
||||
|
||||
#define STATACTIVE (1<<0)
|
||||
@@ -186,7 +238,7 @@ typedef struct {
|
||||
#define IDLE_CONN_INTV 60 /* 1 minute */
|
||||
|
||||
/* internal function declarations */
|
||||
static PLMYSQL *plmysql_init(char *hostnames[], int);
|
||||
static PLMYSQL *plmysql_init(ARGV *);
|
||||
static MYSQL_RES *plmysql_query(PLMYSQL *, const char *, char *, char *, char *);
|
||||
static void plmysql_dealloc(PLMYSQL *);
|
||||
static void plmysql_close_host(HOST *);
|
||||
@@ -195,89 +247,120 @@ static void plmysql_connect_single(HOST *, char *, char *, char *);
|
||||
static const char *dict_mysql_lookup(DICT *, const char *);
|
||||
DICT *dict_mysql_open(const char *, int, int);
|
||||
static void dict_mysql_close(DICT *);
|
||||
static MYSQL_NAME *mysqlname_parse(const char *);
|
||||
static void mysql_parse_config(DICT_MYSQL *, const char *);
|
||||
static HOST *host_init(const char *);
|
||||
|
||||
/* dict_mysql_quote - escape SQL metacharacters in input string */
|
||||
|
||||
static void dict_mysql_quote(DICT *dict, const char *name, VSTRING *result)
|
||||
{
|
||||
DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict;
|
||||
int len = strlen(name);
|
||||
int buflen = 2*len + 1;
|
||||
|
||||
/*
|
||||
* We won't get integer overflows in 2*len + 1, because Postfix
|
||||
* input keys have reasonable size limits, better safe than sorry.
|
||||
*/
|
||||
if (buflen < len)
|
||||
msg_panic("dict_mysql_quote: integer overflow in 2*%d+1", len);
|
||||
VSTRING_SPACE(result, buflen);
|
||||
|
||||
/*
|
||||
* XXX Too expensive to find out which connection is still open at
|
||||
* this point. Grrr!
|
||||
*/
|
||||
#if 0 && defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
|
||||
mysql_real_escape_string(dict_mysql->pldb->db_hosts[i].db,
|
||||
vstring_end(result), name, len);
|
||||
#else
|
||||
mysql_escape_string(vstring_end(result), name, len);
|
||||
#endif
|
||||
VSTRING_SKIP(result);
|
||||
}
|
||||
|
||||
/* dict_mysql_lookup - find database entry */
|
||||
|
||||
/**********************************************************************
|
||||
* public interface dict_mysql_lookup
|
||||
* find database entry return 0 if no alias found, set dict_errno
|
||||
* on errors to DICT_ERRBO_RETRY and set dict_errno to 0 on success
|
||||
*********************************************************************/
|
||||
static const char *dict_mysql_lookup(DICT *dict, const char *name)
|
||||
{
|
||||
char *myname = "dict_mysql_lookup";
|
||||
DICT_MYSQL *dict_mysql = (DICT_MYSQL *)dict;
|
||||
PLMYSQL *pldb = dict_mysql->pldb;
|
||||
MYSQL_RES *query_res;
|
||||
MYSQL_ROW row;
|
||||
DICT_MYSQL *dict_mysql;
|
||||
PLMYSQL *pldb;
|
||||
static VSTRING *result;
|
||||
static VSTRING *query = 0;
|
||||
int i,
|
||||
j,
|
||||
numrows;
|
||||
char *name_escaped = 0;
|
||||
static VSTRING *query;
|
||||
int i;
|
||||
int j;
|
||||
int numrows;
|
||||
int expansion;
|
||||
const char *r;
|
||||
|
||||
dict_mysql = (DICT_MYSQL *) dict;
|
||||
pldb = dict_mysql->pldb;
|
||||
/* initialization for query */
|
||||
query = vstring_alloc(24);
|
||||
vstring_strcpy(query, "");
|
||||
if ((name_escaped = (char *) mymalloc((sizeof(char) * (strlen(name) * 2) +1))) == NULL) {
|
||||
msg_fatal("dict_mysql_lookup: out of memory.");
|
||||
}
|
||||
/* prepare the query */
|
||||
mysql_escape_string(name_escaped, name, (unsigned int) strlen(name));
|
||||
vstring_sprintf(query, "select %s from %s where %s = '%s' %s", dict_mysql->name->select_field,
|
||||
dict_mysql->name->table, dict_mysql->name->where_field, name_escaped,
|
||||
dict_mysql->name->additional_conditions);
|
||||
if (msg_verbose)
|
||||
msg_info("dict_mysql_lookup using sql query: %s", vstring_str(query));
|
||||
/* free mem associated with preparing the query */
|
||||
myfree(name_escaped);
|
||||
/* do the query - set dict_errno & cleanup if there's an error */
|
||||
if ((query_res = plmysql_query(pldb,
|
||||
vstring_str(query),
|
||||
dict_mysql->name->dbname,
|
||||
dict_mysql->name->username,
|
||||
dict_mysql->name->password)) == 0) {
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
vstring_free(query);
|
||||
return 0;
|
||||
}
|
||||
dict_errno = 0;
|
||||
/* free the vstring query */
|
||||
vstring_free(query);
|
||||
|
||||
/*
|
||||
* If there is a domain list for this map, then only search for
|
||||
* addresses in domains on the list. This can significantly reduce
|
||||
* the load on the server. Do not try "@domain" keys.
|
||||
*/
|
||||
if (db_common_check_domain(dict_mysql->domain, name) == 0) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Skipping lookup of '%s'", myname, name);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define INIT_VSTR(buf, len) do { \
|
||||
if (buf == 0) \
|
||||
buf = vstring_alloc(len); \
|
||||
VSTRING_RESET(buf); \
|
||||
VSTRING_TERMINATE(buf); \
|
||||
} while (0)
|
||||
|
||||
INIT_VSTR(query, 10);
|
||||
|
||||
/*
|
||||
* Suppress the lookup if the query expansion is empty
|
||||
*/
|
||||
if (!db_common_expand(dict_mysql->ctx, dict_mysql->query,
|
||||
name, 0, query, dict_mysql_quote))
|
||||
return (0);
|
||||
|
||||
/* do the query - set dict_errno & cleanup if there's an error */
|
||||
if ((query_res = plmysql_query(pldb, vstring_str(query),
|
||||
dict_mysql->dbname,
|
||||
dict_mysql->username,
|
||||
dict_mysql->password)) == 0) {
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
return (0);
|
||||
}
|
||||
|
||||
numrows = mysql_num_rows(query_res);
|
||||
if (msg_verbose)
|
||||
msg_info("dict_mysql_lookup: retrieved %d rows", numrows);
|
||||
msg_info("%s: retrieved %d rows", myname, numrows);
|
||||
if (numrows == 0) {
|
||||
mysql_free_result(query_res);
|
||||
return 0;
|
||||
}
|
||||
if (result == 0)
|
||||
result = vstring_alloc(10);
|
||||
vstring_strcpy(result, "");
|
||||
for (i = 0; i < numrows; i++) {
|
||||
|
||||
INIT_VSTR(result, 10);
|
||||
|
||||
for (expansion = i = 0; i < numrows && dict_errno == 0; i++) {
|
||||
row = mysql_fetch_row(query_res);
|
||||
if (i > 0)
|
||||
vstring_strcat(result, ",");
|
||||
for (j = 0; j < mysql_num_fields(query_res); j++) {
|
||||
if (row[j] == 0) {
|
||||
if (msg_verbose > 1)
|
||||
msg_info("dict_mysql_lookup: null field #%d row #%d", j, i);
|
||||
mysql_free_result(query_res);
|
||||
return (0);
|
||||
if (db_common_expand(dict_mysql->ctx, dict_mysql->result_format,
|
||||
row[j], name, result, 0)
|
||||
&& dict_mysql->expansion_limit > 0
|
||||
&& ++expansion > dict_mysql->expansion_limit) {
|
||||
msg_warn("%s: %s: Expansion limit exceeded for key: '%s'",
|
||||
myname, dict_mysql->parser->name, name);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
break;
|
||||
}
|
||||
if (j > 0)
|
||||
vstring_strcat(result, ",");
|
||||
vstring_strcat(result, row[j]);
|
||||
if (msg_verbose > 1)
|
||||
msg_info("dict_mysql_lookup: retrieved field: %d: %s", j, row[j]);
|
||||
}
|
||||
}
|
||||
mysql_free_result(query_res);
|
||||
return vstring_str(result);
|
||||
r = vstring_str(result);
|
||||
return ((dict_errno == 0 && *r) ? r : 0);
|
||||
}
|
||||
|
||||
/* dict_mysql_check_stat - check the status of a host */
|
||||
@@ -461,12 +544,77 @@ static void plmysql_down_host(HOST *host)
|
||||
event_cancel_timer(dict_mysql_event, (char *) host);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* public interface dict_mysql_open
|
||||
* create association with database with appropriate values
|
||||
* parse the map's config file
|
||||
* allocate memory
|
||||
**********************************************************************/
|
||||
/* mysql_parse_config - parse mysql configuration file */
|
||||
|
||||
static void mysql_parse_config(DICT_MYSQL *dict_mysql, const char *mysqlcf)
|
||||
{
|
||||
const char *myname = "mysqlname_parse";
|
||||
CFG_PARSER *p;
|
||||
VSTRING *buf;
|
||||
int i;
|
||||
char *hosts;
|
||||
char *domain;
|
||||
|
||||
p = dict_mysql->parser = cfg_parser_alloc(mysqlcf);
|
||||
dict_mysql->username = cfg_get_str(p, "user", "", 0, 0);
|
||||
dict_mysql->password = cfg_get_str(p, "password", "", 0, 0);
|
||||
dict_mysql->dbname = cfg_get_str(p, "dbname", "", 1, 0);
|
||||
dict_mysql->result_format = cfg_get_str(p, "result_format", "%s", 1, 0);
|
||||
/*
|
||||
* XXX: The default should be non-zero for safety, but that is not
|
||||
* backwards compatible.
|
||||
*/
|
||||
dict_mysql->expansion_limit = cfg_get_int(dict_mysql->parser,
|
||||
"expansion_limit", 0, 0, 0);
|
||||
|
||||
if ((dict_mysql->query = cfg_get_str(p, "query", NULL, 0, 0)) == 0) {
|
||||
/*
|
||||
* No query specified -- fallback to building it from components
|
||||
* (old style "select %s from %s where %s")
|
||||
*/
|
||||
buf = vstring_alloc(64);
|
||||
db_common_sql_build_query(buf, p);
|
||||
dict_mysql->query = vstring_export(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must parse all templates before we can use db_common_expand()
|
||||
*/
|
||||
dict_mysql->ctx = 0;
|
||||
(void) db_common_parse(&dict_mysql->dict, &dict_mysql->ctx,
|
||||
dict_mysql->query, 1);
|
||||
(void) db_common_parse(0, &dict_mysql->ctx, dict_mysql->result_format, 0);
|
||||
|
||||
domain = cfg_get_str(p, "domain", "", 0, 0);
|
||||
if (*domain) {
|
||||
if (!(dict_mysql->domain = string_list_init(MATCH_FLAG_NONE, domain)))
|
||||
/*
|
||||
* The "domain" optimization skips input keys that may in fact
|
||||
* have unwanted matches in the database, so failure to create
|
||||
* the match list is fatal.
|
||||
*/
|
||||
msg_fatal("%s: %s: domain match list creation using '%s' failed",
|
||||
myname, mysqlcf, domain);
|
||||
}
|
||||
else
|
||||
dict_mysql->domain = 0;
|
||||
myfree(domain);
|
||||
|
||||
hosts = cfg_get_str(p, "hosts", "", 0, 0);
|
||||
|
||||
dict_mysql->hosts = argv_split(hosts, " ,\t\r\n");
|
||||
if (dict_mysql->hosts->argc == 0) {
|
||||
argv_add(dict_mysql->hosts, "localhost", ARGV_END);
|
||||
argv_terminate(dict_mysql->hosts);
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s: no hostnames specified, defaulting to '%s'",
|
||||
myname, mysqlcf, dict_mysql->hosts->argv[0]);
|
||||
}
|
||||
myfree(hosts);
|
||||
}
|
||||
|
||||
/* dict_mysql_open - open MYSQL data base */
|
||||
|
||||
DICT *dict_mysql_open(const char *name, int open_flags, int dict_flags)
|
||||
{
|
||||
DICT_MYSQL *dict_mysql;
|
||||
@@ -483,95 +631,31 @@ DICT *dict_mysql_open(const char *name, int open_flags, int dict_flags)
|
||||
dict_mysql->dict.lookup = dict_mysql_lookup;
|
||||
dict_mysql->dict.close = dict_mysql_close;
|
||||
dict_mysql->dict.flags = dict_flags | DICT_FLAG_FIXED;
|
||||
dict_mysql->name = mysqlname_parse(name);
|
||||
dict_mysql->pldb = plmysql_init(dict_mysql->name->hostnames,
|
||||
dict_mysql->name->len_hosts);
|
||||
mysql_parse_config(dict_mysql, name);
|
||||
dict_mysql->pldb = plmysql_init(dict_mysql->hosts);
|
||||
if (dict_mysql->pldb == NULL)
|
||||
msg_fatal("couldn't intialize pldb!\n");
|
||||
return (DICT_DEBUG (&dict_mysql->dict));
|
||||
}
|
||||
|
||||
/* mysqlname_parse - parse mysql configuration file */
|
||||
static MYSQL_NAME *mysqlname_parse(const char *mysqlcf)
|
||||
{
|
||||
const char *myname = "mysqlname_parse";
|
||||
int i;
|
||||
char *hosts;
|
||||
MYSQL_NAME *name = (MYSQL_NAME *) mymalloc(sizeof(MYSQL_NAME));
|
||||
ARGV *hosts_argv;
|
||||
|
||||
/* parser */
|
||||
name->parser = cfg_parser_alloc(mysqlcf);
|
||||
|
||||
/* username */
|
||||
name->username = cfg_get_str(name->parser, "user", "", 0, 0);
|
||||
|
||||
/* password */
|
||||
name->password = cfg_get_str(name->parser, "password", "", 0, 0);
|
||||
|
||||
/* database name */
|
||||
name->dbname = cfg_get_str(name->parser, "dbname", "", 1, 0);
|
||||
|
||||
/* table name */
|
||||
name->table = cfg_get_str(name->parser, "table", "", 1, 0);
|
||||
|
||||
/* select field */
|
||||
name->select_field = cfg_get_str(name->parser, "select_field", "", 1, 0);
|
||||
|
||||
/* where field */
|
||||
name->where_field = cfg_get_str(name->parser, "where_field", "", 1, 0);
|
||||
|
||||
/* additional conditions */
|
||||
name->additional_conditions = cfg_get_str(name->parser,
|
||||
"additional_conditions",
|
||||
"", 0, 0);
|
||||
|
||||
/* mysql server hosts */
|
||||
hosts = cfg_get_str(name->parser, "hosts", "", 0, 0);
|
||||
|
||||
/* coo argv interface */
|
||||
hosts_argv = argv_split(hosts, " ,\t\r\n");
|
||||
if (hosts_argv->argc == 0) { /* no hosts specified,
|
||||
* default to 'localhost' */
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s: no hostnames specified, defaulting to 'localhost'",
|
||||
myname, mysqlcf);
|
||||
argv_add(hosts_argv, "localhost", ARGV_END);
|
||||
argv_terminate(hosts_argv);
|
||||
}
|
||||
name->len_hosts = hosts_argv->argc;
|
||||
name->hostnames = (char **) mymalloc((sizeof(char *)) * name->len_hosts);
|
||||
i = 0;
|
||||
for (i = 0; hosts_argv->argv[i] != NULL; i++) {
|
||||
name->hostnames[i] = mystrdup(hosts_argv->argv[i]);
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s: adding host '%s' to list of mysql server hosts",
|
||||
myname, mysqlcf, name->hostnames[i]);
|
||||
}
|
||||
myfree(hosts);
|
||||
argv_free(hosts_argv);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* plmysql_init - initalize a MYSQL database.
|
||||
* Return NULL on failure, or a PLMYSQL * on success.
|
||||
*/
|
||||
static PLMYSQL *plmysql_init(char *hostnames[], int len_hosts)
|
||||
static PLMYSQL *plmysql_init(ARGV *hosts)
|
||||
{
|
||||
PLMYSQL *PLDB;
|
||||
int i;
|
||||
|
||||
if ((PLDB = (PLMYSQL *) mymalloc(sizeof(PLMYSQL))) == NULL) {
|
||||
if ((PLDB = (PLMYSQL *) mymalloc(sizeof(PLMYSQL))) == 0)
|
||||
msg_fatal("mymalloc of pldb failed");
|
||||
}
|
||||
PLDB->len_hosts = len_hosts;
|
||||
if ((PLDB->db_hosts = (HOST **) mymalloc(sizeof(HOST *) * len_hosts)) == NULL)
|
||||
return NULL;
|
||||
for (i = 0; i < len_hosts; i++) {
|
||||
PLDB->db_hosts[i] = host_init(hostnames[i]);
|
||||
}
|
||||
|
||||
PLDB->len_hosts = hosts->argc;
|
||||
if ((PLDB->db_hosts = (HOST **) mymalloc(sizeof(HOST *) * hosts->argc)) == 0)
|
||||
return (0);
|
||||
for (i = 0; i < hosts->argc; i++)
|
||||
PLDB->db_hosts[i] = host_init(hosts->argv[i]);
|
||||
|
||||
return PLDB;
|
||||
}
|
||||
|
||||
@@ -619,29 +703,26 @@ static HOST *host_init(const char *hostname)
|
||||
return host;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* public interface dict_mysql_close
|
||||
* unregister, disassociate from database, freeing appropriate memory
|
||||
**********************************************************************/
|
||||
/* dict_mysql_close - close MYSQL database */
|
||||
|
||||
static void dict_mysql_close(DICT *dict)
|
||||
{
|
||||
int i;
|
||||
DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict;
|
||||
|
||||
plmysql_dealloc(dict_mysql->pldb);
|
||||
cfg_parser_free(dict_mysql->name->parser);
|
||||
myfree(dict_mysql->name->username);
|
||||
myfree(dict_mysql->name->password);
|
||||
myfree(dict_mysql->name->dbname);
|
||||
myfree(dict_mysql->name->table);
|
||||
myfree(dict_mysql->name->select_field);
|
||||
myfree(dict_mysql->name->where_field);
|
||||
myfree(dict_mysql->name->additional_conditions);
|
||||
for (i = 0; i < dict_mysql->name->len_hosts; i++) {
|
||||
myfree(dict_mysql->name->hostnames[i]);
|
||||
}
|
||||
myfree((char *) dict_mysql->name->hostnames);
|
||||
myfree((char *) dict_mysql->name);
|
||||
cfg_parser_free(dict_mysql->parser);
|
||||
myfree(dict_mysql->username);
|
||||
myfree(dict_mysql->password);
|
||||
myfree(dict_mysql->dbname);
|
||||
myfree(dict_mysql->query);
|
||||
myfree(dict_mysql->result_format);
|
||||
if (dict_mysql->domain)
|
||||
string_list_free(dict_mysql->domain);
|
||||
if (dict_mysql->hosts)
|
||||
argv_free(dict_mysql->hosts);
|
||||
if (dict_mysql->ctx)
|
||||
db_common_free_ctx(dict_mysql->ctx);
|
||||
dict_free(dict);
|
||||
}
|
||||
|
||||
|
@@ -58,24 +58,44 @@
|
||||
/* Password for the above.
|
||||
/* .IP \fIdbname\fR
|
||||
/* Name of the database.
|
||||
/* .IP \fItable\fR
|
||||
/* Name of the table.
|
||||
/* .IP \fIselect_field\fR
|
||||
/* Name of the result field.
|
||||
/* .IP \fIwhere_field\fR
|
||||
/* Field used in the WHERE clause.
|
||||
/* .IP \fIadditional_conditions\fR
|
||||
/* Additional conditions to the WHERE clause.
|
||||
/* .IP \fIquery\fR
|
||||
/* Query overriding \fItable\fR, \fIselect_field\fR,
|
||||
/* \fIwhere_field\fR, and \fIadditional_conditions\fR. Before the
|
||||
/* query is actually issued, all occurrences of %s are replaced
|
||||
/* with the address to look up, %u are replaced with the user
|
||||
/* portion, and %d with the domain portion.
|
||||
/* Query template. If not defined a default query template is constructed
|
||||
/* from the legacy \fIselect_function\fR or failing that the \fItable\fR,
|
||||
/* \fIselect_field\fR, \fIwhere_field\fR, and \fIadditional_conditions\fR
|
||||
/* parameters. Before the query is issues, variable substitutions are
|
||||
/* performed. See pgsql_table(5).
|
||||
/* .IP \fIdomain\fR
|
||||
/* List of domains the queries should be restricted to. If
|
||||
/* specified, only FQDN addresses whose domain parts matching this
|
||||
/* list will be queried against the SQL database. Lookups for
|
||||
/* partial addresses are also supressed. This can significantly
|
||||
/* reduce the query load on the server.
|
||||
/* .IP \fIresult_format\fR
|
||||
/* The format used to expand results from queries. Substitutions
|
||||
/* are performed as described in pgsql_table(5). Defaults to returning
|
||||
/* the lookup result unchanged.
|
||||
/* .IP expansion_limit
|
||||
/* Limit (if any) on the total number of lookup result values. Lookups which
|
||||
/* exceed the limit fail with dict_errno=DICT_ERR_RETRY. Note that each
|
||||
/* non-empty (and non-NULL) column of a multi-column result row counts as
|
||||
/* one result.
|
||||
/* .IP \fIselect_function\fR
|
||||
/* Function to be used instead of the SELECT statement. Overrides
|
||||
/* both \fIquery\fR and \fItable\fR, \fIselect_field\fR,
|
||||
/* \fIwhere_field\fR, and \fIadditional_conditions\fR settings.
|
||||
/* When \fIquery\fR is not defined, the function to be used instead of
|
||||
/* the default query based on the legacy \fItable\fR, \fIselect_field\fR,
|
||||
/* \fIwhere_field\fR, and \fIadditional_conditions\fR parameters.
|
||||
/* .IP \fItable\fR
|
||||
/* When \fIquery\fR and \fIselect_function\fR are not defined, the name of the
|
||||
/* FROM table used to construct the default query template, see pgsql_table(5).
|
||||
/* .IP \fIselect_field\fR
|
||||
/* When \fIquery\fR and \fIselect_function\fR are not defined, the name of the
|
||||
/* SELECT field used to construct the default query template, see pgsql_table(5).
|
||||
/* .IP \fIwhere_field\fR
|
||||
/* When \fIquery\fR and \fIselect_function\fR are not defined, the name of the
|
||||
/* WHERE field used to construct the default query template, see pgsql_table(5).
|
||||
/* .IP \fIadditional_conditions\fR
|
||||
/* When \fIquery\fR and \fIselect_function\fR are not defined, the name of the
|
||||
/* additional text to add to the WHERE field in the default query template (this
|
||||
/* usually begins with "and") see pgsql_table(5).
|
||||
/* .IP \fIhosts\fR
|
||||
/* List of hosts to connect to.
|
||||
/* .PP
|
||||
@@ -151,6 +171,7 @@
|
||||
/* Global library. */
|
||||
|
||||
#include "cfg_parser.h"
|
||||
#include "db_common.h"
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
@@ -183,24 +204,19 @@ typedef struct {
|
||||
} PLPGSQL;
|
||||
|
||||
typedef struct {
|
||||
DICT dict;
|
||||
CFG_PARSER *parser;
|
||||
char *query;
|
||||
char *result_format;
|
||||
STRING_LIST *domain;
|
||||
void *ctx;
|
||||
int expansion_limit;
|
||||
char *username;
|
||||
char *password;
|
||||
char *dbname;
|
||||
char *table;
|
||||
char *query; /* if set, overrides fields, etc */
|
||||
char *select_function;
|
||||
char *select_field;
|
||||
char *where_field;
|
||||
char *additional_conditions;
|
||||
char **hostnames;
|
||||
int len_hosts;
|
||||
} PGSQL_NAME;
|
||||
|
||||
typedef struct {
|
||||
DICT dict;
|
||||
ARGV *hosts;
|
||||
PLPGSQL *pldb;
|
||||
PGSQL_NAME *name;
|
||||
} DICT_PGSQL;
|
||||
|
||||
|
||||
@@ -208,7 +224,7 @@ typedef struct {
|
||||
#define PGSQL_RES PGresult
|
||||
|
||||
/* internal function declarations */
|
||||
static PLPGSQL *plpgsql_init(char *hostnames[], int);
|
||||
static PLPGSQL *plpgsql_init(ARGV *);
|
||||
static PGSQL_RES *plpgsql_query(PLPGSQL *, const char *, char *, char *, char *);
|
||||
static void plpgsql_dealloc(PLPGSQL *);
|
||||
static void plpgsql_close_host(HOST *);
|
||||
@@ -217,213 +233,129 @@ static void plpgsql_connect_single(HOST *, char *, char *, char *);
|
||||
static const char *dict_pgsql_lookup(DICT *, const char *);
|
||||
DICT *dict_pgsql_open(const char *, int, int);
|
||||
static void dict_pgsql_close(DICT *);
|
||||
static PGSQL_NAME *pgsqlname_parse(const char *);
|
||||
static HOST *host_init(const char *);
|
||||
|
||||
|
||||
/* dict_pgsql_quote - escape SQL metacharacters in input string */
|
||||
|
||||
/**********************************************************************
|
||||
* public interface dict_pgsql_lookup
|
||||
* find database entry return 0 if no alias found, set dict_errno
|
||||
* on errors to DICT_ERROR_RETRY and set dict_errno to 0 on success
|
||||
*********************************************************************/
|
||||
static void pgsql_escape_string(char *new, const char *old, unsigned int len)
|
||||
static void dict_pgsql_quote(DICT *unused, const char *name, VSTRING *result)
|
||||
{
|
||||
unsigned int x,
|
||||
y;
|
||||
const char *sub;
|
||||
|
||||
/*
|
||||
* XXX We really should be using an escaper that is provided by the PGSQL
|
||||
* library. The code below seems to be over-kill (see RUS-CERT Advisory
|
||||
* 2001-08:01), but it's better to be safe than to be sorry -- Wietse
|
||||
*/
|
||||
for (x = 0, y = 0; x < len; x++, y++) {
|
||||
switch (old[x]) {
|
||||
for (sub = name; *sub; sub++) {
|
||||
switch(*sub) {
|
||||
case '\n':
|
||||
new[y++] = '\\';
|
||||
new[y] = 'n';
|
||||
vstring_strcat(result, "\\n");
|
||||
break;
|
||||
case '\r':
|
||||
new[y++] = '\\';
|
||||
new[y] = 'r';
|
||||
vstring_strcat(result, "\\r");
|
||||
break;
|
||||
case '\'':
|
||||
new[y++] = '\\';
|
||||
new[y] = '\'';
|
||||
vstring_strcat(result, "\\'");
|
||||
break;
|
||||
case '"':
|
||||
new[y++] = '\\';
|
||||
new[y] = '"';
|
||||
vstring_strcat(result, "\\\"");
|
||||
break;
|
||||
case 0:
|
||||
new[y++] = '\\';
|
||||
new[y] = '0';
|
||||
vstring_strcat(result, "\\0");
|
||||
break;
|
||||
default:
|
||||
new[y] = old[x];
|
||||
VSTRING_ADDCH(result, *sub);
|
||||
break;
|
||||
}
|
||||
}
|
||||
new[y] = 0;
|
||||
VSTRING_TERMINATE(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* expand a filter (lookup or result)
|
||||
*/
|
||||
static void dict_pgsql_expand_filter(char *filter, char *value, VSTRING *out)
|
||||
{
|
||||
const char *myname = "dict_pgsql_expand_filter";
|
||||
char *sub,
|
||||
*end;
|
||||
|
||||
/*
|
||||
* Yes, replace all instances of %s with the address to look up. Replace
|
||||
* %u with the user portion, and %d with the domain portion.
|
||||
*/
|
||||
sub = filter;
|
||||
end = sub + strlen(filter);
|
||||
while (sub < end) {
|
||||
|
||||
/*
|
||||
* Make sure it's %[sud] and not something else. For backward
|
||||
* compatibilty, treat anything other than %u or %d as %s, with a
|
||||
* warning.
|
||||
*/
|
||||
if (*(sub) == '%') {
|
||||
char *u = value;
|
||||
char *p = strrchr(u, '@');
|
||||
|
||||
switch (*(sub + 1)) {
|
||||
case 'd':
|
||||
if (p)
|
||||
vstring_strcat(out, p + 1);
|
||||
break;
|
||||
case 'u':
|
||||
if (p)
|
||||
vstring_strncat(out, u, p - u);
|
||||
else
|
||||
vstring_strcat(out, u);
|
||||
break;
|
||||
default:
|
||||
msg_warn
|
||||
("%s: Invalid filter substitution format '%%%c'!",
|
||||
myname, *(sub + 1));
|
||||
break;
|
||||
case 's':
|
||||
vstring_strcat(out, u);
|
||||
break;
|
||||
}
|
||||
sub++;
|
||||
} else
|
||||
vstring_strncat(out, sub, 1);
|
||||
sub++;
|
||||
}
|
||||
}
|
||||
/* dict_pgsql_lookup - find database entry */
|
||||
|
||||
static const char *dict_pgsql_lookup(DICT *dict, const char *name)
|
||||
{
|
||||
char *myname = "dict_pgsql_lookup";
|
||||
PGSQL_RES *query_res;
|
||||
DICT_PGSQL *dict_pgsql;
|
||||
PLPGSQL *pldb;
|
||||
static VSTRING *query;
|
||||
static VSTRING *result;
|
||||
static VSTRING *query = 0;
|
||||
int i,
|
||||
j,
|
||||
numrows;
|
||||
char *name_escaped = 0;
|
||||
int isFunctionCall;
|
||||
int i;
|
||||
int j;
|
||||
int numrows;
|
||||
int numcols;
|
||||
|
||||
int expansion;
|
||||
const char *r;
|
||||
|
||||
dict_pgsql = (DICT_PGSQL *) dict;
|
||||
pldb = dict_pgsql->pldb;
|
||||
/* initialization for query */
|
||||
query = vstring_alloc(24);
|
||||
vstring_strcpy(query, "");
|
||||
if ((name_escaped = (char *) mymalloc((sizeof(char) * (strlen(name) * 2) +1))) == NULL) {
|
||||
msg_fatal("dict_pgsql_lookup: out of memory.");
|
||||
}
|
||||
/* prepare the query */
|
||||
pgsql_escape_string(name_escaped, name, (unsigned int) strlen(name));
|
||||
|
||||
/* Build SQL - either a select from table or select a function */
|
||||
#define INIT_VSTR(buf, len) do { \
|
||||
if (buf == 0) \
|
||||
buf = vstring_alloc(len); \
|
||||
VSTRING_RESET(buf); \
|
||||
VSTRING_TERMINATE(buf); \
|
||||
} while (0)
|
||||
|
||||
isFunctionCall = (dict_pgsql->name->select_function != NULL);
|
||||
if (isFunctionCall) {
|
||||
vstring_sprintf(query, "select %s('%s')",
|
||||
dict_pgsql->name->select_function,
|
||||
name_escaped);
|
||||
} else if (dict_pgsql->name->query) {
|
||||
dict_pgsql_expand_filter(dict_pgsql->name->query, name_escaped, query);
|
||||
} else {
|
||||
vstring_sprintf(query, "select %s from %s where %s = '%s' %s",
|
||||
dict_pgsql->name->select_field,
|
||||
dict_pgsql->name->table,
|
||||
dict_pgsql->name->where_field,
|
||||
name_escaped,
|
||||
dict_pgsql->name->additional_conditions);
|
||||
INIT_VSTR(query, 10);
|
||||
INIT_VSTR(result, 10);
|
||||
|
||||
dict_errno = 0;
|
||||
/*
|
||||
* If there is a domain list for this map, then only search for
|
||||
* addresses in domains on the list. This can significantly reduce
|
||||
* the load on the server. Do not try "@domain" keys.
|
||||
*/
|
||||
if (db_common_check_domain(dict_pgsql->domain, name) == 0) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Skipping lookup of '%s'", myname, name);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("dict_pgsql_lookup using sql query: %s", vstring_str(query));
|
||||
|
||||
/* free mem associated with preparing the query */
|
||||
myfree(name_escaped);
|
||||
|
||||
/*
|
||||
* Suppress the actual lookup if the expansion is empty
|
||||
*/
|
||||
if (!db_common_expand(dict_pgsql->ctx, dict_pgsql->query,
|
||||
name, 0, query, dict_pgsql_quote))
|
||||
return (0);
|
||||
|
||||
/* do the query - set dict_errno & cleanup if there's an error */
|
||||
if ((query_res = plpgsql_query(pldb,
|
||||
vstring_str(query),
|
||||
dict_pgsql->name->dbname,
|
||||
dict_pgsql->name->username,
|
||||
dict_pgsql->name->password)) == 0) {
|
||||
if ((query_res = plpgsql_query(pldb, vstring_str(query),
|
||||
dict_pgsql->dbname,
|
||||
dict_pgsql->username,
|
||||
dict_pgsql->password)) == 0) {
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
vstring_free(query);
|
||||
return 0;
|
||||
}
|
||||
dict_errno = 0;
|
||||
/* free the vstring query */
|
||||
vstring_free(query);
|
||||
|
||||
numrows = PQntuples(query_res);
|
||||
if (msg_verbose)
|
||||
msg_info("dict_pgsql_lookup: retrieved %d rows", numrows);
|
||||
msg_info("%s: retrieved %d rows", myname, numrows);
|
||||
if (numrows == 0) {
|
||||
PQclear(query_res);
|
||||
return 0;
|
||||
}
|
||||
numcols = PQnfields(query_res);
|
||||
|
||||
if (numcols == 1 && numrows == 1 && isFunctionCall) {
|
||||
|
||||
/*
|
||||
* We do the above check because PostgreSQL 7.3 will allow functions
|
||||
* to return result sets
|
||||
*/
|
||||
if (PQgetisnull(query_res, 0, 0) == 1) {
|
||||
|
||||
/*
|
||||
* Functions returning a single row & column that is null are
|
||||
* deemed to have not found the key.
|
||||
*/
|
||||
PQclear(query_res);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (result == 0)
|
||||
result = vstring_alloc(10);
|
||||
|
||||
vstring_strcpy(result, "");
|
||||
for (i = 0; i < numrows; i++) {
|
||||
if (i > 0)
|
||||
vstring_strcat(result, ",");
|
||||
for (expansion = i = 0; i < numrows && dict_errno == 0; i++) {
|
||||
for (j = 0; j < numcols; j++) {
|
||||
if (j > 0)
|
||||
vstring_strcat(result, ",");
|
||||
vstring_strcat(result, PQgetvalue(query_res, i, j));
|
||||
if (msg_verbose > 1)
|
||||
msg_info("dict_pgsql_lookup: retrieved field: %d: %s", j, PQgetvalue(query_res, i, j));
|
||||
r = PQgetvalue(query_res, i, j);
|
||||
if (db_common_expand(dict_pgsql->ctx, dict_pgsql->result_format,
|
||||
r, name, result, 0)
|
||||
&& dict_pgsql->expansion_limit > 0
|
||||
&& ++expansion > dict_pgsql->expansion_limit) {
|
||||
msg_warn("%s: %s: Expansion limit exceeded for key: '%s'",
|
||||
myname, dict_pgsql->parser->name, name);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
PQclear(query_res);
|
||||
return vstring_str(result);
|
||||
r = vstring_str(result);
|
||||
return ((dict_errno == 0 && *r) ? r : 0);
|
||||
}
|
||||
|
||||
/* dict_pgsql_check_stat - check the status of a host */
|
||||
@@ -603,19 +535,87 @@ static void plpgsql_down_host(HOST *host)
|
||||
event_cancel_timer(dict_pgsql_event, (char *) host);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* public interface dict_pgsql_open
|
||||
* create association with database with appropriate values
|
||||
* parse the map's config file
|
||||
* allocate memory
|
||||
**********************************************************************/
|
||||
/* pgsql_parse_config - parse pgsql configuration file */
|
||||
|
||||
static void pgsql_parse_config(DICT_PGSQL *dict_pgsql, const char *pgsqlcf)
|
||||
{
|
||||
const char *myname = "pgsql_parse_config";
|
||||
CFG_PARSER *p;
|
||||
int i;
|
||||
char *hosts;
|
||||
VSTRING *query;
|
||||
char *select_function;
|
||||
char *domain;
|
||||
|
||||
p = dict_pgsql->parser = cfg_parser_alloc(pgsqlcf);
|
||||
dict_pgsql->username = cfg_get_str(p, "user", "", 0, 0);
|
||||
dict_pgsql->password = cfg_get_str(p, "password", "", 0, 0);
|
||||
dict_pgsql->dbname = cfg_get_str(p, "dbname", "", 1, 0);
|
||||
dict_pgsql->result_format = cfg_get_str(p, "result_format", "%s", 1, 0);
|
||||
/*
|
||||
* XXX: The default should be non-zero for safety, but that is not
|
||||
* backwards compatible.
|
||||
*/
|
||||
dict_pgsql->expansion_limit = cfg_get_int(dict_pgsql->parser,
|
||||
"expansion_limit", 0, 0, 0);
|
||||
|
||||
if ((dict_pgsql->query = cfg_get_str(p, "query", 0, 0, 0)) == 0) {
|
||||
/*
|
||||
* No query specified -- fallback to building it from components
|
||||
* ( old style "select %s from %s where %s" )
|
||||
*/
|
||||
query = vstring_alloc(64);
|
||||
select_function = cfg_get_str(p, "select_function", 0, 0, 0);
|
||||
if (select_function != 0) {
|
||||
vstring_sprintf(query, "SELECT %s('%%s')", select_function);
|
||||
myfree(select_function);
|
||||
} else
|
||||
db_common_sql_build_query(query, p);
|
||||
dict_pgsql->query = vstring_export(query);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must parse all templates before we can use db_common_expand()
|
||||
*/
|
||||
dict_pgsql->ctx = 0;
|
||||
(void) db_common_parse(&dict_pgsql->dict, &dict_pgsql->ctx,
|
||||
dict_pgsql->query, 1);
|
||||
(void) db_common_parse(0, &dict_pgsql->ctx, dict_pgsql->result_format, 0);
|
||||
|
||||
domain = cfg_get_str(p, "domain", "", 0, 0);
|
||||
if (*domain) {
|
||||
if (!(dict_pgsql->domain = string_list_init(MATCH_FLAG_NONE, domain)))
|
||||
/*
|
||||
* The "domain" optimization skips input keys that may in fact
|
||||
* have unwanted matches in the database, so failure to create
|
||||
* the match list is fatal.
|
||||
*/
|
||||
msg_fatal("%s: %s: domain match list creation using '%s' failed",
|
||||
myname, pgsqlcf, domain);
|
||||
}
|
||||
else
|
||||
dict_pgsql->domain = 0;
|
||||
myfree(domain);
|
||||
|
||||
hosts = cfg_get_str(p, "hosts", "", 0, 0);
|
||||
|
||||
dict_pgsql->hosts = argv_split(hosts, " ,\t\r\n");
|
||||
if (dict_pgsql->hosts == 0) {
|
||||
argv_add(dict_pgsql->hosts, "localhost", ARGV_END);
|
||||
argv_terminate(dict_pgsql->hosts);
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s: no hostnames specified, defaulting to '%s'",
|
||||
myname, pgsqlcf, dict_pgsql->hosts->argv[0]);
|
||||
}
|
||||
myfree(hosts);
|
||||
}
|
||||
|
||||
/* dict_pgsql_open - open PGSQL data base */
|
||||
|
||||
DICT *dict_pgsql_open(const char *name, int open_flags, int dict_flags)
|
||||
{
|
||||
DICT_PGSQL *dict_pgsql;
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
if (open_flags != O_RDONLY)
|
||||
msg_fatal("%s:%s map requires O_RDONLY access mode",
|
||||
DICT_TYPE_PGSQL, name);
|
||||
@@ -624,122 +624,33 @@ DICT *dict_pgsql_open(const char *name, int open_flags, int dict_flags)
|
||||
sizeof(DICT_PGSQL));
|
||||
dict_pgsql->dict.lookup = dict_pgsql_lookup;
|
||||
dict_pgsql->dict.close = dict_pgsql_close;
|
||||
dict_pgsql->name = pgsqlname_parse(name);
|
||||
dict_pgsql->pldb = plpgsql_init(dict_pgsql->name->hostnames,
|
||||
dict_pgsql->name->len_hosts);
|
||||
pgsql_parse_config(dict_pgsql, name);
|
||||
dict_pgsql->pldb = plpgsql_init(dict_pgsql->hosts);
|
||||
dict_pgsql->dict.flags = dict_flags | DICT_FLAG_FIXED;
|
||||
if (dict_pgsql->pldb == NULL)
|
||||
msg_fatal("couldn't intialize pldb!\n");
|
||||
return &dict_pgsql->dict;
|
||||
}
|
||||
|
||||
/* pgsqlname_parse - parse pgsql configuration file */
|
||||
static PGSQL_NAME *pgsqlname_parse(const char *pgsqlcf)
|
||||
{
|
||||
const char *myname = "pgsqlname_parse";
|
||||
int i;
|
||||
char *hosts;
|
||||
PGSQL_NAME *name = (PGSQL_NAME *) mymalloc(sizeof(PGSQL_NAME));
|
||||
ARGV *hosts_argv;
|
||||
/* plpgsql_init - initalize a PGSQL database */
|
||||
|
||||
name->parser = cfg_parser_alloc(pgsqlcf);
|
||||
|
||||
/* username */
|
||||
name->username = cfg_get_str(name->parser, "user", "", 0, 0);
|
||||
|
||||
/* password */
|
||||
name->password = cfg_get_str(name->parser, "password", "", 0, 0);
|
||||
|
||||
/* database name lookup */
|
||||
name->dbname = cfg_get_str(name->parser, "dbname", "", 1, 0);
|
||||
|
||||
/*
|
||||
* See what kind of lookup we have - a traditional 'select' or a function
|
||||
* call
|
||||
*/
|
||||
name->select_function = cfg_get_str(name->parser, "select_function",
|
||||
NULL, 0, 0);
|
||||
name->query = cfg_get_str(name->parser, "query", NULL, 0, 0);
|
||||
|
||||
if (name->select_function == 0 && name->query == 0) {
|
||||
|
||||
/*
|
||||
* We have an old style 'select %s from %s...' call
|
||||
*/
|
||||
|
||||
/* table name */
|
||||
name->table = cfg_get_str(name->parser, "table", "", 1, 0);
|
||||
|
||||
/* select field */
|
||||
name->select_field = cfg_get_str(name->parser, "select_field",
|
||||
"", 1, 0);
|
||||
|
||||
/* where field */
|
||||
name->where_field = cfg_get_str(name->parser, "where_field",
|
||||
"", 1, 0);
|
||||
|
||||
/* additional conditions */
|
||||
name->additional_conditions = cfg_get_str(name->parser,
|
||||
"additional_conditions",
|
||||
"", 0, 0);
|
||||
} else {
|
||||
name->table = 0;
|
||||
name->select_field = 0;
|
||||
name->where_field = 0;
|
||||
name->additional_conditions = 0;
|
||||
}
|
||||
|
||||
/* server hosts */
|
||||
hosts = cfg_get_str(name->parser, "hosts", "", 0, 0);
|
||||
|
||||
/* coo argv interface */
|
||||
hosts_argv = argv_split(hosts, " ,\t\r\n");
|
||||
if (hosts_argv->argc == 0) { /* no hosts specified,
|
||||
* default to 'localhost' */
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s: no hostnames specified, defaulting to 'localhost'",
|
||||
myname, pgsqlcf);
|
||||
argv_add(hosts_argv, "localhost", ARGV_END);
|
||||
argv_terminate(hosts_argv);
|
||||
}
|
||||
name->len_hosts = hosts_argv->argc;
|
||||
name->hostnames = (char **) mymalloc((sizeof(char *)) * name->len_hosts);
|
||||
i = 0;
|
||||
for (i = 0; hosts_argv->argv[i] != NULL; i++) {
|
||||
name->hostnames[i] = mystrdup(hosts_argv->argv[i]);
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s: adding host '%s' to list of pgsql server hosts",
|
||||
myname, pgsqlcf, name->hostnames[i]);
|
||||
}
|
||||
myfree(hosts);
|
||||
argv_free(hosts_argv);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* plpgsql_init - initalize a PGSQL database.
|
||||
* Return NULL on failure, or a PLPGSQL * on success.
|
||||
*/
|
||||
static PLPGSQL *plpgsql_init(char *hostnames[], int len_hosts)
|
||||
static PLPGSQL *plpgsql_init(ARGV *hosts)
|
||||
{
|
||||
PLPGSQL *PLDB;
|
||||
int i;
|
||||
|
||||
if ((PLDB = (PLPGSQL *) mymalloc(sizeof(PLPGSQL))) == NULL) {
|
||||
msg_fatal("mymalloc of pldb failed");
|
||||
}
|
||||
PLDB->len_hosts = len_hosts;
|
||||
if ((PLDB->db_hosts = (HOST **) mymalloc(sizeof(HOST *) * len_hosts)) == NULL)
|
||||
return NULL;
|
||||
for (i = 0; i < len_hosts; i++) {
|
||||
PLDB->db_hosts[i] = host_init(hostnames[i]);
|
||||
}
|
||||
PLDB = (PLPGSQL *) mymalloc(sizeof(PLPGSQL));
|
||||
PLDB->len_hosts = hosts->argc;
|
||||
PLDB->db_hosts = (HOST **) mymalloc(sizeof(HOST *) * hosts->argc);
|
||||
for (i = 0; i < hosts->argc; i++)
|
||||
PLDB->db_hosts[i] = host_init(hosts->argv[i]);
|
||||
|
||||
return PLDB;
|
||||
}
|
||||
|
||||
|
||||
/* host_init - initialize HOST structure */
|
||||
|
||||
static HOST *host_init(const char *hostname)
|
||||
{
|
||||
const char *myname = "pgsql host_init";
|
||||
@@ -773,41 +684,31 @@ static HOST *host_init(const char *hostname)
|
||||
return host;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* public interface dict_pgsql_close
|
||||
* unregister, disassociate from database, freeing appropriate memory
|
||||
**********************************************************************/
|
||||
/* dict_pgsql_close - close PGSQL data base */
|
||||
|
||||
static void dict_pgsql_close(DICT *dict)
|
||||
{
|
||||
int i;
|
||||
DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
|
||||
|
||||
plpgsql_dealloc(dict_pgsql->pldb);
|
||||
cfg_parser_free(dict_pgsql->name->parser);
|
||||
myfree(dict_pgsql->name->username);
|
||||
myfree(dict_pgsql->name->password);
|
||||
myfree(dict_pgsql->name->dbname);
|
||||
if (dict_pgsql->name->table)
|
||||
myfree(dict_pgsql->name->table);
|
||||
if (dict_pgsql->name->query)
|
||||
myfree(dict_pgsql->name->query);
|
||||
if (dict_pgsql->name->select_function)
|
||||
myfree(dict_pgsql->name->select_function);
|
||||
if (dict_pgsql->name->select_field)
|
||||
myfree(dict_pgsql->name->select_field);
|
||||
if (dict_pgsql->name->where_field)
|
||||
myfree(dict_pgsql->name->where_field);
|
||||
if (dict_pgsql->name->additional_conditions)
|
||||
myfree(dict_pgsql->name->additional_conditions);
|
||||
for (i = 0; i < dict_pgsql->name->len_hosts; i++) {
|
||||
myfree(dict_pgsql->name->hostnames[i]);
|
||||
}
|
||||
myfree((char *) dict_pgsql->name->hostnames);
|
||||
myfree((char *) dict_pgsql->name);
|
||||
cfg_parser_free(dict_pgsql->parser);
|
||||
myfree(dict_pgsql->username);
|
||||
myfree(dict_pgsql->password);
|
||||
myfree(dict_pgsql->dbname);
|
||||
myfree(dict_pgsql->query);
|
||||
myfree(dict_pgsql->result_format);
|
||||
if (dict_pgsql->domain)
|
||||
string_list_free(dict_pgsql->domain);
|
||||
if (dict_pgsql->hosts)
|
||||
argv_free(dict_pgsql->hosts);
|
||||
if (dict_pgsql->ctx)
|
||||
db_common_free_ctx(dict_pgsql->ctx);
|
||||
dict_free(dict);
|
||||
}
|
||||
|
||||
/* plpgsql_dealloc - free memory associated with PLPGSQL close databases */
|
||||
|
||||
static void plpgsql_dealloc(PLPGSQL *PLDB)
|
||||
{
|
||||
int i;
|
||||
|
@@ -20,8 +20,8 @@
|
||||
* Patches change the patchlevel and the release date. Snapshots change the
|
||||
* release date only.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20050304"
|
||||
#define MAIL_VERSION_NUMBER "2.2"
|
||||
#define MAIL_RELEASE_DATE "20050308"
|
||||
#define MAIL_VERSION_NUMBER "2.3"
|
||||
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#ifdef SNAPSHOT
|
||||
|
@@ -416,7 +416,7 @@ DNS_RR *smtp_domain_addr(char *name, int misc_flags, VSTRING *why,
|
||||
if (addr_list == 0) {
|
||||
if (var_smtp_defer_mxaddr)
|
||||
smtp_errno = SMTP_ERR_RETRY;
|
||||
msg_warn("no MX host for %s has a valid A record", name);
|
||||
msg_warn("no MX host for %s has a valid address record", name);
|
||||
break;
|
||||
}
|
||||
best_found = (addr_list ? addr_list->pref : IMPOSSIBLE_PREFERENCE);
|
||||
|
@@ -2260,6 +2260,33 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
|
||||
else
|
||||
domain = name;
|
||||
|
||||
/*
|
||||
* Treat an address literal as its own MX server, just like we treat a
|
||||
* name without MX record as its own MX server. There is, however, no
|
||||
* applicable NS server equivalent.
|
||||
*/
|
||||
if (*domain == '[') {
|
||||
char *saved_addr;
|
||||
const char *bare_addr;
|
||||
int len;
|
||||
|
||||
if (type != T_MX)
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
len = strlen(domain);
|
||||
if (domain[len - 1] != ']')
|
||||
return (SMTPD_CHECK_DUNNO);
|
||||
/* Memory leak alert: no early returns after this point. */
|
||||
saved_addr = mystrndup(domain + 1, len - 2);
|
||||
if ((bare_addr = valid_mailhost_addr(saved_addr, DONT_GRIPE)) == 0)
|
||||
status = SMTPD_CHECK_DUNNO;
|
||||
else
|
||||
status = check_addr_access(state, table, bare_addr, FULL,
|
||||
&found, reply_name, reply_class,
|
||||
def_acl);
|
||||
myfree(saved_addr);
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the domain name does not exist then we apply no restriction.
|
||||
*
|
||||
|
Reference in New Issue
Block a user