]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.10-20120625
authorWietse Venema <wietse@porcupine.org>
Thu, 21 Jun 2012 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:38:12 +0000 (06:38 +0000)
55 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/html/postconf.5.html
postfix/html/postscreen.8.html
postfix/html/smtpd.8.html
postfix/makedefs
postfix/man/man5/postconf.5
postfix/man/man8/postscreen.8
postfix/man/man8/smtpd.8
postfix/mantools/postlink
postfix/proto/postconf.proto
postfix/src/global/Makefile.in
postfix/src/global/haproxy_srvr.c [new file with mode: 0644]
postfix/src/global/haproxy_srvr.h [new file with mode: 0644]
postfix/src/global/mail_params.h
postfix/src/global/mail_proto.h
postfix/src/global/mail_version.h
postfix/src/master/Makefile.in
postfix/src/master/event_server.c
postfix/src/master/master_listen.c
postfix/src/master/master_wakeup.c
postfix/src/master/multi_server.c
postfix/src/master/single_server.c
postfix/src/master/trigger_server.c
postfix/src/postscreen/Makefile.in
postfix/src/postscreen/postscreen.c
postfix/src/postscreen/postscreen.h
postfix/src/postscreen/postscreen_endpt.c [new file with mode: 0644]
postfix/src/postscreen/postscreen_haproxy.c [new file with mode: 0644]
postfix/src/postscreen/postscreen_haproxy.h [new file with mode: 0644]
postfix/src/postscreen/postscreen_send.c
postfix/src/postscreen/postscreen_state.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd.h
postfix/src/smtpd/smtpd_haproxy.c [new file with mode: 0644]
postfix/src/smtpd/smtpd_peer.c
postfix/src/smtpd/smtpd_sasl_glue.c
postfix/src/util/Makefile.in
postfix/src/util/connect.h
postfix/src/util/listen.h
postfix/src/util/msg_output.c
postfix/src/util/pass_accept.c [new file with mode: 0644]
postfix/src/util/pass_trigger.c [moved from postfix/src/util/unix_pass_trigger.c with 51% similarity]
postfix/src/util/recv_pass_attr.c [new file with mode: 0644]
postfix/src/util/stream_listen.c
postfix/src/util/stream_pass_connect.c [deleted file]
postfix/src/util/sys_defs.h
postfix/src/util/trigger.h
postfix/src/util/unix_pass_listen.c [deleted file]
postfix/src/util/valid_hostname.c
postfix/src/util/valid_hostname.h
postfix/src/util/vstream.c
postfix/src/util/vstream.h

index 634794f726ffb1da06e3b495560ecaaf3ae7962e..df478eb1f5c91b305f0353d0a3b9d608cf858d4c 100644 (file)
 -TPSC_DNSBL_HEAD
 -TPSC_DNSBL_SCORE
 -TPSC_DNSBL_SITE
+-TPSC_ENDPT_LOOKUP_INFO
+-TPSC_HAPROXY_STATE
 -TPSC_SMTPD_COMMAND
 -TPSC_STARTTLS
 -TPSC_STATE
 -TSMFICTX
 -TSMTPD_CMD
 -TSMTPD_DEFER
+-TSMTPD_ENDPT_LOOKUP_INFO
 -TSMTPD_PROXY
 -TSMTPD_RBL_EXPAND_CONTEXT
 -TSMTPD_RBL_STATE
index 57ab40cc4510f7e2e3c9fd92449ea23b0b3708b2..611c9d40990290da6c8e368dd8db4b929587086b 100644 (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.
index 096b2d08abcb1621e6e569f2fe5f348a38945672..0fb18079ceca2f0c530b1128e78293637db1e4c4 100644 (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
 ====================================
 
index 06f74178d898f73c246c161be0c1a01f9dbc02da..072b7be32f2bc41766282162bab3ed04c52ea163 100644 (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>
index 4ef299d7b894ac97dd0b62ffea7c0a6132135d1d..901b7163131b600bd48cf7256c4bb1cd34ebfb5f 100644 (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>
index f814378bc3f56a222c241f195e22a4dd8e123271..ee9ae6a92d571405c45a79461d76213eadcb9239 100644 (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
index 92a9717c37469ea5e8fe901d2068cea42189c97f..875ecc213dfa31ad1e74bc71ca6f0294bd140bd0 100644 (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
index 9b2f6955f5e8cf7fd4d3b20ef92a97068b47e899..ab0b7e31a165afb684b790b729735f24672f1394 100644 (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.
index 34dd9627480133e96554bc2328743df6c171c0e0..bd797622203bc0f823269b013a0d9f528dcf601c 100644 (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
index b4e311a159a5e15e7ba2e77f31d37b860924aa82..26611a3675b251594b7bc9548eada0e4dfcaab98 100644 (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
index d7bb6b5e55c7626df9155589dbf90cf8fadbb4b7..2500420fb09ccc0598525f9a199a165f2d7bc726 100755 (executable)
@@ -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;
index 24fd6b5dbab833a55ae1b2dc9ab0b5d74e273f71..416ed5b4ac818fc570eefc7be69666a1752597dc 100644 (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
index d8fb3dbd5a3a9aa937484f55a1c90209423f73fb..8e11da58ddf11aed01d58d66da601371917aea0d 100644 (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
diff --git a/postfix/src/global/haproxy_srvr.c b/postfix/src/global/haproxy_srvr.c
new file mode 100644 (file)
index 0000000..db3d0c1
--- /dev/null
@@ -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);
+}
diff --git a/postfix/src/global/haproxy_srvr.h b/postfix/src/global/haproxy_srvr.h
new file mode 100644 (file)
index 0000000..7cd3262
--- /dev/null
@@ -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
index ae960984b1d60ee88deeda7532b199e078af4e04..8913eed9ce572671b5909eb05a64f545d8575c6c 100644 (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.
   */
index 538b01e57bed5f15630ba42553071ff3aa78d627..a4dd8d4c4b3eaf42fba36f38513be1c79d8e2e66 100644 (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 */
index 81910ced01658a272721b6eb5663d84e01d6ced8..f4306c63f2cbd7ac8b231825ebb6952286861f7f 100644 (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
index 2305da34648f7938d0483552ea47fee70729e462..9a74c6917fe1e42a5bd0ce9042268dff1f872ec9 100644 (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
index b58d22578b785d2e8490bd7461260a99d9b84d3f..aa6f97d1b25da988cba557bf76272ac2b429f3c5 100644 (file)
 /*     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 */
index 494d429f738675caab4b3c151e0388d9c365ed3c..a17bde1cbd6d81cd28203c8916ad0a3f597f2229 100644 (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());
index ee6062023a3782e16fd358396b019032fe1664da..47c2e41345cff5536683fb8ee8a5a9557acec17c 100644 (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
 
index c16118db3761fc78104089ff4cfe401f7d1d0bd1..19c04040d78f9bf8dfa440d42fda725d63858d43 100644 (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 */
index 7b6d8bfd7eb179957d7bf6687bbfb6e6f82f069f..01bc89218a15feb2f0e9b16b7eb63ba9eb9ce183 100644 (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.
index bc4a16ceae7bbcd9f0d0289407e5016186325dfd..cdfdd75bbddca4f3eddf9501cef2aaa5160af0af 100644 (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)
index a7a61837fa32b82a75fcc66c6b5a45c79ca559c8..d83a10bba13d0354f88f16dc46a875d6cdeb3880 100644 (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
index fa85d6d4810149ad70cab7265257bd8c25a9c096..2c55a660c8c6b8fe27e8924da88488d019975ac7 100644 (file)
 /* .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.
@@ -612,84 +617,52 @@ 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.
+     * Look up the remote SMTP client address and port.
      */
+    psc_endpt_lookup(smtp_client_stream, psc_endpt_lookup_done);
+}
 
-    /* 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);
+/* psc_endpt_lookup_done - endpoint lookup completed */
 
-    /*
-     * 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);
-    }
+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[] = {
index 87cc2c13022e4525273ec39872c3a31103f3ea1a..860a134b6feda164111333d4a413ad51ae4e4a91 100644 (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.
   */
diff --git a/postfix/src/postscreen/postscreen_endpt.c b/postfix/src/postscreen/postscreen_endpt.c
new file mode 100644 (file)
index 0000000..44f332e
--- /dev/null
@@ -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;
+       }
+    }
+}
diff --git a/postfix/src/postscreen/postscreen_haproxy.c b/postfix/src/postscreen/postscreen_haproxy.c
new file mode 100644 (file)
index 0000000..a8cb736
--- /dev/null
@@ -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);
+}
diff --git a/postfix/src/postscreen/postscreen_haproxy.h b/postfix/src/postscreen/postscreen_haproxy.h
new file mode 100644 (file)
index 0000000..2691e48
--- /dev/null
@@ -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
+/*--*/
index cbbbf97c7f08743ef2056336f8970a058b6dbb1e..61a5f0cf2dc784f5a181df62e458cafcb4609887 100644 (file)
 #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);
index 581647b6f9a6fb5d222a83bdc36e0c18c0a9ff86..e199eb88554e20bd6e299a250f4848f176ce2f34 100644 (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;
 /* 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)
index a311c77ec48fee9c338be61e4f51aabff6003070..3178a0a20a6abc7c41ce9a60365d7a0c486a66d6 100644 (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
index 6651424b4d6c288fd630434848f5a8985101e31b..df6ee36ee602a57933841f66351fe747d8fe5dfe 100644 (file)
 /*     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[] = {
index cc459068223e2d0cead79cdb7b603d9f7b0475f3..a4932ac88054b2aa298b793163674e781499bb75 100644 (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
diff --git a/postfix/src/smtpd/smtpd_haproxy.c b/postfix/src/smtpd/smtpd_haproxy.c
new file mode 100644 (file)
index 0000000..d104d9d
--- /dev/null
@@ -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);
+    }
+}
index 330e07938a4cda27d874dbf77ef11f76963e2b6e..5faa1e4454d8b14e9b13e7a2d3985c8278c5eb0e 100644 (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:
 #include <errno.h>
 #include <netdb.h>
 #include <string.h>
+#include <htable.h>
 
 /* Utility library. */
 
 #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 */
-
-void    smtpd_peer_init(SMTPD_STATE *state)
+static INET_PROTO_INFO *proto_info;
+
+ /*
+  * 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);
-
-    /*
-     * 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.
-     */
-    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);
-    }
+    const char *myname = "smtpd_peer_sockaddr_to_hostaddr";
+    struct sockaddr *sa = (struct sockaddr *) & (state->sockaddr);
+    SOCKADDR_SIZE sa_length = state->sockaddr_len;
 
     /*
-     * 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).
+     * 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) ?
-                              SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
-           state->reverse_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);
-       } 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;
+               }
+               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;
                }
-               freeaddrinfo(res0);
+               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);
 }
index 5062ee9acb31783519b4e782468cd03c71d71fd4..29021cd0de96c106686a6a45a9655ef081d7c10d 100644 (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,
index f5119a32c0e52c9f66e7a321b07747dce5b07e5e..59bbc35875f9b9bbf68f15f1643b104967e61135 100644 (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
index 9ec9c58832b448182c3467e30d1e260896e3b47f..080b99c064a37826cb6ada39bb5ea36479889da8 100644 (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
index 848543752de98ce4b73ae43a2c87e01556d402ca..ccd45bc73610d7a91d9c359015c4a438050de25e 100644 (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
index 0c34bb5db43ac19dc5fd2bafe98e9f6c52d87e97..be2ceaabba412ccd514addc5fb115b33894d6995 100644 (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 */
diff --git a/postfix/src/util/pass_accept.c b/postfix/src/util/pass_accept.c
new file mode 100644 (file)
index 0000000..3e15049
--- /dev/null
@@ -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);
+    }
+}
similarity index 51%
rename from postfix/src/util/unix_pass_trigger.c
rename to postfix/src/util/pass_trigger.c
index 61230092486c5e1830788b7f697269038f6bb2fa..9567abc0f42474563183a45d8d70a496dbd821b0 100644 (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
 #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);
 }
diff --git a/postfix/src/util/recv_pass_attr.c b/postfix/src/util/recv_pass_attr.c
new file mode 100644 (file)
index 0000000..3e7a9d0
--- /dev/null
@@ -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);
+    }
+}
index 5882c30d986be3a1f07e3e08743116c9e10c3e89..b522b764d3e89041c853eb911156f9a45f92e28c 100644 (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
 }
diff --git a/postfix/src/util/stream_pass_connect.c b/postfix/src/util/stream_pass_connect.c
deleted file mode 100644 (file)
index 9bacdf4..0000000
+++ /dev/null
@@ -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
-}
index 482fa7327432d3a9b616778b524a5b5a25433edb..5c5b9d78436722f179b656204f1e08cb2e734f14 100644 (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
index 5e578d2b402e750618df7eebdf263a750520bd89..e716d53744a4c7a289239dbbee7bdcbc484ba843 100644 (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
diff --git a/postfix/src/util/unix_pass_listen.c b/postfix/src/util/unix_pass_listen.c
deleted file mode 100644 (file)
index 8226159..0000000
+++ /dev/null
@@ -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);
-    }
-}
index 1beeb9af404501425ba02561f08aef5602509971..7a40d6e4bd19e45ef62f7ed203b96576cf908222 100644 (file)
 /*     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
 
  /*
index 8860153b595f09f0843e8917dfb06baf50885b61..b06fc175861d03fb91c03672d33812033c250949 100644 (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
index 0f12d203c77824a5228f2933c89206397d213fc9..ee718b4571d560b71e7581836e402af5c9dd02e9 100644 (file)
 /*     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
index ddb8fda6a0aa5e7b2f809fda9b9e7b5ac4b8835a..ee8d843478980b5373b93e2746dc3d7defe429f1 100644 (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