diff --git a/postfix/HISTORY b/postfix/HISTORY
index 9f25df299..581117f68 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -7630,11 +7630,8 @@ Apologies for any names omitted.
20030102
- Workaround: use different client instances when the same
- map is opened with different flags. This silences warnings
- from maps_append() when the same map is opened by
- virtual_alias_maps and by virtual_mailbox_maps. File:
- global/maps.c.
+ Cleanup: use different client instances when the same map
+ is opened with different flags. File: global/maps.c.
Feature: proxymap server for Postfix table lookups. This
helps to consolidate the number of open lookup tables (such
@@ -7649,6 +7646,25 @@ Apologies for any names omitted.
after the limit is reached. Based on a patch by Victor
Duchovni, Morgan Stanley. File: master/multi_server.c.
+20030103
+
+ Cleanup: client stream endpoints not only have an idle time
+ limit ($ipc_idle) before a connection is closed, they now
+ also have a time to live ($ipc_ttl) to prevent connections
+ from becoming too persistent. This allows multi-servers
+ such as trivial-rewrite or the proxymap server to refresh
+ more frequently on busy systems. File: global/clnt_stream.c.
+
+20030104
+
+ Cleanup: avoid warnings about flag mismatches when the same
+ lookup table is listed under both virtual_alias_maps and
+ virtual_mailbox_maps. Files: global/virtual8.h, virtual/virtual.c.
+
+ Bugfix: an obscure memory leak that puzzled me for more
+ than a year until I found out how to reproduce it. File:
+ util/vstream.c.
+
Open problems:
Med: do not postpone rejected "MAIL FROM" size information,
diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES
index 24526a461..68ae6f7a0 100644
--- a/postfix/RELEASE_NOTES
+++ b/postfix/RELEASE_NOTES
@@ -22,6 +22,37 @@ snapshot release). Patches change the patchlevel and the release
date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release.
+Incompatible changes with Postfix snapshot 2.0.0-20030104
+=========================================================
+
+This release adds the new proxymap service (table lookup via a
+proxy process) to the the master.cf file. If you get warnings about
+problems connecting to the proxymap service, then you did not
+properly upgrade Postfix.
+
+Major changes with Postfix snapshot 2.0.0-20030104
+==================================================
+
+This release introduces the proxymap service for Postfix lookup
+table access. This can be used to overcome chroot restrictions in
+the Postfix SMTP server (specify proxy:unix:passwd.byname for
+password file lookup through the proxymap server) and can be used
+to consolidate the number of open tables by sharing one open table
+among multiple processes (specify proxy:mysql:/file/name to avoid
+"too many connections" conditions). The proxy_read_maps parameter
+specifies what maps are approved for access via the proxy service
+(only map references starting with "proxy:" are considered approved).
+
+Multi-server daemons (servers that accept simultaneous connections
+from multiple clients) will now stop accepting new connections
+after serving $max_use clients. This allows multi-server daemons
+to automatically restart even on busy mail systems.
+
+Clients of multi-server daemons such as trivial-rewrite and the
+new proxymap service now automatically disconnect after $ipc_ttl
+seconds of activity (default: 1000s). This allows multi-server
+daemons to automatically restart even on busy mail mail systems.
+
Incompatible changes with Postfix snapshot 1.1.11-trace-20021119
================================================================
diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf
index c5ebc9987..f088bd1c9 100644
--- a/postfix/conf/main.cf
+++ b/postfix/conf/main.cf
@@ -175,18 +175,20 @@ mail_owner = postfix
# For example, you define $mydestination domain recipients in
# the $virtual_mailbox_maps files.
#
-# - You redefined the local delivery agent in master.cf.
+# - You redefine the local delivery agent in master.cf.
#
-# - You redefined the "local_transport" setting in main.cf.
+# - You redefine the "local_transport" setting in main.cf.
#
# - You use the "luser_relay", "mailbox_transport", or "fallback_transport"
# feature of the Postfix local delivery agent (see sample-local.cf).
#
# Beware: if the Postfix SMTP server runs chrooted, you probably have
-# to copy the passwd (not shadow) database into the jail, and perhaps
-# other files. This is system dependent.
+# to access the passwd file via the proxymap service, in order to
+# overcome chroot restrictions. The alternative, having a copy of
+# the system passwd file in the chroot jail is just not practical.
#
#local_recipient_maps = unix:passwd.byname $alias_maps
+#local_recipient_maps = proxy:passwd.byname $alias_maps
#local_recipient_maps =
# The unknown_local_recipient_reject_code specifies the SMTP server
diff --git a/postfix/conf/sample-local.cf b/postfix/conf/sample-local.cf
index c901c0b24..e15bff232 100644
--- a/postfix/conf/sample-local.cf
+++ b/postfix/conf/sample-local.cf
@@ -11,6 +11,10 @@
# precedence, from highest to lowest priority: mailbox_transport,
# mailbox_command_maps, mailbox_command, home_mailbox.
+#
+# MISCELLANEOUS PARAMETERS
+#
+
# The biff parameter specifies whether or not to contact the biff
# server. This server sends "new mail" notifications to users who
# have requested new mail notification with "biff y".
diff --git a/postfix/conf/sample-misc.cf b/postfix/conf/sample-misc.cf
index 18792e312..2c83b8a34 100644
--- a/postfix/conf/sample-misc.cf
+++ b/postfix/conf/sample-misc.cf
@@ -236,7 +236,7 @@ max_use = 100
# a name matches a lookup key. Continue long lines by starting the
# next line with whitespace.
#
-# See sample-local.cf for a description of the local_recipient_maps
+# See sample-smtpd.cf for a description of the local_recipient_maps
# and unknown_local_recipient_reject_code parameters. By default,
# the SMTP server rejects mail for recipients not listed with the
# local_recipient_maps parameter.
diff --git a/postfix/conf/sample-smtpd.cf b/postfix/conf/sample-smtpd.cf
index 4fd7c08cc..ac9b17bef 100644
--- a/postfix/conf/sample-smtpd.cf
+++ b/postfix/conf/sample-smtpd.cf
@@ -4,6 +4,65 @@
# This file contains example settings of Postfix configuration parameters
# that control the SMTP server program.
+# REJECTING MAIL FOR UNKNOWN LOCAL USERS
+#
+# The local_recipient_maps parameter specifies optional lookup tables
+# with all names or addresses of users that are local with respect
+# to $mydestination and $inet_interfaces.
+#
+# If this parameter is defined, then the SMTP server will reject
+# mail for unknown local users. This parameter is defined by default.
+#
+# To turn off local recipient checking in the SMTP server, specify
+# local_recipient_maps = (i.e. empty).
+#
+# The default setting assumes that you use the default Postfix local
+# delivery agent for local delivery. You need to update the
+# local_recipient_maps setting if:
+#
+# - You define $mydestination domain recipients in files other than
+# /etc/passwd, /etc/aliases, or the $virtual_alias_maps files.
+# For example, you define $mydestination domain recipients in
+# the $virtual_mailbox_maps files.
+#
+# - You redefine the local delivery agent in master.cf.
+#
+# - You redefine the "local_transport" setting in main.cf.
+#
+# - You use the "luser_relay", "mailbox_transport", or "fallback_transport"
+# feature of the Postfix local delivery agent (see sample-local.cf).
+#
+# Beware: if the Postfix SMTP server runs chrooted, you probably have
+# to access the passwd file via the proxymap service, in order to
+# overcome chroot restrictions. The alternative, having a copy of
+# the system passwd file in the chroot jail is just not practical.
+#
+#local_recipient_maps =
+#local_recipient_maps = unix:passwd.byname $alias_maps
+local_recipient_maps = proxy:passwd.byname $alias_maps
+
+# The unknown_local_recipient_reject_code specifies the SMTP server
+# response code when a recipient domain matches $mydestination or
+# $inet_interfaces, while $local_recipient_maps is non-empty and the
+# recipient address or address local-part is not found.
+#
+# The default setting is 550 (reject mail) but it is safer to start
+# with 450 (try again later) until you are certain that your
+# local_recipient_maps settings are OK.
+#
+#unknown_local_recipient_reject_code = 450
+unknown_local_recipient_reject_code = 550
+
+# REJECTING UNKNOWN RELAY USERS
+#
+# The relay_recipient_maps parameter specifies optional lookup tables
+# with all addresses in the domains that match $relay_domains.
+#
+# If this parameter is defined, then the SMTP server will reject
+# mail for unknown relay users. This feature is off by default.
+#
+#relay_recipient_maps = hash:/etc/postfix/relay_recipients
+
#
# SENDER ANTI-SPOOFING
#
diff --git a/postfix/html/faq.html b/postfix/html/faq.html
index 587d0e283..31ef4b176 100644
--- a/postfix/html/faq.html
+++ b/postfix/html/faq.html
@@ -674,7 +674,7 @@ to send mail only to user@domain.com.
Specify what recipients exist (so that your queue does not fill up
with undeliverable mail from spammers).
-
Specify local_recipient_maps = if maintaining recipient
information is not practical.
@@ -2090,7 +2090,7 @@ you use the default Postfix local delivery agent:
/etc/postfix/main.cf:
- local_recipient_maps = $alias_maps, unix:passwd.byname
+ local_recipient_maps = $alias_maps, proxy:unix:passwd.byname
@@ -2107,10 +2107,12 @@ To stop Postfix from rejecting local mail incorrectly:
-- If you run the Postfix SMTP server chrooted, it may be necessary
-to place a copy of the passwd file inside the chroot jail (typically:
-in /var/spool/postfix/etc). This is system dependent. The
-only way to find out is to try.
+
- If you run the Postfix SMTP server chrooted, you need to access
+the system password database through the Postfix
+proxymap service, as shown in the above example. The alternative
+is simply not practical: placing a copy of the passwd file inside
+the chroot jail (typically: in /var/spool/postfix/etc)
+together with a list of system dependent files.
@@ -2313,21 +2315,30 @@ database" mean?
This message is logged when, for example, the Postfix SMTP server
is unable to access the UNIX password database.
+
+
diff --git a/postfix/html/postconf.1.html b/postfix/html/postconf.1.html
index b13c0357d..4289928bf 100644
--- a/postfix/html/postconf.1.html
+++ b/postfix/html/postconf.1.html
@@ -91,7 +91,7 @@ POSTCONF(1) POSTCONF(1)
proxy (read-only)
A lookup table that is implemented via the
- Postfix proxymap(8) service. The table name
+ Postfix proxymap(8) service. The table name
syntax is type:name.
regexp (read-only)
diff --git a/postfix/html/proxymap.8.html b/postfix/html/proxymap.8.html
index bc96ab220..e1d0cf4b7 100644
--- a/postfix/html/proxymap.8.html
+++ b/postfix/html/proxymap.8.html
@@ -15,34 +15,39 @@ PROXYMAP(8) PROXYMAP(8)
o To overcome chroot restrictions. For example, a
chrooted SMTP server needs access to the system
passwd file in order to reject mail for non-exis-
- tent local addresses. The solution is to specify:
+ tent local addresses, but it is not practical to
+ maintain a copy of the passwd file in the chroot
+ jail. The solution:
local_recipient_maps =
proxy:unix:passwd.byname $alias_maps
o To consolidate the number of open lookup tables by
sharing one open table among multiple processes.
- For example, to avoid problems due to "too many
- connections" to, e.g., mysql servers, specify:
+ For example, making mysql connections from every
+ Postfix daemon process results in "too many connec-
+ tions" errors. The solution:
virtual_alias_maps =
proxy:mysql:/etc/postfix/virtual.cf
-PROXYMAP SERVICES
+ The total number of connections is limited by the
+ number of proxymap server server processes.
+
The proxymap server implements the following requests:
PROXY_REQ_OPEN maptype:mapname flags
Open the table with type maptype and name mapname,
as controlled by flags. The reply is the request
- completion status code and the map type dependent
- flags.
+ completion status code (below) and the map type
+ dependent flags.
PROXY_REQ_LOOKUP maptype:mapname flags key
Look up the data stored under the requested key.
- The reply is the request completion status code and
- the lookup result value. The maptype:mapname and
- flags are the same as with the PROXY_REQ_OPEN
- request.
+ The reply is the request completion status code
+ (below) and the lookup result value. The map-
+ type:mapname and flags are the same as with the
+ PROXY_REQ_OPEN request.
There is no close command. This does not seem to be useful
because tables are meant to be shared among client pro-
@@ -51,52 +56,63 @@ PROXYMAP(8) PROXYMAP(8)
The request completion status code is one of:
PROXY_STAT_OK
- The requested table or lookup key was found.
+ The specified table was opened, or the requested
+ entry was found.
- PROXY_STAT_FAIL
- The requested table or lookup key does not exist.
+ PROXY_STAT_NOKEY
+ The requested table entry was not found.
PROXY_STAT_BAD
- The request was rejected (bad request parameter
+ The request was rejected (bad request parameter
value).
PROXY_STAT_RETRY
- The request was not completed.
+ The lookup request could not be completed.
-MASTER INTERFACE
+ PROXY_STAT_DENY
+ The specified table was not approved for access via
+ the proxymap service.
+
+SERVER PROCESS MANAGEMENT
The proxymap servers run under control by the Postfix mas-
ter server. Each server can handle multiple simultaneous
connections. When all servers are busy while a client
connects, the master creates a new proxymap server pro-
cess, provided that the proxymap server process limit is
- not exceeded. Each proxymap server terminates after serv-
- ing $max_use clients or after $max_idle seconds of idle
- time.
+ not exceeded. Each proxymap server stops accepting new
+ connections after serving $max_use clients or terminates
+ after $max_idle seconds of idle time.
SECURITY
- The proxymap server is not security-sensitive. It opens
- only tables that are approved via the proxymap_filter con-
- figuration parameter, does not talk to users, and can run
- at fixed low privilege, chrooted or not.
+ The proxymap server opens only tables that are approved
+ via the proxy_read_maps configuration parameter, does not
+ talk to users, and can run at fixed low privilege,
+ chrooted or not.
+
+ The proxymap server is not a trusted daemon process, and
+ must not be used to look up sensitive information such as
+ user or group IDs, mailbox file/directory names or exter-
+ nal commands.
DIAGNOSTICS
Problems and transactions are logged to syslogd(8).
BUGS
- The proxymap server provides service to multiple clients,
- and must therefore not be used for tables that have high-
+ The proxymap server provides service to multiple clients,
+ and must therefore not be used for tables that have high-
latency lookups.
CONFIGURATION PARAMETERS
- The following main.cf parameters are especially relevant
- to this program. Use the postfix reload command after a
+ The following main.cf parameters are especially relevant
+ to this program. Use the postfix reload command after a
configuration change.
- proxymap_filter
- A list of zero or more parameter values that may
- contain Postfix lookup table references. Only table
- references that begin with proxy: are approved for
- access via the proxymap server.
+ proxy_read_maps
+ A list of zero or more parameter values that may
+ contain references to Postfix lookup tables. Only
+ table references that begin with proxy: are
+ approved for read-only access via the proxymap
+ server.
SEE ALSO
dict_proxy(3) proxy map client
diff --git a/postfix/html/trivial-rewrite.8.html b/postfix/html/trivial-rewrite.8.html
index 97ce29da9..9705a6732 100644
--- a/postfix/html/trivial-rewrite.8.html
+++ b/postfix/html/trivial-rewrite.8.html
@@ -37,14 +37,6 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8)
The envelope recipient address that is
passed on to nexthop.
- trivial-rewrite servers run under control by the Postfix
- master server. Each server can handle multiple simultane-
- ous connections. When all servers are busy while a client
- connects, a new server process is created, provided that
- the trivial-rewrite server process limit is not exceeded.
- Each server terminates after serving $max_use clients or
- after $max_idle seconds of idle time.
-
DEFAULT DELIVERY METHODS
By default, Postfix uses one of the following delivery
methods. This may be overruled with the optional trans-
@@ -83,14 +75,24 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8)
$relayhost. The default nexthop is the recipient
domain.
+SERVER PROCESS MANAGEMENT
+ The trivial-rewrite servers run under control by the Post-
+ fix master server. Each server can handle multiple simul-
+ taneous connections. When all servers are busy while a
+ client connects, the master creates a new server process,
+ provided that the trivial-rewrite server process limit is
+ not exceeded. Each trivial-rewrite server stops accepting
+ new connections after serving $max_use clients or termi-
+ nates after $max_idle seconds of idle time.
+
STANDARDS
- None. The command does not interact with the outside
+ None. The command does not interact with the outside
world.
SECURITY
- The trivial-rewrite daemon is not security sensitive. By
- default, this daemon does not talk to remote or local
- users. It can run at a fixed low privilege in a chrooted
+ The trivial-rewrite daemon is not security sensitive. By
+ default, this daemon does not talk to remote or local
+ users. It can run at a fixed low privilege in a chrooted
environment.
DIAGNOSTICS
@@ -98,21 +100,21 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8)
BUGS
CONFIGURATION PARAMETERS
- The following main.cf parameters are especially relevant
- to this program. See the Postfix main.cf file for syntax
- details and for default values. Use the postfix reload
+ The following main.cf parameters are especially relevant
+ to this program. See the Postfix main.cf file for syntax
+ details and for default values. Use the postfix reload
command after a configuration change.
Miscellaneous
empty_address_recipient
- The recipient that is substituted for the null
+ The recipient that is substituted for the null
address.
inet_interfaces
- The network interfaces that this mail system
- receives mail on. This information is used to
- determine if user@[net.work.addr.ess] is local or
- remote. Mail for local users is given to the
+ The network interfaces that this mail system
+ receives mail on. This information is used to
+ determine if user@[net.work.addr.ess] is local or
+ remote. Mail for local users is given to the
$local_transport.
mydestination
@@ -121,7 +123,7 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8)
virtual_alias_domains
List of simulated virtual domains (domains with all
- recipients aliased to some other local or remote
+ recipients aliased to some other local or remote
domain).
virtual_mailbox_domains
@@ -134,10 +136,10 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8)
resolve_unquoted_address
When resolving an address, do not quote the address
- localpart as per RFC 822, so that additional @, %
- or ! characters remain visible. This is techni-
+ localpart as per RFC 822, so that additional @, %
+ or ! characters remain visible. This is techni-
cally incorrect, but allows us to stop relay
- attacks when forwarding mail to a Sendmail primary
+ attacks when forwarding mail to a Sendmail primary
MX host.
relocated_maps
@@ -163,50 +165,50 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8)
Routing
local_transport
- Where to deliver mail for destinations that match
- $mydestination or $inet_interfaces. The default
+ Where to deliver mail for destinations that match
+ $mydestination or $inet_interfaces. The default
transport is local:$myhostname.
+ Syntax is transport:nexthop; see transport(5) for
+ details. The :nexthop part is optional.
+
+ virtual_transport
+ Where to deliver mail for non-local domains that
+ match $virtual_mailbox_domains. The default trans-
+ port is virtual.
+
Syntax is transport:nexthop; see transport(5) for
details. The :nexthop part is optional.
- virtual_transport
- Where to deliver mail for non-local domains that
- match $virtual_mailbox_domains. The default trans-
- port is virtual.
-
- Syntax is transport:nexthop; see transport(5) for
- details. The :nexthop part is optional.
-
relay_transport
- Where to deliver mail for non-local domains that
- match $relay_domains. The default transport is
+ Where to deliver mail for non-local domains that
+ match $relay_domains. The default transport is
relay (which normally is a clone of the smtp trans-
port).
- Syntax is transport:nexthop; see transport(5) for
+ Syntax is transport:nexthop; see transport(5) for
details. The :nexthop part is optional.
default_transport
- Where to deliver all other non-local mail. The
+ Where to deliver all other non-local mail. The
default transport is smtp.
- Syntax is transport:nexthop; see transport(5) for
+ Syntax is transport:nexthop; see transport(5) for
details. The :nexthop part is optional.
parent_domain_matches_subdomains
- List of Postfix features that use domain.tld pat-
- terns to match sub.domain.tld (as opposed to
+ List of Postfix features that use domain.tld pat-
+ terns to match sub.domain.tld (as opposed to
requiring .domain.tld patterns).
relayhost
- The default host to send non-local mail to when no
- host is specified with $relay_transport or
- $default_transport, and when the recipient address
+ The default host to send non-local mail to when no
+ host is specified with $relay_transport or
+ $default_transport, and when the recipient address
does not match the optional the transport(5) table.
transport_maps
- List of tables with recipient or domain to (trans-
+ List of tables with recipient or domain to (trans-
port, nexthop) mappings.
SEE ALSO
@@ -216,7 +218,7 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8)
relocated(5) format of the "user has moved" table
LICENSE
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
AUTHOR(S)
diff --git a/postfix/man/man8/proxymap.8 b/postfix/man/man8/proxymap.8
index 533ef958d..876563fdb 100644
--- a/postfix/man/man8/proxymap.8
+++ b/postfix/man/man8/proxymap.8
@@ -18,35 +18,35 @@ of the service is:
.IP \(bu
To overcome chroot restrictions. For example, a chrooted SMTP
server needs access to the system passwd file in order to
-reject mail for non-existent local addresses.
-The solution is to specify:
+reject mail for non-existent local addresses, but it is not
+practical to maintain a copy of the passwd file in the chroot
+jail. The solution:
.sp
local_recipient_maps =
.ti +4
proxy:unix:passwd.byname $alias_maps
.IP \(bu
To consolidate the number of open lookup tables by sharing
-one open table among multiple processes. For example, to avoid
-problems due to "too many connections" to, e.g., mysql servers,
-specify:
+one open table among multiple processes. For example, making
+mysql connections from every Postfix daemon process results
+in "too many connections" errors. The solution:
.sp
virtual_alias_maps =
.ti +4
proxy:mysql:/etc/postfix/virtual.cf
-.SH PROXYMAP SERVICES
-.na
-.nf
-.ad
-.fi
+.sp
+The total number of connections is limited by the number of
+proxymap server server processes.
+.PP
The proxymap server implements the following requests:
.IP "\fBPROXY_REQ_OPEN\fI maptype:mapname flags\fR"
Open the table with type \fImaptype\fR and name \fImapname\fR,
as controlled by \fIflags\fR.
-The reply is the request completion status code and the
+The reply is the request completion status code (below) and the
map type dependent flags.
.IP "\fBPROXY_REQ_LOOKUP\fI maptype:mapname flags key\fR"
Look up the data stored under the requested key.
-The reply is the request completion status code and
+The reply is the request completion status code (below) and
the lookup result value.
The \fImaptype:mapname\fR and \fIflags\fR are the same
as with the \fBPROXY_REQ_OPEN\fR request.
@@ -56,14 +56,17 @@ because tables are meant to be shared among client processes.
The request completion status code is one of:
.IP \fBPROXY_STAT_OK\fR
-The requested table or lookup key was found.
-.IP \fBPROXY_STAT_FAIL\fR
-The requested table or lookup key does not exist.
+The specified table was opened, or the requested entry was found.
+.IP \fBPROXY_STAT_NOKEY\fR
+The requested table entry was not found.
.IP \fBPROXY_STAT_BAD\fR
The request was rejected (bad request parameter value).
.IP \fBPROXY_STAT_RETRY\fR
-The request was not completed.
-.SH MASTER INTERFACE
+The lookup request could not be completed.
+.IP \fBPROXY_STAT_DENY\fR
+The specified table was not approved for access via the
+proxymap service.
+.SH SERVER PROCESS MANAGEMENT
.na
.nf
.ad
@@ -73,17 +76,21 @@ server. Each server can handle multiple simultaneous connections.
When all servers are busy while a client connects, the master
creates a new proxymap server process, provided that the proxymap
server process limit is not exceeded.
-Each proxymap server terminates after serving \fB$max_use\fR clients
-or after \fB$max_idle\fR seconds of idle time.
+Each proxymap server stops accepting new connections after serving
+\fB$max_use\fR clients or terminates after \fB$max_idle\fR seconds
+of idle time.
.SH SECURITY
.na
.nf
.ad
.fi
-The proxymap server is not security-sensitive. It opens only
-tables that are approved via the \fBproxymap_filter\fR
-configuration parameter, does not talk to users, and
-can run at fixed low privilege, chrooted or not.
+The proxymap server opens only tables that are approved via the
+\fBproxy_read_maps\fR configuration parameter, does not talk to
+users, and can run at fixed low privilege, chrooted or not.
+
+The proxymap server is not a trusted daemon process, and must
+not be used to look up sensitive information such as user or
+group IDs, mailbox file/directory names or external commands.
.SH DIAGNOSTICS
.ad
.fi
@@ -102,11 +109,11 @@ lookups.
The following main.cf parameters are especially relevant
to this program. Use the \fBpostfix reload\fR command
after a configuration change.
-.IP \fBproxymap_filter\fR
+.IP \fBproxy_read_maps\fR
A list of zero or more parameter values that may contain
-Postfix lookup table references. Only table references that
-begin with \fBproxy:\fR are approved for access via the
-proxymap server.
+references to Postfix lookup tables. Only table references
+that begin with \fBproxy:\fR are approved for read-only
+access via the proxymap server.
.SH SEE ALSO
.na
.nf
diff --git a/postfix/man/man8/trivial-rewrite.8 b/postfix/man/man8/trivial-rewrite.8
index bd56ad96f..807bcb85e 100644
--- a/postfix/man/man8/trivial-rewrite.8
+++ b/postfix/man/man8/trivial-rewrite.8
@@ -32,14 +32,6 @@ The host to send to and optional delivery method information.
.IP \fIrecipient\fR
The envelope recipient address that is passed on to \fInexthop\fR.
.RE
-.PP
-\fBtrivial-rewrite\fR servers run under control by the Postfix master
-server. Each server can handle multiple simultaneous connections.
-When all servers are busy while a client connects, a new server
-process is created, provided that the trivial-rewrite server
-process limit is not exceeded.
-Each server terminates after serving \fB$max_use\fR clients
-or after \fB$max_idle\fR seconds of idle time.
.SH DEFAULT DELIVERY METHODS
.na
.nf
@@ -73,6 +65,19 @@ The transport and optional nexthop are specified with
This overrides the optional nexthop information that is specified
with \fB$relayhost\fR.
The default nexthop is the recipient domain.
+.SH SERVER PROCESS MANAGEMENT
+.na
+.nf
+.ad
+.fi
+The trivial-rewrite servers run under control by the Postfix master
+server. Each server can handle multiple simultaneous connections.
+When all servers are busy while a client connects, the master
+creates a new server process, provided that the trivial-rewrite
+server process limit is not exceeded.
+Each trivial-rewrite server stops accepting new connections after
+serving \fB$max_use\fR clients or terminates after \fB$max_idle\fR
+seconds of idle time.
.SH STANDARDS
.na
.nf
diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink
index be5d77bb4..1f6d26ebd 100755
--- a/postfix/mantools/postlink
+++ b/postfix/mantools/postlink
@@ -44,7 +44,7 @@ exec sed '
s/[]*canonical[]*(5)/&<\/a>/
s/[]*etrn[]*(5)/&<\/a>/
s/[]*pcre[]*_[]*table[]*(5)/&<\/a>/
- s/[]*proxymap[]*(8)/&<\/a>/
+ s/[]*proxymap[]*(8)/&<\/a>/
s/[]*reg[-]*\n*[ ]*exp[]*_[]*table[]*(5)/&<\/a>/
s/[]*relocated[]*(5)/&<\/a>/
s/[]*trans[-]*\n*[ ]*port[]*(5)/&<\/a>/
diff --git a/postfix/src/global/clnt_stream.c b/postfix/src/global/clnt_stream.c
index 7c182372a..8a736939e 100644
--- a/postfix/src/global/clnt_stream.c
+++ b/postfix/src/global/clnt_stream.c
@@ -48,7 +48,7 @@
/* .IP timeout
/* Idle time after which the client disconnects.
/* .IP ttl
-/* Time to live after which the client disconnects.
+/* Upper bound on the time that a connection is allowed to persist.
/* DIAGNOSTICS
/* Warnings: communication failure. Fatal error: mail system is down,
/* out of memory.
@@ -121,10 +121,16 @@ static void clnt_stream_ttl_event(int event, char *context)
{
/*
- * XXX This function is needed only because the event_request_timer()
- * function cannot distinguish requests with the same callback routine.
- * The fix is obvious: specify a request ID along with the callback
- * routine, but there is too much code that would have to be changed.
+ * XXX This function is needed only because event_request_timer() cannot
+ * distinguish between requests that specify the same call-back routine
+ * and call-back context. The fix is obvious: specify a request ID along
+ * with the call-back routine, but there is too much code that would have
+ * to be changed.
+ *
+ * XXX Should we be concerned that an overly agressive optimizer will
+ * eliminate this function and replace calls to clnt_stream_ttl_event()
+ * by direct calls to clnt_stream_event()? It should not, because there
+ * exists code that takes the address of both functions.
*/
clnt_stream_event(event, context);
}
diff --git a/postfix/src/global/dict_proxy.c b/postfix/src/global/dict_proxy.c
index 626eb9a3e..6cbe8ee59 100644
--- a/postfix/src/global/dict_proxy.c
+++ b/postfix/src/global/dict_proxy.c
@@ -17,7 +17,8 @@
/* The \fIopen_flags\fR argument must specify O_RDONLY.
/*
/* The connection to the Postfix proxymap server is automatically
-/* closed after $ipc_idle seconds of idle time.
+/* closed after $ipc_idle seconds of idle time, or after $ipc_ttl
+/* seconds of activity.
/* SECURITY
/* The proxy map server is not meant to be a trusted process. Proxy
/* maps must not be used to look up security sensitive information
@@ -27,7 +28,7 @@
/* clnt_stream(3) client endpoint connection management
/* DIAGNOSTICS
/* Fatal errors: out of memory, unimplemented operation,
-/* bad request parameter.
+/* bad request parameter, map not approved for proxy access.
/* LICENSE
/* .ad
/* .fi
@@ -78,8 +79,7 @@ typedef struct {
#define VSTREQ(v,s) (strcmp(STR(v),s) == 0)
/*
- * All proxied maps within the same process share the same query/reply
- * socket.
+ * All proxied maps within a process share the same query/reply socket.
*/
static CLNT_STREAM *proxy_stream;
@@ -115,25 +115,31 @@ static const char *dict_proxy_lookup(DICT *dict, const char *key)
ATTR_TYPE_STR, MAIL_ATTR_VALUE, dict_proxy->result,
ATTR_TYPE_END) != 2) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
- msg_warn("%s: service %s: %m", VSTREAM_PATH(stream), myname);
+ msg_warn("%s: service %s: %m", myname, VSTREAM_PATH(stream));
} else {
if (msg_verbose)
msg_info("%s: table=%s flags=0%o key=%s -> status=%d result=%s",
myname, dict->name, dict_proxy->in_flags, key,
status, STR(dict_proxy->result));
- if (status == PROXY_STAT_OK) {
+ switch (status) {
+ case PROXY_STAT_BAD:
+ msg_fatal("%s lookup failed for table \"%s\" key \"%s\": "
+ "invalid request",
+ MAIL_SERVICE_PROXYMAP, dict->name, key);
+ case PROXY_STAT_DENY:
+ msg_fatal("%s service is not configured for table \"%s\"",
+ MAIL_SERVICE_PROXYMAP, dict->name);
+ case PROXY_STAT_OK:
return (STR(dict_proxy->result));
- } else if (status == PROXY_STAT_FAIL) {
+ case PROXY_STAT_NOKEY:
return (0);
- } else if (status == PROXY_STAT_RETRY) {
+ case PROXY_STAT_RETRY:
dict_errno = DICT_ERR_RETRY;
return (0);
- } else if (status == PROXY_STAT_BAD) {
- msg_fatal("%s: %s lookup %s failed: bad request",
- myname, dict->name, key);
- } else {
- msg_warn("%s: %s lookup %s failed with unknown status %d",
- myname, dict->name, key, status);
+ default:
+ msg_warn("%s lookup failed for table \"%s\" key \"%s\": "
+ "unexpected reply status %d",
+ MAIL_SERVICE_PROXYMAP, dict->name, key, status);
}
}
clnt_stream_recover(proxy_stream);
@@ -166,10 +172,10 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
/*
* Sanity checks.
*/
+ if (dict_flags & DICT_FLAG_NO_PROXY)
+ msg_fatal("%s: proxy map must not be used with this map type", map);
if (open_flags != O_RDONLY)
msg_fatal("%s: proxy map open requires O_RDONLY access mode", map);
- if (dict_flags & DICT_FLAG_NO_PROXY)
- msg_fatal("%s: proxy map is not allowed for this map type", map);
/*
* Local initialization.
@@ -201,7 +207,9 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
}
/*
- * Establish initial contact and finalize the flags.
+ * Establish initial contact and get the map type specific flags.
+ *
+ * XXX Should retrieve flags from local instance.
*/
for (;;) {
stream = clnt_stream_access(proxy_stream);
@@ -217,21 +225,26 @@ DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
ATTR_TYPE_END) != 2) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
msg_warn("%s: service %s: %m", VSTREAM_PATH(stream), myname);
- } else if (status == PROXY_STAT_OK) {
+ } else {
if (msg_verbose)
msg_info("%s: connect to map=%s status=%d server_flags=0%o",
myname, dict_proxy->dict.name, status, server_flags);
- dict_proxy->dict.flags = dict_proxy->in_flags | server_flags;
- break;
- } else if (status == PROXY_STAT_BAD) {
- msg_fatal("%s: %s connection request failed: bad request",
- myname, dict_proxy->dict.name);
- } else {
- msg_warn("%s: %s connection request failed with status %d",
- myname, dict_proxy->dict.name, status);
+ switch (status) {
+ case PROXY_STAT_BAD:
+ msg_fatal("%s open failed for table \"%s\": invalid request",
+ MAIL_SERVICE_PROXYMAP, dict_proxy->dict.name);
+ case PROXY_STAT_DENY:
+ msg_fatal("%s service is not configured for table \"%s\"",
+ MAIL_SERVICE_PROXYMAP, dict_proxy->dict.name);
+ case PROXY_STAT_OK:
+ dict_proxy->dict.flags = dict_proxy->in_flags | server_flags;
+ return (DICT_DEBUG (&dict_proxy->dict));
+ default:
+ msg_warn("%s open failed for table \"%s\": unexpected status %d",
+ MAIL_SERVICE_PROXYMAP, dict_proxy->dict.name, status);
+ }
}
clnt_stream_recover(proxy_stream);
sleep(1); /* XXX make configurable */
}
- return (DICT_DEBUG (&dict_proxy->dict));
}
diff --git a/postfix/src/global/dict_proxy.h b/postfix/src/global/dict_proxy.h
index 50932b0c4..ce4962609 100644
--- a/postfix/src/global/dict_proxy.h
+++ b/postfix/src/global/dict_proxy.h
@@ -29,10 +29,11 @@ extern DICT *dict_proxy_open(const char *, int, int);
#define PROXY_REQ_OPEN "open"
#define PROXY_REQ_LOOKUP "lookup"
-#define PROXY_STAT_OK 0
-#define PROXY_STAT_FAIL 1
-#define PROXY_STAT_BAD 2
-#define PROXY_STAT_RETRY 3
+#define PROXY_STAT_OK 0 /* operation succeeded */
+#define PROXY_STAT_NOKEY 1 /* requested key not found */
+#define PROXY_STAT_RETRY 2 /* try lookup again later */
+#define PROXY_STAT_BAD 3 /* invalid request parameter */
+#define PROXY_STAT_DENY 4 /* table not approved for proxying */
/* LICENSE
/* .ad
diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h
index 554e94a03..9f8e01e41 100644
--- a/postfix/src/global/mail_params.h
+++ b/postfix/src/global/mail_params.h
@@ -1332,8 +1332,8 @@ extern int var_local_rcpt_code;
/*
* List of pre-approved maps that are OK to open with the proxymap service.
*/
-#define VAR_PROXYMAP_FILTER "proxymap_filter"
-#define DEF_PROXYMAP_FILTER "$" VAR_LOCAL_RCPT_MAPS \
+#define VAR_PROXY_READ_MAPS "proxy_read_maps"
+#define DEF_PROXY_READ_MAPS "$" VAR_LOCAL_RCPT_MAPS \
" $" VAR_MYDEST \
" $" VAR_VIRT_ALIAS_MAPS \
" $" VAR_VIRT_ALIAS_DOMS \
@@ -1346,7 +1346,7 @@ extern int var_local_rcpt_code;
" $" VAR_RCPT_CANON_MAPS \
" $" VAR_RELOCATED_MAPS \
" $" VAR_TRANSPORT_MAPS
-extern char *var_proxymap_filter;
+extern char *var_proxy_read_maps;
/*
* Other.
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index 8c770247e..59b18fdb2 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,7 +20,7 @@
* Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release.
*/
-#define MAIL_RELEASE_DATE "20030103"
+#define MAIL_RELEASE_DATE "20030104"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "2.0.0-" MAIL_RELEASE_DATE
diff --git a/postfix/src/global/resolve_clnt.c b/postfix/src/global/resolve_clnt.c
index 41cd78584..698617952 100644
--- a/postfix/src/global/resolve_clnt.c
+++ b/postfix/src/global/resolve_clnt.c
@@ -184,22 +184,20 @@ void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
for (;;) {
stream = clnt_stream_access(rewrite_clnt_stream);
+ errno = 0;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, RESOLVE_ADDR,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
- ATTR_TYPE_END)
- || vstream_fflush(stream)) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
- msg_warn("%s: bad write: %m", myname);
- } else if (attr_scan(stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_END) != 0
+ || attr_scan(stream, ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_TRANSPORT, reply->transport,
- ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, reply->nexthop,
-
- ATTR_TYPE_STR, MAIL_ATTR_RECIP, reply->recipient,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &reply->flags,
- ATTR_TYPE_END) != 4) {
+ ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, reply->nexthop,
+ ATTR_TYPE_STR, MAIL_ATTR_RECIP, reply->recipient,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &reply->flags,
+ ATTR_TYPE_END) != 4) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
- msg_warn("%s: bad read: %m", myname);
+ msg_warn("problem talking to service %s: %m",
+ var_rewrite_service);
} else {
if (msg_verbose)
msg_info("%s: `%s' -> t=`%s' h=`%s' r=`%s'",
@@ -212,7 +210,7 @@ void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
else
break;
}
- sleep(10); /* XXX make configurable */
+ sleep(1); /* XXX make configurable */
clnt_stream_recover(rewrite_clnt_stream);
}
diff --git a/postfix/src/global/rewrite_clnt.c b/postfix/src/global/rewrite_clnt.c
index ce7850d9e..24bb4d432 100644
--- a/postfix/src/global/rewrite_clnt.c
+++ b/postfix/src/global/rewrite_clnt.c
@@ -125,26 +125,25 @@ VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
for (;;) {
stream = clnt_stream_access(rewrite_clnt_stream);
+ errno = 0;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, REWRITE_ADDR,
ATTR_TYPE_STR, MAIL_ATTR_RULE, rule,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
- ATTR_TYPE_END),
- vstream_fflush(stream)) {
+ ATTR_TYPE_END) != 0
+ || attr_scan(stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_STR, MAIL_ATTR_ADDR, result,
+ ATTR_TYPE_END) != 1) {
if (msg_verbose || (errno != EPIPE && errno != ENOENT))
- msg_warn("%s: bad write: %m", myname);
- } else if (attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_STR, MAIL_ATTR_ADDR, result,
- ATTR_TYPE_END) != 1) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
- msg_warn("%s: bad read: %m", myname);
+ msg_warn("problem talking to service %s: %m",
+ var_rewrite_service);
} else {
if (msg_verbose)
msg_info("rewrite_clnt: %s: %s -> %s",
rule, addr, vstring_str(result));
break;
}
- sleep(10); /* XXX make configurable */
+ sleep(1); /* XXX make configurable */
clnt_stream_recover(rewrite_clnt_stream);
}
diff --git a/postfix/src/global/verify_clnt.c b/postfix/src/global/verify_clnt.c
index 878df8f9e..dd7a09156 100644
--- a/postfix/src/global/verify_clnt.c
+++ b/postfix/src/global/verify_clnt.c
@@ -117,24 +117,19 @@ int verify_clnt_query(const char *addr, int *addr_status, VSTRING *why)
*/
for (;;) {
stream = clnt_stream_access(vrfy_clnt);
+ errno = 0;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, VRFY_REQ_QUERY,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
ATTR_TYPE_END) != 0
- || vstream_fflush(stream)) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT)) {
- msg_warn("service %s: bad write: %m", var_verify_service);
- sleep(10); /* XXX make configurable */
- }
- } else if (attr_scan(stream, ATTR_FLAG_MISSING,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &request_status,
- ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, addr_status,
- ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
- ATTR_TYPE_END) != 3) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT)) {
- msg_warn("service %s: bad read: %m", var_verify_service);
- sleep(10); /* XXX make configurable */
- }
+ || attr_scan(stream, ATTR_FLAG_MISSING,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &request_status,
+ ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, addr_status,
+ ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
+ ATTR_TYPE_END) != 3) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ msg_warn("problem talking to service %s: %m",
+ var_verify_service);
} else {
break;
}
@@ -181,25 +176,19 @@ int verify_clnt_vupdate(const char *addr, int addr_status,
vstring_vsprintf(text, format, ap);
for (;;) {
stream = clnt_stream_access(vrfy_clnt);
+ errno = 0;
if (attr_print(stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REQ, VRFY_REQ_UPDATE,
ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr,
ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, addr_status,
ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(text),
ATTR_TYPE_END) != 0
- || vstream_fflush(stream)) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT)) {
- msg_warn("service %s: bad write: %m", var_verify_service);
- msg_warn("service %s: bad write: %m", var_verify_service);
- sleep(10); /* XXX make configurable */
- }
- } else if (attr_scan(stream, ATTR_FLAG_MISSING,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &request_status,
- ATTR_TYPE_END) != 1) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT)) {
- msg_warn("service %s: bad read: %m", var_verify_service);
- sleep(10); /* XXX make configurable */
- }
+ || attr_scan(stream, ATTR_FLAG_MISSING,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &request_status,
+ ATTR_TYPE_END) != 1) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ msg_warn("problem talking to service %s: %m",
+ var_verify_service);
} else {
break;
}
diff --git a/postfix/src/global/virtual8_maps.c b/postfix/src/global/virtual8_maps.c
index c911737ec..fb05dc7d0 100644
--- a/postfix/src/global/virtual8_maps.c
+++ b/postfix/src/global/virtual8_maps.c
@@ -28,11 +28,7 @@
/* named dictionaries.
/* The result is a handle that must be specified along with all
/* other virtual8_maps_xxx() operations.
-/* See dict_open(3) for a description of flags. virtual8_maps_create()
-/* implicitly sets the DICT_FLAG_NO_REGSUB flag in order to disable
-/* regular expression substitution into the lookup result, and
-/* implicitly sets the DICT_FLAG_NO_PROXY flag in order to disable
-/* lookup of sensitive information via an untrusted process.
+/* See dict_open(3) for a description of flags.
/*
/* virtual8_maps_find() searches the specified list of dictionaries
/* in the specified order for the named key. The result is in
diff --git a/postfix/src/global/virtual8_maps.h b/postfix/src/global/virtual8_maps.h
index 2cf89f6c8..67c5df910 100644
--- a/postfix/src/global/virtual8_maps.h
+++ b/postfix/src/global/virtual8_maps.h
@@ -20,8 +20,7 @@
* External interface.
*/
#define virtual8_maps_create(title, map_names, flags) \
- maps_create((title), (map_names), \
- (flags) | DICT_FLAG_NO_REGSUB | DICT_FLAG_NO_PROXY)
+ maps_create((title), (map_names), (flags))
extern const char *virtual8_maps_find(MAPS *, const char *);
#define virtual8_maps_free(maps) maps_free((maps))
diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c
index 7b4584547..d6019f441 100644
--- a/postfix/src/local/local.c
+++ b/postfix/src/local/local.c
@@ -696,10 +696,8 @@ static void pre_init(char *unused_name, char **unused_argv)
VAR_MAILBOX_LIMIT, VAR_MESSAGE_LIMIT);
set_file_limit(var_mailbox_limit);
}
-#define INSECURE_DICT_FLAGS (DICT_FLAG_NO_REGSUB | DICT_FLAG_NO_PROXY)
-
alias_maps = maps_create("aliases", var_alias_maps,
- DICT_FLAG_LOCK | INSECURE_DICT_FLAGS);
+ DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
}
/* main - pass control to the single-threaded skeleton */
diff --git a/postfix/src/proxymap/proxymap.c b/postfix/src/proxymap/proxymap.c
index d29507529..871200efd 100644
--- a/postfix/src/proxymap/proxymap.c
+++ b/postfix/src/proxymap/proxymap.c
@@ -12,33 +12,35 @@
/* .IP \(bu
/* To overcome chroot restrictions. For example, a chrooted SMTP
/* server needs access to the system passwd file in order to
-/* reject mail for non-existent local addresses.
-/* The solution is to specify:
+/* reject mail for non-existent local addresses, but it is not
+/* practical to maintain a copy of the passwd file in the chroot
+/* jail. The solution:
/* .sp
/* local_recipient_maps =
/* .ti +4
/* proxy:unix:passwd.byname $alias_maps
/* .IP \(bu
/* To consolidate the number of open lookup tables by sharing
-/* one open table among multiple processes. For example, to avoid
-/* problems due to "too many connections" to, e.g., mysql servers,
-/* specify:
+/* one open table among multiple processes. For example, making
+/* mysql connections from every Postfix daemon process results
+/* in "too many connections" errors. The solution:
/* .sp
/* virtual_alias_maps =
/* .ti +4
/* proxy:mysql:/etc/postfix/virtual.cf
-/* PROXYMAP SERVICES
-/* .ad
-/* .fi
+/* .sp
+/* The total number of connections is limited by the number of
+/* proxymap server server processes.
+/* .PP
/* The proxymap server implements the following requests:
/* .IP "\fBPROXY_REQ_OPEN\fI maptype:mapname flags\fR"
/* Open the table with type \fImaptype\fR and name \fImapname\fR,
/* as controlled by \fIflags\fR.
-/* The reply is the request completion status code and the
+/* The reply is the request completion status code (below) and the
/* map type dependent flags.
/* .IP "\fBPROXY_REQ_LOOKUP\fI maptype:mapname flags key\fR"
/* Look up the data stored under the requested key.
-/* The reply is the request completion status code and
+/* The reply is the request completion status code (below) and
/* the lookup result value.
/* The \fImaptype:mapname\fR and \fIflags\fR are the same
/* as with the \fBPROXY_REQ_OPEN\fR request.
@@ -48,30 +50,37 @@
/*
/* The request completion status code is one of:
/* .IP \fBPROXY_STAT_OK\fR
-/* The requested table or lookup key was found.
-/* .IP \fBPROXY_STAT_FAIL\fR
-/* The requested table or lookup key does not exist.
+/* The specified table was opened, or the requested entry was found.
+/* .IP \fBPROXY_STAT_NOKEY\fR
+/* The requested table entry was not found.
/* .IP \fBPROXY_STAT_BAD\fR
/* The request was rejected (bad request parameter value).
/* .IP \fBPROXY_STAT_RETRY\fR
-/* The request was not completed.
-/* MASTER INTERFACE
+/* The lookup request could not be completed.
+/* .IP \fBPROXY_STAT_DENY\fR
+/* The specified table was not approved for access via the
+/* proxymap service.
+/* SERVER PROCESS MANAGEMENT
/* .ad
/* .fi
/* The proxymap servers run under control by the Postfix master
/* server. Each server can handle multiple simultaneous connections.
/* When all servers are busy while a client connects, the master
-/* creates a new proxymap server process, provided that the proxymap
+/* creates a new proxymap server process, provided that the proxymap
/* server process limit is not exceeded.
-/* Each proxymap server terminates after serving \fB$max_use\fR clients
-/* or after \fB$max_idle\fR seconds of idle time.
+/* Each proxymap server stops accepting new connections after serving
+/* \fB$max_use\fR clients or terminates after \fB$max_idle\fR seconds
+/* of idle time.
/* SECURITY
/* .ad
/* .fi
-/* The proxymap server is not security-sensitive. It opens only
-/* tables that are approved via the \fBproxymap_filter\fR
-/* configuration parameter, does not talk to users, and
-/* can run at fixed low privilege, chrooted or not.
+/* The proxymap server opens only tables that are approved via the
+/* \fBproxy_read_maps\fR configuration parameter, does not talk to
+/* users, and can run at fixed low privilege, chrooted or not.
+/*
+/* The proxymap server is not a trusted daemon process, and must
+/* not be used to look up sensitive information such as user or
+/* group IDs, mailbox file/directory names or external commands.
/* DIAGNOSTICS
/* Problems and transactions are logged to \fBsyslogd\fR(8).
/* BUGS
@@ -84,11 +93,11 @@
/* The following main.cf parameters are especially relevant
/* to this program. Use the \fBpostfix reload\fR command
/* after a configuration change.
-/* .IP \fBproxymap_filter\fR
+/* .IP \fBproxy_read_maps\fR
/* A list of zero or more parameter values that may contain
-/* Postfix lookup table references. Only table references that
-/* begin with \fBproxy:\fR are approved for access via the
-/* proxymap server.
+/* references to Postfix lookup tables. Only table references
+/* that begin with \fBproxy:\fR are approved for read-only
+/* access via the proxymap server.
/* SEE ALSO
/* dict_proxy(3) proxy map client
/* LICENSE
@@ -148,20 +157,20 @@ char *var_send_canon_maps;
char *var_rcpt_canon_maps;
char *var_relocatedmaps;
char *var_transport_maps;
-char *var_proxymap_filter;
+char *var_proxy_read_maps;
/*
* The pre-approved, pre-parsed list of maps.
*/
-static HTABLE *proxymap_filter;
+static HTABLE *proxy_read_maps;
/*
* Shared and static to reduce memory allocation overhead.
*/
static VSTRING *request;
+static VSTRING *request_map;
+static VSTRING *request_key;
static VSTRING *map_type_name_flags;
-static VSTRING *map_type_name;
-static VSTRING *key;
/*
* Silly little macros.
@@ -171,13 +180,13 @@ static VSTRING *key;
/* proxy_map_find - look up or open table */
-static DICT *proxy_map_find(const char *map_type_name, int dict_flags)
+static DICT *proxy_map_find(const char *map_type_name, int request_flags)
{
DICT *dict;
#define PROXY_COLON DICT_TYPE_PROXY ":"
#define PROXY_COLON_LEN (sizeof(PROXY_COLON) - 1)
-#define OPEN_FLAGS O_RDONLY
+#define READ_OPEN_FLAGS O_RDONLY
/*
* Canonicalize the map name. If the map is not on the approved list,
@@ -185,8 +194,10 @@ static DICT *proxy_map_find(const char *map_type_name, int dict_flags)
*/
while (strncmp(map_type_name, PROXY_COLON, PROXY_COLON_LEN) == 0)
map_type_name += PROXY_COLON_LEN;
- if (htable_locate(proxymap_filter, map_type_name) == 0) {
- msg_warn("request for unapproved map: %s", map_type_name);
+ if (htable_locate(proxy_read_maps, map_type_name) == 0) {
+ msg_warn("request for unapproved table: \"%s\"", map_type_name);
+ msg_warn("to approve a table for %s access, specify it in %s with %s",
+ MAIL_SERVICE_PROXYMAP, MAIN_CONF_FILE, VAR_PROXY_READ_MAPS);
return (0);
}
@@ -194,9 +205,9 @@ static DICT *proxy_map_find(const char *map_type_name, int dict_flags)
* Open one instance of a map for each combination of name+flags.
*/
vstring_sprintf(map_type_name_flags, "%s:%o",
- map_type_name, dict_flags);
+ map_type_name, request_flags);
if ((dict = dict_handle(STR(map_type_name_flags))) == 0)
- dict = dict_open(map_type_name, OPEN_FLAGS, dict_flags);
+ dict = dict_open(map_type_name, READ_OPEN_FLAGS, request_flags);
if (dict == 0)
msg_panic("proxy_map_find: dict_open null result");
dict_register(STR(map_type_name_flags), dict);
@@ -207,35 +218,40 @@ static DICT *proxy_map_find(const char *map_type_name, int dict_flags)
static void proxymap_lookup_service(VSTREAM *client_stream)
{
- int status = PROXY_STAT_BAD;
+ int request_flags;
DICT *dict;
- const char *value = "";
- int dict_flags;
+ const char *reply_value;
+ int reply_status;
+ /*
+ * Process the request.
+ */
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_STR, MAIL_ATTR_TABLE, map_type_name,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &dict_flags,
- ATTR_TYPE_STR, MAIL_ATTR_KEY, key,
- ATTR_TYPE_END) == 3
- && (dict = proxy_map_find(STR(map_type_name), dict_flags)) != 0) {
-
- if ((value = dict_get(dict, STR(key))) != 0) {
- status = PROXY_STAT_OK;
- } else if (dict_errno == 0) {
- status = PROXY_STAT_FAIL;
- value = "";
- } else {
- status = PROXY_STAT_RETRY;
- value = "";
- }
+ ATTR_TYPE_STR, MAIL_ATTR_TABLE, request_map,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &request_flags,
+ ATTR_TYPE_STR, MAIL_ATTR_KEY, request_key,
+ ATTR_TYPE_END) != 3) {
+ reply_status = PROXY_STAT_BAD;
+ reply_value = "";
+ } else if ((dict = proxy_map_find(STR(request_map), request_flags)) == 0) {
+ reply_status = PROXY_STAT_DENY;
+ reply_value = "";
+ } else if ((reply_value = dict_get(dict, STR(request_key))) != 0) {
+ reply_status = PROXY_STAT_OK;
+ } else if (dict_errno == 0) {
+ reply_status = PROXY_STAT_NOKEY;
+ reply_value = "";
+ } else {
+ reply_status = PROXY_STAT_RETRY;
+ reply_value = "";
}
/*
* Respond to the client.
*/
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
- ATTR_TYPE_STR, MAIL_ATTR_VALUE, value,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, reply_status,
+ ATTR_TYPE_STR, MAIL_ATTR_VALUE, reply_value,
ATTR_TYPE_END);
}
@@ -243,27 +259,34 @@ static void proxymap_lookup_service(VSTREAM *client_stream)
static void proxymap_open_service(VSTREAM *client_stream)
{
- int dict_flags;
+ int request_flags;
DICT *dict;
- int status = PROXY_STAT_BAD;
- int flags = 0;
+ int reply_status;
+ int reply_flags;
+ /*
+ * Process the request.
+ */
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_STR, MAIL_ATTR_TABLE, map_type_name,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &dict_flags,
- ATTR_TYPE_END) == 2
- && (dict = proxy_map_find(STR(map_type_name), dict_flags)) != 0) {
-
- status = PROXY_STAT_OK;
- flags = dict->flags;
+ ATTR_TYPE_STR, MAIL_ATTR_TABLE, request_map,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &request_flags,
+ ATTR_TYPE_END) != 2) {
+ reply_status = PROXY_STAT_BAD;
+ reply_flags = 0;
+ } else if ((dict = proxy_map_find(STR(request_map), request_flags)) == 0) {
+ reply_status = PROXY_STAT_DENY;
+ reply_flags = 0;
+ } else {
+ reply_status = PROXY_STAT_OK;
+ reply_flags = dict->flags;
}
/*
* Respond to the client.
*/
attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
- ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, reply_status,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, reply_flags,
ATTR_TYPE_END);
}
@@ -311,28 +334,41 @@ static void post_jail_init(char *unused_name, char **unused_argv)
char *bp;
char *type_name;
+ /*
+ * Pre-allocate buffers.
+ */
request = vstring_alloc(10);
- map_type_name = vstring_alloc(10);
+ request_map = vstring_alloc(10);
+ request_key = vstring_alloc(10);
map_type_name_flags = vstring_alloc(10);
- key = vstring_alloc(10);
/*
* Prepare the pre-approved list of proxied tables.
*/
- saved_filter = bp = mystrdup(var_proxymap_filter);
- proxymap_filter = htable_create(13);
+ saved_filter = bp = mystrdup(var_proxy_read_maps);
+ proxy_read_maps = htable_create(13);
while ((type_name = mystrtok(&bp, sep)) != 0) {
if (strncmp(type_name, PROXY_COLON, PROXY_COLON_LEN))
continue;
do {
type_name += PROXY_COLON_LEN;
} while (!strncmp(type_name, PROXY_COLON, PROXY_COLON_LEN));
- if (htable_find(proxymap_filter, type_name) == 0)
- (void) htable_enter(proxymap_filter, type_name, (char *) 0);
+ if (htable_locate(proxy_read_maps, type_name) == 0)
+ (void) htable_enter(proxy_read_maps, type_name, (char *) 0);
}
myfree(saved_filter);
}
+/* pre_accept - see if tables have changed */
+
+static void pre_accept(char *unused_name, char **unused_argv)
+{
+ if (dict_changed()) {
+ msg_info("some lookup table has changed -- restarting");
+ exit(0);
+ }
+}
+
/* main - pass control to the multi-threaded skeleton */
int main(int argc, char **argv)
@@ -350,12 +386,13 @@ int main(int argc, char **argv)
VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0,
VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocatedmaps, 0, 0,
VAR_TRANSPORT_MAPS, DEF_TRANSPORT_MAPS, &var_transport_maps, 0, 0,
- VAR_PROXYMAP_FILTER, DEF_PROXYMAP_FILTER, &var_proxymap_filter, 0, 0,
+ VAR_PROXY_READ_MAPS, DEF_PROXY_READ_MAPS, &var_proxy_read_maps, 0, 0,
0,
};
multi_server_main(argc, argv, proxymap_service,
MAIL_SERVER_STR_TABLE, str_table,
MAIL_SERVER_POST_INIT, post_jail_init,
+ MAIL_SERVER_PRE_ACCEPT, pre_accept,
0);
}
diff --git a/postfix/src/trivial-rewrite/trivial-rewrite.c b/postfix/src/trivial-rewrite/trivial-rewrite.c
index b69f482b0..60948ec95 100644
--- a/postfix/src/trivial-rewrite/trivial-rewrite.c
+++ b/postfix/src/trivial-rewrite/trivial-rewrite.c
@@ -26,14 +26,6 @@
/* .IP \fIrecipient\fR
/* The envelope recipient address that is passed on to \fInexthop\fR.
/* .RE
-/* .PP
-/* \fBtrivial-rewrite\fR servers run under control by the Postfix master
-/* server. Each server can handle multiple simultaneous connections.
-/* When all servers are busy while a client connects, a new server
-/* process is created, provided that the trivial-rewrite server
-/* process limit is not exceeded.
-/* Each server terminates after serving \fB$max_use\fR clients
-/* or after \fB$max_idle\fR seconds of idle time.
/* DEFAULT DELIVERY METHODS
/* .ad
/* .fi
@@ -65,6 +57,17 @@
/* This overrides the optional nexthop information that is specified
/* with \fB$relayhost\fR.
/* The default nexthop is the recipient domain.
+/* SERVER PROCESS MANAGEMENT
+/* .ad
+/* .fi
+/* The trivial-rewrite servers run under control by the Postfix master
+/* server. Each server can handle multiple simultaneous connections.
+/* When all servers are busy while a client connects, the master
+/* creates a new server process, provided that the trivial-rewrite
+/* server process limit is not exceeded.
+/* Each trivial-rewrite server stops accepting new connections after
+/* serving \fB$max_use\fR clients or terminates after \fB$max_idle\fR
+/* seconds of idle time.
/* STANDARDS
/* .ad
/* .fi
diff --git a/postfix/src/util/dict.h b/postfix/src/util/dict.h
index 546420dd2..6f30e2fd7 100644
--- a/postfix/src/util/dict.h
+++ b/postfix/src/util/dict.h
@@ -58,10 +58,11 @@ extern DICT *dict_debug(DICT *);
#define DICT_FLAG_SYNC_UPDATE (1<<8) /* if file, sync updates */
#define DICT_FLAG_DEBUG (1<<9) /* log access */
#define DICT_FLAG_FOLD_KEY (1<<10) /* lowercase the lookup key */
-
#define DICT_FLAG_NO_REGSUB (1<<11) /* no lhs->rhs regexp substitution */
#define DICT_FLAG_NO_PROXY (1<<12) /* no proxy mapping */
+#define DICT_FLAG_PARANOID (DICT_FLAG_NO_REGSUB | DICT_FLAG_NO_PROXY)
+
extern int dict_unknown_allowed;
extern int dict_errno;
diff --git a/postfix/src/util/dict_open.c b/postfix/src/util/dict_open.c
index 2f50076fe..f94950283 100644
--- a/postfix/src/util/dict_open.c
+++ b/postfix/src/util/dict_open.c
@@ -84,6 +84,11 @@
/* .IP DICT_FLAG_NO_REGSUB
/* Disallow regular expression substitution from left-hand side data
/* into the right-hand side.
+/* .IP DICT_FLAG_NO_PROXY
+/* Disallow access through the \fBproxymap\fR service.
+/* .IP DICT_FLAG_PARANOID
+/* A combination of all the paranoia flags: DICT_FLAG_NO_REGSUB
+/* and DICT_FLAG_NO_PROXY.
/* .PP
/* Specify DICT_FLAG_NONE for no special processing.
/*
diff --git a/postfix/src/util/vstream.c b/postfix/src/util/vstream.c
index 22c59440c..5cff45140 100644
--- a/postfix/src/util/vstream.c
+++ b/postfix/src/util/vstream.c
@@ -640,8 +640,11 @@ static int vstream_buf_get_ready(VBUF *bp)
* allocation gives the application a chance to override the default
* buffering policy.
*/
- if (bp->data == 0)
+ if (bp->data == 0) {
vstream_buf_alloc(bp, VSTREAM_BUFSIZE);
+ if (bp->flags & VSTREAM_FLAG_DOUBLE)
+ VSTREAM_SAVE_STATE(stream, read_buf, read_fd);
+ }
/*
* If the stream is double-buffered and the write buffer is not empty,
@@ -724,6 +727,8 @@ static int vstream_buf_put_ready(VBUF *bp)
*/
if (bp->data == 0) {
vstream_buf_alloc(bp, VSTREAM_BUFSIZE);
+ if (bp->flags & VSTREAM_FLAG_DOUBLE)
+ VSTREAM_SAVE_STATE(stream, write_buf, write_fd);
} else if (bp->cnt <= 0) {
if (VSTREAM_FFLUSH_SOME(stream))
return (VSTREAM_EOF);
diff --git a/postfix/src/virtual/virtual.c b/postfix/src/virtual/virtual.c
index 49ed051df..e0896f0b0 100644
--- a/postfix/src/virtual/virtual.c
+++ b/postfix/src/virtual/virtual.c
@@ -413,15 +413,15 @@ static void post_init(char *unused_name, char **unused_argv)
virtual_mailbox_maps =
virtual8_maps_create(VAR_VIRT_MAILBOX_MAPS, var_virt_mailbox_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
virtual_uid_maps =
virtual8_maps_create(VAR_VIRT_UID_MAPS, var_virt_uid_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
virtual_gid_maps =
virtual8_maps_create(VAR_VIRT_GID_MAPS, var_virt_gid_maps,
- DICT_FLAG_LOCK);
+ DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
virtual_mbox_lock_mask = mbox_lock_mask(var_virt_mailbox_lock);
}