-TDICT_PCRE_PRESCAN_CONTEXT
-TDICT_PCRE_REGEXP
-TDICT_PCRE_RULE
+-TDICT_PROXY
-TDICT_REGEXP
-TDICT_REGEXP_EXPAND_CONTEXT
-TDICT_REGEXP_IF_RULE
advanced content filtering example. Files: FILTER_README,
RELEASE_NOTES-2.0.
+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.
+
+ Feature: proxymap server for Postfix table lookups. This
+ helps to consolidate the number of open lookup tables (such
+ as MYSQL or LDAP), or to overcome chroot restrictions
+ (example: specify proxy:unix:passwd.byname to avoid the
+ need for a copy of the UNIX passwd file in chroot jails).
+ Files: global/dict_proxy.[hc], proxymap/proxymap.c
+
+ Cleanup: multiservers such as trivial-rewrite and the new
+ proxymap server now enforce the max_use total client number
+ limit more agressively, by not accepting new connections
+ after the limit is reached. Based on a patch by Victor
+ Duchovni, Morgan Stanley. File: master/multi_server.c.
+
Open problems:
Med: do not postpone rejected "MAIL FROM" size information,
src/showq src/postalias src/postcat src/postconf src/postdrop \
src/postkick src/postlock src/postlog src/postmap src/postqueue \
src/postsuper src/nqmgr src/qmqpd src/spawn src/flush src/verify \
- src/virtual
+ src/virtual src/proxymap
MANDIRS = proto man html
default: update
$POSTCONF -e "$unknown_local = 450" || exit 1
fi
+ # Add missing proxymap service to master.cf.
+
+ grep '^proxymap.*proxymap' $config_directory/master.cf >/dev/null || {
+ echo Editing $config_directory/master.cf, adding missing entry for proxymap service
+ cat >>$config_directory/master.cf <<EOF || exit 1
+proxymap unix - - n - - proxymap
+EOF
+ }
+
}
# A reminder if this is the first time Postfix is being installed.
$daemon_directory/nqmgr:f:root:-:755
$daemon_directory/pickup:f:root:-:755
$daemon_directory/pipe:f:root:-:755
+$daemon_directory/proxymap:f:root:-:755
$daemon_directory/qmgr:f:root:-:755
$daemon_directory/qmqpd:f:root:-:755
$daemon_directory/showq:f:root:-:755
$manpage_directory/man8/nqmgr.8:f:root:-:644
$manpage_directory/man8/pickup.8:f:root:-:644
$manpage_directory/man8/pipe.8:f:root:-:644
+$manpage_directory/man8/proxymap.8:f:root:-:644
$manpage_directory/man8/qmgr.8:f:root:-:644
$manpage_directory/man8/qmqpd.8:f:root:-:644
$manpage_directory/man8/showq.8:f:root:-:644
# The ipc_idle parameter bounds the idle time for internal communication
# channels after which a client disconnects voluntarily. The purpose
# is to allow servers to terminate voluntarily after they become
-# idle. Currently this is used by the address resolving and rewriting
-# clients.
+# idle. This is used, for example, by the address resolving and
+# rewriting clients.
#
# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
# The default time unit is s (seconds).
#
ipc_idle = 100s
+# The ipc_ttl parameter bounds the active time for internal communication
+# channels after which a client disconnects voluntarily. The purpose
+# is to allow servers to terminate voluntarily after reaching their
+# client limit. This is used, for example, by the address resolving
+# and rewriting clients.
+#
+# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
+# The default time unit is s (seconds).
+#
+ipc_ttl = 1000s
+
# The ipc_timeout parameter specifies a timeout for I/O on internal
# communication channels. The purpose is to break out of deadlock
# situations. If the timeout is exceeded the software aborts with a
lmtp.8.html master.8.html pickup.8.html pipe.8.html qmgr.8.html \
showq.8.html smtp.8.html smtpd.8.html trivial-rewrite.8.html \
nqmgr.8.html spawn.8.html flush.8.html virtual.8.html qmqpd.8.html \
- trace.8.html verify.8.html
+ trace.8.html verify.8.html proxymap.8.html
COMMANDS= mailq.1.html newaliases.1.html postalias.1.html postcat.1.html \
postconf.1.html postfix.1.html postkick.1.html postlock.1.html \
postlog.1.html postdrop.1.html postmap.1.html sendmail.1.html \
PATH=../mantools:$$PATH; \
srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
+proxymap.8.html: ../src/proxymap/proxymap.c
+ PATH=../mantools:$$PATH; \
+ srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
+
qmgr.8.html: ../src/qmgr/qmgr.c
PATH=../mantools:$$PATH; \
srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
<p>
+<li>The <a href="proxymap.8.html">proxymap</a> daemon provides
+read-only lookup service to Postfix client processes. The purpose
+is to overcome chroot restrictions, and to consolidate the number
+of open lookup tables by sharing one open table among multiple
+processes.
+
+<p>
+
<li>The <a href="spawn.8.html">spawn</a> daemon listens on a TCP
port, UNIX-domain socket or FIFO, and runs non-Postfix commands on
request, with the socket or FIFO connected to the standard input,
were left behind after abnormal termination.
<b>-m</b> List the names of all supported lookup table types.
+ Postfix lookup tables are specified as <i>type</i><b>:</b><i>name</i>,
+ where <i>type</i> is one of the types listed below. The
+ table <i>name</i> syntax depends on the lookup table type.
- <b>btree</b> A sorted, balanced tree structure. This is
- available only on systems with support for
+ <b>btree</b> A sorted, balanced tree structure. This is
+ available only on systems with support for
Berkeley DB databases.
<b>dbm</b> An indexed file type based on hashing. This
- is available only on systems with support
+ is available only on systems with support
for DBM databases.
<b>environ</b>
The UNIX process environment array. The
- lookup key is the variable name. Originally
- implemented for testing, someone may find
+ lookup key is the variable name. Originally
+ implemented for testing, someone may find
this useful someday.
<b>hash</b> An indexed file type based on hashing. This
- is available only on systems with support
+ is available only on systems with support
for Berkeley DB databases.
<b>ldap</b> (read-only)
- Perform lookups using the LDAP protocol.
+ Perform lookups using the LDAP protocol.
This is described in an LDAP_README file.
<b>mysql</b> (read-only)
- Perform lookups using the MYSQL protocol.
+ Perform lookups using the MYSQL protocol.
This is described in a MYSQL_README file.
<b>pcre</b> (read-only)
A lookup table based on Perl Compatible Reg-
- ular Expressions. The file format is
+ ular Expressions. The file format is
described in <a href="pcre_table.5.html"><b>pcre</b><i>_</i><b>table</b>(5)</a>.
+ <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
+ syntax is <i>type</i><b>:</b><i>name</i>.
+
<b>regexp</b> (read-only)
A lookup table based on regular expressions.
- The file format is described in <a href="regexp_table.5.html"><b>reg-</b>
+ The file format is described in <a href="regexp_table.5.html"><b>reg-</b>
<b>exp</b><i>_</i><b>table</b>(5)</a>.
<b>static</b> (read-only)
- A table that always returns its name as
- lookup result. For example, <b>static:foobar</b>
- always returns the string <b>foobar</b> as lookup
+ A table that always returns its name as
+ lookup result. For example, <b>static:foobar</b>
+ always returns the string <b>foobar</b> as lookup
result.
<b>unix</b> (read-only)
- A limited way to query the UNIX authentica-
+ A limited way to query the UNIX authentica-
tion database. The following tables are
implemented:
<b>unix:passwd.byname</b>
- The table is the UNIX password
- database. The key is a login name.
- The result is a password file entry
+ The table is the UNIX password
+ database. The key is a login name.
+ The result is a password file entry
in passwd(5) format.
<b>unix:group.byname</b>
- The table is the UNIX group
- database. The key is a group name.
- The result is a group file entry in
+ The table is the UNIX group
+ database. The key is a group name.
+ The result is a group file entry in
group(5) format.
- Other table types may exist depending on how Postfix was
+ Other table types may exist depending on how Postfix was
built.
<b>-n</b> Print non-default parameter settings only.
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
+ tiple <b>-v</b> options make the software increasingly
verbose.
<b>DIAGNOSTICS</b>
Directory with Postfix configuration files.
<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>
--- /dev/null
+<html> <head> </head> <body> <pre>
+PROXYMAP(8) PROXYMAP(8)
+
+<b>NAME</b>
+ proxymap - Postfix lookup table proxy server
+
+<b>SYNOPSIS</b>
+ <b>proxymap</b> [generic Postfix daemon options]
+
+<b>DESCRIPTION</b>
+ The <b>proxymap</b> server provides read-only table lookup ser-
+ vice to Postfix client processes. The purpose of the ser-
+ vice is:
+
+ <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:
+
+ 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:
+
+ virtual_alias_maps =
+ proxy:mysql:/etc/postfix/virtual.cf
+
+<b>PROXYMAP</b> <b>SERVICES</b>
+ 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.
+
+ <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.
+
+ There is no close command. This does not seem to be useful
+ because tables are meant to be shared among client pro-
+ cesses.
+
+ 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.
+
+ <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>BAD</b>
+ 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.
+
+<b>MASTER</b> <b>INTERFACE</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.
+
+<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.
+
+<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-
+ 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
+ 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>SEE</b> <b>ALSO</b>
+ dict_proxy(3) proxy map client
+
+<b>LICENSE</b>
+ The Secure Mailer license must be distributed with this
+ software.
+
+<b>AUTHOR(S)</b>
+ Wietse Venema
+ IBM T.J. Watson Research
+ P.O. Box 704
+ Yorktown Heights, NY 10598, USA
+
+ PROXYMAP(8)
+</pre> </body> </html>
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>
The server reply status is one of:
- <b>VRFYSTAT</b><i>_</i><b>OK</b>
+ <b>VRFY</b><i>_</i><b>STAT</b><i>_</i><b>OK</b>
The request completed normally.
- <b>VRFYSTAT</b><i>_</i><b>BAD</b>
+ <b>VRFY</b><i>_</i><b>STAT</b><i>_</i><b>BAD</b>
The server rejected the request (bad request name,
bad request parameter value).
- <b>VRFYSTAT</b><i>_</i><b>FAIL</b>
+ <b>VRFY</b><i>_</i><b>STAT</b><i>_</i><b>FAIL</b>
The request failed.
The recipient status is one of:
etc. is disallowed, because that would open a secu-
rity hole.
+ For security reasons, proxied table lookup is not
+ allowed, because that would open a security hole.
+
<b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>domains</b>
- The list of domains that should be delivered via
- the Postfix virtual delivery agent. This uses the
+ The list of domains that should be delivered via
+ the Postfix virtual delivery agent. This uses the
same syntax as the <b>mydestination</b> configuration
parameter.
<b>virtual</b><i>_</i><b>minimum</b><i>_</i><b>uid</b>
- Specifies a minimum uid that will be accepted as a
- return from a <b>virtual</b><i>_</i><b>owner</b><i>_</i><b>maps</b> or <b>vir-</b>
- <b>tual</b><i>_</i><b>uid</b><i>_</i><b>maps</b> lookup. Returned values less than
- this will be rejected, and the message will be
+ Specifies a minimum uid that will be accepted as a
+ return from a <b>virtual</b><i>_</i><b>owner</b><i>_</i><b>maps</b> or <b>vir-</b>
+ <b>tual</b><i>_</i><b>uid</b><i>_</i><b>maps</b> lookup. Returned values less than
+ this will be rejected, and the message will be
deferred.
<b>virtual</b><i>_</i><b>uid</b><i>_</i><b>maps</b>
Recipients are looked up in these maps to determine
- the user ID to be used when writing to the target
+ the user ID to be used when writing to the target
mailbox.
- While searching a lookup table, an address exten-
+ While searching a lookup table, an address exten-
sion (<i>user+foo@domain.tld</i>) is ignored.
- In a lookup table, specify a left-hand side of
- <i>@domain.tld</i> to match any user in the specified
- domain that does not have a specific
+ In a lookup table, specify a left-hand side of
+ <i>@domain.tld</i> to match any user in the specified
+ domain that does not have a specific
<i>user@domain.tld</i> entry.
- For security reasons, regular expression maps are
- allowed but regular expression substitution of $1
+ For security reasons, regular expression maps are
+ allowed but regular expression substitution of $1
etc. is disallowed, because that would open a secu-
rity hole.
+ For security reasons, proxied table lookup is not
+ allowed, because that would open a security hole.
+
<b>virtual</b><i>_</i><b>gid</b><i>_</i><b>maps</b>
Recipients are looked up in these maps to determine
the group ID to be used when writing to the target
etc. is disallowed, because that would open a secu-
rity hole.
+ For security reasons, proxied table lookup is not
+ allowed, because that would open a security hole.
+
<b>Locking</b> <b>controls</b>
<b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>lock</b>
- How to lock UNIX-style mailboxes: one or more of
- <b>flock</b>, <b>fcntl</b> or <b>dotlock</b>. The <b>dotlock</b> method
- requires that the recipient UID or GID has write
+ How to lock UNIX-style mailboxes: one or more of
+ <b>flock</b>, <b>fcntl</b> or <b>dotlock</b>. The <b>dotlock</b> method
+ requires that the recipient UID or GID has write
access to the parent directory of the mailbox file.
- This setting is ignored with <b>maildir</b> style deliv-
+ This setting is ignored with <b>maildir</b> style deliv-
ery, because such deliveries are safe without
explicit locks.
- Use the command <b>postconf</b> <b>-l</b> to find out what lock-
+ Use the command <b>postconf</b> <b>-l</b> to find out what lock-
ing methods are available on your system.
<b>deliver</b><i>_</i><b>lock</b><i>_</i><b>attempts</b>
- Limit the number of attempts to acquire an exclu-
+ Limit the number of attempts to acquire an exclu-
sive lock on a UNIX-style mailbox file.
<b>deliver</b><i>_</i><b>lock</b><i>_</i><b>delay</b>
Time (default: seconds) between successive attempts
- to acquire an exclusive lock on a UNIX-style mail-
- box file. The actual delay is slightly randomized.
+ to acquire an exclusive lock on a UNIX-style mail-
+ box file. The actual delay is slightly randomized.
<b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b>
- Limit the time after which a stale lockfile is
- removed (applicable to UNIX-style mailboxes only).
+ Limit the time after which a stale lockfile is
+ removed (applicable to UNIX-style mailboxes only).
<b>Resource</b> <b>controls</b>
<b>virtual</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
Limit the number of parallel deliveries to the same
domain via the <b>virtual</b> delivery agent. The default
limit is taken from the <b>default</b><i>_</i><b>destination</b><i>_</i><b>concur-</b>
- <b>rency</b><i>_</i><b>limit</b> parameter. The limit is enforced by
+ <b>rency</b><i>_</i><b>limit</b> parameter. The limit is enforced by
the Postfix queue manager.
<b>virtual</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
Limit the number of recipients per message delivery
- via the <b>virtual</b> delivery agent. The default limit
- is taken from the <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipi-</b>
- <b>ent</b><i>_</i><b>limit</b> parameter. The limit is enforced by the
+ via the <b>virtual</b> delivery agent. The default limit
+ is taken from the <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipi-</b>
+ <b>ent</b><i>_</i><b>limit</b> parameter. The limit is enforced by the
Postfix queue manager.
<b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>limit</b>
- The maximal size in bytes of a mailbox or maildir
+ The maximal size in bytes of a mailbox or maildir
file. Set to zero to disable the limit.
<b>HISTORY</b>
- This agent was originally based on the Postfix local
+ This agent was originally based on the Postfix local
delivery agent. Modifications mainly consisted of removing
- code that either was not applicable or that was not safe
- in this context: aliases, ~user/.forward files, delivery
+ code that either was not applicable or that was not safe
+ in this context: aliases, ~user/.forward files, delivery
to "|command" or to /file/name.
- The <b>Delivered-To:</b> header appears in the <b>qmail</b> system by
+ The <b>Delivered-To:</b> header appears in the <b>qmail</b> system by
Daniel Bernstein.
- The <b>maildir</b> structure appears in the <b>qmail</b> system by
+ The <b>maildir</b> structure appears in the <b>qmail</b> system by
Daniel Bernstein.
<b>SEE</b> <b>ALSO</b>
<a href="qmgr.8.html">qmgr(8)</a> queue manager
<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>
man8/lmtp.8 man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 \
man8/showq.8 man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 \
man8/nqmgr.8 man8/spawn.8 man8/flush.8 man8/virtual.8 man8/qmqpd.8 \
- man8/verify.8 man8/trace.8
+ man8/verify.8 man8/trace.8 man8/proxymap.8
COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
man8/pipe.8: ../src/pipe/pipe.c
../mantools/srctoman $? >$@
+man8/proxymap.8: ../src/proxymap/proxymap.c
+ ../mantools/srctoman $? >$@
+
man8/qmgr.8: ../src/qmgr/qmgr.c
../mantools/srctoman $? >$@
stale lock files that were left behind after abnormal termination.
.RE
.IP \fB-m\fR
-List the names of all supported lookup table types.
+List the names of all supported lookup table types. Postfix
+lookup tables are specified as \fItype\fB:\fIname\fR, where
+\fItype\fR is one of the types listed below. The table \fIname\fR
+syntax depends on the lookup table type.
.RS
.IP \fBbtree\fR
A sorted, balanced tree structure.
.IP "\fBpcre\fR (read-only)"
A lookup table based on Perl Compatible Regular Expressions. The
file format is described in \fBpcre_table\fR(5).
+.IP "\fBproxy\fR (read-only)"
+A lookup table that is implemented via the Postfix
+\fBproxymap\fR(8) service. The table name syntax is
+\fItype\fB:\fIname\fR.
.IP "\fBregexp\fR (read-only)"
A lookup table based on regular expressions. The file format is
described in \fBregexp_table\fR(5).
--- /dev/null
+.TH PROXYMAP 8
+.ad
+.fi
+.SH NAME
+proxymap
+\-
+Postfix lookup table proxy server
+.SH SYNOPSIS
+.na
+.nf
+\fBproxymap\fR [generic Postfix daemon options]
+.SH DESCRIPTION
+.ad
+.fi
+The \fBproxymap\fR server provides read-only table
+lookup service to Postfix client processes. The purpose
+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:
+.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:
+.sp
+virtual_alias_maps =
+.ti +4
+proxy:mysql:/etc/postfix/virtual.cf
+.SH PROXYMAP SERVICES
+.na
+.nf
+.ad
+.fi
+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
+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 lookup result value.
+The \fImaptype:mapname\fR and \fIflags\fR are the same
+as with the \fBPROXY_REQ_OPEN\fR request.
+.PP
+There is no close command. This does not seem to be useful
+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.
+.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
+.na
+.nf
+.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
+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.
+.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.
+.SH DIAGNOSTICS
+.ad
+.fi
+Problems and transactions are logged to \fBsyslogd\fR(8).
+.SH BUGS
+.ad
+.fi
+The proxymap server provides service to multiple clients,
+and must therefore not be used for tables that have high-latency
+lookups.
+.SH CONFIGURATION PARAMETERS
+.na
+.nf
+.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
+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.
+.SH SEE ALSO
+.na
+.nf
+dict_proxy(3) proxy map client
+.SH LICENSE
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH AUTHOR(S)
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
.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
returned.
.PP
The server reply status is one of:
-.IP \fBVRFYSTAT_OK\fR
+.IP \fBVRFY_STAT_OK\fR
The request completed normally.
-.IP \fBVRFYSTAT_BAD\fR
+.IP \fBVRFY_STAT_BAD\fR
The server rejected the request (bad request name, bad
request parameter value).
-.IP \fBVRFYSTAT_FAIL\fR
+.IP \fBVRFY_STAT_FAIL\fR
The request failed.
.PP
The recipient status is one of:
For security reasons, regular expression maps are allowed but
regular expression substitution of $1 etc. is disallowed,
because that would open a security hole.
+
+For security reasons, proxied table lookup is not allowed,
+because that would open a security hole.
.IP \fBvirtual_mailbox_domains\fR
The list of domains that should be delivered via the Postfix virtual
delivery agent. This uses the same syntax as the \fBmydestination\fR
For security reasons, regular expression maps are allowed but
regular expression substitution of $1 etc. is disallowed,
because that would open a security hole.
+
+For security reasons, proxied table lookup is not allowed,
+because that would open a security hole.
.IP \fBvirtual_gid_maps\fR
Recipients are looked up in these maps to determine the group ID to be
used when writing to the target mailbox.
For security reasons, regular expression maps are allowed but
regular expression substitution of $1 etc. is disallowed,
because that would open a security hole.
+
+For security reasons, proxied table lookup is not allowed,
+because that would open a security hole.
.SH "Locking controls"
.ad
.fi
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>]*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>/
+ s/[<bB>]*verify[</bB>]*(8)/<a href="verify.8.html">&<\/a>/
s/[<bB>]*virtual[</bB>]*(5)/<a href="virtual.5.html">&<\/a>/
s/[<bB>]*virtual[</bB>]*(8)/<a href="virtual.8.html">&<\/a>/
s/\(<a href="[^"]*">\)\([<bB>]*[a-z0-9-]*[-</bB>]*\)\(\n *\)\([<bB>]*[a-z0-9-]*[</bB>]*([0-9])\)\(<\/a>\)/\1\2\5\3\1\4\5/
flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c \
verp_sender.c match_parent_style.c mime_state.c header_token.c \
strip_addr.c virtual8_maps.c hold_message.c verify_clnt.c \
- trace.c log_adhoc.c verify.c
+ trace.c log_adhoc.c verify.c dict_proxy.c mail_dict.c
OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
debug_peer.o debug_process.o defer.o deliver_completed.o \
deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \
flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o \
verp_sender.o match_parent_style.o mime_state.o header_token.o \
strip_addr.o virtual8_maps.o hold_message.o verify_clnt.o \
- trace.o log_adhoc.o verify.o
+ trace.o log_adhoc.o verify.o dict_proxy.o mail_dict.o
HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \
mbox_conf.h mbox_open.h abounce.h qmqp_proto.h verp_sender.h \
match_parent_style.h quote_flags.h mime_state.h header_token.h \
lex_822.h strip_addr.h virtual8_maps.h hold_message.h verify_clnt.h \
- trace.h log_adhoc.h verify.h
+ trace.h log_adhoc.h verify.h dict_proxy.h mail_dict.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
deliver_request.o: mail_open_ok.h
deliver_request.o: recipient_list.h
deliver_request.o: deliver_request.h
+dict_proxy.o: dict_proxy.c
+dict_proxy.o: ../../include/sys_defs.h
+dict_proxy.o: ../../include/msg.h
+dict_proxy.o: ../../include/mymalloc.h
+dict_proxy.o: ../../include/stringops.h
+dict_proxy.o: ../../include/vstring.h
+dict_proxy.o: ../../include/vbuf.h
+dict_proxy.o: ../../include/vstream.h
+dict_proxy.o: ../../include/attr.h
+dict_proxy.o: ../../include/dict.h
+dict_proxy.o: ../../include/argv.h
+dict_proxy.o: mail_proto.h
+dict_proxy.o: ../../include/iostuff.h
+dict_proxy.o: mail_params.h
+dict_proxy.o: clnt_stream.h
+dict_proxy.o: dict_proxy.h
domain_list.o: domain_list.c
domain_list.o: ../../include/sys_defs.h
domain_list.o: ../../include/match_list.h
mail_date.o: ../../include/vstring.h
mail_date.o: ../../include/vbuf.h
mail_date.o: mail_date.h
+mail_dict.o: mail_dict.c
+mail_dict.o: ../../include/sys_defs.h
+mail_dict.o: ../../include/dict.h
+mail_dict.o: ../../include/vstream.h
+mail_dict.o: ../../include/vbuf.h
+mail_dict.o: ../../include/argv.h
+mail_dict.o: ../../include/msg.h
+mail_dict.o: dict_proxy.h
+mail_dict.o: mail_dict.h
mail_error.o: mail_error.c
mail_error.o: ../../include/sys_defs.h
mail_error.o: mail_error.h
/* SYNOPSIS
/* #include <clnt_stream.h>
/*
-/* CLNT_STREAM *clnt_stream_create(class, service, timeout)
+/* CLNT_STREAM *clnt_stream_create(class, service, timeout, ttl)
/* const char *class;
/* const char *service;
/* int timeout;
+/* int ttl;
/*
/* VSTREAM *clnt_stream_access(clnt_stream)
/* CLNT_STREAM *clnt_stream;
/* DESCRIPTION
/* This module maintains local IPC client endpoints that automatically
/* disconnect after a being idle for a configurable amount of time,
+/* that disconnect after a configurable time to live,
/* and that transparently handle most server-initiated disconnects.
/* Server disconnect is detected by read-selecting the client endpoint.
/* The code assumes that the server has disconnected when the endpoint
/* that happened in the middle of an I/O operation.
/*
/* clnt_stream_free() destroys of the specified client endpoint.
+/*
+/* Arguments:
+/* .IP class
+/* The service class, private or public.
+/* .IP service
+/* The service endpoint name. The name is limited to local IPC
+/* over sockets or equivalent.
+/* .IP timeout
+/* Idle time after which the client disconnects.
+/* .IP ttl
+/* Time to live after which the client disconnects.
/* DIAGNOSTICS
/* Warnings: communication failure. Fatal error: mail system is down,
/* out of memory.
struct CLNT_STREAM {
VSTREAM *vstream; /* buffered I/O */
int timeout; /* time before client disconnect */
+ int ttl; /* time before client disconnect */
char *class; /* server class */
char *service; /* server name */
};
clnt_stream_close(clnt_stream);
}
+/* clnt_stream_ttl_event - server-initiated disconnect or client-side timeout */
+
+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.
+ */
+ clnt_stream_event(event, context);
+}
+
/* clnt_stream_open - connect to service */
static void clnt_stream_open(CLNT_STREAM *clnt_stream)
* Schedule a read event so that we can clean up when the remote side
* disconnects, and schedule a timer event so that we can cleanup an idle
* connection. Note that both events are handled by the same routine.
+ *
+ * Finally, schedule an event to force disconnection even when the
+ * connection is not idle. This is to prevent one client from clinging on
+ * to a server forever.
*/
clnt_stream->vstream = mail_connect_wait(clnt_stream->class,
clnt_stream->service);
(char *) clnt_stream);
event_request_timer(clnt_stream_event, (char *) clnt_stream,
clnt_stream->timeout);
+ event_request_timer(clnt_stream_ttl_event, (char *) clnt_stream,
+ clnt_stream->ttl);
}
/* clnt_stream_close - disconnect from service */
msg_info("%s stream disconnect", clnt_stream->service);
event_disable_readwrite(vstream_fileno(clnt_stream->vstream));
event_cancel_timer(clnt_stream_event, (char *) clnt_stream);
+ event_cancel_timer(clnt_stream_ttl_event, (char *) clnt_stream);
(void) vstream_fclose(clnt_stream->vstream);
clnt_stream->vstream = 0;
}
/*
* Open a stream or restart the idle timer.
+ *
+ * Important! Do not restart the TTL timer!
*/
if (clnt_stream->vstream == 0) {
clnt_stream_open(clnt_stream);
/* clnt_stream_create - create client stream connection */
CLNT_STREAM *clnt_stream_create(const char *class, const char *service,
- int timeout)
+ int timeout, int ttl)
{
CLNT_STREAM *clnt_stream;
clnt_stream = (CLNT_STREAM *) mymalloc(sizeof(*clnt_stream));
clnt_stream->vstream = 0;
clnt_stream->timeout = timeout;
+ clnt_stream->ttl = ttl;
clnt_stream->class = mystrdup(class);
clnt_stream->service = mystrdup(service);
return (clnt_stream);
*/
typedef struct CLNT_STREAM CLNT_STREAM;
-extern CLNT_STREAM *clnt_stream_create(const char *, const char *, int);
+extern CLNT_STREAM *clnt_stream_create(const char *, const char *, int, int);
extern VSTREAM *clnt_stream_access(CLNT_STREAM *);
extern void clnt_stream_recover(CLNT_STREAM *);
extern void clnt_stream_free(CLNT_STREAM *);
--- /dev/null
+/*++
+/* NAME
+/* dict_proxy 3
+/* SUMMARY
+/* generic dictionary proxy client
+/* SYNOPSIS
+/* #include <dict_proxy.h>
+/*
+/* DICT *dict_proxy_open(map, open_flags, dict_flags)
+/* const char *map;
+/* int dummy;
+/* int dict_flags;
+/* DESCRIPTION
+/* dict_proxy_open() relays read-only operations through
+/* the Postfix proxymap server.
+/*
+/* 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.
+/* 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
+/* such as user/group IDs, output files, or external commands.
+/* SEE ALSO
+/* dict(3) generic dictionary manager
+/* clnt_stream(3) client endpoint connection management
+/* DIAGNOSTICS
+/* Fatal errors: out of memory, unimplemented operation,
+/* bad request parameter.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <errno.h>
+#include <unistd.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <stringops.h>
+#include <vstring.h>
+#include <vstream.h>
+#include <attr.h>
+#include <dict.h>
+
+/* Global library. */
+
+#include <mail_proto.h>
+#include <mail_params.h>
+#include <clnt_stream.h>
+#include <dict_proxy.h>
+
+/* Application-specific. */
+
+typedef struct {
+ DICT dict; /* generic members */
+ int in_flags; /* caller-specified flags */
+ CLNT_STREAM *client; /* server handle */
+ VSTRING *result; /* storage */
+} DICT_PROXY;
+
+ /*
+ * SLMs.
+ */
+#define STR(x) vstring_str(x)
+#define VSTREQ(v,s) (strcmp(STR(v),s) == 0)
+
+ /*
+ * All proxied maps within the same process share the same query/reply
+ * socket.
+ */
+static CLNT_STREAM *proxy_stream;
+
+/* dict_proxy_lookup - find table entry */
+
+static const char *dict_proxy_lookup(DICT *dict, const char *key)
+{
+ const char *myname = "dict_proxy_lookup";
+ DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
+ VSTREAM *stream;
+ int status;
+
+ /*
+ * The client and server live in separate processes that may start and
+ * terminate independently. We cannot rely on a persistent connection,
+ * let alone on persistent state (such as a specific open table) that is
+ * associated with a specific connection. Each lookup needs to specify
+ * the table and the flags that were specified to dict_proxy_open().
+ */
+ VSTRING_RESET(dict_proxy->result);
+ VSTRING_TERMINATE(dict_proxy->result);
+ for (;;) {
+ stream = clnt_stream_access(proxy_stream);
+ errno = 0;
+ if (attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_REQ, PROXY_REQ_LOOKUP,
+ ATTR_TYPE_STR, MAIL_ATTR_TABLE, dict->name,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, dict_proxy->in_flags,
+ ATTR_TYPE_STR, MAIL_ATTR_KEY, key,
+ ATTR_TYPE_END) != 0
+ || attr_scan(stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ 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);
+ } 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) {
+ return (STR(dict_proxy->result));
+ } else if (status == PROXY_STAT_FAIL) {
+ return (0);
+ } else if (status == 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);
+ }
+ }
+ clnt_stream_recover(proxy_stream);
+ sleep(1); /* XXX make configurable */
+ }
+}
+
+/* dict_proxy_close - disconnect */
+
+static void dict_proxy_close(DICT *dict)
+{
+ DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
+
+ vstring_free(dict_proxy->result);
+ dict_free(dict);
+}
+
+/* dict_proxy_open - open remote map */
+
+DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
+{
+ const char *myname = "dict_proxy_open";
+ DICT_PROXY *dict_proxy;
+ VSTREAM *stream;
+ int server_flags;
+ int status;
+ char *kludge = 0;
+ char *prefix;
+
+ /*
+ * Sanity checks.
+ */
+ 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.
+ */
+ dict_proxy = (DICT_PROXY *)
+ dict_alloc(DICT_TYPE_PROXY, map, sizeof(*dict_proxy));
+ dict_proxy->dict.lookup = dict_proxy_lookup;
+ dict_proxy->dict.close = dict_proxy_close;
+ dict_proxy->in_flags = dict_flags;
+ dict_proxy->result = vstring_alloc(10);
+
+ /*
+ * Use a shared stream for all proxied table lookups.
+ *
+ * XXX Use absolute pathname to make this work from non-daemon processes.
+ */
+ if (proxy_stream == 0) {
+ if (access(var_queue_dir, F_OK) == 0)
+ prefix = kludge = concatenate(var_queue_dir, "/",
+ MAIL_CLASS_PRIVATE, (char *) 0);
+ else
+ prefix = MAIL_CLASS_PRIVATE;
+ proxy_stream = clnt_stream_create(prefix,
+ MAIL_SERVICE_PROXYMAP,
+ var_ipc_idle_limit,
+ var_ipc_ttl_limit);
+ if (kludge)
+ myfree(kludge);
+ }
+
+ /*
+ * Establish initial contact and finalize the flags.
+ */
+ for (;;) {
+ stream = clnt_stream_access(proxy_stream);
+ errno = 0;
+ if (attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_REQ, PROXY_REQ_OPEN,
+ ATTR_TYPE_STR, MAIL_ATTR_TABLE, dict_proxy->dict.name,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, dict_proxy->in_flags,
+ ATTR_TYPE_END) != 0
+ || attr_scan(stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &server_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) {
+ 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);
+ }
+ clnt_stream_recover(proxy_stream);
+ sleep(1); /* XXX make configurable */
+ }
+ return (DICT_DEBUG (&dict_proxy->dict));
+}
--- /dev/null
+#ifndef _DICT_PROXY_H_INCLUDED_
+#define _DICT_PROXY_H_INCLUDED_
+
+/*++
+/* NAME
+/* dict_proxy 3h
+/* SUMMARY
+/* dictionary manager interface to PROXY maps
+/* SYNOPSIS
+/* #include <dict_proxy.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <dict.h>
+
+ /*
+ * External interface.
+ */
+#define DICT_TYPE_PROXY "proxy"
+
+extern DICT *dict_proxy_open(const char *, int, int);
+
+ /*
+ * Protocol interface.
+ */
+#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
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* mail_dict 3
+/* SUMMARY
+/* register application-specific dictionaries
+/* SYNOPSIS
+/* #include <mail_dict.h>
+/*
+/* void mail_dict_init()
+/* DESCRIPTION
+/* This module registers dictionary types that depend on higher-level
+/* Postfix-specific interfaces and protocols.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <dict.h>
+#include <msg.h>
+
+/* Global library. */
+
+#include <dict_proxy.h>
+#include <mail_dict.h>
+
+typedef struct {
+ char *type;
+ struct DICT *(*open) (const char *, int, int);
+} DICT_OPEN_INFO;
+
+static DICT_OPEN_INFO dict_open_info[] = {
+ DICT_TYPE_PROXY, dict_proxy_open,
+ /* XXX LDAP and MYSQL etc. should go here, too. */
+ 0,
+};
+
+/* mail_dict_init - dictionaries that depend on Postfix-specific interfaces */
+
+void mail_dict_init(void)
+{
+ DICT_OPEN_INFO *dp;
+
+ for (dp = dict_open_info; dp->type; dp++)
+ dict_open_register(dp->type, dp->open);
+}
--- /dev/null
+/*++
+/* NAME
+/* mail_dict 3h
+/* SUMMARY
+/* register application-specific dictionaries
+/* SYNOPSIS
+/* #include <mail_dict.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * External interface.
+ */
+extern void mail_dict_init(void);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
/* char *var_mail_release;
/* char *var_mail_version;
/* int var_ipc_idle_limit;
+/* int var_ipc_ttl_limit;
/* char *var_db_type;
/* char *var_hash_queue_names;
/* int var_hash_queue_depth;
char *var_mail_release;
char *var_mail_version;
int var_ipc_idle_limit;
+int var_ipc_ttl_limit;
char *var_db_type;
char *var_hash_queue_names;
int var_hash_queue_depth;
VAR_MAX_IDLE, DEF_MAX_IDLE, &var_idle_limit, 1, 0,
VAR_IPC_TIMEOUT, DEF_IPC_TIMEOUT, &var_ipc_timeout, 1, 0,
VAR_IPC_IDLE, DEF_IPC_IDLE, &var_ipc_idle_limit, 1, 0,
+ VAR_IPC_TTL, DEF_IPC_TTL, &var_ipc_ttl_limit, 1, 0,
VAR_TRIGGER_TIMEOUT, DEF_TRIGGER_TIMEOUT, &var_trigger_timeout, 1, 0,
VAR_FORK_DELAY, DEF_FORK_DELAY, &var_fork_delay, 1, 0,
VAR_FLOCK_DELAY, DEF_FLOCK_DELAY, &var_flock_delay, 1, 0,
/*
* Any subsystem: default amount of time a mail subsystem keeps an internal
- * IPC connection before closing it.
+ * IPC connection before closing it because it is idle for too much time.
*/
#define VAR_IPC_IDLE "ipc_idle"
#define DEF_IPC_IDLE "100s"
extern int var_ipc_idle_limit;
+ /*
+ * Any subsystem: default amount of time a mail subsystem keeps an internal
+ * IPC connection before closing it because the connection has existed for
+ * too much time.
+ */
+#define VAR_IPC_TTL "ipc_ttl"
+#define DEF_IPC_TTL "1000s"
+extern int var_ipc_ttl_limit;
+
/*
* Any front-end subsystem: avoid running out of memory when someone sends
* infinitely-long requests or replies.
* Heuristic to reject unknown local recipients at the SMTP port.
*/
#define VAR_LOCAL_RCPT_MAPS "local_recipient_maps"
-#define DEF_LOCAL_RCPT_MAPS "unix:passwd.byname $alias_maps"
+#define DEF_LOCAL_RCPT_MAPS "proxy:unix:passwd.byname $" VAR_ALIAS_MAPS
extern char *var_local_rcpt_maps;
#define VAR_LOCAL_RCPT_CODE "unknown_local_recipient_reject_code"
#define DEF_LOCAL_RCPT_CODE 550
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 \
+ " $" VAR_MYDEST \
+ " $" VAR_VIRT_ALIAS_MAPS \
+ " $" VAR_VIRT_ALIAS_DOMS \
+ " $" VAR_VIRT_MAILBOX_MAPS \
+ " $" VAR_VIRT_MAILBOX_DOMS \
+ " $" VAR_RELAY_RCPT_MAPS \
+ " $" VAR_RELAY_DOMAINS \
+ " $" VAR_CANONICAL_MAPS \
+ " $" VAR_SEND_CANON_MAPS \
+ " $" VAR_RCPT_CANON_MAPS \
+ " $" VAR_RELOCATED_MAPS \
+ " $" VAR_TRANSPORT_MAPS
+extern char *var_proxymap_filter;
+
/*
* Other.
*/
#define MAIL_SERVICE_VERIFY "verify"
#define MAIL_SERVICE_TRACE "trace"
#define MAIL_SERVICE_RELAY "relay"
+#define MAIL_SERVICE_PROXYMAP "proxymap"
/*
* Well-known socket or FIFO directories. The main difference is in file
#define MAIL_ATTR_TRACE_FLAGS "trace_flags"
#define MAIL_ATTR_ADDR_STATUS "recipient_status"
#define MAIL_ATTR_ACTION "action"
+#define MAIL_ATTR_TABLE "table"
+#define MAIL_ATTR_KEY "key"
+#define MAIL_ATTR_VALUE "value"
/*
* Suffixes for sender_name, sender_domain etc.
* 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 "20030101"
+#define MAIL_RELEASE_DATE "20030103"
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "2.0.0-" MAIL_RELEASE_DATE
/* const char *map_names;
/* int flags;
/*
-/* MAPS *maps_append(maps, map_name, dict_handle)
-/* MAPS *maps;
-/* const char *map_name;
-/* DICT *dict_handle;
-/*
/* const char *maps_find(maps, key, flags)
/* MAPS *maps;
/* const char *key;
/* other maps_xxx() operations.
/* See dict_open(3) for a description of flags.
/*
-/* maps_append() appends a dictionary to an existing handle
-/* under the given name. If dict_handle is a null pointer,
-/* the named dictionary is opened on the fly.
-/*
/* maps_find() searches the specified list of dictionaries
/* in the specified order for the named key. The result is in
/* memory that is overwritten upon each call.
MAPS *maps_create(const char *title, const char *map_names, int flags)
{
+ const char *myname = "maps_create";
char *temp;
char *bufp;
static char sep[] = " \t,\r\n";
MAPS *maps;
char *map_type_name;
+ VSTRING *map_type_name_flags;
+ DICT *dict;
/*
* Initialize.
maps = (MAPS *) mymalloc(sizeof(*maps));
maps->title = mystrdup(title);
maps->argv = argv_alloc(2);
- maps->flags = flags;
/*
* For each specified type:name pair, either register a new dictionary,
*/
if (*map_names) {
bufp = temp = mystrdup(map_names);
- while ((map_type_name = mystrtok(&bufp, sep)) != 0)
- maps_append(maps, map_type_name, dict_handle(map_type_name));
+ map_type_name_flags = vstring_alloc(10);
+
+ while ((map_type_name = mystrtok(&bufp, sep)) != 0) {
+ vstring_sprintf(map_type_name_flags, "%s:%o", map_type_name, flags);
+ if ((dict = dict_handle(vstring_str(map_type_name_flags))) == 0)
+ dict = dict_open(map_type_name, O_RDONLY, flags);
+ if ((dict->flags & flags) != flags)
+ msg_panic("%s: map %s has flags 0%o, want flags 0%o",
+ myname, map_type_name, dict->flags, flags);
+ dict_register(vstring_str(map_type_name_flags), dict);
+ argv_add(maps->argv, vstring_str(map_type_name_flags), ARGV_END);
+ }
myfree(temp);
+ vstring_free(map_type_name_flags);
}
return (maps);
}
-/* maps_append - append dictionary */
-
-MAPS *maps_append(MAPS *maps, const char *map_type_name, DICT *dict)
-{
- char *myname = "maps_append";
-
- if (msg_verbose)
- msg_info("%s: %s", myname, map_type_name);
- if (dict == 0)
- dict = dict_open(map_type_name, O_RDONLY, maps->flags);
- if ((dict->flags & maps->flags) != maps->flags)
- msg_warn("%s: map %s has flags 0%o, want flags 0%o",
- myname, map_type_name, dict->flags, maps->flags);
- dict_register(map_type_name, dict);
- argv_add(maps->argv, map_type_name, ARGV_END);
- argv_terminate(maps->argv);
- return (maps);
-}
-
/* maps_find - search a list of dictionaries */
const char *maps_find(MAPS *maps, const char *name, int flags)
typedef struct MAPS {
char *title;
struct ARGV *argv;
- int flags;
} MAPS;
extern MAPS *maps_create(const char *, const char *, int);
-extern MAPS *maps_append(MAPS *, const char *, DICT *);
extern const char *maps_find(MAPS *, const char *, int);
extern MAPS *maps_free(MAPS *);
*/
if (rewrite_clnt_stream == 0)
rewrite_clnt_stream = clnt_stream_create(MAIL_CLASS_PRIVATE,
- var_rewrite_service, var_ipc_idle_limit);
+ var_rewrite_service,
+ var_ipc_idle_limit,
+ var_ipc_ttl_limit);
for (;;) {
stream = clnt_stream_access(rewrite_clnt_stream);
*/
if (rewrite_clnt_stream == 0)
rewrite_clnt_stream = clnt_stream_create(MAIL_CLASS_PRIVATE,
- var_rewrite_service, var_ipc_idle_limit);
+ var_rewrite_service,
+ var_ipc_idle_limit,
+ var_ipc_ttl_limit);
for (;;) {
stream = clnt_stream_access(rewrite_clnt_stream);
if (vrfy_clnt != 0)
msg_panic("verify_clnt_init: multiple initialization");
vrfy_clnt = clnt_stream_create(MAIL_CLASS_PRIVATE, var_verify_service,
- var_ipc_idle_limit);
+ var_ipc_idle_limit, var_ipc_ttl_limit);
}
/* verify_clnt_query - request address verification status */
/* 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.
+/* 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.
/*
/* 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)
+ maps_create((title), (map_names), \
+ (flags) | DICT_FLAG_NO_REGSUB | DICT_FLAG_NO_PROXY)
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 | DICT_FLAG_NO_REGSUB);
+ DICT_FLAG_LOCK | INSECURE_DICT_FLAGS);
}
/* main - pass control to the single-threaded skeleton */
multi_server.o: ../../include/debug_process.h
multi_server.o: ../../include/mail_params.h
multi_server.o: ../../include/mail_conf.h
+multi_server.o: ../../include/mail_dict.h
multi_server.o: ../../include/timed_ipc.h
multi_server.o: ../../include/resolve_local.h
multi_server.o: mail_flow.h
single_server.o: ../../include/mail_task.h
single_server.o: ../../include/debug_process.h
single_server.o: ../../include/mail_conf.h
+single_server.o: ../../include/mail_dict.h
single_server.o: ../../include/timed_ipc.h
single_server.o: ../../include/resolve_local.h
single_server.o: mail_flow.h
trigger_server.o: ../../include/mail_task.h
trigger_server.o: ../../include/debug_process.h
trigger_server.o: ../../include/mail_conf.h
+trigger_server.o: ../../include/mail_dict.h
trigger_server.o: ../../include/resolve_local.h
trigger_server.o: mail_flow.h
trigger_server.o: master_proto.h
/* This value is taken from the global \fBmain.cf\fR configuration
/* file. Setting \fBvar_use_limit\fR to zero disables the client limit.
/*
+/* When the use count reaches the use limit, the process no longer
+/* accepts new connections. Once all existing clients disconnect the
+/* process terminates.
+/*
/* The var_idle_limit variable limits the time that a service
/* receives no client connection requests before it commits suicide.
/* This value is taken from the global \fBmain.cf\fR configuration
-/* file. Setting \fBvar_use_limit\fR to zero disables the idle limit.
+/* file. Setting \fBvar_idle_limit\fR to zero disables the idle limit.
/* DIAGNOSTICS
/* Problems and transactions are logged to \fBsyslogd\fR(8).
/* SEE ALSO
#include <debug_process.h>
#include <mail_params.h>
#include <mail_conf.h>
+#include <mail_dict.h>
#include <timed_ipc.h>
#include <resolve_local.h>
#include <mail_flow.h>
event_disable_readwrite(vstream_fileno(stream));
(void) vstream_fclose(stream);
client_count--;
- use_count++;
}
/* multi_server_execute - in case (char *) != (struct *) */
* Do not bother the application when the client disconnected.
*/
if (peekfd(vstream_fileno(stream)) > 0) {
- if (master_notify(var_pid, MASTER_STAT_TAKEN) < 0)
+ if (var_use_limit >= 0 && master_notify(var_pid, MASTER_STAT_TAKEN) < 0)
multi_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
multi_server_service(stream, multi_server_name, multi_server_argv);
- if (master_notify(var_pid, MASTER_STAT_AVAIL) < 0)
+ if (var_use_limit >= 0 && master_notify(var_pid, MASTER_STAT_AVAIL) < 0)
multi_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
} else {
multi_server_disconnect(stream);
non_blocking(fd, BLOCKING);
close_on_exec(fd, CLOSE_ON_EXEC);
client_count++;
+ use_count++;
stream = vstream_fdopen(fd, O_RDWR);
tmp = concatenate(multi_server_name, " socket", (char *) 0);
vstream_control(stream, VSTREAM_CTL_PATH, tmp, VSTREAM_CTL_END);
*/
mail_conf_suck();
+ /*
+ * Register dictionaries that use higher-level interfaces and protocols.
+ */
+ mail_dict_init();
+
/*
* Pick up policy settings from master process. Shut up error messages to
* stderr, because no-one is going to see them.
/*
* The event loop, at last.
*/
- while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
+ for (;;) {
+
+ /*
+ * When the use count reaches the use limit, notify the master daemon
+ * that we are no longer listening, close the listen sockets, and
+ * dispose of the accept lock if any. A use_limit < 0 indicates that
+ * the client limit was reached.
+ */
+ if (var_use_limit > 0 && use_count >= var_use_limit) {
+ if (msg_verbose)
+ msg_info("use limit reached -- closing listen socket");
+ if (master_notify(var_pid, MASTER_STAT_TAKEN) < 0)
+ multi_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
+ for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
+ event_disable_readwrite(fd);
+ (void) close(fd);
+ }
+ if (multi_server_lock != 0) {
+ (void) vstream_fclose(multi_server_lock);
+ multi_server_lock = 0;
+ }
+ var_use_limit = -1;
+ }
+
+ /*
+ * Terminate if the client limit was reached and no connections remain.
+ */
+ if (var_use_limit < 0 && client_count == 0) {
+ if (msg_verbose)
+ msg_info("all clients disconnected -- exiting");
+ break;
+ }
+
+ /*
+ * Grab the optional accept lock, do some optional idle processing,
+ * and wait for the next event.
+ */
if (multi_server_lock != 0) {
watchdog_stop(watchdog);
if (myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK,
#include <mail_task.h>
#include <debug_process.h>
#include <mail_conf.h>
+#include <mail_dict.h>
#include <timed_ipc.h>
#include <resolve_local.h>
#include <mail_flow.h>
*/
mail_conf_suck();
+ /*
+ * Register dictionaries that use higher-level interfaces and protocols.
+ */
+ mail_dict_init();
+
/*
* Pick up policy settings from master process. Shut up error messages to
* stderr, because no-one is going to see them.
#include <mail_task.h>
#include <debug_process.h>
#include <mail_conf.h>
+#include <mail_dict.h>
#include <resolve_local.h>
#include <mail_flow.h>
*/
mail_conf_suck();
+ /*
+ * Register dictionaries that use higher-level interfaces and protocols.
+ */
+ mail_dict_init();
+
/*
* Pick up policy settings from master process. Shut up error messages to
* stderr, because no-one is going to see them.
postalias.o: ../../include/tok822.h
postalias.o: ../../include/resolve_clnt.h
postalias.o: ../../include/mail_conf.h
+postalias.o: ../../include/mail_dict.h
postalias.o: ../../include/mail_params.h
postalias.o: ../../include/mkmap.h
postalias.o: ../../include/dict.h
#include <tok822.h>
#include <mail_conf.h>
+#include <mail_dict.h>
#include <mail_params.h>
#include <mkmap.h>
}
}
mail_conf_read();
+ mail_dict_init();
/*
* Use the map type specified by the user, or fall back to a default
postconf.o: ../../include/myflock.h
postconf.o: ../../include/mynetworks.h
postconf.o: ../../include/mail_conf.h
+postconf.o: ../../include/mail_dict.h
postconf.o: ../../include/mail_proto.h
postconf.o: ../../include/iostuff.h
postconf.o: ../../include/attr.h
/* stale lock files that were left behind after abnormal termination.
/* .RE
/* .IP \fB-m\fR
-/* List the names of all supported lookup table types.
+/* List the names of all supported lookup table types. Postfix
+/* lookup tables are specified as \fItype\fB:\fIname\fR, where
+/* \fItype\fR is one of the types listed below. The table \fIname\fR
+/* syntax depends on the lookup table type.
/* .RS
/* .IP \fBbtree\fR
/* A sorted, balanced tree structure.
/* .IP "\fBpcre\fR (read-only)"
/* A lookup table based on Perl Compatible Regular Expressions. The
/* file format is described in \fBpcre_table\fR(5).
+/* .IP "\fBproxy\fR (read-only)"
+/* A lookup table that is implemented via the Postfix
+/* \fBproxymap\fR(8) service. The table name syntax is
+/* \fItype\fB:\fIname\fR.
/* .IP "\fBregexp\fR (read-only)"
/* A lookup table based on regular expressions. The file format is
/* described in \fBregexp_table\fR(5).
#include <mynetworks.h>
#include <mail_conf.h>
+#include <mail_dict.h>
#include <mail_proto.h>
#include <mail_version.h>
#include <mail_params.h>
* If showing map types, show them and exit
*/
if (mode & SHOW_MAPS) {
+ mail_dict_init();
show_maps();
}
postmap.o: ../../include/vstring_vstream.h
postmap.o: ../../include/set_eugid.h
postmap.o: ../../include/mail_conf.h
+postmap.o: ../../include/mail_dict.h
postmap.o: ../../include/mail_params.h
postmap.o: ../../include/mkmap.h
postmap.o: ../../include/dict.h
/* Global library. */
#include <mail_conf.h>
+#include <mail_dict.h>
#include <mail_params.h>
#include <mkmap.h>
}
}
mail_conf_read();
+ mail_dict_init();
/*
* Use the map type specified by the user, or fall back to a default
--- /dev/null
+../../.indent.pro
\ No newline at end of file
--- /dev/null
+SHELL = /bin/sh
+SRCS = proxymap.c
+OBJS = proxymap.o
+HDRS =
+TESTSRC =
+WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
+ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
+ -Wunused
+DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
+CFLAGS = $(DEBUG) $(OPT) $(DEFS)
+TESTPROG=
+PROG = proxymap
+INC_DIR = ../../include
+LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a
+
+.c.o:; $(CC) $(CFLAGS) -c $*.c
+
+$(PROG): $(OBJS) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
+
+Makefile: Makefile.in
+ (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+
+test: $(TESTPROG)
+
+tests: test
+
+update: ../../libexec/$(PROG)
+
+../../libexec/$(PROG): $(PROG)
+ cp $(PROG) ../../libexec
+
+printfck: $(OBJS) $(PROG)
+ rm -rf printfck
+ mkdir printfck
+ sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
+ set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
+ cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o`
+
+lint:
+ lint $(DEFS) $(SRCS) $(LINTFIX)
+
+clean:
+ rm -f *.o *core $(PROG) $(TESTPROG) junk
+ rm -rf printfck
+
+tidy: clean
+
+depend: $(MAKES)
+ (sed '1,/^# do not edit/!d' Makefile.in; \
+ set -e; for i in [a-z][a-z0-9]*.c; do \
+ $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
+ -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \
+ done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
+ @$(EXPORT) make -f Makefile.in Makefile 1>&2
+
+# do not edit below this line - it is generated by 'make depend'
+proxymap.o: proxymap.c
+proxymap.o: ../../include/sys_defs.h
+proxymap.o: ../../include/msg.h
+proxymap.o: ../../include/mymalloc.h
+proxymap.o: ../../include/vstring.h
+proxymap.o: ../../include/vbuf.h
+proxymap.o: ../../include/dict.h
+proxymap.o: ../../include/vstream.h
+proxymap.o: ../../include/argv.h
+proxymap.o: ../../include/mail_conf.h
+proxymap.o: ../../include/mail_params.h
+proxymap.o: ../../include/mail_proto.h
+proxymap.o: ../../include/iostuff.h
+proxymap.o: ../../include/attr.h
+proxymap.o: ../../include/dict_proxy.h
+proxymap.o: ../../include/mail_server.h
--- /dev/null
+/*++
+/* NAME
+/* proxymap 8
+/* SUMMARY
+/* Postfix lookup table proxy server
+/* SYNOPSIS
+/* \fBproxymap\fR [generic Postfix daemon options]
+/* DESCRIPTION
+/* The \fBproxymap\fR server provides read-only table
+/* lookup service to Postfix client processes. The purpose
+/* 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:
+/* .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:
+/* .sp
+/* virtual_alias_maps =
+/* .ti +4
+/* proxy:mysql:/etc/postfix/virtual.cf
+/* PROXYMAP SERVICES
+/* .ad
+/* .fi
+/* 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
+/* 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 lookup result value.
+/* The \fImaptype:mapname\fR and \fIflags\fR are the same
+/* as with the \fBPROXY_REQ_OPEN\fR request.
+/* .PP
+/* There is no close command. This does not seem to be useful
+/* 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.
+/* .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
+/* .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
+/* 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.
+/* 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.
+/* DIAGNOSTICS
+/* Problems and transactions are logged to \fBsyslogd\fR(8).
+/* BUGS
+/* The proxymap server provides service to multiple clients,
+/* and must therefore not be used for tables that have high-latency
+/* lookups.
+/* CONFIGURATION PARAMETERS
+/* .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
+/* 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.
+/* SEE ALSO
+/* dict_proxy(3) proxy map client
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstring.h>
+#include <htable.h>
+#include <stringops.h>
+#include <dict.h>
+
+/* Global library. */
+
+#include <mail_conf.h>
+#include <mail_params.h>
+#include <mail_proto.h>
+#include <dict_proxy.h>
+
+/* Server skeleton. */
+
+#include <mail_server.h>
+
+/* Application-specific. */
+
+ /*
+ * XXX All but the last are needed here so that $name expansion dependencies
+ * aren't too broken. The fix is to gather all parameter default settings in
+ * one place.
+ */
+char *var_local_rcpt_maps;
+char *var_virt_alias_maps;
+char *var_virt_alias_doms;
+char *var_virt_mbox_maps;
+char *var_virt_mbox_doms;
+char *var_relay_rcpt_maps;
+char *var_relay_domains;
+char *var_canonical_maps;
+char *var_send_canon_maps;
+char *var_rcpt_canon_maps;
+char *var_relocatedmaps;
+char *var_transport_maps;
+char *var_proxymap_filter;
+
+ /*
+ * The pre-approved, pre-parsed list of maps.
+ */
+static HTABLE *proxymap_filter;
+
+ /*
+ * Shared and static to reduce memory allocation overhead.
+ */
+static VSTRING *request;
+static VSTRING *map_type_name_flags;
+static VSTRING *map_type_name;
+static VSTRING *key;
+
+ /*
+ * Silly little macros.
+ */
+#define STR(x) vstring_str(x)
+#define VSTREQ(x,y) (strcmp(STR(x),y) == 0)
+
+/* proxy_map_find - look up or open table */
+
+static DICT *proxy_map_find(const char *map_type_name, int dict_flags)
+{
+ DICT *dict;
+
+#define PROXY_COLON DICT_TYPE_PROXY ":"
+#define PROXY_COLON_LEN (sizeof(PROXY_COLON) - 1)
+#define OPEN_FLAGS O_RDONLY
+
+ /*
+ * Canonicalize the map name. If the map is not on the approved list,
+ * deny the request.
+ */
+ 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);
+ 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);
+ if ((dict = dict_handle(STR(map_type_name_flags))) == 0)
+ dict = dict_open(map_type_name, OPEN_FLAGS, dict_flags);
+ if (dict == 0)
+ msg_panic("proxy_map_find: dict_open null result");
+ dict_register(STR(map_type_name_flags), dict);
+ return (dict);
+}
+
+/* proxymap_lookup_service - remote lookup service */
+
+static void proxymap_lookup_service(VSTREAM *client_stream)
+{
+ int status = PROXY_STAT_BAD;
+ DICT *dict;
+ const char *value = "";
+ int dict_flags;
+
+ 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 = "";
+ }
+ }
+
+ /*
+ * 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_END);
+}
+
+/* proxymap_open_service - open remote lookup table */
+
+static void proxymap_open_service(VSTREAM *client_stream)
+{
+ int dict_flags;
+ DICT *dict;
+ int status = PROXY_STAT_BAD;
+ int flags = 0;
+
+ 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;
+ }
+
+ /*
+ * 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_END);
+}
+
+/* proxymap_service - perform service for client */
+
+static void proxymap_service(VSTREAM *client_stream, char *unused_service,
+ char **argv)
+{
+
+ /*
+ * Sanity check. This service takes no command-line arguments.
+ */
+ if (argv[0])
+ msg_fatal("unexpected command-line argument: %s", argv[0]);
+
+ /*
+ * This routine runs whenever a client connects to the socket dedicated
+ * to the address verification service. All connection-management stuff
+ * is handled by the common code in multi_server.c.
+ */
+ if (attr_scan(client_stream,
+ ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
+ ATTR_TYPE_STR, MAIL_ATTR_REQ, request,
+ ATTR_TYPE_END) == 1) {
+ if (VSTREQ(request, PROXY_REQ_LOOKUP)) {
+ proxymap_lookup_service(client_stream);
+ } else if (VSTREQ(request, PROXY_REQ_OPEN)) {
+ proxymap_open_service(client_stream);
+ } else {
+ msg_warn("unrecognized request: \"%s\", ignored", STR(request));
+ attr_print(client_stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, PROXY_STAT_BAD,
+ ATTR_TYPE_END);
+ }
+ }
+ vstream_fflush(client_stream);
+}
+
+/* post_jail_init - initialization after privilege drop */
+
+static void post_jail_init(char *unused_name, char **unused_argv)
+{
+ const char *sep = " \t\r\n";
+ char *saved_filter;
+ char *bp;
+ char *type_name;
+
+ request = vstring_alloc(10);
+ map_type_name = 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);
+ 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);
+ }
+ myfree(saved_filter);
+}
+
+/* main - pass control to the multi-threaded skeleton */
+
+int main(int argc, char **argv)
+{
+ static CONFIG_STR_TABLE str_table[] = {
+ VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
+ VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0,
+ VAR_VIRT_ALIAS_DOMS, DEF_VIRT_ALIAS_DOMS, &var_virt_alias_doms, 0, 0,
+ VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mbox_maps, 0, 0,
+ VAR_VIRT_MAILBOX_DOMS, DEF_VIRT_MAILBOX_DOMS, &var_virt_mbox_doms, 0, 0,
+ VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0,
+ VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0,
+ VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0,
+ VAR_SEND_CANON_MAPS, DEF_SEND_CANON_MAPS, &var_send_canon_maps, 0, 0,
+ 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,
+ 0,
+ };
+
+ multi_server_main(argc, argv, proxymap_service,
+ MAIL_SERVER_STR_TABLE, str_table,
+ MAIL_SERVER_POST_INIT, post_jail_init,
+ 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
#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 */
extern int dict_unknown_allowed;
extern int dict_errno;
/* returned.
/* .PP
/* The server reply status is one of:
-/* .IP \fBVRFYSTAT_OK\fR
+/* .IP \fBVRFY_STAT_OK\fR
/* The request completed normally.
-/* .IP \fBVRFYSTAT_BAD\fR
+/* .IP \fBVRFY_STAT_BAD\fR
/* The server rejected the request (bad request name, bad
/* request parameter value).
-/* .IP \fBVRFYSTAT_FAIL\fR
+/* .IP \fBVRFY_STAT_FAIL\fR
/* The request failed.
/* .PP
/* The recipient status is one of:
#include <post_mail.h>
#include <verify_clnt.h>
-/* Single server skeleton. */
+/* Server skeleton. */
#include <mail_server.h>
setsid();
}
-/* main - pass control to the single-threaded skeleton */
+/* main - pass control to the multi-threaded skeleton */
int main(int argc, char **argv)
{
/* For security reasons, regular expression maps are allowed but
/* regular expression substitution of $1 etc. is disallowed,
/* because that would open a security hole.
+/*
+/* For security reasons, proxied table lookup is not allowed,
+/* because that would open a security hole.
/* .IP \fBvirtual_mailbox_domains\fR
/* The list of domains that should be delivered via the Postfix virtual
/* delivery agent. This uses the same syntax as the \fBmydestination\fR
/* For security reasons, regular expression maps are allowed but
/* regular expression substitution of $1 etc. is disallowed,
/* because that would open a security hole.
+/*
+/* For security reasons, proxied table lookup is not allowed,
+/* because that would open a security hole.
/* .IP \fBvirtual_gid_maps\fR
/* Recipients are looked up in these maps to determine the group ID to be
/* used when writing to the target mailbox.
/* For security reasons, regular expression maps are allowed but
/* regular expression substitution of $1 etc. is disallowed,
/* because that would open a security hole.
+/*
+/* For security reasons, proxied table lookup is not allowed,
+/* because that would open a security hole.
/* .SH "Locking controls"
/* .ad
/* .fi