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
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,
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
================================================================
# 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
# 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".
# 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.
# 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
#
Specify what recipients exist (so that your queue does not fill up
with undeliverable mail from spammers).
-<p.
+<p>
Specify <tt>local_recipient_maps =</tt> if maintaining recipient
information is not practical.
<pre>
/etc/postfix/main.cf:
- local_recipient_maps = $alias_maps, unix:passwd.byname
+ local_recipient_maps = $alias_maps, proxy:unix:passwd.byname
</pre>
<p>
<ul>
-<li> 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 <b>/var/spool/postfix/etc</b>). This is system dependent. The
-only way to find out is to try.
+<li> If you run the Postfix SMTP server chrooted, you need to access
+the system password database through the Postfix <a href="proxymap.8.html">
+proxymap</a> 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 <b>/var/spool/postfix/etc</b>)
+together with a list of system dependent files.
<p>
This message is logged when, for example, the Postfix SMTP server
is unable to access the UNIX password database.
+<p>
+
<ul>
<li> If you're running the Postfix SMTP server chrooted (see
-<b>master.cf</b>) then you may have to copy the password file and
-perhaps a bunch of other files into the Postfix queue directory; a
-typical destination would be <b>/var/spool/postfix/etc</b>. See also
-the chroot setup scripts in the <b>examples</b> directory of the
-Postfix source code distribution.
+<b>master.cf</b>) then you need to access the system password
+database through the Postfix <a href="proxymap.8.html">proxymap</a>
+service. The alternative is not practical: copying the password
+file and perhaps a bunch of other system dependent files into the
+Postfix queue directory.
+
+<p>
+
+<pre>
+ /etc/postfix/main.cf:
+ local_recipient_maps = proxy:unix:passwd.byname $alias_maps ...
+</pre>
<p>
-<li> Be sure that you have world execute permissions on directories
-and world read permission on the passwd file and any auxiliary
-files that may be needed (such as <b>/etc/nsswitch.conf</b> and
-<b>libnss*.so*</b> files referenced by <b>/etc/nsswitch.conf</b>).
+<li> Chrooted or not, be sure that you have world execute permissions
+on directories and world read permission on the passwd file and
+any auxiliary files that may be needed (such as <b>/etc/nsswitch.conf</b>
+and <b>libnss*.so*</b> files referenced by <b>/etc/nsswitch.conf</b>).
</ul>
<b>proxy</b> (read-only)
A lookup table that is implemented via the
- Postfix <a href="verify.8.html"><b>proxymap</b>(8)</a> service. The table name
+ Postfix <a href="proxymap.8.html"><b>proxymap</b>(8)</a> service. The table name
syntax is <i>type</i><b>:</b><i>name</i>.
<b>regexp</b> (read-only)
<b>o</b> 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
<b>o</b> 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
-<b>PROXYMAP</b> <b>SERVICES</b>
+ The total number of connections is limited by the
+ number of proxymap server server processes.
+
The proxymap server implements the following requests:
<b>PROXY</b><i>_</i><b>REQ</b><i>_</i><b>OPEN</b> <i>maptype:mapname</i> <i>flags</i>
Open the table with type <i>maptype</i> and name <i>mapname</i>,
as controlled by <i>flags</i>. The reply is the request
- completion status code and the map type dependent
- flags.
+ completion status code (below) and the map type
+ dependent flags.
<b>PROXY</b><i>_</i><b>REQ</b><i>_</i><b>LOOKUP</b> <i>maptype:mapname</i> <i>flags</i> <i>key</i>
Look up the data stored under the requested key.
- The reply is the request completion status code and
- the lookup result value. The <i>maptype:mapname</i> and
- <i>flags</i> are the same as with the <b>PROXY</b><i>_</i><b>REQ</b><i>_</i><b>OPEN</b>
- request.
+ The reply is the request completion status code
+ (below) and the lookup result value. The <i>map-</i>
+ <i>type:mapname</i> and <i>flags</i> are the same as with the
+ <b>PROXY</b><i>_</i><b>REQ</b><i>_</i><b>OPEN</b> request.
There is no close command. This does not seem to be useful
because tables are meant to be shared among client pro-
The request completion status code is one of:
<b>PROXY</b><i>_</i><b>STAT</b><i>_</i><b>OK</b>
- The requested table or lookup key was found.
+ The specified table was opened, or the requested
+ entry was found.
- <b>PROXY</b><i>_</i><b>STAT</b><i>_</i><b>FAIL</b>
- The requested table or lookup key does not exist.
+ <b>PROXY</b><i>_</i><b>STAT</b><i>_</i><b>NOKEY</b>
+ The requested table entry was not found.
<b>PROXY</b><i>_</i><b>STAT</b><i>_</i><b>BAD</b>
- The request was rejected (bad request parameter
+ The request was rejected (bad request parameter
value).
<b>PROXY</b><i>_</i><b>STAT</b><i>_</i><b>RETRY</b>
- The request was not completed.
+ The lookup request could not be completed.
+
+ <b>PROXY</b><i>_</i><b>STAT</b><i>_</i><b>DENY</b>
+ The specified table was not approved for access via
+ the proxymap service.
-<b>MASTER</b> <b>INTERFACE</b>
+<b>SERVER</b> <b>PROCESS</b> <b>MANAGEMENT</b>
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 <b>$max</b><i>_</i><b>use</b> clients or after <b>$max</b><i>_</i><b>idle</b> seconds of idle
- time.
+ not exceeded. Each proxymap server stops accepting new
+ connections after serving <b>$max</b><i>_</i><b>use</b> clients or terminates
+ after <b>$max</b><i>_</i><b>idle</b> seconds of idle time.
<b>SECURITY</b>
- The proxymap server is not security-sensitive. It opens
- only tables that are approved via the <b>proxymap</b><i>_</i><b>filter</b> 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 <b>proxy</b><i>_</i><b>read</b><i>_</i><b>maps</b> 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.
<b>DIAGNOSTICS</b>
Problems and transactions are logged to <b>syslogd</b>(8).
<b>BUGS</b>
- 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.
<b>CONFIGURATION</b> <b>PARAMETERS</b>
- The following main.cf parameters are especially relevant
- to this program. Use the <b>postfix</b> <b>reload</b> command after a
+ The following main.cf parameters are especially relevant
+ to this program. Use the <b>postfix</b> <b>reload</b> command after a
configuration change.
- <b>proxymap</b><i>_</i><b>filter</b>
- A list of zero or more parameter values that may
- contain Postfix lookup table references. Only table
- references that begin with <b>proxy:</b> are approved for
- access via the proxymap server.
+ <b>proxy</b><i>_</i><b>read</b><i>_</i><b>maps</b>
+ A list of zero or more parameter values that may
+ contain references to Postfix lookup tables. Only
+ table references that begin with <b>proxy:</b> are
+ approved for read-only access via the proxymap
+ server.
<b>SEE</b> <b>ALSO</b>
dict_proxy(3) proxy map client
The envelope recipient address that is
passed on to <i>nexthop</i>.
- <b>trivial-rewrite</b> 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 <b>$max</b><i>_</i><b>use</b> clients or
- after <b>$max</b><i>_</i><b>idle</b> seconds of idle time.
-
<b>DEFAULT</b> <b>DELIVERY</b> <b>METHODS</b>
By default, Postfix uses one of the following delivery
methods. This may be overruled with the optional <a href="transport.5.html">trans-</a>
<b>$relayhost</b>. The default nexthop is the recipient
domain.
+<b>SERVER</b> <b>PROCESS</b> <b>MANAGEMENT</b>
+ 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 <b>$max</b><i>_</i><b>use</b> clients or termi-
+ nates after <b>$max</b><i>_</i><b>idle</b> seconds of idle time.
+
<b>STANDARDS</b>
- None. The command does not interact with the outside
+ None. The command does not interact with the outside
world.
<b>SECURITY</b>
- The <b>trivial-rewrite</b> 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 <b>trivial-rewrite</b> 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.
<b>DIAGNOSTICS</b>
<b>BUGS</b>
<b>CONFIGURATION</b> <b>PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
- to this program. See the Postfix <b>main.cf</b> file for syntax
- details and for default values. Use the <b>postfix</b> <b>reload</b>
+ The following <b>main.cf</b> parameters are especially relevant
+ to this program. See the Postfix <b>main.cf</b> file for syntax
+ details and for default values. Use the <b>postfix</b> <b>reload</b>
command after a configuration change.
<b>Miscellaneous</b>
<b>empty</b><i>_</i><b>address</b><i>_</i><b>recipient</b>
- The recipient that is substituted for the null
+ The recipient that is substituted for the null
address.
<b>inet</b><i>_</i><b>interfaces</b>
- The network interfaces that this mail system
- receives mail on. This information is used to
- determine if <i>user</i>@[<i>net.work.addr.ess</i>] 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 <i>user</i>@[<i>net.work.addr.ess</i>] is local or
+ remote. Mail for local users is given to the
<b>$local</b><i>_</i><b>transport</b>.
<b>mydestination</b>
<b>virtual</b><i>_</i><b>alias</b><i>_</i><b>domains</b>
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).
<b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>domains</b>
<b>resolve</b><i>_</i><b>unquoted</b><i>_</i><b>address</b>
When resolving an address, do not quote the address
- localpart as per <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a>, so that additional <b>@</b>, <b>%</b>
- or <b>!</b> characters remain visible. This is techni-
+ localpart as per <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a>, so that additional <b>@</b>, <b>%</b>
+ or <b>!</b> 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.
<b>relocated</b><i>_</i><b>maps</b>
<b>Routing</b>
<b>local</b><i>_</i><b>transport</b>
- Where to deliver mail for destinations that match
- <b>$mydestination</b> or <b>$inet</b><i>_</i><b>interfaces</b>. The default
+ Where to deliver mail for destinations that match
+ <b>$mydestination</b> or <b>$inet</b><i>_</i><b>interfaces</b>. The default
transport is <b>local:$myhostname</b>.
- Syntax is <i>transport</i>:<i>nexthop</i>; see <a href="transport.5.html"><b>transport</b>(5)</a> for
+ Syntax is <i>transport</i>:<i>nexthop</i>; see <a href="transport.5.html"><b>transport</b>(5)</a> for
details. The :<i>nexthop</i> part is optional.
<b>virtual</b><i>_</i><b>transport</b>
- Where to deliver mail for non-local domains that
+ Where to deliver mail for non-local domains that
match <b>$virtual</b><i>_</i><b>mailbox</b><i>_</i><b>domains</b>. The default trans-
port is <b>virtual</b>.
- Syntax is <i>transport</i>:<i>nexthop</i>; see <a href="transport.5.html"><b>transport</b>(5)</a> for
+ Syntax is <i>transport</i>:<i>nexthop</i>; see <a href="transport.5.html"><b>transport</b>(5)</a> for
details. The :<i>nexthop</i> part is optional.
<b>relay</b><i>_</i><b>transport</b>
- Where to deliver mail for non-local domains that
- match <b>$relay</b><i>_</i><b>domains</b>. The default transport is
+ Where to deliver mail for non-local domains that
+ match <b>$relay</b><i>_</i><b>domains</b>. The default transport is
<b>relay</b> (which normally is a clone of the <b>smtp</b> trans-
port).
- Syntax is <i>transport</i>:<i>nexthop</i>; see <a href="transport.5.html"><b>transport</b>(5)</a> for
+ Syntax is <i>transport</i>:<i>nexthop</i>; see <a href="transport.5.html"><b>transport</b>(5)</a> for
details. The :<i>nexthop</i> part is optional.
<b>default</b><i>_</i><b>transport</b>
- Where to deliver all other non-local mail. The
+ Where to deliver all other non-local mail. The
default transport is <b>smtp</b>.
- Syntax is <i>transport</i>:<i>nexthop</i>; see <a href="transport.5.html"><b>transport</b>(5)</a> for
+ Syntax is <i>transport</i>:<i>nexthop</i>; see <a href="transport.5.html"><b>transport</b>(5)</a> for
details. The :<i>nexthop</i> part is optional.
<b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdomains</b>
- List of Postfix features that use <i>domain.tld</i> pat-
- terns to match <i>sub.domain.tld</i> (as opposed to
+ List of Postfix features that use <i>domain.tld</i> pat-
+ terns to match <i>sub.domain.tld</i> (as opposed to
requiring <i>.domain.tld</i> patterns).
<b>relayhost</b>
- The default host to send non-local mail to when no
- host is specified with <b>$relay</b><i>_</i><b>transport</b> or
- <b>$default</b><i>_</i><b>transport</b>, and when the recipient address
+ The default host to send non-local mail to when no
+ host is specified with <b>$relay</b><i>_</i><b>transport</b> or
+ <b>$default</b><i>_</i><b>transport</b>, and when the recipient address
does not match the optional the <a href="transport.5.html"><b>transport</b>(5)</a> table.
<b>transport</b><i>_</i><b>maps</b>
- List of tables with <i>recipient</i> or <i>domain</i> to (<i>trans-</i>
+ List of tables with <i>recipient</i> or <i>domain</i> to (<i>trans-</i>
<i>port,</i> <i>nexthop</i>) mappings.
<b>SEE</b> <b>ALSO</b>
<a href="relocated.5.html">relocated(5)</a> format of the "user has moved" table
<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>
.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.
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
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
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
.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
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
s/[<bB>]*canonical[</bB>]*(5)/<a href="canonical.5.html">&<\/a>/
s/[<bB>]*etrn[</bB>]*(5)/<a href="etrn.5.html">&<\/a>/
s/[<bB>]*pcre[</bBiI>]*_[</iIbB>]*table[</bB>]*(5)/<a href="pcre_table.5.html">&<\/a>/
- s/[<bB>]*proxymap[</bB>]*(8)/<a href="verify.8.html">&<\/a>/
+ s/[<bB>]*proxymap[</bB>]*(8)/<a href="proxymap.8.html">&<\/a>/
s/[<bB>]*reg[-</bB>]*\n*[ <bB>]*exp[</bBiI>]*_[</iIbB>]*table[</bB>]*(5)/<a href="regexp_table.5.html">&<\/a>/
s/[<bB>]*relocated[</bB>]*(5)/<a href="relocated.5.html">&<\/a>/
s/[<bB>]*trans[-</bB>]*\n*[ <bB>]*port[</bB>]*(5)/<a href="transport.5.html">&<\/a>/
/* .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.
{
/*
- * 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);
}
/* 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
/* 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
#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;
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);
/*
* 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.
}
/*
- * 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);
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));
}
#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
/*
* 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 \
" $" VAR_RCPT_CANON_MAPS \
" $" VAR_RELOCATED_MAPS \
" $" VAR_TRANSPORT_MAPS
-extern char *var_proxymap_filter;
+extern char *var_proxy_read_maps;
/*
* Other.
* 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
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'",
else
break;
}
- sleep(10); /* XXX make configurable */
+ sleep(1); /* XXX make configurable */
clnt_stream_recover(rewrite_clnt_stream);
}
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);
}
*/
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;
}
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;
}
/* 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
* 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))
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 */
/* .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.
/*
/* 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
/* 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
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.
/* 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,
*/
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);
}
* 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);
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);
}
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);
}
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)
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);
}
/* .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
/* 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
#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;
/* .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.
/*
* 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,
*/
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);
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);
}