2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-22 09:57:34 +00:00

postfix-2.10-20120625

This commit is contained in:
Wietse Venema 2012-06-21 00:00:00 -05:00 committed by Viktor Dukhovni
parent 6fe49cc965
commit 6fa85acc3b
55 changed files with 2169 additions and 619 deletions

3
postfix/.indent.pro vendored
View File

@ -213,6 +213,8 @@
-TPSC_DNSBL_HEAD
-TPSC_DNSBL_SCORE
-TPSC_DNSBL_SITE
-TPSC_ENDPT_LOOKUP_INFO
-TPSC_HAPROXY_STATE
-TPSC_SMTPD_COMMAND
-TPSC_STARTTLS
-TPSC_STATE
@ -258,6 +260,7 @@
-TSMFICTX
-TSMTPD_CMD
-TSMTPD_DEFER
-TSMTPD_ENDPT_LOOKUP_INFO
-TSMTPD_PROXY
-TSMTPD_RBL_EXPAND_CONTEXT
-TSMTPD_RBL_STATE

View File

@ -17811,3 +17811,51 @@ Apologies for any names omitted.
Bugfix (introduced: 20031216-21): with soft_bounce=yes, the
SMTP client did not move on to the next MX host or fallback
relay after a 5xx reply. File: smtp/smtp_trouble.c.
20120527-8
Infrastructure: limited support to shrink VSTREAM buffers.
The change takes place when reading from (a stream for the
first time | an empty buffer) or when writing to (a stream
for the first time | a full buffer). TODO: the change should
also happen after purging or flushing a buffer. File:
util/vstream.c.
20120531-617
Feature: haproxy support in postscreen(8) and smtpd(8). To
enable, specify "smtpd_upstream_proxy_protocol = haproxy"
or "postscreen_upstream_proxy_protocol = haproxy". Files:
mantools/postlink, proto/postconf.proto, global/Makefile.in,
global/haproxy_srvr.c, global/haproxy_srvr.h, global/mail_params.h,
global/mail_proto.h, master/single_server.c, master/multi_server.c,
master/event_server.c, postscreen/Makefile.in,
postscreen/postscreen.c, postscreen/postscreen.h,
postscreen/postscreen_endpt.c, postscreen/postscreen_haproxy.c,
postscreen/postscreen_haproxy.h, postscreen/postscreen_send.c,
postscreen/postscreen_state.c, smtpd/Makefile.in, smtpd/smtpd.h,
smtpd/smtpd_peer.c, smtpd/smtpd_sasl_glue.c, smtpd/smtpd_haproxy.c,
util/Makefile.in, util/listen.h, util/recv_pass_attr.c,
util/stream_listen.c, util/sys_defs.h, util/unix_pass_listen.c.
20120618
Cleanup: made the postscreen-to-smtpd haproxy attribute
transmission more robust for Solaris. Files: util/sys_defs.h,
util/connect.h, util/steam_listen.c, postscreen/postscreen_send.c.
Cleanup: simplified the "stream used" workaround. Files:
util/vstream.h, master/event_server.c, master/multi_server.c.
20120621
Cleanup: simplified workarounds for Solaris streams versus
UNIX-domain sockets. Files: util/pass_accept.c (new),
util/pass_trigger.c (new), util/stream_pass_connect.c
(deleted), util/unix_pass_listen.c (deleted),
util/unix_pass_trigger.c (deleted), updated header files,
and replaced PASS_XXX macros by pass_xxx function calls.
Cleanup: don't clobber errno when logging a problem.
File util/msg_output.c.

View File

@ -14,6 +14,30 @@ specifies the release date of a stable release or snapshot release.
If you upgrade from Postfix 2.8 or earlier, read RELEASE_NOTES-2.9
before proceeding.
Incompatible changes with snapshot 20120625
===========================================
The postscreen(8)-to-smtpd(8) protocol has changed. To avoid "cannot
receive connection attributes" warnings and dropped connections,
execute the command "postfix reload". No mail will be lost as long
as the remote SMTP client tries again later.
Major changes with snapshot 20120625
====================================
Support for upstream proxy agent in the postscreen(8) and smtpd(8)
daemons. To enable the haproxy protocol, specify one of the
following:
postscreen_upstream_proxy_protocol = haproxy
smtpd_upstream_proxy_protocol = haproxy
Note 1: smtpd_upstream_proxy_protocol can't be used behind postscreen.
Note 2: To use the nginx proxy with smtpd(8), enable the XCLIENT
protocol with smtpd_authorized_xclient_hosts. This supports SASL
authentication in the proxy agent (Postfix 2.9 and later).
Major changes with snapshot 20120422
====================================

View File

@ -7639,6 +7639,31 @@ for details. </p>
<p> This feature is available in Postfix 2.8 and later. </p>
</DD>
<DT><b><a name="postscreen_upstream_proxy_protocol">postscreen_upstream_proxy_protocol</a>
(default: empty)</b></DT><DD>
<p> The name of the proxy protocol used by an optional before-postscreen
proxy agent. When a proxy agent is used, this protocol conveys local
and remote address and port information. Specify
"<a href="postconf.5.html#postscreen_upstream_proxy_protocol">postscreen_upstream_proxy_protocol</a> = haproxy" to enable the haproxy
protocol. <p>
<p> This feature is available in Postfix 2.10 and later. </p>
</DD>
<DT><b><a name="postscreen_upstream_proxy_timeout">postscreen_upstream_proxy_timeout</a>
(default: 5s)</b></DT><DD>
<p> The time limit for the proxy protocol specified with the
<a href="postconf.5.html#postscreen_upstream_proxy_protocol">postscreen_upstream_proxy_protocol</a> parameter. </p>
<p> This feature is available in Postfix 2.10 and later. </p>
</DD>
<DT><b><a name="postscreen_use_tls">postscreen_use_tls</a>
@ -15142,6 +15167,35 @@ purpose. </p>
<p> This feature is available in Postfix 2.2 and later. </p>
</DD>
<DT><b><a name="smtpd_upstream_proxy_protocol">smtpd_upstream_proxy_protocol</a>
(default: empty)</b></DT><DD>
<p> The name of the proxy protocol used by an optional before-smtpd
proxy agent. When a proxy agent is used, this protocol conveys local
and remote address and port information. Specify
"<a href="postconf.5.html#smtpd_upstream_proxy_protocol">smtpd_upstream_proxy_protocol</a> = haproxy" to enable the haproxy
protocol. </p>
<p> NOTE: To use the nginx proxy with <a href="smtpd.8.html">smtpd(8)</a>, enable the XCLIENT
protocol with <a href="postconf.5.html#smtpd_authorized_xclient_hosts">smtpd_authorized_xclient_hosts</a>. This supports SASL
authentication in the proxy agent (Postfix 2.9 and later). <p>
<p> This feature is available in Postfix 2.10 and later. </p>
</DD>
<DT><b><a name="smtpd_upstream_proxy_timeout">smtpd_upstream_proxy_timeout</a>
(default: 5s)</b></DT><DD>
<p> The time limit for the proxy protocol specified with the
<a href="postconf.5.html#smtpd_upstream_proxy_protocol">smtpd_upstream_proxy_protocol</a> parameter. </p>
<p> This feature is available in Postfix 2.10 and later. </p>
</DD>
<DT><b><a name="smtpd_use_tls">smtpd_use_tls</a>

View File

@ -146,10 +146,22 @@ POSTSCREEN(8) POSTSCREEN(8)
Safety net to keep mail queued that would otherwise
be returned to the sender.
<b>BEFORE-POSTSCREEN PROXY AGENT</b>
Available in Postfix version 2.10 and later:
<b><a href="postconf.5.html#postscreen_upstream_proxy_protocol">postscreen_upstream_proxy_protocol</a> (empty)</b>
The name of the proxy protocol used by an optional
before-postscreen proxy agent.
<b><a href="postconf.5.html#postscreen_upstream_proxy_timeout">postscreen_upstream_proxy_timeout</a> (5s)</b>
The time limit for the proxy protocol specified
with the <a href="postconf.5.html#postscreen_upstream_proxy_protocol">postscreen_upstream_proxy_protocol</a> parame-
ter.
<b>PERMANENT WHITE/BLACKLIST TEST</b>
This test is executed immediately after a remote SMTP
client connects. If a client is permanently whitelisted,
the client will be handed off immediately to a Postfix
This test is executed immediately after a remote SMTP
client connects. If a client is permanently whitelisted,
the client will be handed off immediately to a Postfix
SMTP server process.
<b><a href="postconf.5.html#postscreen_access_list">postscreen_access_list</a> (<a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>)</b>
@ -157,99 +169,99 @@ POSTSCREEN(8) POSTSCREEN(8)
addresses.
<b><a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a> (ignore)</b>
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
SMTP client is permanently blacklisted with the
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
SMTP client is permanently blacklisted with the
<a href="postconf.5.html#postscreen_access_list">postscreen_access_list</a> parameter.
<b>MAIL EXCHANGER POLICY TESTS</b>
When <a href="postscreen.8.html"><b>postscreen</b>(8)</a> is configured to monitor all primary
and backup MX addresses, it can refuse to whitelist
clients that connect to a backup MX address only. For
small sites, this requires configuring primary and backup
MX addresses on the same MTA. Larger sites would have to
share the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> cache between primary and backup
When <a href="postscreen.8.html"><b>postscreen</b>(8)</a> is configured to monitor all primary
and backup MX addresses, it can refuse to whitelist
clients that connect to a backup MX address only. For
small sites, this requires configuring primary and backup
MX addresses on the same MTA. Larger sites would have to
share the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> cache between primary and backup
MTAs, which would introduce a common point of failure.
<b><a href="postconf.5.html#postscreen_whitelist_interfaces">postscreen_whitelist_interfaces</a> (<a href="DATABASE_README.html#types">static</a>:all)</b>
A list of local <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server IP addresses
where a non-whitelisted remote SMTP client can
obtain <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s temporary whitelist status.
A list of local <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server IP addresses
where a non-whitelisted remote SMTP client can
obtain <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s temporary whitelist status.
<b>BEFORE-GREETING TESTS</b>
These tests are executed before the remote SMTP client
These tests are executed before the remote SMTP client
receives the "220 servername" greeting. If no tests remain
after the successful completion of this phase, the client
will be handed off immediately to a Postfix SMTP server
after the successful completion of this phase, the client
will be handed off immediately to a Postfix SMTP server
process.
<b><a href="postconf.5.html#dnsblog_service_name">dnsblog_service_name</a> (dnsblog)</b>
The name of the <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a> service entry in mas-
The name of the <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a> service entry in mas-
ter.cf.
<b><a href="postconf.5.html#postscreen_dnsbl_action">postscreen_dnsbl_action</a> (ignore)</b>
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
SMTP client's combined DNSBL score is equal to or
greater than a threshold (as defined with the
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
SMTP client's combined DNSBL score is equal to or
greater than a threshold (as defined with the
<a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> and <a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_thresh</a>-
<a href="postconf.5.html#postscreen_dnsbl_threshold">old</a> parameters).
<b><a href="postconf.5.html#postscreen_dnsbl_reply_map">postscreen_dnsbl_reply_map</a> (empty)</b>
A mapping from actual DNSBL domain name which
includes a secret password, to the DNSBL domain
A mapping from actual DNSBL domain name which
includes a secret password, to the DNSBL domain
name that postscreen will reply with when it
rejects mail.
<b><a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> (empty)</b>
Optional list of DNS white/blacklist domains, fil-
Optional list of DNS white/blacklist domains, fil-
ters and weight factors.
<b><a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_threshold</a> (1)</b>
The inclusive lower bound for blocking a remote
SMTP client, based on its combined DNSBL score as
defined with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter.
The inclusive lower bound for blocking a remote
SMTP client, based on its combined DNSBL score as
defined with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter.
<b><a href="postconf.5.html#postscreen_greet_action">postscreen_greet_action</a> (ignore)</b>
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
SMTP client speaks before its turn within the time
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
SMTP client speaks before its turn within the time
specified with the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> parameter.
<b><a href="postconf.5.html#postscreen_greet_banner">postscreen_greet_banner</a> ($<a href="postconf.5.html#smtpd_banner">smtpd_banner</a>)</b>
The <i>text</i> in the optional "220-<i>text</i>..." server
response that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> sends ahead of the real
Postfix SMTP server's "220 text..." response, in an
attempt to confuse bad SMTP clients so that they
attempt to confuse bad SMTP clients so that they
speak before their turn (pre-greet).
<b><a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> (${stress?2}${stress:6}s)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will wait for
an SMTP client to send a command before its turn,
and for DNS blocklist lookup results to arrive
(default: up to 2 seconds under stress, up to 6
an SMTP client to send a command before its turn,
and for DNS blocklist lookup results to arrive
(default: up to 2 seconds under stress, up to 6
seconds otherwise).
<b><a href="postconf.5.html#smtpd_service_name">smtpd_service_name</a> (smtpd)</b>
The internal service that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> hands off
The internal service that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> hands off
allowed connections to.
<b>AFTER-GREETING TESTS</b>
These tests are executed after the remote SMTP client
These tests are executed after the remote SMTP client
receives the "220 servername" greeting. If a client passes
all tests during this phase, it will receive a 4XX
response to RCPT TO commands until the client hangs up.
all tests during this phase, it will receive a 4XX
response to RCPT TO commands until the client hangs up.
After this, the client will be allowed to talk directly to
a Postfix SMTP server process.
<b><a href="postconf.5.html#postscreen_bare_newline_action">postscreen_bare_newline_action</a> (ignore)</b>
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
SMTP client sends a bare newline character, that
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
SMTP client sends a bare newline character, that
is, a newline not preceded by carriage return.
<b><a href="postconf.5.html#postscreen_bare_newline_enable">postscreen_bare_newline_enable</a> (no)</b>
Enable "bare newline" SMTP protocol tests in the
Enable "bare newline" SMTP protocol tests in the
<a href="postscreen.8.html"><b>postscreen</b>(8)</a> server.
<b><a href="postconf.5.html#postscreen_disable_vrfy_command">postscreen_disable_vrfy_command</a> ($<a href="postconf.5.html#disable_vrfy_command">disable_vrfy_command</a>)</b>
Disable the SMTP VRFY command in the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
Disable the SMTP VRFY command in the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
daemon.
<b><a href="postconf.5.html#postscreen_forbidden_commands">postscreen_forbidden_commands</a> ($<a href="postconf.5.html#smtpd_forbidden_commands">smtpd_forbidden_commands</a>)</b>
@ -257,159 +269,159 @@ POSTSCREEN(8) POSTSCREEN(8)
siders in violation of the SMTP protocol.
<b><a href="postconf.5.html#postscreen_helo_required">postscreen_helo_required</a> ($<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a>)</b>
Require that a remote SMTP client sends HELO or
Require that a remote SMTP client sends HELO or
EHLO before commencing a MAIL transaction.
<b><a href="postconf.5.html#postscreen_non_smtp_command_action">postscreen_non_smtp_command_action</a> (drop)</b>
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
SMTP client sends non-SMTP commands as specified
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
SMTP client sends non-SMTP commands as specified
with the <a href="postconf.5.html#postscreen_forbidden_commands">postscreen_forbidden_commands</a> parameter.
<b><a href="postconf.5.html#postscreen_non_smtp_command_enable">postscreen_non_smtp_command_enable</a> (no)</b>
Enable "non-SMTP command" tests in the
Enable "non-SMTP command" tests in the
<a href="postscreen.8.html"><b>postscreen</b>(8)</a> server.
<b><a href="postconf.5.html#postscreen_pipelining_action">postscreen_pipelining_action</a> (enforce)</b>
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
SMTP client sends multiple commands instead of
sending one command and waiting for the server to
The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
SMTP client sends multiple commands instead of
sending one command and waiting for the server to
respond.
<b><a href="postconf.5.html#postscreen_pipelining_enable">postscreen_pipelining_enable</a> (no)</b>
Enable "pipelining" SMTP protocol tests in the
Enable "pipelining" SMTP protocol tests in the
<a href="postscreen.8.html"><b>postscreen</b>(8)</a> server.
<b>CACHE CONTROLS</b>
<b><a href="postconf.5.html#postscreen_cache_cleanup_interval">postscreen_cache_cleanup_interval</a> (12h)</b>
The amount of time between <a href="postscreen.8.html"><b>postscreen</b>(8)</a> cache
The amount of time between <a href="postscreen.8.html"><b>postscreen</b>(8)</a> cache
cleanup runs.
<b><a href="postconf.5.html#postscreen_cache_map">postscreen_cache_map</a> (btree:$data_direc-</b>
<b>tory/postscreen_cache)</b>
Persistent storage for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server
Persistent storage for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server
decisions.
<b><a href="postconf.5.html#postscreen_cache_retention_time">postscreen_cache_retention_time</a> (7d)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will cache an
expired temporary whitelist entry before it is
expired temporary whitelist entry before it is
removed.
<b><a href="postconf.5.html#postscreen_bare_newline_ttl">postscreen_bare_newline_ttl</a> (30d)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
result from a successful "bare newline" SMTP proto-
col test.
<b><a href="postconf.5.html#postscreen_dnsbl_ttl">postscreen_dnsbl_ttl</a> (1h)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
result from a successful DNS blocklist test.
<b><a href="postconf.5.html#postscreen_greet_ttl">postscreen_greet_ttl</a> (1d)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
result from a successful PREGREET test.
<b><a href="postconf.5.html#postscreen_non_smtp_command_ttl">postscreen_non_smtp_command_ttl</a> (30d)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
result from a successful "non_smtp_command" SMTP
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
result from a successful "non_smtp_command" SMTP
protocol test.
<b><a href="postconf.5.html#postscreen_pipelining_ttl">postscreen_pipelining_ttl</a> (30d)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
result from a successful "pipelining" SMTP protocol
test.
<b>RESOURCE CONTROLS</b>
<b><a href="postconf.5.html#line_length_limit">line_length_limit</a> (2048)</b>
Upon input, long lines are chopped up into pieces
of at most this length; upon delivery, long lines
Upon input, long lines are chopped up into pieces
of at most this length; upon delivery, long lines
are reconstructed.
<b><a href="postconf.5.html#postscreen_client_connection_count_limit">postscreen_client_connection_count_limit</a></b>
<b>($<a href="postconf.5.html#smtpd_client_connection_count_limit">smtpd_client_connection_count_limit</a>)</b>
How many simultaneous connections any remote SMTP
client is allowed to have with the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
How many simultaneous connections any remote SMTP
client is allowed to have with the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
daemon.
<b><a href="postconf.5.html#postscreen_command_count_limit">postscreen_command_count_limit</a> (20)</b>
The limit on the total number of commands per SMTP
session for <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol
The limit on the total number of commands per SMTP
session for <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol
engine.
<b><a href="postconf.5.html#postscreen_command_time_limit">postscreen_command_time_limit</a> (${stress?10}${stress:300}s)</b>
The time limit to read an entire command line with
The time limit to read an entire command line with
<a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol engine.
<b><a href="postconf.5.html#postscreen_post_queue_limit">postscreen_post_queue_limit</a> ($<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b>
The number of clients that can be waiting for ser-
The number of clients that can be waiting for ser-
vice from a real Postfix SMTP server process.
<b><a href="postconf.5.html#postscreen_pre_queue_limit">postscreen_pre_queue_limit</a> ($<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b>
The number of non-whitelisted clients that can be
waiting for a decision whether they will receive
The number of non-whitelisted clients that can be
waiting for a decision whether they will receive
service from a real Postfix SMTP server process.
<b><a href="postconf.5.html#postscreen_watchdog_timeout">postscreen_watchdog_timeout</a> (10s)</b>
How much time a <a href="postscreen.8.html"><b>postscreen</b>(8)</a> process may take to
respond to a remote SMTP client command or to per-
How much time a <a href="postscreen.8.html"><b>postscreen</b>(8)</a> process may take to
respond to a remote SMTP client command or to per-
form a cache operation before it is terminated by a
built-in watchdog timer.
<b>STARTTLS CONTROLS</b>
<b><a href="postconf.5.html#postscreen_tls_security_level">postscreen_tls_security_level</a> ($<a href="postconf.5.html#smtpd_tls_security_level">smtpd_tls_security_level</a>)</b>
The SMTP TLS security level for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
server; when a non-empty value is specified, this
The SMTP TLS security level for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
server; when a non-empty value is specified, this
overrides the obsolete parameters
<a href="postconf.5.html#postscreen_use_tls">postscreen_use_tls</a> and <a href="postconf.5.html#postscreen_enforce_tls">postscreen_enforce_tls</a>.
<b><a href="postconf.5.html#tlsproxy_service_name">tlsproxy_service_name</a> (tlsproxy)</b>
The name of the <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> service entry in mas-
The name of the <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> service entry in mas-
ter.cf.
<b>OBSOLETE STARTTLS SUPPORT CONTROLS</b>
These parameters are supported for compatibility with
These parameters are supported for compatibility with
<a href="smtpd.8.html"><b>smtpd</b>(8)</a> legacy parameters.
<b><a href="postconf.5.html#postscreen_use_tls">postscreen_use_tls</a> ($<a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a>)</b>
Opportunistic TLS: announce STARTTLS support to
Opportunistic TLS: announce STARTTLS support to
remote SMTP clients, but do not require that
clients use TLS encryption.
<b><a href="postconf.5.html#postscreen_enforce_tls">postscreen_enforce_tls</a> ($<a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>)</b>
Mandatory TLS: announce STARTTLS support to remote
SMTP clients, and require that clients use TLS
Mandatory TLS: announce STARTTLS support to remote
SMTP clients, and require that clients use TLS
encryption.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
The maximal number of digits after the decimal
The maximal number of digits after the decimal
point when logging sub-second delay values.
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
The location of all postfix administrative com-
The location of all postfix administrative com-
mands.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
The maximum amount of time that an idle Postfix
daemon process waits for an incoming connection
The maximum amount of time that an idle Postfix
daemon process waits for an incoming connection
before terminating voluntarily.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
The process ID of a Postfix command or daemon
The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
The process name of a Postfix command or daemon
The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
The mail system name that is prepended to the
process name in syslog records, so that "smtpd"
The mail system name that is prepended to the
process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b>SEE ALSO</b>
@ -422,14 +434,14 @@ POSTSCREEN(8) POSTSCREEN(8)
<a href="POSTSCREEN_README.html">POSTSCREEN_README</a>, Postfix Postscreen Howto
<b>LICENSE</b>
The Secure Mailer license must be distributed with this
The Secure Mailer license must be distributed with this
software.
<b>HISTORY</b>
This service was introduced with Postfix version 2.8.
Many ideas in <a href="postscreen.8.html"><b>postscreen</b>(8)</a> were explored in earlier work
by Michael Tokarev, in OpenBSD spamd, and in MailChannels
Many ideas in <a href="postscreen.8.html"><b>postscreen</b>(8)</a> were explored in earlier work
by Michael Tokarev, in OpenBSD spamd, and in MailChannels
Traffic Control.
<b>AUTHOR(S)</b>

View File

@ -183,6 +183,17 @@ SMTPD(8) SMTPD(8)
addresses with the domain specified in the
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> parameter.
<b>BEFORE-SMTPD PROXY AGENT</b>
Available in Postfix version 2.10 and later:
<b><a href="postconf.5.html#smtpd_upstream_proxy_protocol">smtpd_upstream_proxy_protocol</a> (empty)</b>
The name of the proxy protocol used by an optional
before-smtpd proxy agent.
<b><a href="postconf.5.html#smtpd_upstream_proxy_timeout">smtpd_upstream_proxy_timeout</a> (5s)</b>
The time limit for the proxy protocol specified
with the <a href="postconf.5.html#smtpd_upstream_proxy_protocol">smtpd_upstream_proxy_protocol</a> parameter.
<b>AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS</b>
As of version 1.0, Postfix can be configured to send new
mail to an external content filter AFTER the mail is

View File

@ -666,7 +666,7 @@ CCARGS="$CCARGS -DSNAPSHOT"
# Non-production: needs thorough testing, or major changes are still
# needed before the code stabilizes.
#CCARGS="$CCARGS -DNONPROD"
CCARGS="$CCARGS -DNONPROD"
sed 's/ / /g' <<EOF
SYSTYPE = $SYSTYPE

View File

@ -4426,6 +4426,19 @@ postscreen_use_tls and postscreen_enforce_tls. See smtpd_tls_security_level
for details.
.PP
This feature is available in Postfix 2.8 and later.
.SH postscreen_upstream_proxy_protocol (default: empty)
The name of the proxy protocol used by an optional before-postscreen
proxy agent. When a proxy agent is used, this protocol conveys local
and remote address and port information. Specify
"postscreen_upstream_proxy_protocol = haproxy" to enable the haproxy
protocol.
.PP
This feature is available in Postfix 2.10 and later.
.SH postscreen_upstream_proxy_timeout (default: 5s)
The time limit for the proxy protocol specified with the
postscreen_upstream_proxy_protocol parameter.
.PP
This feature is available in Postfix 2.10 and later.
.SH postscreen_use_tls (default: $smtpd_use_tls)
Opportunistic TLS: announce STARTTLS support to remote SMTP clients,
but do not require that clients use TLS encryption.
@ -9806,6 +9819,23 @@ server's command line. Port 465 (smtps) was once chosen for this
purpose.
.PP
This feature is available in Postfix 2.2 and later.
.SH smtpd_upstream_proxy_protocol (default: empty)
The name of the proxy protocol used by an optional before-smtpd
proxy agent. When a proxy agent is used, this protocol conveys local
and remote address and port information. Specify
"smtpd_upstream_proxy_protocol = haproxy" to enable the haproxy
protocol.
.PP
NOTE: To use the nginx proxy with \fBsmtpd\fR(8), enable the XCLIENT
protocol with smtpd_authorized_xclient_hosts. This supports SASL
authentication in the proxy agent (Postfix 2.9 and later).
.PP
This feature is available in Postfix 2.10 and later.
.SH smtpd_upstream_proxy_timeout (default: 5s)
The time limit for the proxy protocol specified with the
smtpd_upstream_proxy_protocol parameter.
.PP
This feature is available in Postfix 2.10 and later.
.SH smtpd_use_tls (default: no)
Opportunistic TLS: announce STARTTLS support to remote SMTP clients,
but do not require that clients use TLS encryption.

View File

@ -152,6 +152,18 @@ response.
.IP "\fBsoft_bounce (no)\fR"
Safety net to keep mail queued that would otherwise be returned to
the sender.
.SH "BEFORE-POSTSCREEN PROXY AGENT"
.na
.nf
.ad
.fi
Available in Postfix version 2.10 and later:
.IP "\fBpostscreen_upstream_proxy_protocol (empty)\fR"
The name of the proxy protocol used by an optional before-postscreen
proxy agent.
.IP "\fBpostscreen_upstream_proxy_timeout (5s)\fR"
The time limit for the proxy protocol specified with the
postscreen_upstream_proxy_protocol parameter.
.SH "PERMANENT WHITE/BLACKLIST TEST"
.na
.nf

View File

@ -172,6 +172,18 @@ $mydomain; either don't rewrite message headers from other clients
at all, or rewrite message headers and update incomplete addresses
with the domain specified in the remote_header_rewrite_domain
parameter.
.SH "BEFORE-SMTPD PROXY AGENT"
.na
.nf
.ad
.fi
Available in Postfix version 2.10 and later:
.IP "\fBsmtpd_upstream_proxy_protocol (empty)\fR"
The name of the proxy protocol used by an optional before-smtpd
proxy agent.
.IP "\fBsmtpd_upstream_proxy_timeout (5s)\fR"
The time limit for the proxy protocol specified with the
smtpd_upstream_proxy_protocol parameter.
.SH "AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS"
.na
.nf

View File

@ -673,6 +673,8 @@ while (<>) {
s;\bsmtpd_use_tls\b;<a href="postconf.5.html#smtpd_use_tls">$&</a>;g;
s;\bsmtpd_reject_footer\b;<a href="postconf.5.html#smtpd_reject_footer">$&</a>;g;
s;\bsmtpd_per_record_deadline\b;<a href="postconf.5.html#smtpd_per_record_deadline">$&</a>;g;
s;\bsmtpd_upstream_proxy_protocol\b;<a href="postconf.5.html#smtpd_upstream_proxy_protocol">$&</a>;g;
s;\bsmtpd_upstream_proxy_timeout\b;<a href="postconf.5.html#smtpd_upstream_proxy_timeout">$&</a>;g;
s;\btls_daemon_random_bytes\b;<a href="postconf.5.html#tls_daemon_random_bytes">$&</a>;g;
s;\btls_daemon_random_source\b;<a href="postconf.5.html#tls_daemon_random_source">$&</a>;g;
s;\btls_ran[-</Bb>]*\n* *[<Bb>]*dom_bytes\b;<a href="postconf.5.html#tls_random_bytes">$&</a>;g;
@ -969,6 +971,8 @@ while (<>) {
s;\bpostscreen_reject_footer\b;<a href="postconf.5.html#postscreen_reject_footer">$&</a>;g;
s;\bpostscreen_command_filter\b;<a href="postconf.5.html#postscreen_command_filter">$&</a>;g;
s;\bpostscreen_whitelist_interfaces\b;<a href="postconf.5.html#postscreen_whitelist_interfaces">$&</a>;g;
s;\bpostscreen_upstream_proxy_protocol\b;<a href="postconf.5.html#postscreen_upstream_proxy_protocol">$&</a>;g;
s;\bpostscreen_upstream_proxy_timeout\b;<a href="postconf.5.html#postscreen_upstream_proxy_timeout">$&</a>;g;
s;\btlsproxy_watchdog_timeout\b;<a href="postconf.5.html#tlsproxy_watchdog_timeout">$&</a>;g;
s;\btlsproxy_enforce_tls\b;<a href="postconf.5.html#tlsproxy_enforce_tls">$&</a>;g;

View File

@ -14369,6 +14369,44 @@ and will never be allowed to talk to a Postfix SMTP server process.
<p> This feature is available in Postfix 2.9 and later. </p>
%PARAM postscreen_upstream_proxy_protocol
<p> The name of the proxy protocol used by an optional before-postscreen
proxy agent. When a proxy agent is used, this protocol conveys local
and remote address and port information. Specify
"postscreen_upstream_proxy_protocol = haproxy" to enable the haproxy
protocol. <p>
<p> This feature is available in Postfix 2.10 and later. </p>
%PARAM postscreen_upstream_proxy_timeout 5s
<p> The time limit for the proxy protocol specified with the
postscreen_upstream_proxy_protocol parameter. </p>
<p> This feature is available in Postfix 2.10 and later. </p>
%PARAM smtpd_upstream_proxy_protocol
<p> The name of the proxy protocol used by an optional before-smtpd
proxy agent. When a proxy agent is used, this protocol conveys local
and remote address and port information. Specify
"smtpd_upstream_proxy_protocol = haproxy" to enable the haproxy
protocol. </p>
<p> NOTE: To use the nginx proxy with smtpd(8), enable the XCLIENT
protocol with smtpd_authorized_xclient_hosts. This supports SASL
authentication in the proxy agent (Postfix 2.9 and later). <p>
<p> This feature is available in Postfix 2.10 and later. </p>
%PARAM smtpd_upstream_proxy_timeout 5s
<p> The time limit for the proxy protocol specified with the
smtpd_upstream_proxy_protocol parameter. </p>
<p> This feature is available in Postfix 2.10 and later. </p>
%PARAM enable_long_queue_ids no
<p> Enable long, non-repeating, queue IDs (queue file names). The

View File

@ -32,7 +32,7 @@ SRCS = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \
match_service.c mail_conf_nint.c addr_match_list.c mail_conf_nbool.c \
smtp_reply_footer.c safe_ultostr.c verify_sender_addr.c \
dict_memcache.c mail_version.c memcache_proto.c server_acl.c \
mkmap_fail.c
mkmap_fail.c haproxy_srvr.c
OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \
@ -66,7 +66,7 @@ OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
match_service.o mail_conf_nint.o addr_match_list.o mail_conf_nbool.o \
smtp_reply_footer.o safe_ultostr.o verify_sender_addr.o \
dict_memcache.o mail_version.o memcache_proto.o server_acl.o \
mkmap_fail.o
mkmap_fail.o haproxy_srvr.o
HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
conv_time.h db_common.h debug_peer.h debug_process.h defer.h \
@ -92,7 +92,8 @@ HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
verp_sender.h wildcard_inet_addr.h xtext.h delivered_hdr.h \
fold_addr.h header_body_checks.h data_redirect.h match_service.h \
addr_match_list.h smtp_reply_footer.h safe_ultostr.h \
verify_sender_addr.h dict_memcache.h memcache_proto.h server_acl.h
verify_sender_addr.h dict_memcache.h memcache_proto.h server_acl.h \
haproxy_srvr.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
@ -1100,6 +1101,15 @@ fold_addr.o: ../../include/vbuf.h
fold_addr.o: ../../include/vstring.h
fold_addr.o: fold_addr.c
fold_addr.o: fold_addr.h
haproxy_srvr.o: ../../include/msg.h
haproxy_srvr.o: ../../include/myaddrinfo.h
haproxy_srvr.o: ../../include/stringops.h
haproxy_srvr.o: ../../include/sys_defs.h
haproxy_srvr.o: ../../include/valid_hostname.h
haproxy_srvr.o: ../../include/vbuf.h
haproxy_srvr.o: ../../include/vstring.h
haproxy_srvr.o: haproxy_srvr.c
haproxy_srvr.o: haproxy_srvr.h
header_body_checks.o: ../../include/argv.h
header_body_checks.o: ../../include/dict.h
header_body_checks.o: ../../include/msg.h

View File

@ -0,0 +1,197 @@
/*++
/* NAME
/* haproxy_srvr 3
/* SUMMARY
/* server-side haproxy protocol support
/* SYNOPSIS
/* #include <haproxy_srvr.h>
/*
/* const char *haproxy_srvr_parse(str,
/* smtp_client_addr, smtp_client_port,
/* smtp_server_addr, smtp_server_port)
/* const char *str;
/* MAI_HOSTADDR_STR *smtp_client_addr,
/* MAI_SERVPORT_STR *smtp_client_port,
/* MAI_HOSTADDR_STR *smtp_server_addr,
/* MAI_SERVPORT_STR *smtp_server_port;
/* DESCRIPTION
/* haproxy_srvr_parse() parses a haproxy line. The result is
/* null in case of success, a pointer to text (with the error
/* type) in case of error. If both IPv6 and IPv4 support are
/* enabled, IPV4_IN_IPV6 address syntax (::ffff:1.2.3.4) is
/* converted to IPV4 syntax.
/* 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 <stdarg.h>
#include <stdlib.h>
#include <string.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
/* Utility library. */
#include <msg.h>
#include <myaddrinfo.h>
#include <valid_hostname.h>
#include <stringops.h>
#include <mymalloc.h>
#include <inet_proto.h>
/* Global library. */
#include <haproxy_srvr.h>
/* Application-specific. */
static INET_PROTO_INFO *proto_info;
/* haproxy_srvr_parse_lit - extract and validate string literal */
static int haproxy_srvr_parse_lit(const char *str,...)
{
va_list ap;
const char *cp;
int result = -1;
if (msg_verbose)
msg_info("haproxy_srvr_parse: %s", str);
if (str != 0) {
va_start(ap, str);
while (result < 0 && (cp = va_arg(ap, const char *)) != 0)
if (strcmp(str, cp) == 0)
result = 0;
va_end(ap);
}
return (result);
}
/* haproxy_srvr_parse_proto - parse and validate the protocol type */
static int haproxy_srvr_parse_proto(const char *str, int *addr_family)
{
if (msg_verbose)
msg_info("haproxy_srvr_parse: proto=%s", str);
#ifdef AF_INET6
if (strcasecmp(str, "TCP6") == 0) {
if (strchr((char *) proto_info->sa_family_list, AF_INET6) != 0) {
*addr_family = AF_INET6;
return (0);
}
} else
#endif
if (strcasecmp(str, "TCP4") == 0) {
if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0) {
*addr_family = AF_INET;
return (0);
}
}
return (-1);
}
/* haproxy_srvr_parse_addr - extract and validate IP address */
static int haproxy_srvr_parse_addr(const char *str, MAI_HOSTADDR_STR *addr,
int addr_family)
{
if (msg_verbose)
msg_info("haproxy_srvr_parse: addr=%s proto=%d", str, addr_family);
if (str == 0 || strlen(str) >= sizeof(MAI_HOSTADDR_STR))
return (-1);
switch (addr_family) {
#ifdef AF_INET6
case AF_INET6:
if (!valid_ipv6_hostaddr(str, DONT_GRIPE))
return (-1);
if (strncasecmp("::ffff:", str, 7) == 0
&& strchr((char *) proto_info->sa_family_list, AF_INET) != 0) {
memcpy(addr->buf, str + 7, strlen(str) + 1 - 7);
return (0);
} else {
memcpy(addr->buf, str, strlen(str) + 1);
return (0);
}
#endif
case AF_INET:
if (!valid_ipv4_hostaddr(str, DONT_GRIPE))
return (-1);
memcpy(addr->buf, str, strlen(str) + 1);
return (0);
default:
msg_panic("haproxy_srvr_parse: unexpected address family: %d",
addr_family);
}
}
/* haproxy_srvr_parse_port - extract and validate TCP port */
static int haproxy_srvr_parse_port(const char *str, MAI_SERVPORT_STR *port)
{
if (msg_verbose)
msg_info("haproxy_srvr_parse: port=%s", str);
if (str == 0 || strlen(str) >= sizeof(MAI_SERVPORT_STR)
|| !valid_hostport(str, DONT_GRIPE)) {
return (-1);
} else {
memcpy(port->buf, str, strlen(str) + 1);
return (0);
}
}
/* haproxy_srvr_parse - parse haproxy line */
const char *haproxy_srvr_parse(const char *str,
MAI_HOSTADDR_STR *smtp_client_addr,
MAI_SERVPORT_STR *smtp_client_port,
MAI_HOSTADDR_STR *smtp_server_addr,
MAI_SERVPORT_STR *smtp_server_port)
{
char *saved_str = mystrdup(str);
char *cp = saved_str;
const char *err;
int addr_family;
if (proto_info == 0)
proto_info = inet_proto_info();
/*
* XXX We don't accept connections with the "UNKNOWN" protocol type,
* because those would sidestep address-based access control mechanisms.
*/
#define NEXT_TOKEN mystrtok(&cp, " \r\n")
if (haproxy_srvr_parse_lit(NEXT_TOKEN, "PROXY", (char *) 0) < 0)
err = "unexpected protocol header";
else if (haproxy_srvr_parse_proto(NEXT_TOKEN, &addr_family) < 0)
err = "unsupported protocol type";
else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_client_addr,
addr_family) < 0)
err = "unexpected client address syntax";
else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_server_addr,
addr_family) < 0)
err = "unexpected server address syntax";
else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_client_port) < 0)
err = "unexpected client port syntax";
else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_server_port) < 0)
err = "unexpected server port syntax";
else
err = 0;
myfree(saved_str);
return (err);
}

View File

@ -0,0 +1,45 @@
#ifndef _HAPROXY_SRVR_H_INCLUDED_
#define _HAPROXY_SRVR_H_INCLUDED_
/*++
/* NAME
/* haproxy_srvr 3h
/* SUMMARY
/* server-side haproxy protocol support
/* SYNOPSIS
/* #include <haproxy_srvr.h>
/* DESCRIPTION
/* .nf
/*
* Utility library.
*/
#include <myaddrinfo.h>
/*
* External interface.
*/
extern const char *haproxy_srvr_parse(const char *,
MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *,
MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *);
#define HAPROXY_PROTO_NAME "haproxy"
#define HAPROXY_MAX_LEN (256 + 2)
#ifndef DO_GRIPE
#define DO_GRIPE 1
#define DONT_GRIPE 0
#endif
/* 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

View File

@ -3458,6 +3458,14 @@ extern char *var_psc_acl;
#define DEF_PSC_WLIST_IF "static:all"
extern char *var_psc_wlist_if;
#define VAR_PSC_UPROXY_PROTO "postscreen_upstream_proxy_protocol"
#define DEF_PSC_UPROXY_PROTO ""
extern char *var_psc_uproxy_proto;
#define VAR_PSC_UPROXY_TMOUT "postscreen_upstream_proxy_timeout"
#define DEF_PSC_UPROXY_TMOUT "5s"
extern int var_psc_uproxy_tmout;
#define VAR_DNSBLOG_SERVICE "dnsblog_service_name"
#define DEF_DNSBLOG_SERVICE MAIL_SERVICE_DNSBLOG
extern char *var_dnsblog_service;
@ -3620,6 +3628,17 @@ extern bool var_smtp_rec_deadline;
#define DEF_SMTPD_ACL_PERM_LOG ""
extern char *var_smtpd_acl_perm_log;
/*
* Before-smtpd proxy support.
*/
#define VAR_SMTPD_UPROXY_PROTO "smtpd_upstream_proxy_protocol"
#define DEF_SMTPD_UPROXY_PROTO ""
extern char *var_smtpd_uproxy_proto;
#define VAR_SMTPD_UPROXY_TMOUT "smtpd_upstream_proxy_timeout"
#define DEF_SMTPD_UPROXY_TMOUT "5s"
extern int var_smtpd_uproxy_tmout;
/*
* Postfix sendmail command compatibility features.
*/

View File

@ -193,6 +193,9 @@ extern char *mail_pathname(const char *, const char *);
#define MAIL_ATTR_ACT_REVERSE_CLIENT_NAME "reverse_client_name"
#define MAIL_ATTR_ACT_FORWARD_CLIENT_NAME "forward_client_name"
#define MAIL_ATTR_ACT_SERVER_ADDR "server_address" /* server address */
#define MAIL_ATTR_ACT_SERVER_PORT "server_port" /* server TCP port */
#define MAIL_ATTR_PROTO_STATE "protocol_state" /* MAIL/RCPT/... */
#define MAIL_ATTR_ORG_NONE "unknown" /* origin unknown */
#define MAIL_ATTR_ORG_LOCAL "local" /* local submission */

View File

@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
#define MAIL_RELEASE_DATE "20120617"
#define MAIL_RELEASE_DATE "20120621"
#define MAIL_VERSION_NUMBER "2.10"
#ifdef SNAPSHOT

View File

@ -90,6 +90,7 @@ event_server.o: ../../include/chroot_uid.h
event_server.o: ../../include/debug_process.h
event_server.o: ../../include/dict.h
event_server.o: ../../include/events.h
event_server.o: ../../include/htable.h
event_server.o: ../../include/iostuff.h
event_server.o: ../../include/listen.h
event_server.o: ../../include/mail_conf.h
@ -193,6 +194,7 @@ master_flow.o: ../../include/sys_defs.h
master_flow.o: master.h
master_flow.o: master_flow.c
master_flow.o: master_proto.h
master_listen.o: ../../include/htable.h
master_listen.o: ../../include/inet_addr_list.h
master_listen.o: ../../include/iostuff.h
master_listen.o: ../../include/listen.h
@ -286,6 +288,7 @@ multi_server.o: ../../include/chroot_uid.h
multi_server.o: ../../include/debug_process.h
multi_server.o: ../../include/dict.h
multi_server.o: ../../include/events.h
multi_server.o: ../../include/htable.h
multi_server.o: ../../include/iostuff.h
multi_server.o: ../../include/listen.h
multi_server.o: ../../include/mail_conf.h
@ -318,6 +321,7 @@ single_server.o: ../../include/chroot_uid.h
single_server.o: ../../include/debug_process.h
single_server.o: ../../include/dict.h
single_server.o: ../../include/events.h
single_server.o: ../../include/htable.h
single_server.o: ../../include/iostuff.h
single_server.o: ../../include/listen.h
single_server.o: ../../include/mail_conf.h
@ -350,6 +354,7 @@ trigger_server.o: ../../include/chroot_uid.h
trigger_server.o: ../../include/debug_process.h
trigger_server.o: ../../include/dict.h
trigger_server.o: ../../include/events.h
trigger_server.o: ../../include/htable.h
trigger_server.o: ../../include/iostuff.h
trigger_server.o: ../../include/listen.h
trigger_server.o: ../../include/mail_conf.h

View File

@ -38,7 +38,10 @@
/* its privileges. The application is responsible for managing
/* subsequent I/O events on the stream, and is responsible for
/* calling event_server_disconnect() when the stream is closed.
/* The stream initial state is non-blocking mode. The service
/* The stream initial state is non-blocking mode.
/* Optional connection attributes are provided as a hash that
/* is attached as stream context. NOTE: the attributes are
/* destroyed after this function is called. The service
/* name argument corresponds to the service name in the master.cf
/* file. The argv argument specifies command-line arguments
/* left over after options processing.
@ -255,6 +258,7 @@ static unsigned event_server_generation;
static void (*event_server_pre_disconn) (VSTREAM *, char *, char **);
static void (*event_server_slow_exit) (char *, char **);
static int event_server_watchdog = 1000;
static int event_server_saved_flags;
/* event_server_exit - normal termination */
@ -339,6 +343,8 @@ void event_server_disconnect(VSTREAM *stream)
static void event_server_execute(int unused_event, char *context)
{
VSTREAM *stream = (VSTREAM *) context;
HTABLE *attr = (vstream_flags(stream) == event_server_saved_flags ?
(HTABLE *) vstream_context(stream) : 0);
if (event_server_lock != 0
&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
@ -355,11 +361,13 @@ static void event_server_execute(int unused_event, char *context)
event_server_service(stream, event_server_name, event_server_argv);
if (master_notify(var_pid, event_server_generation, MASTER_STAT_AVAIL) < 0)
event_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
if (attr)
htable_free(attr, myfree);
}
/* event_server_wakeup - wake up application */
static void event_server_wakeup(int fd)
static void event_server_wakeup(int fd, HTABLE *attr)
{
VSTREAM *stream;
char *tmp;
@ -388,9 +396,13 @@ static void event_server_wakeup(int fd)
client_count++;
stream = vstream_fdopen(fd, O_RDWR);
tmp = concatenate(event_server_name, " socket", (char *) 0);
vstream_control(stream, VSTREAM_CTL_PATH, tmp, VSTREAM_CTL_END);
vstream_control(stream,
VSTREAM_CTL_PATH, tmp,
VSTREAM_CTL_CONTEXT, (char *) attr,
VSTREAM_CTL_END);
myfree(tmp);
timed_ipc_setup(stream);
event_server_saved_flags = vstream_flags(stream);
if (event_server_in_flow_delay && mail_flow_get(1) < 0)
event_request_timer(event_server_execute, (char *) stream,
var_in_flow_delay);
@ -430,7 +442,7 @@ static void event_server_accept_local(int unused_event, char *context)
event_request_timer(event_server_timeout, (char *) 0, time_left);
return;
}
event_server_wakeup(fd);
event_server_wakeup(fd, (HTABLE *) 0);
}
#ifdef MASTER_XPORT_NAME_PASS
@ -442,6 +454,7 @@ static void event_server_accept_pass(int unused_event, char *context)
int listen_fd = CAST_CHAR_PTR_TO_INT(context);
int time_left = -1;
int fd;
HTABLE *attr = 0;
/*
* Be prepared for accept() to fail because some other process already
@ -455,7 +468,7 @@ static void event_server_accept_pass(int unused_event, char *context)
if (event_server_pre_accept)
event_server_pre_accept(event_server_name, event_server_argv);
fd = PASS_ACCEPT(listen_fd);
fd = pass_accept_attr(listen_fd, &attr);
if (event_server_lock != 0
&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
MYFLOCK_OP_NONE) < 0)
@ -467,7 +480,7 @@ static void event_server_accept_pass(int unused_event, char *context)
event_request_timer(event_server_timeout, (char *) 0, time_left);
return;
}
event_server_wakeup(fd);
event_server_wakeup(fd, attr);
}
#endif
@ -504,7 +517,7 @@ static void event_server_accept_inet(int unused_event, char *context)
event_request_timer(event_server_timeout, (char *) 0, time_left);
return;
}
event_server_wakeup(fd);
event_server_wakeup(fd, (HTABLE *) 0);
}
/* event_server_main - the real main program */

View File

@ -136,7 +136,7 @@ void master_listen_init(MASTER_SERV *serv)
case MASTER_SERV_TYPE_PASS:
set_eugid(var_owner_uid, var_owner_gid);
serv->listen_fd[0] =
PASS_LISTEN(serv->name, serv->max_proc > var_proc_limit ?
LOCAL_LISTEN(serv->name, serv->max_proc > var_proc_limit ?
serv->max_proc : var_proc_limit, NON_BLOCKING);
close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
set_ugid(getuid(), getgid());

View File

@ -107,7 +107,7 @@ static void master_wakeup_timer_event(int unused_event, char *context)
break;
#ifdef MASTER_SERV_TYPE_PASS
case MASTER_SERV_TYPE_PASS:
status = PASS_TRIGGER(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
status = pass_trigger(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
break;
#endif

View File

@ -35,6 +35,9 @@
/* function is run after the program has optionally dropped its
/* privileges. This function should not attempt to preserve state
/* across calls. The stream initial state is non-blocking mode.
/* Optional connection attributes are provided as a hash that
/* is attached as stream context. NOTE: the attributes are
/* destroyed after this function is called.
/* The service name argument corresponds to the service name in the
/* master.cf file.
/* The argv argument specifies command-line arguments left over
@ -241,6 +244,7 @@ static VSTREAM *multi_server_lock;
static int multi_server_in_flow_delay;
static unsigned multi_server_generation;
static void (*multi_server_pre_disconn) (VSTREAM *, char *, char **);
static int multi_server_saved_flags;
/* multi_server_exit - normal termination */
@ -322,6 +326,8 @@ void multi_server_disconnect(VSTREAM *stream)
static void multi_server_execute(int unused_event, char *context)
{
VSTREAM *stream = (VSTREAM *) context;
HTABLE *attr = (vstream_flags(stream) == multi_server_saved_flags ?
(HTABLE *) vstream_context(stream) : 0);
if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK,
@ -342,6 +348,8 @@ static void multi_server_execute(int unused_event, char *context)
} else {
multi_server_disconnect(stream);
}
if (attr)
htable_free(attr, myfree);
}
/* multi_server_enable_read - enable read events */
@ -355,7 +363,7 @@ static void multi_server_enable_read(int unused_event, char *context)
/* multi_server_wakeup - wake up application */
static void multi_server_wakeup(int fd)
static void multi_server_wakeup(int fd, HTABLE *attr)
{
VSTREAM *stream;
char *tmp;
@ -384,9 +392,13 @@ static void multi_server_wakeup(int fd)
client_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);
vstream_control(stream,
VSTREAM_CTL_PATH, tmp,
VSTREAM_CTL_CONTEXT, (char *) attr,
VSTREAM_CTL_END);
myfree(tmp);
timed_ipc_setup(stream);
multi_server_saved_flags = vstream_flags(stream);
if (multi_server_in_flow_delay && mail_flow_get(1) < 0)
event_request_timer(multi_server_enable_read, (char *) stream,
var_in_flow_delay);
@ -426,7 +438,7 @@ static void multi_server_accept_local(int unused_event, char *context)
event_request_timer(multi_server_timeout, (char *) 0, time_left);
return;
}
multi_server_wakeup(fd);
multi_server_wakeup(fd, (HTABLE *) 0);
}
#ifdef MASTER_XPORT_NAME_PASS
@ -438,6 +450,7 @@ static void multi_server_accept_pass(int unused_event, char *context)
int listen_fd = CAST_CHAR_PTR_TO_INT(context);
int time_left = -1;
int fd;
HTABLE *attr = 0;
/*
* Be prepared for accept() to fail because some other process already
@ -451,7 +464,7 @@ static void multi_server_accept_pass(int unused_event, char *context)
if (multi_server_pre_accept)
multi_server_pre_accept(multi_server_name, multi_server_argv);
fd = PASS_ACCEPT(listen_fd);
fd = pass_accept_attr(listen_fd, &attr);
if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK,
MYFLOCK_OP_NONE) < 0)
@ -463,7 +476,7 @@ static void multi_server_accept_pass(int unused_event, char *context)
event_request_timer(multi_server_timeout, (char *) 0, time_left);
return;
}
multi_server_wakeup(fd);
multi_server_wakeup(fd, attr);
}
#endif
@ -500,7 +513,7 @@ static void multi_server_accept_inet(int unused_event, char *context)
event_request_timer(multi_server_timeout, (char *) 0, time_left);
return;
}
multi_server_wakeup(fd);
multi_server_wakeup(fd, (HTABLE *) 0);
}
/* multi_server_main - the real main program */

View File

@ -29,6 +29,8 @@
/* a client connects to the program's service port. The function is
/* run after the program has irrevocably dropped its privileges.
/* The stream initial state is non-blocking mode.
/* Optional connection attributes are provided as a hash that
/* is attached as stream context.
/* The service name argument corresponds to the service name in the
/* master.cf file.
/* The argv argument specifies command-line arguments left over
@ -245,7 +247,7 @@ static void single_server_timeout(int unused_event, char *unused_context)
/* single_server_wakeup - wake up application */
static void single_server_wakeup(int fd)
static void single_server_wakeup(int fd, HTABLE *attr)
{
VSTREAM *stream;
char *tmp;
@ -263,7 +265,10 @@ static void single_server_wakeup(int fd)
close_on_exec(fd, CLOSE_ON_EXEC);
stream = vstream_fdopen(fd, O_RDWR);
tmp = concatenate(single_server_name, " socket", (char *) 0);
vstream_control(stream, VSTREAM_CTL_PATH, tmp, VSTREAM_CTL_END);
vstream_control(stream,
VSTREAM_CTL_PATH, tmp,
VSTREAM_CTL_CONTEXT, (char *) attr,
VSTREAM_CTL_END);
myfree(tmp);
timed_ipc_setup(stream);
if (master_notify(var_pid, single_server_generation, MASTER_STAT_TAKEN) < 0)
@ -281,6 +286,8 @@ static void single_server_wakeup(int fd)
use_count++;
if (var_idle_limit > 0)
event_request_timer(single_server_timeout, (char *) 0, var_idle_limit);
if (attr)
htable_free(attr, myfree);
}
/* single_server_accept_local - accept client connection request */
@ -314,7 +321,7 @@ static void single_server_accept_local(int unused_event, char *context)
event_request_timer(single_server_timeout, (char *) 0, time_left);
return;
}
single_server_wakeup(fd);
single_server_wakeup(fd, (HTABLE *) 0);
}
#ifdef MASTER_XPORT_NAME_PASS
@ -326,6 +333,7 @@ static void single_server_accept_pass(int unused_event, char *context)
int listen_fd = CAST_CHAR_PTR_TO_INT(context);
int time_left = -1;
int fd;
HTABLE *attr = 0;
/*
* Be prepared for accept() to fail because some other process already
@ -338,7 +346,7 @@ static void single_server_accept_pass(int unused_event, char *context)
if (single_server_pre_accept)
single_server_pre_accept(single_server_name, single_server_argv);
fd = PASS_ACCEPT(listen_fd);
fd = pass_accept_attr(listen_fd, &attr);
if (single_server_lock != 0
&& myflock(vstream_fileno(single_server_lock), INTERNAL_LOCK,
MYFLOCK_OP_NONE) < 0)
@ -350,7 +358,7 @@ static void single_server_accept_pass(int unused_event, char *context)
event_request_timer(single_server_timeout, (char *) 0, time_left);
return;
}
single_server_wakeup(fd);
single_server_wakeup(fd, attr);
}
#endif
@ -386,7 +394,7 @@ static void single_server_accept_inet(int unused_event, char *context)
event_request_timer(single_server_timeout, (char *) 0, time_left);
return;
}
single_server_wakeup(fd);
single_server_wakeup(fd, (HTABLE *) 0);
}
/* single_server_main - the real main program */
@ -472,7 +480,7 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
* Register dictionaries that use higher-level interfaces and protocols.
*/
mail_dict_init();
/*
* After database open error, continue execution with reduced
* functionality.

View File

@ -376,7 +376,7 @@ static void trigger_server_accept_pass(int unused_event, char *context)
if (trigger_server_pre_accept)
trigger_server_pre_accept(trigger_server_name, trigger_server_argv);
fd = PASS_ACCEPT(listen_fd);
fd = pass_accept(listen_fd);
if (trigger_server_lock != 0
&& myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
MYFLOCK_OP_NONE) < 0)

View File

@ -2,11 +2,13 @@ SHELL = /bin/sh
SRCS = postscreen.c postscreen_dict.c postscreen_dnsbl.c \
postscreen_early.c postscreen_smtpd.c postscreen_misc.c \
postscreen_state.c postscreen_tests.c postscreen_send.c \
postscreen_starttls.c postscreen_expand.c
postscreen_starttls.c postscreen_expand.c postscreen_endpt.c \
postscreen_haproxy.c
OBJS = postscreen.o postscreen_dict.o postscreen_dnsbl.o \
postscreen_early.o postscreen_smtpd.o postscreen_misc.o \
postscreen_state.o postscreen_tests.o postscreen_send.o \
postscreen_starttls.o postscreen_expand.o
postscreen_starttls.o postscreen_expand.o postscreen_endpt.o \
postscreen_haproxy.o
HDRS =
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
@ -103,6 +105,7 @@ postscreen_dict.o: ../../include/htable.h
postscreen_dict.o: ../../include/maps.h
postscreen_dict.o: ../../include/match_list.h
postscreen_dict.o: ../../include/msg.h
postscreen_dict.o: ../../include/myaddrinfo.h
postscreen_dict.o: ../../include/server_acl.h
postscreen_dict.o: ../../include/string_list.h
postscreen_dict.o: ../../include/sys_defs.h
@ -149,6 +152,7 @@ postscreen_early.o: ../../include/mail_params.h
postscreen_early.o: ../../include/maps.h
postscreen_early.o: ../../include/match_list.h
postscreen_early.o: ../../include/msg.h
postscreen_early.o: ../../include/myaddrinfo.h
postscreen_early.o: ../../include/mymalloc.h
postscreen_early.o: ../../include/server_acl.h
postscreen_early.o: ../../include/string_list.h
@ -159,6 +163,27 @@ postscreen_early.o: ../../include/vstream.h
postscreen_early.o: ../../include/vstring.h
postscreen_early.o: postscreen.h
postscreen_early.o: postscreen_early.c
postscreen_endpt.o: ../../include/addr_match_list.h
postscreen_endpt.o: ../../include/argv.h
postscreen_endpt.o: ../../include/dict.h
postscreen_endpt.o: ../../include/dict_cache.h
postscreen_endpt.o: ../../include/events.h
postscreen_endpt.o: ../../include/haproxy_srvr.h
postscreen_endpt.o: ../../include/htable.h
postscreen_endpt.o: ../../include/mail_params.h
postscreen_endpt.o: ../../include/maps.h
postscreen_endpt.o: ../../include/match_list.h
postscreen_endpt.o: ../../include/msg.h
postscreen_endpt.o: ../../include/myaddrinfo.h
postscreen_endpt.o: ../../include/server_acl.h
postscreen_endpt.o: ../../include/string_list.h
postscreen_endpt.o: ../../include/sys_defs.h
postscreen_endpt.o: ../../include/vbuf.h
postscreen_endpt.o: ../../include/vstream.h
postscreen_endpt.o: ../../include/vstring.h
postscreen_endpt.o: postscreen.h
postscreen_endpt.o: postscreen_endpt.c
postscreen_endpt.o: postscreen_haproxy.h
postscreen_expand.o: ../../include/addr_match_list.h
postscreen_expand.o: ../../include/argv.h
postscreen_expand.o: ../../include/attr.h
@ -172,6 +197,7 @@ postscreen_expand.o: ../../include/mail_proto.h
postscreen_expand.o: ../../include/maps.h
postscreen_expand.o: ../../include/match_list.h
postscreen_expand.o: ../../include/msg.h
postscreen_expand.o: ../../include/myaddrinfo.h
postscreen_expand.o: ../../include/server_acl.h
postscreen_expand.o: ../../include/string_list.h
postscreen_expand.o: ../../include/stringops.h
@ -181,6 +207,28 @@ postscreen_expand.o: ../../include/vstream.h
postscreen_expand.o: ../../include/vstring.h
postscreen_expand.o: postscreen.h
postscreen_expand.o: postscreen_expand.c
postscreen_haproxy.o: ../../include/addr_match_list.h
postscreen_haproxy.o: ../../include/argv.h
postscreen_haproxy.o: ../../include/dict.h
postscreen_haproxy.o: ../../include/dict_cache.h
postscreen_haproxy.o: ../../include/events.h
postscreen_haproxy.o: ../../include/haproxy_srvr.h
postscreen_haproxy.o: ../../include/htable.h
postscreen_haproxy.o: ../../include/maps.h
postscreen_haproxy.o: ../../include/match_list.h
postscreen_haproxy.o: ../../include/msg.h
postscreen_haproxy.o: ../../include/myaddrinfo.h
postscreen_haproxy.o: ../../include/mymalloc.h
postscreen_haproxy.o: ../../include/server_acl.h
postscreen_haproxy.o: ../../include/string_list.h
postscreen_haproxy.o: ../../include/stringops.h
postscreen_haproxy.o: ../../include/sys_defs.h
postscreen_haproxy.o: ../../include/vbuf.h
postscreen_haproxy.o: ../../include/vstream.h
postscreen_haproxy.o: ../../include/vstring.h
postscreen_haproxy.o: postscreen.h
postscreen_haproxy.o: postscreen_haproxy.c
postscreen_haproxy.o: postscreen_haproxy.h
postscreen_misc.o: ../../include/addr_match_list.h
postscreen_misc.o: ../../include/argv.h
postscreen_misc.o: ../../include/dict.h
@ -193,6 +241,7 @@ postscreen_misc.o: ../../include/mail_params.h
postscreen_misc.o: ../../include/maps.h
postscreen_misc.o: ../../include/match_list.h
postscreen_misc.o: ../../include/msg.h
postscreen_misc.o: ../../include/myaddrinfo.h
postscreen_misc.o: ../../include/server_acl.h
postscreen_misc.o: ../../include/string_list.h
postscreen_misc.o: ../../include/sys_defs.h
@ -203,6 +252,7 @@ postscreen_misc.o: postscreen.h
postscreen_misc.o: postscreen_misc.c
postscreen_send.o: ../../include/addr_match_list.h
postscreen_send.o: ../../include/argv.h
postscreen_send.o: ../../include/attr.h
postscreen_send.o: ../../include/connect.h
postscreen_send.o: ../../include/dict.h
postscreen_send.o: ../../include/dict_cache.h
@ -212,9 +262,11 @@ postscreen_send.o: ../../include/iostuff.h
postscreen_send.o: ../../include/mac_expand.h
postscreen_send.o: ../../include/mac_parse.h
postscreen_send.o: ../../include/mail_params.h
postscreen_send.o: ../../include/mail_proto.h
postscreen_send.o: ../../include/maps.h
postscreen_send.o: ../../include/match_list.h
postscreen_send.o: ../../include/msg.h
postscreen_send.o: ../../include/myaddrinfo.h
postscreen_send.o: ../../include/server_acl.h
postscreen_send.o: ../../include/smtp_reply_footer.h
postscreen_send.o: ../../include/string_list.h
@ -240,6 +292,7 @@ postscreen_smtpd.o: ../../include/mail_proto.h
postscreen_smtpd.o: ../../include/maps.h
postscreen_smtpd.o: ../../include/match_list.h
postscreen_smtpd.o: ../../include/msg.h
postscreen_smtpd.o: ../../include/myaddrinfo.h
postscreen_smtpd.o: ../../include/mymalloc.h
postscreen_smtpd.o: ../../include/name_code.h
postscreen_smtpd.o: ../../include/name_mask.h
@ -267,6 +320,7 @@ postscreen_starttls.o: ../../include/mail_proto.h
postscreen_starttls.o: ../../include/maps.h
postscreen_starttls.o: ../../include/match_list.h
postscreen_starttls.o: ../../include/msg.h
postscreen_starttls.o: ../../include/myaddrinfo.h
postscreen_starttls.o: ../../include/mymalloc.h
postscreen_starttls.o: ../../include/name_code.h
postscreen_starttls.o: ../../include/name_mask.h
@ -294,6 +348,7 @@ postscreen_state.o: ../../include/mail_server.h
postscreen_state.o: ../../include/maps.h
postscreen_state.o: ../../include/match_list.h
postscreen_state.o: ../../include/msg.h
postscreen_state.o: ../../include/myaddrinfo.h
postscreen_state.o: ../../include/mymalloc.h
postscreen_state.o: ../../include/name_mask.h
postscreen_state.o: ../../include/server_acl.h
@ -314,6 +369,7 @@ postscreen_tests.o: ../../include/mail_params.h
postscreen_tests.o: ../../include/maps.h
postscreen_tests.o: ../../include/match_list.h
postscreen_tests.o: ../../include/msg.h
postscreen_tests.o: ../../include/myaddrinfo.h
postscreen_tests.o: ../../include/server_acl.h
postscreen_tests.o: ../../include/string_list.h
postscreen_tests.o: ../../include/sys_defs.h

View File

@ -132,6 +132,16 @@
/* .IP "\fBsoft_bounce (no)\fR"
/* Safety net to keep mail queued that would otherwise be returned to
/* the sender.
/* BEFORE-POSTSCREEN PROXY AGENT
/* .ad
/* .fi
/* Available in Postfix version 2.10 and later:
/* .IP "\fBpostscreen_upstream_proxy_protocol (empty)\fR"
/* The name of the proxy protocol used by an optional before-postscreen
/* proxy agent.
/* .IP "\fBpostscreen_upstream_proxy_timeout (5s)\fR"
/* The time limit for the proxy protocol specified with the
/* postscreen_upstream_proxy_protocol parameter.
/* PERMANENT WHITE/BLACKLIST TEST
/* .ad
/* .fi
@ -484,6 +494,8 @@ char *var_smtpd_exp_filter;
char *var_psc_exp_filter;
char *var_psc_wlist_if;
char *var_psc_uproxy_proto;
int var_psc_uproxy_tmout;
/*
* Global variables.
@ -512,12 +524,16 @@ DICT *psc_dnsbl_reply; /* DNSBL name mapper */
HTABLE *psc_client_concurrency; /* per-client concurrency */
/*
* Local variables.
* Local variables and functions.
*/
static ARGV *psc_acl; /* permanent white/backlist */
static int psc_blist_action; /* PSC_ACT_DROP/ENFORCE/etc */
static ADDR_MATCH_LIST *psc_wlist_if; /* whitelist interfaces */
static void psc_endpt_lookup_done(int, VSTREAM *,
MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *,
MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *);
/* psc_dump - dump some statistics before exit */
static void psc_dump(void)
@ -581,17 +597,6 @@ static void psc_service(VSTREAM *smtp_client_stream,
char *unused_service,
char **unused_argv)
{
const char *myname = "psc_service";
PSC_STATE *state;
struct sockaddr_storage addr_storage;
SOCKADDR_SIZE addr_storage_len = sizeof(addr_storage);
MAI_HOSTADDR_STR smtp_client_addr;
MAI_SERVPORT_STR smtp_client_port;
MAI_HOSTADDR_STR smtp_server_addr;
MAI_SERVPORT_STR smtp_server_port;
int aierr;
const char *stamp_str;
int saved_flags;
/*
* For sanity, require that at least one of INET or INET6 is enabled.
@ -611,85 +616,53 @@ static void psc_service(VSTREAM *smtp_client_stream,
*/
non_blocking(vstream_fileno(smtp_client_stream), NON_BLOCKING);
/*
* We use the event_server framework. This means we get already-accepted
* connections so we have to invoke getpeername() to find out the remote
* address and port.
*/
/* Best effort - if this non-blocking write(2) fails, so be it. */
#define PSC_SERVICE_DISCONNECT_AND_RETURN(stream) do { \
(void) write(vstream_fileno(stream), \
"421 4.3.2 No system resources\r\n", \
sizeof("421 4.3.2 No system resources\r\n") - 1); \
event_server_disconnect(stream); \
return; \
} while (0);
/*
* Look up the remote SMTP client address and port.
*/
if (getpeername(vstream_fileno(smtp_client_stream), (struct sockaddr *)
& addr_storage, &addr_storage_len) < 0) {
msg_warn("getpeername: %m -- dropping this connection");
PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
}
psc_endpt_lookup(smtp_client_stream, psc_endpt_lookup_done);
}
/* psc_endpt_lookup_done - endpoint lookup completed */
static void psc_endpt_lookup_done(int endpt_status,
VSTREAM *smtp_client_stream,
MAI_HOSTADDR_STR *smtp_client_addr,
MAI_SERVPORT_STR *smtp_client_port,
MAI_HOSTADDR_STR *smtp_server_addr,
MAI_SERVPORT_STR *smtp_server_port)
{
const char *myname = "psc_endpt_lookup_done";
PSC_STATE *state;
const char *stamp_str;
int saved_flags;
/*
* Convert the remote SMTP client address and port to printable form for
* logging and access control.
* Best effort - if this non-blocking write(2) fails, so be it.
*/
if ((aierr = sockaddr_to_hostaddr((struct sockaddr *) & addr_storage,
addr_storage_len, &smtp_client_addr,
&smtp_client_port, 0)) != 0) {
msg_warn("cannot convert client address/port to string: %s"
" -- dropping this connection",
MAI_STRERROR(aierr));
PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
if (endpt_status < 0) {
(void) write(vstream_fileno(smtp_client_stream),
"421 4.3.2 No system resources\r\n",
sizeof("421 4.3.2 No system resources\r\n") - 1);
event_server_disconnect(smtp_client_stream);
return;
}
if (strncasecmp("::ffff:", smtp_client_addr.buf, 7) == 0)
memmove(smtp_client_addr.buf, smtp_client_addr.buf + 7,
sizeof(smtp_client_addr.buf) - 7);
if (msg_verbose > 1)
msg_info("%s: sq=%d cq=%d connect from [%s]:%s",
myname, psc_post_queue_length, psc_check_queue_length,
smtp_client_addr.buf, smtp_client_port.buf);
/*
* Look up the local SMTP server address and port.
*/
if (getsockname(vstream_fileno(smtp_client_stream), (struct sockaddr *)
& addr_storage, &addr_storage_len) < 0) {
msg_warn("getsockname: %m -- dropping this connection");
PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
}
/*
* Convert the local SMTP server address and port to printable form for
* logging and access control.
*/
if ((aierr = sockaddr_to_hostaddr((struct sockaddr *) & addr_storage,
addr_storage_len, &smtp_server_addr,
&smtp_server_port, 0)) != 0) {
msg_warn("cannot convert server address/port to string: %s"
" -- dropping this connection",
MAI_STRERROR(aierr));
PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
}
if (strncasecmp("::ffff:", smtp_server_addr.buf, 7) == 0)
memmove(smtp_server_addr.buf, smtp_server_addr.buf + 7,
sizeof(smtp_server_addr.buf) - 7);
smtp_client_addr->buf, smtp_client_port->buf);
msg_info("CONNECT from [%s]:%s to [%s]:%s",
smtp_client_addr.buf, smtp_client_port.buf,
smtp_server_addr.buf, smtp_server_port.buf);
smtp_client_addr->buf, smtp_client_port->buf,
smtp_server_addr->buf, smtp_server_port->buf);
/*
* Bundle up all the loose session pieces. This zeroes all flags and time
* stamps.
*/
state = psc_new_session_state(smtp_client_stream, smtp_client_addr.buf,
smtp_client_port.buf);
state = psc_new_session_state(smtp_client_stream, smtp_client_addr->buf,
smtp_client_port->buf,
smtp_server_addr->buf,
smtp_server_port->buf);
/*
* Reply with 421 when the client has too many open connections.
@ -799,7 +772,7 @@ static void psc_service(VSTREAM *smtp_client_stream,
* Don't whitelist clients that connect to backup MX addresses. Fail
* "closed" on error.
*/
if (addr_match_list_match(psc_wlist_if, smtp_server_addr.buf) == 0) {
if (addr_match_list_match(psc_wlist_if, smtp_server_addr->buf) == 0) {
state->flags |= (PSC_STATE_FLAG_WLIST_FAIL | PSC_STATE_FLAG_NOFORWARD);
msg_info("WHITELIST VETO [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
}
@ -1114,6 +1087,7 @@ int main(int argc, char **argv)
VAR_DNSBLOG_SERVICE, DEF_DNSBLOG_SERVICE, &var_dnsblog_service, 1, 0,
VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
VAR_PSC_WLIST_IF, DEF_PSC_WLIST_IF, &var_psc_wlist_if, 0, 0,
VAR_PSC_UPROXY_PROTO, DEF_PSC_UPROXY_PROTO, &var_psc_uproxy_proto, 0, 0,
0,
};
static const CONFIG_INT_TABLE int_table[] = {
@ -1139,6 +1113,7 @@ int main(int argc, char **argv)
VAR_PSC_CACHE_RET, DEF_PSC_CACHE_RET, &var_psc_cache_ret, 1, 0,
VAR_PSC_CACHE_SCAN, DEF_PSC_CACHE_SCAN, &var_psc_cache_scan, 0, 0,
VAR_PSC_WATCHDOG, DEF_PSC_WATCHDOG, &var_psc_watchdog, 10, 0,
VAR_PSC_UPROXY_TMOUT, DEF_PSC_UPROXY_TMOUT, &var_psc_uproxy_tmout, 1, 0,
0,
};
static const CONFIG_BOOL_TABLE bool_table[] = {

View File

@ -20,6 +20,7 @@
#include <vstring.h>
#include <events.h>
#include <htable.h>
#include <myaddrinfo.h>
/*
* Global library.
@ -44,6 +45,8 @@ typedef struct {
int smtp_server_fd; /* real SMTP server */
char *smtp_client_addr; /* client address */
char *smtp_client_port; /* client port */
char *smtp_server_addr; /* server address */
char *smtp_server_port; /* server port */
int client_concurrency; /* per-client */
const char *final_reply; /* cause for hanging up */
VSTRING *send_buf; /* pending output */
@ -379,7 +382,7 @@ extern HTABLE *psc_client_concurrency; /* per-client concurrency */
(state)->smtp_client_stream = 0; \
psc_check_queue_length--; \
} while (0)
extern PSC_STATE *psc_new_session_state(VSTREAM *, const char *, const char *);
extern PSC_STATE *psc_new_session_state(VSTREAM *, const char *, const char *, const char *, const char *);
extern void psc_free_session_state(PSC_STATE *);
extern const char *psc_print_state_flags(int, const char *);
@ -468,6 +471,14 @@ extern VSTRING *psc_expand_filter;
extern void psc_expand_init(void);
extern const char *psc_expand_lookup(const char *, int, char *);
/*
* postscreen_endpt.c
*/
typedef void (*PSC_ENDPT_LOOKUP_FN) (int, VSTREAM *,
MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *,
MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *);
extern void psc_endpt_lookup(VSTREAM *, PSC_ENDPT_LOOKUP_FN);
/*
* postscreen_access emulation.
*/

View File

@ -0,0 +1,186 @@
/*++
/* NAME
/* postscreen_endpt 3
/* SUMMARY
/* look up connection endpoint information
/* SYNOPSIS
/* #include <postscreen.h>
/*
/* void psc_endpt_lookup(smtp_client_stream,
/* void *lookup_done(status, smtp_client_stream,
/* smtp_client_addr, smtp_client_port,
/* smtp_server_addr, smtp_server_port))
/* VSTRING *smtp_client_stream;
/* int status;
/* MAI_HOSTADDR_STR *smtp_client_addr;
/* MAI_SERVPORT_STR *smtp_client_port;
/* MAI_HOSTADDR_STR *smtp_server_addr;
/* MAI_SERVPORT_STR *smtp_server_port;
/* DESCRIPTION
/* psc_endpt_lookup() looks up remote and local connection
/* endpoint information through local system calls or through
/* a remote proxy protocol. The lookup_done() call-back routine
/* passes the result status, address and port information. The
/* result status is -1 in case of error, 0 in case of success.
/* This function (and its supporting routines) logs a warning
/* in case of error, and never communicates with a remote SMTP
/* 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>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
/* Utility library. */
#include <msg.h>
#include <myaddrinfo.h>
#include <vstream.h>
#include <inet_proto.h>
/* Global library. */
#include <mail_params.h>
#include <haproxy_srvr.h>
/* Application-specific. */
#include <postscreen.h>
#include <postscreen_haproxy.h>
static INET_PROTO_INFO *proto_info;
/* psc_sockaddr_to_hostaddr - transform endpoint address and port to string */
static int psc_sockaddr_to_hostaddr(struct sockaddr * addr_storage,
SOCKADDR_SIZE addr_storage_len,
MAI_HOSTADDR_STR *addr_buf,
MAI_SERVPORT_STR *port_buf,
int socktype)
{
int aierr;
if ((aierr = sockaddr_to_hostaddr(addr_storage, addr_storage_len,
addr_buf, port_buf, socktype)) == 0
&& strncasecmp("::ffff:", addr_buf->buf, 7) == 0
&& strchr((char *) proto_info->sa_family_list, AF_INET) != 0)
memmove(addr_buf->buf, addr_buf->buf + 7,
sizeof(addr_buf->buf) - 7);
return (aierr);
}
/* psc_endpt_local_lookup - look up local system connection information */
static void psc_endpt_local_lookup(VSTREAM *smtp_client_stream,
PSC_ENDPT_LOOKUP_FN lookup_done)
{
struct sockaddr_storage addr_storage;
SOCKADDR_SIZE addr_storage_len = sizeof(addr_storage);
int status;
MAI_HOSTADDR_STR smtp_client_addr;
MAI_SERVPORT_STR smtp_client_port;
MAI_HOSTADDR_STR smtp_server_addr;
MAI_SERVPORT_STR smtp_server_port;
int aierr;
/*
* Look up the remote SMTP client address and port.
*/
if (getpeername(vstream_fileno(smtp_client_stream), (struct sockaddr *)
& addr_storage, &addr_storage_len) < 0) {
msg_warn("getpeername: %m -- dropping this connection");
status = -1;
}
/*
* Convert the remote SMTP client address and port to printable form for
* logging and access control.
*/
else if ((aierr = psc_sockaddr_to_hostaddr(
(struct sockaddr *) & addr_storage,
addr_storage_len, &smtp_client_addr,
&smtp_client_port, SOCK_STREAM)) != 0) {
msg_warn("cannot convert client address/port to string: %s"
" -- dropping this connection",
MAI_STRERROR(aierr));
status = -1;
}
/*
* Look up the local SMTP server address and port.
*/
else if (getsockname(vstream_fileno(smtp_client_stream),
(struct sockaddr *) & addr_storage,
&addr_storage_len) < 0) {
msg_warn("getsockname: %m -- dropping this connection");
status = -1;
}
/*
* Convert the local SMTP server address and port to printable form for
* logging.
*/
else if ((aierr = psc_sockaddr_to_hostaddr(
(struct sockaddr *) & addr_storage,
addr_storage_len, &smtp_server_addr,
&smtp_server_port, SOCK_STREAM)) != 0) {
msg_warn("cannot convert server address/port to string: %s"
" -- dropping this connection",
MAI_STRERROR(aierr));
status = -1;
} else {
status = 0;
}
lookup_done(status, smtp_client_stream,
&smtp_client_addr, &smtp_client_port,
&smtp_server_addr, &smtp_server_port);
}
/*
* Lookup table for available proxy protocols.
*/
typedef struct {
const char *name;
void (*endpt_lookup) (VSTREAM *, PSC_ENDPT_LOOKUP_FN);
} PSC_ENDPT_LOOKUP_INFO;
static const PSC_ENDPT_LOOKUP_INFO psc_endpt_lookup_info[] = {
DEF_PSC_UPROXY_PROTO, psc_endpt_local_lookup,
HAPROXY_PROTO_NAME, psc_endpt_haproxy_lookup,
0,
};
/* psc_endpt_lookup - look up connection endpoint information */
void psc_endpt_lookup(VSTREAM *smtp_client_stream,
PSC_ENDPT_LOOKUP_FN notify)
{
const PSC_ENDPT_LOOKUP_INFO *pp;
if (proto_info == 0)
proto_info = inet_proto_info();
for (pp = psc_endpt_lookup_info; /* see below */ ; pp++) {
if (pp->name == 0)
msg_fatal("unsupported %s value: %s",
VAR_PSC_UPROXY_PROTO, var_psc_uproxy_proto);
if (strcmp(var_psc_uproxy_proto, pp->name) == 0) {
pp->endpt_lookup(smtp_client_stream, notify);
return;
}
}
}

View File

@ -0,0 +1,194 @@
/*++
/* NAME
/* postscreen_haproxy 3
/* SUMMARY
/* haproxy protocol adapter
/* SYNOPSIS
/* #include <postscreen_haproxy.h>
/*
/* void psc_endpt_haproxy_lookup(smtp_client_stream,
/* void *lookup_done(status, smtp_client_stream,
/* smtp_client_addr, smtp_client_port,
/* smtp_server_addr, smtp_server_port))
/* VSTRING *smtp_client_stream;
/* int status;
/* MAI_HOSTADDR_STR *smtp_client_addr;
/* MAI_SERVPORT_STR *smtp_client_port;
/* MAI_HOSTADDR_STR *smtp_server_addr;
/* MAI_SERVPORT_STR *smtp_server_port;
/* DESCRIPTION
/* psc_endpt_haproxy_lookup() looks up connection endpoint
/* information via the haproxy protocol. Arguments and results
/* conform to the postscreen_endpt(3) API.
/*
/* The following summarizes what the Postfix SMTP server expects
/* from an up-stream proxy adapter.
/* .IP \(bu
/* Validate address and port syntax. Permit only protocols
/* that are configured with the main.cf:inet_protocols
/* setting.
/* .IP \(bu
/* Convert IPv4-in-IPv6 address syntax to IPv4 form, when both
/* IPv4 and IPv6 support are enabled with main.cf:inet_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>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <events.h>
#include <myaddrinfo.h>
#include <vstream.h>
#include <vstring.h>
#include <stringops.h>
/* Global library. */
#include <haproxy_srvr.h>
#include <mail_params.h>
/* Application-specific. */
#include <postscreen.h>
#include <postscreen_haproxy.h>
/*
* Per-session state.
*/
typedef struct {
VSTREAM *stream;
PSC_ENDPT_LOOKUP_FN notify;
VSTRING *buffer;
} PSC_HAPROXY_STATE;
/* psc_endpt_haproxy_event - read or time event */
static void psc_endpt_haproxy_event(int event, char *context)
{
const char *myname = "psc_endpt_haproxy_event";
PSC_HAPROXY_STATE *state = (PSC_HAPROXY_STATE *) context;
int status = 0;
MAI_HOSTADDR_STR smtp_client_addr;
MAI_SERVPORT_STR smtp_client_port;
MAI_HOSTADDR_STR smtp_server_addr;
MAI_SERVPORT_STR smtp_server_port;
int last_char = 0;
const char *err;
VSTRING *escape_buf;
/*
* Basic event processing.
*/
switch (event) {
case EVENT_TIME:
msg_warn("haproxy read: time limit exceeded");
status = -1;
break;
case EVENT_READ:
if ((last_char = VSTREAM_GETC(state->stream)) == VSTREAM_EOF) {
if (vstream_ferror(state->stream))
msg_warn("haproxy read: %m");
else
msg_warn("haproxy read: lost connection");
status = -1;
break;
}
if (VSTRING_LEN(state->buffer) >= HAPROXY_MAX_LEN) {
msg_warn("haproxy read: line too long");
status = -1;
break;
}
VSTRING_ADDCH(state->buffer, last_char);
break;
}
/*
* Parse the haproxy line. Note: the haproxy_srvr_parse() routine
* performs address protocol checks, address and port syntax checks, and
* converts IPv4-in-IPv6 address string syntax (:ffff::1.2.3.4) to IPv4
* syntax where permitted by the main.cf:inet_protocols setting.
*/
if (status == 0 && last_char == '\n') {
VSTRING_TERMINATE(state->buffer);
if ((err = haproxy_srvr_parse(vstring_str(state->buffer),
&smtp_client_addr, &smtp_client_port,
&smtp_server_addr, &smtp_server_port)) != 0) {
escape_buf = vstring_alloc(HAPROXY_MAX_LEN + 2);
escape(escape_buf, vstring_str(state->buffer),
VSTRING_LEN(state->buffer));
msg_warn("haproxy read: %s: %s", err, vstring_str(escape_buf));
status = -1;
vstring_free(escape_buf);
}
}
/*
* Are we done yet?
*/
if (status < 0 || last_char == '\n') {
PSC_CLEAR_EVENT_REQUEST(vstream_fileno(state->stream),
psc_endpt_haproxy_event, context);
vstream_control(state->stream,
VSTREAM_CTL_BUFSIZE, VSTREAM_BUFSIZE,
VSTREAM_CTL_END);
state->notify(status, state->stream,
&smtp_client_addr, &smtp_client_port,
&smtp_server_addr, &smtp_server_port);
/* Note: the stream may be closed at this point. */
vstring_free(state->buffer);
myfree((char *) state);
}
}
/* psc_endpt_haproxy_lookup - event-driven haproxy client */
void psc_endpt_haproxy_lookup(VSTREAM *stream,
PSC_ENDPT_LOOKUP_FN notify)
{
const char *myname = "psc_endpt_haproxy_lookup";
PSC_HAPROXY_STATE *state;
/*
* Prepare the per-session state. XXX To improve overload behavior,
* maintain a pool of these so that we can reduce memory allocator
* activity.
*/
state = (PSC_HAPROXY_STATE *) mymalloc(sizeof(*state));
state->stream = stream;
state->notify = notify;
state->buffer = vstring_alloc(100);
/*
* We don't assume that the haproxy line will be unfragmented. Therefore,
* we use read(2) instead of recv(..., MSG_PEEK).
*
* We must not read(2) past the <CR><LF> that terminates the haproxy line.
* Therefore we force one-character read(2) calls.
*
* We want to (eventually) build this on top of a reusable line read
* routine, once we have figured out an easy-to-use and efficient API.
*/
vstream_control(stream, VSTREAM_CTL_BUFSIZE, 1, VSTREAM_CTL_END);
/*
* Read the haproxy line.
*/
PSC_READ_EVENT_REQUEST(vstream_fileno(stream), psc_endpt_haproxy_event,
(char *) state, var_psc_uproxy_tmout);
}

View File

@ -0,0 +1,25 @@
/*++
/* NAME
/* postscreen_haproxy 3h
/* SUMMARY
/* postscreen haproxy protocol support
/* SYNOPSIS
/* #include <postscreen_haproxy.h>
/* DESCRIPTION
/* .nf
/*
* haproxy protocol interface.
*/
extern void psc_endpt_haproxy_lookup(VSTREAM *, PSC_ENDPT_LOOKUP_FN);
/* 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
/*--*/

View File

@ -61,11 +61,14 @@
#include <msg.h>
#include <iostuff.h>
#include <connect.h>
#include <attr.h>
#include <vstream.h>
/* Global library. */
#include <mail_params.h>
#include <smtp_reply_footer.h>
#include <mail_proto.h>
/* Application-specific. */
@ -163,6 +166,8 @@ void psc_send_socket(PSC_STATE *state)
{
const char *myname = "psc_send_socket";
int server_fd;
int pass_err;
VSTREAM *fp;
if (msg_verbose > 1)
msg_info("%s: sq=%d cq=%d send socket %d from [%s]:%s",
@ -187,8 +192,8 @@ void psc_send_socket(PSC_STATE *state)
* Postfix-specific.
*/
if ((server_fd =
PASS_CONNECT(psc_smtpd_service_name, NON_BLOCKING,
PSC_SEND_SOCK_CONNECT_TIMEOUT)) < 0) {
LOCAL_CONNECT(psc_smtpd_service_name, NON_BLOCKING,
PSC_SEND_SOCK_CONNECT_TIMEOUT)) < 0) {
msg_warn("cannot connect to service %s: %m", psc_smtpd_service_name);
if (state->flags & PSC_STATE_FLAG_PREGR_TODO) {
PSC_SMTPD_X21(state, "421 4.3.2 No system resources\r\n");
@ -198,8 +203,19 @@ void psc_send_socket(PSC_STATE *state)
}
return;
}
if (LOCAL_SEND_FD(server_fd,
vstream_fileno(state->smtp_client_stream)) < 0) {
/* XXX Note: no dummy read between LOCAL_SEND_FD() and attr_print(). */
fp = vstream_fdopen(server_fd, O_RDWR);
pass_err =
(LOCAL_SEND_FD(server_fd,
vstream_fileno(state->smtp_client_stream)) < 0
|| (attr_print(fp, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, state->smtp_client_addr,
ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_PORT, state->smtp_client_port,
ATTR_TYPE_STR, MAIL_ATTR_ACT_SERVER_ADDR, state->smtp_server_addr,
ATTR_TYPE_STR, MAIL_ATTR_ACT_SERVER_PORT, state->smtp_server_port,
ATTR_TYPE_END) || vstream_fflush(fp)));
(void) vstream_fdclose(fp);
if (pass_err != 0) {
msg_warn("cannot pass connection to service %s: %m",
psc_smtpd_service_name);
(void) close(server_fd);

View File

@ -6,10 +6,13 @@
/* SYNOPSIS
/* #include <postscreen.h>
/*
/* PSC_STATE *psc_new_session_state(stream, addr, port)
/* PSC_STATE *psc_new_session_state(stream, client_addr, client_port,
/* server_addr, server_port)
/* VSTREAM *stream;
/* const char *addr;
/* const char *port;
/* const char *client_addr;
/* const char *client_port;
/* const char *server_addr;
/* const char *server_port;
/*
/* void psc_free_session_state(state)
/* PSC_STATE *state;
@ -140,8 +143,10 @@
/* psc_new_session_state - fill in connection state for event processing */
PSC_STATE *psc_new_session_state(VSTREAM *stream,
const char *addr,
const char *port)
const char *client_addr,
const char *client_port,
const char *server_addr,
const char *server_port)
{
PSC_STATE *state;
HTABLE_INFO *ht;
@ -151,8 +156,10 @@ PSC_STATE *psc_new_session_state(VSTREAM *stream,
if ((state->smtp_client_stream = stream) != 0)
psc_check_queue_length++;
state->smtp_server_fd = (-1);
state->smtp_client_addr = mystrdup(addr);
state->smtp_client_port = mystrdup(port);
state->smtp_client_addr = mystrdup(client_addr);
state->smtp_client_port = mystrdup(client_port);
state->smtp_server_addr = mystrdup(server_addr);
state->smtp_server_port = mystrdup(server_port);
state->send_buf = vstring_alloc(100);
state->test_name = "TEST NAME HERE";
state->dnsbl_reply = 0;
@ -180,8 +187,8 @@ PSC_STATE *psc_new_session_state(VSTREAM *stream,
/*
* Update the per-client session count.
*/
if ((ht = htable_locate(psc_client_concurrency, addr)) == 0)
ht = htable_enter(psc_client_concurrency, addr, (char *) 0);
if ((ht = htable_locate(psc_client_concurrency, client_addr)) == 0)
ht = htable_enter(psc_client_concurrency, client_addr, (char *) 0);
ht->value += 1;
state->client_concurrency = CAST_CHAR_PTR_TO_INT(ht->value);
@ -218,6 +225,8 @@ void psc_free_session_state(PSC_STATE *state)
state->send_buf = vstring_free(state->send_buf);
myfree(state->smtp_client_addr);
myfree(state->smtp_client_port);
myfree(state->smtp_server_addr);
myfree(state->smtp_server_port);
if (state->dnsbl_reply)
vstring_free(state->dnsbl_reply);
if (state->helo_name)

View File

@ -2,11 +2,11 @@ SHELL = /bin/sh
SRCS = smtpd.c smtpd_token.c smtpd_check.c smtpd_chat.c smtpd_state.c \
smtpd_peer.c smtpd_sasl_proto.c smtpd_sasl_glue.c smtpd_proxy.c \
smtpd_xforward.c smtpd_dsn_fix.c smtpd_milter.c smtpd_resolve.c \
smtpd_expand.c
smtpd_expand.c smtpd_haproxy.c
OBJS = smtpd.o smtpd_token.o smtpd_check.o smtpd_chat.o smtpd_state.o \
smtpd_peer.o smtpd_sasl_proto.o smtpd_sasl_glue.o smtpd_proxy.o \
smtpd_xforward.o smtpd_dsn_fix.o smtpd_milter.o smtpd_resolve.o \
smtpd_expand.o
smtpd_expand.o smtpd_haproxy.o
HDRS = smtpd_token.h smtpd_check.h smtpd_chat.h smtpd_sasl_proto.h \
smtpd_sasl_glue.h smtpd_proxy.h smtpd_dsn_fix.h smtpd_milter.h \
smtpd_resolve.h smtpd_expand.h
@ -346,6 +346,28 @@ smtpd_expand.o: ../../include/vstring.h
smtpd_expand.o: smtpd.h
smtpd_expand.o: smtpd_expand.c
smtpd_expand.o: smtpd_expand.h
smtpd_haproxy.o: ../../include/argv.h
smtpd_haproxy.o: ../../include/attr.h
smtpd_haproxy.o: ../../include/haproxy_srvr.h
smtpd_haproxy.o: ../../include/mail_params.h
smtpd_haproxy.o: ../../include/mail_stream.h
smtpd_haproxy.o: ../../include/milter.h
smtpd_haproxy.o: ../../include/msg.h
smtpd_haproxy.o: ../../include/myaddrinfo.h
smtpd_haproxy.o: ../../include/mymalloc.h
smtpd_haproxy.o: ../../include/name_code.h
smtpd_haproxy.o: ../../include/name_mask.h
smtpd_haproxy.o: ../../include/smtp_stream.h
smtpd_haproxy.o: ../../include/stringops.h
smtpd_haproxy.o: ../../include/sys_defs.h
smtpd_haproxy.o: ../../include/tls.h
smtpd_haproxy.o: ../../include/valid_hostname.h
smtpd_haproxy.o: ../../include/valid_mailhost_addr.h
smtpd_haproxy.o: ../../include/vbuf.h
smtpd_haproxy.o: ../../include/vstream.h
smtpd_haproxy.o: ../../include/vstring.h
smtpd_haproxy.o: smtpd.h
smtpd_haproxy.o: smtpd_haproxy.c
smtpd_milter.o: ../../include/argv.h
smtpd_milter.o: ../../include/attr.h
smtpd_milter.o: ../../include/mail_params.h
@ -370,6 +392,8 @@ smtpd_milter.o: smtpd_resolve.h
smtpd_milter.o: smtpd_sasl_glue.h
smtpd_peer.o: ../../include/argv.h
smtpd_peer.o: ../../include/attr.h
smtpd_peer.o: ../../include/haproxy_srvr.h
smtpd_peer.o: ../../include/htable.h
smtpd_peer.o: ../../include/inet_proto.h
smtpd_peer.o: ../../include/iostuff.h
smtpd_peer.o: ../../include/mail_params.h

View File

@ -154,6 +154,16 @@
/* at all, or rewrite message headers and update incomplete addresses
/* with the domain specified in the remote_header_rewrite_domain
/* parameter.
/* BEFORE-SMTPD PROXY AGENT
/* .ad
/* .fi
/* Available in Postfix version 2.10 and later:
/* .IP "\fBsmtpd_upstream_proxy_protocol (empty)\fR"
/* The name of the proxy protocol used by an optional before-smtpd
/* proxy agent.
/* .IP "\fBsmtpd_upstream_proxy_timeout (5s)\fR"
/* The time limit for the proxy protocol specified with the
/* smtpd_upstream_proxy_protocol parameter.
/* AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS
/* .ad
/* .fi
@ -1291,6 +1301,9 @@ char *var_tlsproxy_service;
#endif
char *var_smtpd_uproxy_proto;
int var_smtpd_uproxy_tmout;
/*
* Silly little macros.
*/
@ -4924,7 +4937,8 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv)
/*
* Provide the SMTP service.
*/
smtpd_proto(&state);
if ((state.flags & SMTPD_FLAG_HANGUP) == 0)
smtpd_proto(&state);
/*
* After the client has gone away, clean up whatever we have set up at
@ -5273,6 +5287,7 @@ int main(int argc, char **argv)
VAR_MILT_CMD_TIME, DEF_MILT_CMD_TIME, &var_milt_cmd_time, 1, 0,
VAR_MILT_MSG_TIME, DEF_MILT_MSG_TIME, &var_milt_msg_time, 1, 0,
VAR_VERIFY_SENDER_TTL, DEF_VERIFY_SENDER_TTL, &var_verify_sender_ttl, 0, 0,
VAR_SMTPD_UPROXY_TMOUT, DEF_SMTPD_UPROXY_TMOUT, &var_smtpd_uproxy_tmout, 1, 0,
0,
};
static const CONFIG_BOOL_TABLE bool_table[] = {
@ -5401,6 +5416,7 @@ int main(int argc, char **argv)
VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
#endif
VAR_SMTPD_ACL_PERM_LOG, DEF_SMTPD_ACL_PERM_LOG, &var_smtpd_acl_perm_log, 0, 0,
VAR_SMTPD_UPROXY_PROTO, DEF_SMTPD_UPROXY_PROTO, &var_smtpd_uproxy_proto, 0, 0,
0,
};
static const CONFIG_RAW_TABLE raw_table[] = {

View File

@ -79,7 +79,9 @@ typedef struct {
char *namaddr; /* name[address]:port */
char *rfc_addr; /* address for RFC 2821 */
int addr_family; /* address family */
char *dest_addr; /* for Dovecot AUTH */
struct sockaddr_storage sockaddr; /* binary client endpoint */
SOCKADDR_SIZE sockaddr_len; /* binary client endpoint */
int name_status; /* 2=ok 4=soft 5=hard 6=forged */
int reverse_name_status; /* 2=ok 4=soft 5=hard */
int conn_count; /* connections from this client */
@ -308,6 +310,7 @@ extern void smtpd_state_reset(SMTPD_STATE *);
*/
extern void smtpd_peer_init(SMTPD_STATE *state);
extern void smtpd_peer_reset(SMTPD_STATE *state);
extern int smtpd_peer_from_haproxy(SMTPD_STATE *state);
#define SMTPD_PEER_CODE_OK 2
#define SMTPD_PEER_CODE_TEMP 4

View File

@ -0,0 +1,144 @@
/*++
/* NAME
/* smtpd_haproxy 3
/* SUMMARY
/* Postfix SMTP server haproxy adapter
/* SYNOPSIS
/* #include "smtpd.h"
/*
/* int smtpd_peer_from_haproxy(state)
/* SMTPD_STATE *state;
/* DESCRIPTION
/* smtpd_peer_from_haproxy() receives endpoint address and
/* port information via the haproxy protocol.
/*
/* The following summarizes what the Postfix SMTP server expects
/* from an up-stream proxy adapter.
/* .IP \(bu
/* Validate address and port syntax. Permit only protocols
/* that are configured with the main.cf:inet_protocols
/* setting.
/* .IP \(bu
/* Convert IPv4-in-IPv6 address syntax to IPv4 syntax, when
/* both IPv4 and IPv6 support are enabled with main.cf:inet_protocols.
/* .IP \(bu
/* Update the following session context fields: addr, port,
/* rfc_addr, addr_family, dest_addr. The addr_family field
/* applies to the client address.
/* .IP \(bu
/* Dynamically allocate storage for string information with
/* mystrdup(). In case of error, leave unassigned string fields
/* at their initial zero value.
/* .IP \(bu
/* Log warnings in case of data format error.
/* .PP
/* Arguments:
/* .IP state
/* Session context.
/* DIAGNOSTICS
/* Warnings: I/O errors, malformed haproxy line.
/*
/* The result value is 0 in case of success, -1 in case of
/* error.
/* 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 <sys/socket.h>
/* Utility library. */
#include <msg.h>
#include <myaddrinfo.h>
#include <mymalloc.h>
#include <stringops.h>
/* Global library. */
#include <smtp_stream.h>
#include <mail_params.h>
#include <valid_mailhost_addr.h>
#include <haproxy_srvr.h>
/* Application-specific. */
#include <smtpd.h>
/* SLMs. */
#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)
/* smtpd_peer_from_haproxy - initialize peer information from haproxy */
int smtpd_peer_from_haproxy(SMTPD_STATE *state)
{
const char *myname = "smtpd_peer_from_haproxy";
MAI_HOSTADDR_STR smtp_client_addr;
MAI_SERVPORT_STR smtp_client_port;
MAI_HOSTADDR_STR smtp_server_addr;
MAI_SERVPORT_STR smtp_server_port;
const char *proxy_err;
int io_err;
VSTRING *escape_buf;
/*
* Note: the haproxy_srvr_parse() routine performs address protocol
* checks, address and port syntax checks, and converts IPv4-in-IPv6
* address string syntax (:ffff::1.2.3.4) to IPv4 syntax where permitted
* by the main.cf:inet_protocols setting, but logs no warnings.
*/
#define ENABLE_DEADLINE 1
smtp_stream_setup(state->client, var_smtpd_uproxy_tmout, ENABLE_DEADLINE);
switch (io_err = vstream_setjmp(state->client)) {
default:
msg_panic("%s: unhandled I/O error %d", myname, io_err);
case SMTP_ERR_EOF:
msg_warn("haproxy read: unexpected EOF");
return (-1);
case SMTP_ERR_TIME:
msg_warn("haproxy read: timeout error");
return (-1);
case 0:
if (smtp_get(state->buffer, state->client, HAPROXY_MAX_LEN,
SMTP_GET_FLAG_NONE) != '\n') {
msg_warn("haproxy line > %d characters", HAPROXY_MAX_LEN);
return (-1);
}
if ((proxy_err = haproxy_srvr_parse(STR(state->buffer),
&smtp_client_addr, &smtp_client_port,
&smtp_server_addr, &smtp_server_port)) != 0) {
escape_buf = vstring_alloc(HAPROXY_MAX_LEN + 2);
escape(escape_buf, STR(state->buffer), LEN(state->buffer));
msg_warn("haproxy read: %s: %s", proxy_err, STR(escape_buf));
vstring_free(escape_buf);
return (-1);
}
state->addr = mystrdup(smtp_client_addr.buf);
if (strrchr(state->addr, ':') != 0) {
state->rfc_addr = concatenate(IPV6_COL, state->addr, (char *) 0);
state->addr_family = AF_INET6;
} else {
state->rfc_addr = mystrdup(state->addr);
state->addr_family = AF_INET;
}
state->port = mystrdup(smtp_client_port.buf);
/*
* Avoid surprises in the Dovecot authentication server.
*/
state->dest_addr = mystrdup(smtp_server_addr.buf);
return (0);
}
}

View File

@ -17,6 +17,9 @@
/* Where information is unavailable, the name and/or address
/* are set to "unknown".
/*
/* Alternatively, the peer address and port may be obtained
/* from a proxy server.
/*
/* This module uses the local name service via getaddrinfo()
/* and getnameinfo(). It does not query the DNS directly.
/*
@ -45,6 +48,8 @@
/* .IP rfc_addr
/* String of the form "ipv4addr" or "ipv6:ipv6addr" for use
/* in Received: message headers.
/* .IP dest_addr
/* Server address, used by the Dovecot authentication server.
/* .IP name_status
/* The name_status result field specifies how the name
/* information should be interpreted:
@ -104,6 +109,7 @@
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <htable.h>
/* Utility library. */
@ -120,75 +126,51 @@
#include <mail_proto.h>
#include <valid_mailhost_addr.h>
#include <mail_params.h>
#include <haproxy_srvr.h>
/* Application-specific. */
#include "smtpd.h"
/* smtpd_peer_init - initialize peer information */
static INET_PROTO_INFO *proto_info;
void smtpd_peer_init(SMTPD_STATE *state)
/*
* XXX If we make local endpoint (getsockname) information available to
* Milter applications as {if_name} and {if_addr}, then we also must be able
* to provide this via the XCLIENT command for Milter testing.
*
* XXX If we make local port information available to policy servers or Milter
* applications, then we must also make this testable with the XCLIENT
* command, otherwise there will be confusion.
*
* XXX If we make local port information available via logging, then we must
* also support these attributes with the XFORWARD command.
*
* XXX If support were to be added for Milter applications in down-stream MTAs,
* then consistency demands that we propagate a lot of Sendmail macro
* information via the XFORWARD command. Otherwise we could end up with a
* very confusing situation.
*/
/* smtpd_peer_sockaddr_to_hostaddr - client address/port to printable form */
static int smtpd_peer_sockaddr_to_hostaddr(SMTPD_STATE *state)
{
const char *myname = "smtpd_peer_init";
SOCKADDR_SIZE sa_length;
struct sockaddr *sa;
INET_PROTO_INFO *proto_info = inet_proto_info();
sa = (struct sockaddr *) & (state->sockaddr);
sa_length = sizeof(state->sockaddr);
const char *myname = "smtpd_peer_sockaddr_to_hostaddr";
struct sockaddr *sa = (struct sockaddr *) & (state->sockaddr);
SOCKADDR_SIZE sa_length = state->sockaddr_len;
/*
* Look up the peer address information.
*
* XXX If we make local endpoint (getsockname) information available to
* Milter applications as {if_name} and {if_addr}, then we also must be
* able to provide this via the XCLIENT command for Milter testing.
*
* XXX If we make local or remote port information available to policy
* servers or Milter applications, then we must also make this testable
* with the XCLIENT command, otherwise there will be confusion.
*
* XXX If we make local or remote port information available via logging,
* then we must also support these attributes with the XFORWARD command.
*
* XXX If support were to be added for Milter applications in down-stream
* MTAs, then consistency demands that we propagate a lot of Sendmail
* macro information via the XFORWARD command. Otherwise we could end up
* with a very confusing situation.
* XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd,
* while Postfix IPv6 (or IPv4) support is turned off, don't (skip to the
* final else clause, pretend the origin is localhost[127.0.0.1], and
* become an open relay).
*/
if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) {
errno = 0;
}
/*
* If peer went away, give up.
*/
if (errno != 0 && errno != ENOTSOCK) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
state->addr_family = AF_UNSPEC;
state->name_status = SMTPD_PEER_CODE_PERM;
state->reverse_name_status = SMTPD_PEER_CODE_PERM;
state->port = mystrdup(CLIENT_PORT_UNKNOWN);
}
/*
* Convert the client address to printable address and hostname.
*
* XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd, while
* Postfix IPv6 (or IPv4) support is turned off, don't (skip to the final
* else clause, pretend the origin is localhost[127.0.0.1], and become an
* open relay).
*/
else if (errno == 0
&& (sa->sa_family == AF_INET
if (sa->sa_family == AF_INET
#ifdef AF_INET6
|| sa->sa_family == AF_INET6
|| sa->sa_family == AF_INET6
#endif
)) {
MAI_HOSTNAME_STR client_name;
) {
MAI_HOSTADDR_STR client_addr;
MAI_SERVPORT_STR client_port;
int aierr;
@ -290,16 +272,35 @@ void smtpd_peer_init(SMTPD_STATE *state)
state->rfc_addr = mystrdup(client_addr.buf);
state->addr_family = sa->sa_family;
}
return (0);
}
/*
* Look up and sanity check the client hostname.
*
* It is unsafe to allow numeric hostnames, especially because there
* exists pressure to turn off the name->addr double check. In that
* case an attacker could trivally bypass access restrictions.
*
* sockaddr_to_hostname() already rejects malformed or numeric names.
*/
/*
* It's not Internet.
*/
else {
return (-1);
}
}
/* smtpd_peer_sockaddr_to_hostname - client hostname lookup */
static void smtpd_peer_sockaddr_to_hostname(SMTPD_STATE *state)
{
struct sockaddr *sa = (struct sockaddr *) & (state->sockaddr);
SOCKADDR_SIZE sa_length = state->sockaddr_len;
MAI_HOSTNAME_STR client_name;
int aierr;
/*
* Look up and sanity check the client hostname.
*
* It is unsafe to allow numeric hostnames, especially because there exists
* pressure to turn off the name->addr double check. In that case an
* attacker could trivally bypass access restrictions.
*
* sockaddr_to_hostname() already rejects malformed or numeric names.
*/
#define TEMP_AI_ERROR(e) \
((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM)
@ -309,81 +310,276 @@ void smtpd_peer_init(SMTPD_STATE *state)
state->name_status = code; \
}
if (var_smtpd_peername_lookup == 0) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
state->name_status = SMTPD_PEER_CODE_PERM;
state->reverse_name_status = SMTPD_PEER_CODE_PERM;
} else if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name,
if (var_smtpd_peername_lookup == 0) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
state->name_status = SMTPD_PEER_CODE_PERM;
state->reverse_name_status = SMTPD_PEER_CODE_PERM;
} else if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name,
(MAI_SERVNAME_STR *) 0, 0)) != 0) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
state->name_status = (TEMP_AI_ERROR(aierr) ?
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
state->name_status = (TEMP_AI_ERROR(aierr) ?
SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
state->reverse_name_status = (TEMP_AI_ERROR(aierr) ?
SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
state->reverse_name_status = (TEMP_AI_ERROR(aierr) ?
SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
} else {
struct addrinfo *res0;
struct addrinfo *res;
} else {
struct addrinfo *res0;
struct addrinfo *res;
state->name = mystrdup(client_name.buf);
state->reverse_name = mystrdup(client_name.buf);
state->name_status = SMTPD_PEER_CODE_OK;
state->reverse_name_status = SMTPD_PEER_CODE_OK;
state->name = mystrdup(client_name.buf);
state->reverse_name = mystrdup(client_name.buf);
state->name_status = SMTPD_PEER_CODE_OK;
state->reverse_name_status = SMTPD_PEER_CODE_OK;
/*
* Reject the hostname if it does not list the peer address.
* Without further validation or qualification, such information
* must not be allowed to enter the audit trail, as people would
* draw false conclusions.
*/
aierr = hostname_to_sockaddr_pf(state->name, state->addr_family,
(char *) 0, 0, &res0);
if (aierr) {
msg_warn("hostname %s does not resolve to address %s: %s",
state->name, state->addr, MAI_STRERROR(aierr));
REJECT_PEER_NAME(state, (TEMP_AI_ERROR(aierr) ?
/*
* Reject the hostname if it does not list the peer address. Without
* further validation or qualification, such information must not be
* allowed to enter the audit trail, as people would draw false
* conclusions.
*/
aierr = hostname_to_sockaddr_pf(state->name, state->addr_family,
(char *) 0, 0, &res0);
if (aierr) {
msg_warn("hostname %s does not resolve to address %s: %s",
state->name, state->addr, MAI_STRERROR(aierr));
REJECT_PEER_NAME(state, (TEMP_AI_ERROR(aierr) ?
SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_FORGED));
} else {
for (res = res0; /* void */ ; res = res->ai_next) {
if (res == 0) {
msg_warn("hostname %s does not resolve to address %s",
state->name, state->addr);
REJECT_PEER_NAME(state, SMTPD_PEER_CODE_FORGED);
break;
}
if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
msg_info("skipping address family %d for host %s",
res->ai_family, state->name);
continue;
}
if (sock_addr_cmp_addr(res->ai_addr, sa) == 0)
break; /* keep peer name */
} else {
for (res = res0; /* void */ ; res = res->ai_next) {
if (res == 0) {
msg_warn("hostname %s does not resolve to address %s",
state->name, state->addr);
REJECT_PEER_NAME(state, SMTPD_PEER_CODE_FORGED);
break;
}
freeaddrinfo(res0);
if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
msg_info("skipping address family %d for host %s",
res->ai_family, state->name);
continue;
}
if (sock_addr_cmp_addr(res->ai_addr, sa) == 0)
break; /* keep peer name */
}
freeaddrinfo(res0);
}
}
}
/* smtpd_peer_hostaddr_to_sockaddr - convert numeric string to binary */
static void smtpd_peer_hostaddr_to_sockaddr(SMTPD_STATE *state)
{
const char *myname = "smtpd_peer_hostaddr_to_sockaddr";
struct addrinfo *res;
int aierr;
if ((aierr = hostaddr_to_sockaddr(state->addr, state->port,
SOCK_STREAM, &res)) != 0)
msg_fatal("%s: cannot convert client address/port to string: %s",
myname, MAI_STRERROR(aierr));
if (res->ai_addrlen > sizeof(state->sockaddr))
msg_panic("%s: address length > struct sockaddr_storage", myname);
memcpy((char *) &(state->sockaddr), res->ai_addr, res->ai_addrlen);
state->sockaddr_len = res->ai_addrlen;
freeaddrinfo(res);
}
/* smtpd_peer_not_inet - non-socket or non-Internet endpoint */
static void smtpd_peer_not_inet(SMTPD_STATE *state)
{
/*
* If it's not Internet, assume the client is local, and avoid using the
* naming service because that can hang when the machine is disconnected.
*/
else {
state->name = mystrdup("localhost");
state->reverse_name = mystrdup("localhost");
if (proto_info->sa_family_list[0] == PF_INET6) {
state->addr = mystrdup("::1"); /* XXX bogus. */
state->rfc_addr = mystrdup(IPV6_COL "::1"); /* XXX bogus. */
} else {
state->addr = mystrdup("127.0.0.1");/* XXX bogus. */
state->rfc_addr = mystrdup("127.0.0.1"); /* XXX bogus. */
}
state->addr_family = AF_UNSPEC;
state->name_status = SMTPD_PEER_CODE_OK;
state->reverse_name_status = SMTPD_PEER_CODE_OK;
state->port = mystrdup("0"); /* XXX bogus. */
state->name = mystrdup("localhost");
state->reverse_name = mystrdup("localhost");
#ifdef AF_INET6
if (proto_info->sa_family_list[0] == PF_INET6) {
state->addr = mystrdup("::1"); /* XXX bogus. */
state->rfc_addr = mystrdup(IPV6_COL "::1"); /* XXX bogus. */
} else
#endif
{
state->addr = mystrdup("127.0.0.1"); /* XXX bogus. */
state->rfc_addr = mystrdup("127.0.0.1");/* XXX bogus. */
}
state->addr_family = AF_UNSPEC;
state->name_status = SMTPD_PEER_CODE_OK;
state->reverse_name_status = SMTPD_PEER_CODE_OK;
state->port = mystrdup("0"); /* XXX bogus. */
}
/* smtpd_peer_no_client - peer went away, or peer info unavailable */
static void smtpd_peer_no_client(SMTPD_STATE *state)
{
smtpd_peer_reset(state);
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
state->addr_family = AF_UNSPEC;
state->name_status = SMTPD_PEER_CODE_PERM;
state->reverse_name_status = SMTPD_PEER_CODE_PERM;
state->port = mystrdup(CLIENT_PORT_UNKNOWN);
}
/* smtpd_peer_from_pass_attr - initialize from attribute hash */
static void smtpd_peer_from_pass_attr(SMTPD_STATE *state)
{
HTABLE *attr = (HTABLE *) vstream_context(state->client);
const char *cp;
/*
* Extract the client endpoint information from the attribute hash.
*/
if ((cp = htable_find(attr, MAIL_ATTR_ACT_CLIENT_ADDR)) == 0)
msg_fatal("missing client address from proxy");
if (strrchr(cp, ':') != 0) {
if (valid_ipv6_hostaddr(cp, DO_GRIPE) == 0)
msg_fatal("bad IPv6 client address syntax from proxy: %s", cp);
state->addr = mystrdup(cp);
state->rfc_addr = concatenate(IPV6_COL, cp, (char *) 0);
state->addr_family = AF_INET6;
} else {
if (valid_ipv4_hostaddr(cp, DO_GRIPE) == 0)
msg_fatal("bad IPv4 client address syntax from proxy: %s", cp);
state->addr = mystrdup(cp);
state->rfc_addr = mystrdup(cp);
state->addr_family = AF_INET;
}
if ((cp = htable_find(attr, MAIL_ATTR_ACT_CLIENT_PORT)) == 0)
msg_fatal("missing client port from proxy");
if (valid_hostport(cp, DO_GRIPE) == 0)
msg_fatal("bad TCP client port number syntax from proxy: %s", cp);
state->port = mystrdup(cp);
/*
* Avoid surprises in the Dovecot authentication server.
*/
if ((cp = htable_find(attr, MAIL_ATTR_ACT_SERVER_ADDR)) == 0)
msg_fatal("missing server address from proxy");
if (valid_hostaddr(cp, DO_GRIPE) == 0)
msg_fatal("bad IPv6 client address syntax from proxy: %s", cp);
state->dest_addr = mystrdup(cp);
/*
* Convert the client address from string to binary form.
*/
smtpd_peer_hostaddr_to_sockaddr(state);
}
/* smtpd_peer_from_default - try to initialize peer information from socket */
static void smtpd_peer_from_default(SMTPD_STATE *state)
{
SOCKADDR_SIZE sa_length = sizeof(state->sockaddr);
struct sockaddr *sa = (struct sockaddr *) & (state->sockaddr);
/*
* The "no client" routine provides surrogate information so that the
* application can produce sensible logging when a client disconnects
* before the server wakes up. The "not inet" routine provides surrogate
* state for (presumably) local IPC channels.
*/
if (getpeername(vstream_fileno(state->client), sa, &sa_length) < 0) {
if (errno == ENOTSOCK)
smtpd_peer_not_inet(state);
else
smtpd_peer_no_client(state);
} else {
state->sockaddr_len = sa_length;
if (smtpd_peer_sockaddr_to_hostaddr(state) < 0)
smtpd_peer_not_inet(state);
}
}
/* smtpd_peer_from_proxy - get endpoint info from proxy agent */
static void smtpd_peer_from_proxy(SMTPD_STATE *state)
{
typedef struct {
const char *name;
int (*endpt_lookup) (SMTPD_STATE *);
} SMTPD_ENDPT_LOOKUP_INFO;
static const SMTPD_ENDPT_LOOKUP_INFO smtpd_endpt_lookup_info[] = {
HAPROXY_PROTO_NAME, smtpd_peer_from_haproxy,
0,
};
const SMTPD_ENDPT_LOOKUP_INFO *pp;
/*
* When the proxy information is unavailable, we can't maintain an audit
* trail or enforce access control, therefore we forcibly hang up.
*/
for (pp = smtpd_endpt_lookup_info; /* see below */ ; pp++) {
if (pp->name == 0)
msg_fatal("unsupported %s value: %s",
VAR_SMTPD_UPROXY_PROTO, var_smtpd_uproxy_proto);
if (strcmp(var_smtpd_uproxy_proto, pp->name) == 0)
break;
}
if (pp->endpt_lookup(state) < 0) {
smtpd_peer_no_client(state);
state->flags |= SMTPD_FLAG_HANGUP;
} else {
smtpd_peer_hostaddr_to_sockaddr(state);
}
}
/* smtpd_peer_init - initialize peer information */
void smtpd_peer_init(SMTPD_STATE *state)
{
/*
* Initialize.
*/
if (proto_info == 0)
proto_info = inet_proto_info();
/*
* Prepare for partial initialization after error.
*/
memset((char *) &(state->sockaddr), 0, sizeof(state->sockaddr));
state->sockaddr_len = 0;
state->name = 0;
state->reverse_name = 0;
state->addr = 0;
state->namaddr = 0;
state->rfc_addr = 0;
state->port = 0;
state->dest_addr = 0;
/*
* Determine the remote SMTP client address and port.
*
* XXX In stand-alone mode, don't assume that the peer will be a local
* process. That could introduce a gaping hole when the SMTP daemon is
* hooked up to the network via inetd or some other super-server.
*/
if (vstream_context(state->client) != 0) {
smtpd_peer_from_pass_attr(state);
if (*var_smtpd_uproxy_proto != 0)
msg_warn("ignoring non-empty %s setting behind postscreen",
VAR_SMTPD_UPROXY_PROTO);
} else if (SMTPD_STAND_ALONE(state) || *var_smtpd_uproxy_proto == 0) {
smtpd_peer_from_default(state);
} else {
smtpd_peer_from_proxy(state);
}
/*
* Determine the remote SMTP client hostname. Note: some of the handlers
* above provide surrogate endpoint information in case of error. In that
* case, leave the surrogate information alone.
*/
if (state->name == 0)
smtpd_peer_sockaddr_to_hostname(state);
/*
* Do the name[addr]:port formatting for pretty reports.
@ -396,10 +592,18 @@ void smtpd_peer_init(SMTPD_STATE *state)
void smtpd_peer_reset(SMTPD_STATE *state)
{
myfree(state->name);
myfree(state->reverse_name);
myfree(state->addr);
myfree(state->namaddr);
myfree(state->rfc_addr);
myfree(state->port);
if (state->name)
myfree(state->name);
if (state->reverse_name)
myfree(state->reverse_name);
if (state->addr)
myfree(state->addr);
if (state->namaddr)
myfree(state->namaddr);
if (state->rfc_addr)
myfree(state->rfc_addr);
if (state->port)
myfree(state->port);
if (state->dest_addr)
myfree(state->dest_addr);
}

View File

@ -214,7 +214,8 @@ void smtpd_sasl_activate(SMTPD_STATE *state, const char *sasl_opts_name,
if ((state->sasl_server =
XSASL_SERVER_CREATE(smtpd_sasl_impl, &create_args,
stream = state->client,
server_addr = "", /* need smtpd_peer.c update */
server_addr = (state->dest_addr ?
state->dest_addr : ""),
client_addr = ADDR_OR_EMPTY(state->addr,
CLIENT_ADDR_UNKNOWN),
service = SMTPD_SASL_SERVICE,

View File

@ -31,11 +31,11 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \
write_buf.c write_wait.c sane_basename.c format_tv.c allspace.c \
allascii.c load_file.c killme_after.c vstream_tweak.c \
unix_pass_listen.c unix_pass_trigger.c edit_file.c inet_windowsize.c \
pass_trigger.c edit_file.c inet_windowsize.c \
unix_pass_fd_fix.c dict_cache.c valid_utf_8.c dict_thash.c \
ip_match.c nbbio.c stream_pass_connect.c base32_code.c dict_test.c \
ip_match.c nbbio.c base32_code.c dict_test.c \
dict_fail.c msg_rate_delay.c dict_surrogate.c warn_stat.c \
dict_sockmap.c line_number.c
dict_sockmap.c line_number.c recv_pass_attr.c pass_accept.c
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@ -68,11 +68,11 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \
write_buf.o write_wait.o sane_basename.o format_tv.o allspace.o \
allascii.o load_file.o killme_after.o vstream_tweak.o \
unix_pass_listen.o unix_pass_trigger.o edit_file.o inet_windowsize.o \
pass_trigger.o edit_file.o inet_windowsize.o \
unix_pass_fd_fix.o dict_cache.o valid_utf_8.o dict_thash.o \
ip_match.o nbbio.o stream_pass_connect.o base32_code.o dict_test.o \
ip_match.o nbbio.o base32_code.o dict_test.o \
dict_fail.o msg_rate_delay.o dict_surrogate.o warn_stat.o \
dict_sockmap.o line_number.o
dict_sockmap.o line_number.o recv_pass_attr.o pass_accept.o
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
@ -111,7 +111,8 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
attr_scan0 host_port attr_scan_plain attr_print_plain htable \
unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \
myaddrinfo myaddrinfo4 inet_proto sane_basename format_tv \
valid_utf_8 ip_match base32_code msg_rate_delay netstring
valid_utf_8 ip_match base32_code msg_rate_delay netstring \
vstream
LIB_DIR = ../../lib
INC_DIR = ../../include
@ -446,6 +447,11 @@ netstring: $(LIB)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
vstream: $(LIB)
mv $@.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
tests: valid_hostname_test mac_expand_test dict_test unescape_test \
hex_quote_test ctable_test inet_addr_list_test base64_code_test \
attr_scan64_test attr_scan0_test dict_pcre_test host_port_test \
@ -1203,6 +1209,7 @@ exec_command.o: exec_command.h
exec_command.o: msg.h
exec_command.o: sys_defs.h
fifo_listen.o: fifo_listen.c
fifo_listen.o: htable.h
fifo_listen.o: iostuff.h
fifo_listen.o: listen.h
fifo_listen.o: msg.h
@ -1329,6 +1336,7 @@ inet_connect.o: sock_addr.h
inet_connect.o: sys_defs.h
inet_connect.o: timed_connect.h
inet_listen.o: host_port.h
inet_listen.o: htable.h
inet_listen.o: inet_listen.c
inet_listen.o: inet_proto.h
inet_listen.o: iostuff.h
@ -1572,6 +1580,23 @@ open_lock.o: sys_defs.h
open_lock.o: vbuf.h
open_lock.o: vstream.h
open_lock.o: vstring.h
pass_accept.o: attr.h
pass_accept.o: htable.h
pass_accept.o: iostuff.h
pass_accept.o: listen.h
pass_accept.o: msg.h
pass_accept.o: pass_accept.c
pass_accept.o: sys_defs.h
pass_accept.o: vbuf.h
pass_accept.o: vstream.h
pass_trigger.o: connect.h
pass_trigger.o: events.h
pass_trigger.o: iostuff.h
pass_trigger.o: msg.h
pass_trigger.o: mymalloc.h
pass_trigger.o: pass_trigger.c
pass_trigger.o: sys_defs.h
pass_trigger.o: trigger.h
peekfd.o: iostuff.h
peekfd.o: peekfd.c
peekfd.o: sys_defs.h
@ -1608,6 +1633,15 @@ readlline.o: sys_defs.h
readlline.o: vbuf.h
readlline.o: vstream.h
readlline.o: vstring.h
recv_pass_attr.o: attr.h
recv_pass_attr.o: htable.h
recv_pass_attr.o: iostuff.h
recv_pass_attr.o: listen.h
recv_pass_attr.o: mymalloc.h
recv_pass_attr.o: recv_pass_attr.c
recv_pass_attr.o: sys_defs.h
recv_pass_attr.o: vbuf.h
recv_pass_attr.o: vstream.h
ring.o: ring.c
ring.o: ring.h
safe_getenv.o: safe.h
@ -1720,16 +1754,12 @@ stream_connect.o: iostuff.h
stream_connect.o: msg.h
stream_connect.o: stream_connect.c
stream_connect.o: sys_defs.h
stream_listen.o: htable.h
stream_listen.o: iostuff.h
stream_listen.o: listen.h
stream_listen.o: msg.h
stream_listen.o: stream_listen.c
stream_listen.o: sys_defs.h
stream_pass_connect.o: connect.h
stream_pass_connect.o: iostuff.h
stream_pass_connect.o: msg.h
stream_pass_connect.o: stream_pass_connect.c
stream_pass_connect.o: sys_defs.h
stream_recv_fd.o: iostuff.h
stream_recv_fd.o: msg.h
stream_recv_fd.o: stream_recv_fd.c
@ -1739,6 +1769,7 @@ stream_send_fd.o: msg.h
stream_send_fd.o: stream_send_fd.c
stream_send_fd.o: sys_defs.h
stream_test.o: connect.h
stream_test.o: htable.h
stream_test.o: iostuff.h
stream_test.o: listen.h
stream_test.o: msg.h
@ -1798,6 +1829,7 @@ unix_connect.o: sane_connect.h
unix_connect.o: sys_defs.h
unix_connect.o: timed_connect.h
unix_connect.o: unix_connect.c
unix_listen.o: htable.h
unix_listen.o: iostuff.h
unix_listen.o: listen.h
unix_listen.o: msg.h
@ -1810,20 +1842,6 @@ unix_pass_fd_fix.o: sys_defs.h
unix_pass_fd_fix.o: unix_pass_fd_fix.c
unix_pass_fd_fix.o: vbuf.h
unix_pass_fd_fix.o: vstring.h
unix_pass_listen.o: iostuff.h
unix_pass_listen.o: listen.h
unix_pass_listen.o: msg.h
unix_pass_listen.o: sane_accept.h
unix_pass_listen.o: sys_defs.h
unix_pass_listen.o: unix_pass_listen.c
unix_pass_trigger.o: connect.h
unix_pass_trigger.o: events.h
unix_pass_trigger.o: iostuff.h
unix_pass_trigger.o: msg.h
unix_pass_trigger.o: mymalloc.h
unix_pass_trigger.o: sys_defs.h
unix_pass_trigger.o: trigger.h
unix_pass_trigger.o: unix_pass_trigger.c
unix_recv_fd.o: iostuff.h
unix_recv_fd.o: msg.h
unix_recv_fd.o: sys_defs.h

View File

@ -22,9 +22,6 @@
extern int unix_connect(const char *, int, int);
extern int inet_connect(const char *, int, int);
extern int stream_connect(const char *, int, int);
extern int stream_pass_connect(const char *, int, int);
#define unix_pass_connect unix_connect
/* LICENSE
/* .ad

View File

@ -15,6 +15,7 @@
* Utility library.
*/
#include <iostuff.h>
#include <htable.h>
/*
* Listener external interface.
@ -24,15 +25,13 @@ extern int inet_listen(const char *, int, int);
extern int fifo_listen(const char *, int, int);
extern int stream_listen(const char *, int, int);
#define unix_pass_listen unix_listen
#define stream_pass_listen stream_listen
extern int inet_accept(int);
extern int unix_accept(int);
extern int stream_accept(int);
extern int unix_pass_accept(int);
#define stream_pass_accept stream_accept
extern int recv_pass_attr(int, HTABLE **, int, ssize_t);
extern int pass_accept(int);
extern int pass_accept_attr(int, HTABLE **);
/* LICENSE
/* .ad

View File

@ -148,6 +148,8 @@ void msg_printf(int level, const char *format,...)
void msg_vprintf(int level, const char *format, va_list ap)
{
int saved_errno = errno;
if (msg_vprintf_lock == 0) {
msg_vprintf_lock = 1;
/* On-the-fly initialization for debugging test programs only. */
@ -158,6 +160,7 @@ void msg_vprintf(int level, const char *format, va_list ap)
msg_text(level, vstring_str(msg_buffer));
msg_vprintf_lock = 0;
}
errno = saved_errno;
}
/* msg_text - sanitize and log pre-formatted text */

View File

@ -0,0 +1,106 @@
/*++
/* NAME
/* pass_accept 3
/* SUMMARY
/* start UNIX-domain file descriptor listener
/* SYNOPSIS
/* #include <listen.h>
/*
/* int pass_accept(listen_fd)
/* int listen_fd;
/*
/* int pass_accept_attr(listen_fd, attr)
/* int listen_fd;
/* HTABLE **attr;
/* DESCRIPTION
/* This module implements a listener that receives one attribute list
/* and file descriptor over each a local connection that is made to it.
/*
/* Arguments:
/* .IP attr
/* Pointer to attribute list pointer. In case of error, or
/* no attributes, the attribute list pointer is set to null.
/* .IP listen_fd
/* File descriptor returned by LOCAL_LISTEN().
/* DIAGNOSTICS
/* Warnings: I/O errors, timeout.
/* 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 <listen.h>
#include <attr.h>
#define PASS_ACCEPT_TMOUT 100
/* pass_accept - accept descriptor */
int pass_accept(int listen_fd)
{
const char *myname = "pass_accept";
int accept_fd;
int recv_fd = -1;
accept_fd = LOCAL_ACCEPT(listen_fd);
if (accept_fd < 0) {
if (errno != EAGAIN)
msg_warn("%s: cannot accept connection: %m", myname);
return (-1);
} else {
if (read_wait(accept_fd, PASS_ACCEPT_TMOUT) < 0)
msg_warn("%s: timeout receiving file descriptor: %m", myname);
else if ((recv_fd = LOCAL_RECV_FD(accept_fd)) < 0)
msg_warn("%s: cannot receive file descriptor: %m", myname);
if (close(accept_fd) < 0)
msg_warn("%s: close: %m", myname);
return (recv_fd);
}
}
/* pass_accept_attr - accept attribute list and descriptor */
int pass_accept_attr(int listen_fd, HTABLE **attr)
{
const char *myname = "pass_accept_attr";
int accept_fd;
int recv_fd = -1;
*attr = 0;
accept_fd = LOCAL_ACCEPT(listen_fd);
if (accept_fd < 0) {
if (errno != EAGAIN)
msg_warn("%s: cannot accept connection: %m", myname);
return (-1);
} else {
if (read_wait(accept_fd, PASS_ACCEPT_TMOUT) < 0)
msg_warn("%s: timeout receiving file descriptor: %m", myname);
else if ((recv_fd = LOCAL_RECV_FD(accept_fd)) < 0)
msg_warn("%s: cannot receive file descriptor: %m", myname);
else if (read_wait(accept_fd, PASS_ACCEPT_TMOUT) < 0
|| recv_pass_attr(accept_fd, attr, PASS_ACCEPT_TMOUT, 0) < 0) {
msg_warn("%s: cannot receive connection attributes: %m", myname);
if (close(recv_fd) < 0)
msg_warn("%s: close: %m", myname);
recv_fd = -1;
}
if (close(accept_fd) < 0)
msg_warn("%s: close: %m", myname);
return (recv_fd);
}
}

View File

@ -1,19 +1,19 @@
/*++
/* NAME
/* unix_pass_trigger 3
/* pass_trigger 3
/* SUMMARY
/* wakeup UNIX-domain file descriptor listener
/* trigger file descriptor listener
/* SYNOPSIS
/* #include <trigger.h>
/*
/* int unix_pass_trigger(service, buf, len, timeout)
/* int pass_trigger(service, buf, len, timeout)
/* const char *service;
/* const char *buf;
/* ssize_t len;
/* int timeout;
/* DESCRIPTION
/* unix_pass_trigger() wakes up the named UNIX-domain server by sending
/* a brief connection to it and writing the named buffer.
/* pass_trigger() connects to the named local server by sending
/* a file descriptor to it and writing the named buffer.
/*
/* The connection is closed by a background thread. Some kernels
/* cannot handle client-side disconnect before the server has
@ -32,7 +32,8 @@
/* DIAGNOSTICS
/* The result is zero in case of success, -1 in case of problems.
/* SEE ALSO
/* unix_pass_connect(3), UNIX-domain client
/* unix_connect(3), local client
/* stream_connect(3), streams-based client
/* LICENSE
/* .ad
/* .fi
@ -60,45 +61,45 @@
#include <events.h>
#include <trigger.h>
struct unix_pass_trigger {
int fd;
struct pass_trigger {
int connect_fd;
char *service;
int *pair;
int pass_fd[2];
};
/* unix_pass_trigger_event - disconnect from peer */
/* pass_trigger_event - disconnect from peer */
static void unix_pass_trigger_event(int event, char *context)
static void pass_trigger_event(int event, char *context)
{
struct unix_pass_trigger *up = (struct unix_pass_trigger *) context;
static const char *myname = "unix_pass_trigger_event";
struct pass_trigger *pp = (struct pass_trigger *) context;
static const char *myname = "pass_trigger_event";
/*
* Disconnect.
*/
if (event == EVENT_TIME)
msg_warn("%s: read timeout for service %s", myname, up->service);
event_disable_readwrite(up->fd);
event_cancel_timer(unix_pass_trigger_event, context);
msg_warn("%s: read timeout for service %s", myname, pp->service);
event_disable_readwrite(pp->connect_fd);
event_cancel_timer(pass_trigger_event, context);
/* Don't combine multiple close() calls into one boolean expression. */
if (close(up->fd) < 0)
msg_warn("%s: close %s: %m", myname, up->service);
if (close(up->pair[0]) < 0)
if (close(pp->connect_fd) < 0)
msg_warn("%s: close %s: %m", myname, pp->service);
if (close(pp->pass_fd[0]) < 0)
msg_warn("%s: close pipe: %m", myname);
if (close(up->pair[1]) < 0)
if (close(pp->pass_fd[1]) < 0)
msg_warn("%s: close pipe: %m", myname);
myfree(up->service);
myfree((char *) up);
myfree(pp->service);
myfree((char *) pp);
}
/* unix_pass_trigger - wakeup UNIX-domain server */
/* pass_trigger - wakeup local server */
int unix_pass_trigger(const char *service, const char *buf, ssize_t len, int timeout)
int pass_trigger(const char *service, const char *buf, ssize_t len, int timeout)
{
const char *myname = "unix_pass_trigger";
int pair[2];
struct unix_pass_trigger *up;
int fd;
const char *myname = "pass_trigger";
int pass_fd[2];
struct pass_trigger *pp;
int connect_fd;
if (msg_verbose > 1)
msg_info("%s: service %s", myname, service);
@ -106,36 +107,37 @@ int unix_pass_trigger(const char *service, const char *buf, ssize_t len, int
/*
* Connect...
*/
if ((fd = unix_pass_connect(service, BLOCKING, timeout)) < 0) {
if ((connect_fd = LOCAL_CONNECT(service, BLOCKING, timeout)) < 0) {
if (msg_verbose)
msg_warn("%s: connect to %s: %m", myname, service);
return (-1);
}
close_on_exec(fd, CLOSE_ON_EXEC);
close_on_exec(connect_fd, CLOSE_ON_EXEC);
/*
* Create a pipe, and send one pipe end to the server.
*/
if (pipe(pair) < 0)
if (pipe(pass_fd) < 0)
msg_fatal("%s: pipe: %m", myname);
close_on_exec(pair[0], CLOSE_ON_EXEC);
close_on_exec(pair[1], CLOSE_ON_EXEC);
if (unix_send_fd(fd, pair[0]) < 0)
close_on_exec(pass_fd[0], CLOSE_ON_EXEC);
close_on_exec(pass_fd[1], CLOSE_ON_EXEC);
if (LOCAL_SEND_FD(connect_fd, pass_fd[0]) < 0)
msg_fatal("%s: send file descriptor: %m", myname);
/*
* Stash away context.
*/
up = (struct unix_pass_trigger *) mymalloc(sizeof(*up));
up->fd = fd;
up->service = mystrdup(service);
up->pair = pair;
pp = (struct pass_trigger *) mymalloc(sizeof(*pp));
pp->connect_fd = connect_fd;
pp->service = mystrdup(service);
pp->pass_fd[0] = pass_fd[0];
pp->pass_fd[1] = pass_fd[1];
/*
* Write the request...
*/
if (write_buf(pair[1], buf, len, timeout) < 0
|| write_buf(pair[1], "", 1, timeout) < 0)
if (write_buf(pass_fd[1], buf, len, timeout) < 0
|| write_buf(pass_fd[1], "", 1, timeout) < 0)
if (msg_verbose)
msg_warn("%s: write to %s: %m", myname, service);
@ -143,7 +145,7 @@ int unix_pass_trigger(const char *service, const char *buf, ssize_t len, int
* Wakeup when the peer disconnects, or when we lose patience.
*/
if (timeout > 0)
event_request_timer(unix_pass_trigger_event, (char *) up, timeout + 100);
event_enable_read(fd, unix_pass_trigger_event, (char *) up);
event_request_timer(pass_trigger_event, (char *) pp, timeout + 100);
event_enable_read(connect_fd, pass_trigger_event, (char *) pp);
return (0);
}

View File

@ -0,0 +1,93 @@
/*++
/* NAME
/* recv_pass_attr 3
/* SUMMARY
/* predicate if string is all numerical
/* SYNOPSIS
/* #include <listen.h>
/*
/* int recv_pass_attr(fd, attr, timeout, bufsize)
/* int fd;
/* HTABLE **attr;
/* int timeout;
/* ssize_t bufsize;
/* DESCRIPTION
/* recv_pass_attr() receives named attributes over the specified
/* The result value is zero for success, -1 for error.
/*
/* Arguments:
/* .IP fd
/* The file descriptor to read from.
/* .IP attr
/* Pointer to attribute list pointer. The target is set to
/* zero on error or when the received attribute list is empty,
/* ohterwise it is assigned a pointer to non-empty attribute
/* list.
/* .IP timeout
/* The deadline for receiving all attributes.
/* .IP bufsize
/* The read buffer size. Specify 1 to avoid reading past the
/* end of the attribute list.
/* 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 <iostuff.h>
#include <htable.h>
#include <vstream.h>
#include <attr.h>
#include <mymalloc.h>
#include <listen.h>
/* recv_pass_attr - receive connection attributes */
int recv_pass_attr(int fd, HTABLE **attr, int timeout, ssize_t bufsize)
{
VSTREAM *fp;
int stream_err;
/*
* Set up a temporary VSTREAM to receive the attributes.
*
* XXX We use one-character reads to simplify the implementation.
*/
fp = vstream_fdopen(fd, O_RDWR);
vstream_control(fp,
VSTREAM_CTL_BUFSIZE, bufsize,
VSTREAM_CTL_TIMEOUT, timeout,
VSTREAM_CTL_START_DEADLINE,
VSTREAM_CTL_END);
(void) attr_scan(fp, ATTR_FLAG_NONE,
ATTR_TYPE_HASH, *attr = htable_create(1),
ATTR_TYPE_END);
stream_err = (vstream_feof(fp) || vstream_ferror(fp));
vstream_fdclose(fp);
/*
* Error reporting and recovery.
*/
if (stream_err) {
htable_free(*attr, myfree);
*attr = 0;
return (-1);
} else {
if ((*attr)->used == 0) {
htable_free(*attr, myfree);
*attr = 0;
}
return (0);
}
}

View File

@ -97,6 +97,6 @@ int stream_accept(int fd)
return (-1);
return (fdinfo.fd);
#else
msg_fatal("stream connections are not implemented");
msg_fatal("stream connections are not implemented");
#endif
}

View File

@ -1,86 +0,0 @@
/*++
/* NAME
/* stream_pass_connect 3
/* SUMMARY
/* connect to stream-based descriptor listener
/* SYNOPSIS
/* #include <connect.h>
/*
/* int stream_pass_connect(path, block_mode, timeout)
/* const char *path;
/* int block_mode;
/* int timeout;
/* DESCRIPTION
/* stream_pass_connect() connects to a stream-based descriptor
/* listener for the specified pathname, and returns the resulting
/* file descriptor. The next operation is to stream_send_fd()
/* a file descriptor and then close() the connection once the
/* server has received the file descriptor.
/*
/* Arguments:
/* .IP path
/* Null-terminated string with listener endpoint name.
/* .IP block_mode
/* Either NON_BLOCKING for a non-blocking stream, or BLOCKING for
/* blocking mode. However, a stream connection succeeds or fails
/* immediately.
/* .IP timeout
/* This argument is ignored; it is present for compatibility with
/* other interfaces. Stream connections succeed or fail immediately.
/* DIAGNOSTICS
/* The result is -1 in case the connection could not be made.
/* Fatal errors: other system call failures.
/* 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>
#ifdef STREAM_CONNECTIONS
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#endif
/* Utility library. */
#include <msg.h>
#include <connect.h>
/* stream_pass_connect - connect to stream-based descriptor listener */
int stream_pass_connect(const char *path, int block_mode, int unused_timeout)
{
#ifdef STREAM_CONNECTIONS
const char *myname = "stream_pass_connect";
int fifo;
/*
* The requested file system object must exist, otherwise we can't reach
* the server.
*/
if ((fifo = open(path, O_WRONLY | O_NONBLOCK, 0)) < 0)
return (-1);
/*
* This is for {unix,inet}_connect() compatibility.
*/
non_blocking(fifo, block_mode);
return (fifo);
#else
msg_fatal("stream connections are not implemented");
#endif
}

View File

@ -436,10 +436,6 @@ extern int opterr;
#define LOCAL_TRIGGER stream_trigger
#define LOCAL_SEND_FD stream_send_fd
#define LOCAL_RECV_FD stream_recv_fd
#define PASS_CONNECT stream_pass_connect
#define PASS_LISTEN stream_pass_listen
#define PASS_ACCEPT stream_pass_accept
#define PASS_TRIGGER stream_pass_trigger
#define HAS_VOLATILE_LOCKS
#define BROKEN_READ_SELECT_ON_TCP_SOCKET
#define CANT_WRITE_BEFORE_SENDING_FD
@ -1410,13 +1406,6 @@ extern int inet_pton(int, const char *, void *);
#define LOCAL_RECV_FD unix_recv_fd
#endif
#ifndef PASS_LISTEN
#define PASS_CONNECT unix_pass_connect
#define PASS_LISTEN unix_pass_listen
#define PASS_ACCEPT unix_pass_accept
#define PASS_TRIGGER unix_pass_trigger
#endif
#if !defined (HAVE_SYS_NDIR_H) && !defined (HAVE_SYS_DIR_H) \
&& !defined (HAVE_NDIR_H)
#define HAVE_DIRENT_H

View File

@ -18,9 +18,7 @@ extern int unix_trigger(const char *, const char *, ssize_t, int);
extern int inet_trigger(const char *, const char *, ssize_t, int);
extern int fifo_trigger(const char *, const char *, ssize_t, int);
extern int stream_trigger(const char *, const char *, ssize_t, int);
extern int unix_pass_trigger(const char *, const char *, ssize_t, int);
#define stream_pass_trigger stream_trigger
extern int pass_trigger(const char *, const char *, ssize_t, int);
/* LICENSE
/* .ad

View File

@ -1,85 +0,0 @@
/*++
/* NAME
/* unix_pass_listen 3
/* SUMMARY
/* start UNIX-domain file descriptor listener
/* SYNOPSIS
/* #include <listen.h>
/*
/* int unix_pass_listen(path, backlog, block_mode)
/* const char *path;
/* int backlog;
/* int block_mode;
/*
/* int unix_pass_accept(fd)
/* int fd;
/* DESCRIPTION
/* This module implements a listener that receives one file descriptor
/* across each UNIX-domain connection that is made to it.
/*
/* unix_pass_listen() creates a listener endpoint with the specified
/* permissions, and returns a file descriptor to be used for accepting
/* descriptors.
/*
/* unix_pass_accept() accepts a descriptor.
/*
/* Arguments:
/* .IP path
/* Null-terminated string with connection destination.
/* .IP backlog
/* This argument exists for compatibility and is ignored.
/* .IP block_mode
/* Either NON_BLOCKING or BLOCKING. This does not affect the
/* mode of accepted connections.
/* .IP fd
/* File descriptor returned by unix_pass_listen().
/* DIAGNOSTICS
/* Fatal errors: unix_pass_listen() aborts upon any system call failure.
/* unix_pass_accept() leaves all error handling up to the caller.
/* 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 <sys/socket.h>
#include <errno.h>
#include <unistd.h>
/* Utility library. */
#include <msg.h>
#include <sane_accept.h>
#include <listen.h>
/* unix_pass_accept - accept descriptor */
int unix_pass_accept(int listen_fd)
{
const char *myname = "unix_pass_accept";
int accept_fd;
int recv_fd = -1;
accept_fd = sane_accept(listen_fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0);
if (accept_fd < 0) {
if (errno != EAGAIN)
msg_warn("%s: accept connection: %m", myname);
return (-1);
} else {
if (read_wait(accept_fd, 100) < 0)
msg_warn("%s: timeout receiving file descriptor: %m", myname);
else if ((recv_fd = unix_recv_fd(accept_fd)) < 0)
msg_warn("%s: cannot receive file descriptor: %m", myname);
if (close(accept_fd) < 0)
msg_warn("%s: close: %m", myname);
return (recv_fd);
}
}

View File

@ -21,6 +21,10 @@
/* int valid_ipv6_hostaddr(addr, gripe)
/* const char *addr;
/* int gripe;
/*
/* int valid_hostport(port, gripe)
/* const char *port;
/* int gripe;
/* DESCRIPTION
/* valid_hostname() scrutinizes a hostname: the name should
/* be no longer than VALID_HOSTNAME_LEN characters, should
@ -42,6 +46,9 @@
/* These routines operate silently unless the gripe parameter
/* specifies a non-zero value. The macros DO_GRIPE and DONT_GRIPE
/* provide suitable constants.
/*
/* valid_hostport() requires that the input is a valid string
/* representation of a TCP or UDP port number.
/* BUGS
/* valid_hostmumble() does not guarantee that string lengths
/* fit the buffer sizes defined in myaddrinfo(3h).
@ -65,6 +72,7 @@
#include <sys_defs.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
/* Utility library. */
@ -337,6 +345,32 @@ int valid_ipv6_hostaddr(const char *addr, int gripe)
}
}
/* valid_hostport - validate numeric port */
int valid_hostport(const char *str, int gripe)
{
const char *myname = "valid_hostport";
int port;
if (str[0] == '0' && str[1] != 0) {
if (gripe)
msg_warn("%s: leading zero in port number: %.100s", myname, str);
return (0);
}
if (alldig(str) == 0) {
if (gripe)
msg_warn("%s: non-numeric port number: %.100s", myname, str);
return (0);
}
if (strlen(str) > strlen("65535")
|| (port = atoi(str)) > 65535 || port < 0) {
if (gripe)
msg_warn("%s: out-of-range port number: %.100s", myname, str);
return (0);
}
return (1);
}
#ifdef TEST
/*

View File

@ -23,6 +23,7 @@ extern int valid_hostname(const char *, int);
extern int valid_hostaddr(const char *, int);
extern int valid_ipv4_hostaddr(const char *, int);
extern int valid_ipv6_hostaddr(const char *, int);
extern int valid_hostport(const char *, int);
/* LICENSE
/* .ad

View File

@ -324,16 +324,21 @@
/* This involves allocation of additional memory that normally isn't
/* used.
/* .IP "VSTREAM_CTL_BUFSIZE (ssize_t)"
/* Specify a non-default write buffer size, or zero to implement
/* a no-op. Requests to shrink an existing buffer size are
/* ignored. Requests to change a fixed-size buffer (stdin,
/* stdout, stderr) are not allowed.
/* Specify a non-default buffer size, or zero to implement
/* a no-op. Requests to resize a fixed-size buffer (stderr)
/* are not allowed.
/*
/* NOTE: the VSTREAM_CTL_BUFSIZE request specifies intent, not
/* reality. Actual buffer sizes are not updated immediately.
/* Instead, an existing write buffer will be resized when it
/* is full, and an existing read buffer will be resized when
/* the buffer is filled.
/* Instead, a write buffer size will be updated when writing
/* to a stream for the first time, or when writing to a full
/* buffer, and a read buffer size will be updated when reading
/* from a stream for the first time, or when reading from an
/* empty buffer.
/*
/* NOTE: the vstream_*printf() routines may silently expand a
/* buffer, so that the result of some %letter specifiers can
/* be written to contiguous memory.
/*
/* NOTE: the VSTREAM_CTL_BUFSIZE argument type is ssize_t, not
/* int. Use an explicit cast to avoid problems on LP64
@ -621,10 +626,17 @@ static void vstream_buf_alloc(VBUF *bp, ssize_t len)
ssize_t used = bp->ptr - bp->data;
const char *myname = "vstream_buf_alloc";
if (len < bp->len)
msg_panic("%s: attempt to shrink buffer", myname);
/*
* Don't shrink a non-empty read buffer, or a non-flushed write buffer.
*/
if (len <= 0)
msg_panic("%s: bad buffer length: %ld", myname, (long) len);
if (len < bp->len
&& (((bp->flags & VSTREAM_FLAG_READ) && bp->cnt != 0)
|| ((bp->flags & VSTREAM_FLAG_WRITE) && bp->cnt != bp->len)))
msg_panic("%s: attempt to shrink non-empty buffer", myname);
if (bp->flags & VSTREAM_FLAG_FIXED)
msg_panic("%s: unable to extend fixed-size buffer", myname);
msg_panic("%s: attempt to resize fixed-length buffer", myname);
/*
* Late buffer allocation allows the user to override the default policy.
@ -842,7 +854,7 @@ static int vstream_buf_get_ready(VBUF *bp)
* allocation gives the application a chance to override the default
* buffering policy.
*/
if (bp->len < stream->req_bufsize)
if (bp->len != stream->req_bufsize)
vstream_buf_alloc(bp, stream->req_bufsize);
/*
@ -956,6 +968,8 @@ static int vstream_buf_put_ready(VBUF *bp)
if (VSTREAM_FFLUSH_SOME(stream))
return (VSTREAM_EOF);
}
if (bp->len > stream->req_bufsize)
vstream_buf_alloc(bp, stream->req_bufsize);
return (0);
}
@ -1467,8 +1481,7 @@ void vstream_control(VSTREAM *stream, int name,...)
if (req_bufsize < 0)
msg_panic("VSTREAM_CTL_BUFSIZE with negative size: %ld",
(long) req_bufsize);
if (stream != VSTREAM_ERR
&& req_bufsize > stream->req_bufsize)
if (req_bufsize > 0 && stream != VSTREAM_ERR)
stream->req_bufsize = req_bufsize;
break;
@ -1578,3 +1591,44 @@ const char *vstream_peek_data(VSTREAM *vp)
return (0);
}
}
#ifdef TEST
static void copy_line(ssize_t bufsize)
{
int c;
vstream_control(VSTREAM_IN, VSTREAM_CTL_BUFSIZE, bufsize, VSTREAM_CTL_END);
vstream_control(VSTREAM_OUT, VSTREAM_CTL_BUFSIZE, bufsize, VSTREAM_CTL_END);
while ((c = VSTREAM_GETC(VSTREAM_IN)) != VSTREAM_EOF) {
VSTREAM_PUTC(c, VSTREAM_OUT);
if (c == '\n')
break;
}
vstream_fflush(VSTREAM_OUT);
}
static void printf_number(void)
{
vstream_printf("%d\n", __MAXINT__(int));
vstream_fflush(VSTREAM_OUT);
}
/*
* Exercise some of the features.
*/
int main(int argc, char **argv)
{
/*
* Test buffer expansion and shrinking. Formatted print may silently
* expand the write buffer and cause multiple bytes to be written.
*/
copy_line(1); /* one-byte read/write */
copy_line(2); /* two-byte read/write */
copy_line(1); /* one-byte read/write */
printf_number(); /* multi-byte write */
exit(0);
}
#endif

View File

@ -207,6 +207,8 @@ extern const char *vstream_peek_data(VSTREAM *);
extern int vstream_tweak_sock(VSTREAM *);
extern int vstream_tweak_tcp(VSTREAM *);
#define vstream_flags(stream) ((const int) (stream)->buf.flags)
/* LICENSE
/* .ad
/* .fi