]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.2-20040621
authorWietse Venema <wietse@porcupine.org>
Mon, 21 Jun 2004 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:29:41 +0000 (06:29 +0000)
42 files changed:
postfix/HISTORY
postfix/README_FILES/BACKSCATTER_README
postfix/README_FILES/INSTALL
postfix/RELEASE_NOTES
postfix/conf/transport
postfix/html/BACKSCATTER_README.html
postfix/html/INSTALL.html
postfix/html/local.8.html
postfix/html/pipe.8.html
postfix/html/postconf.5.html
postfix/html/regexp_table.5.html
postfix/html/transport.5.html
postfix/man/man5/postconf.5
postfix/man/man5/regexp_table.5
postfix/man/man5/transport.5
postfix/man/man8/local.8
postfix/man/man8/pipe.8
postfix/mantools/postlink
postfix/mantools/xpostdef
postfix/proto/BACKSCATTER_README.html
postfix/proto/INSTALL.html
postfix/proto/postconf.proto
postfix/proto/regexp_table
postfix/proto/transport
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/pipe_command.c
postfix/src/global/pipe_command.h
postfix/src/local/command.c
postfix/src/local/local.c
postfix/src/pipe/pipe.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp.h
postfix/src/smtp/smtp_chat.c
postfix/src/smtp/smtp_connect.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_sasl.h
postfix/src/smtp/smtp_sasl_glue.c
postfix/src/smtp/smtp_sasl_proto.c
postfix/src/smtp/smtp_session.c
postfix/src/smtp/smtp_state.c
postfix/src/smtp/smtp_trouble.c

index 67c97aebb154303af1f32884f9a4e3875162e863..9c442ceed1b1dc936c89753d404d8fdc2b3e6881 100644 (file)
@@ -9414,6 +9414,40 @@ Apologies for any names omitted.
        Bugfix: space in HELO commands could end up in XFORWARD
        commands.  File: smtpd/smtpd.c.
 
+20040619
+
+       Code reorganization: in preparation for SMTP session caching,
+       the SMTP client data structures were changed from the
+       original "one session per delivery request" model to an
+       explicit "multiple sessions per delivery request" model.
+       This uncovered ESMTP and SASL missing re-initialization
+       problems that were fixed in past week.  Design by Victor
+       and Wietse, initial implementation by Victor Duchovny.
+
+20040620
+
+       Future proofing: after the reorganization of SMTP request
+       state and session state, added code to the smtp client
+       error handling routines to more consistently deal with the
+       possibility that session information is not be available.
+
+20040621
+
+       Feature: directory=pathname option for the pipe(8) delivery
+       agent. This allows a command to run from a fixed directory.
+       Failure to change directory causes delivery to be deferred.
+       Files: pipe/pipe.c.
+
+       Feature: command_execution_directory for local(8) delivery
+       to external command. This supports the usual $home etc.
+       expansions, subject to filtering with the character set
+       specified with $execution_directory_expansion_filter.
+       Failure to change directory causes delivery to be deferred.
+       Files:  global/mail_params.h, local/command.c.
+
+       Support for external command execution directory. Files:
+       global/pipe_command.[hc].
+
 Open problems:
 
        Low: make sure CCARGS -I options come at the end.
index be0d750c5d3f147ca73c6b1e1a8d4e46cfaae634..86e8aa8e19ca74c41c0b1e6240860ae2af1dd968 100644 (file)
@@ -146,8 +146,9 @@ Notes:
   * The example is simplified for educational purposes. In reality, my patterns
     list multiple email addresses as "(user1@domain1\.tld|user2@domain2\.tld)".
 
-  * The [[:<:]] matches the beginning of a word, and the [[:>:]] matches the
-    end.
+  * The "[[:<:]]" and "[[:>:]]" match the beginning and end of a word,
+    respectively. On some systems you should specify "\<" and "\>" instead. For
+    details see your system documentation.
 
   * The "\." matches "." literally. Without the "\", the "." would match any
     character.
@@ -171,7 +172,8 @@ techniques to recognize forgeries.
 Recognizing virus scanner mail is an error prone process, because there is a
 lot of variation in report formats. The following is only a small example of
 message header patterns. For a large collection of header and body patterns
-that recognize virus notification email, see http://www.dkuug.dk/keld/virus/.
+that recognize virus notification email, see http://www.dkuug.dk/keld/virus/ or
+http://www.t29.dk/antiantivirus.txt.
 
     /etc/postfix/header_checks:
         /^Subject: *Your email contains VIRUSES/ DISCARD virus notification
index 7590a31620d511d4e83ed8d4a4df62cd07cdffcb..08df531cd4dba6943c42a564b22da7ad74db5d4e 100644 (file)
@@ -648,9 +648,15 @@ systems.
 Additionally, you almost certainly need to configure syslogd so that it listens
 on a socket inside the Postfix queue directory. Examples for specific systems:
 
-FreeBSD: syslogd -l /var/spool/postfix/var/run/log
+FreeBSD:
 
-Linux, OpenBSD: syslogd -a /var/spool/postfix/dev/log
+    # mkdir -p /var/spool/postfix/var/run
+    # syslogd -l /var/spool/postfix/var/run/log
+
+Linux, OpenBSD:
+
+    # mkdir -p /var/spool/postfix/dev
+    # syslogd -a /var/spool/postfix/dev/log
 
 1\b12\b2 -\b- C\bCa\bar\bre\be a\ban\bnd\bd f\bfe\bee\bed\bdi\bin\bng\bg o\bof\bf t\bth\bhe\be P\bPo\bos\bst\btf\bfi\bix\bx s\bsy\bys\bst\bte\bem\bm
 
index 8a0050609629825af3604394c272b651e4387387..6105973ea5691f7d58287cfb850d465df05b9791 100644 (file)
@@ -7,4 +7,12 @@ snapshot release).  Patches are issued for the official release
 and change the patchlevel and the release date. Patches are never
 issued for snapshot releases.
 
-[nothing to report here, except great relief that 2.1 is frozen]
+Major changes with snapshot Postfix-2.2-20040621
+================================================
+
+Control over the working directory when executing an external
+command.  With the pipe(8) mailer, specify directory=pathname, and
+with local(8) specify "command_execution_directory = expression"
+where "expression" is subject to $home etc. macro expansion. The
+result of macro expansion is restricted by the set of charaacters
+specified with execution_directory_expansion_filter.
index 9f6265515e5896dfeee1e8682372af6f2f2e079a..b15146806f67c039e470254910ad8ce8c1071729 100644 (file)
 #        $empty_address_recipient@$myhostname (default: mailer-dae-
 #        mon@hostname).
 # 
+#        Note  3:  user@domain  or  user+extension@domain lookup is
+#        available in Postfix 2.0 and later.
+# 
 # RESULT FORMAT
-#        The  lookup  result is of the form transport:nexthop.  The
-#        transport field specifies a mail delivery  transport  such
-#        as  smtp  or  local. The nexthop field specifies where and
+#        The lookup result is of the form  transport:nexthop.   The
+#        transport  field  specifies a mail delivery transport such
+#        as smtp or local. The nexthop field  specifies  where  and
 #        how to deliver mail.
 # 
-#        The transport field specifies the name of a mail  delivery
+#        The  transport field specifies the name of a mail delivery
 #        transport (the first name of a mail delivery service entry
 #        in the Postfix master.cf file).
 # 
-#        The interpretation  of  the  nexthop  field  is  transport
-#        dependent.  In  the  case  of SMTP, specify a service on a
-#        non-default port as host:service,  and  disable  MX  (mail
-#        exchanger)  DNS lookups with [host] or [host]:port. The []
+#        The  interpretation  of  the  nexthop  field  is transport
+#        dependent. In the case of SMTP, specify  a  service  on  a
+#        non-default  port  as  host:service,  and disable MX (mail
+#        exchanger) DNS lookups with [host] or [host]:port. The  []
 #        form is required when you specify an IP address instead of
 #        a hostname.
 # 
-#        A  null  transport  and  null nexthop result means "do not
-#        change": use the delivery transport and  nexthop  informa-
-#        tion  that  would  be used when the entire transport table
+#        A null transport and null nexthop  result  means  "do  not
+#        change":  use  the delivery transport and nexthop informa-
+#        tion that would be used when the  entire  transport  table
 #        did not exist.
 # 
-#        A non-null transport  field  with  a  null  nexthop  field
+#        A  non-null  transport  field  with  a  null nexthop field
 #        resets the nexthop information to the recipient domain.
 # 
-#        A  null  transport  field with non-null nexthop field does
+#        A null transport field with non-null  nexthop  field  does
 #        not modify the transport information.
 # 
 # EXAMPLES
-#        In order to deliver internal mail directly, while using  a
-#        mail  relay  for  all other mail, specify a null entry for
-#        internal destinations (do not change the  delivery  trans-
-#        port  or  the  nexthop information) and specify a wildcard
+#        In  order to deliver internal mail directly, while using a
+#        mail relay for all other mail, specify a  null  entry  for
+#        internal  destinations  (do not change the delivery trans-
+#        port or the nexthop information) and  specify  a  wildcard
 #        for all other destinations.
 # 
 #             my.domain    :
 #             .my.domain   :
 #             *         smtp:outbound-relay.my.domain
 # 
-#        In order to send mail for example.com and  its  subdomains
+#        In  order  to send mail for example.com and its subdomains
 #        via the uucp transport to the UUCP host named example:
 # 
 #             example.com      uucp:example
 #             .example.com     uucp:example
 # 
-#        When  no  nexthop  host name is specified, the destination
-#        domain name is used instead. For  example,  the  following
-#        directs  mail  for user@example.com via the slow transport
-#        to a mail exchanger for example.com.  The  slow  transport
+#        When no nexthop host name is  specified,  the  destination
+#        domain  name  is  used instead. For example, the following
+#        directs mail for user@example.com via the  slow  transport
+#        to  a  mail exchanger for example.com.  The slow transport
 #        could be configured to run at most one delivery process at
 #        a time:
 # 
 #             example.com      slow:
 # 
 #        When no transport is specified, Postfix uses the transport
-#        that  matches  the  address  domain class (see DESCRIPTION
-#        above).  The following sends all mail for example.com  and
+#        that matches the address  domain  class  (see  DESCRIPTION
+#        above).   The following sends all mail for example.com and
 #        its subdomains to host gateway.example.com:
 # 
 #             example.com      :[gateway.example.com]
 #             .example.com     :[gateway.example.com]
 # 
-#        In  the  above  example, the [] suppress MX lookups.  This
-#        prevents mail routing loops when your machine  is  primary
+#        In the above example, the [] suppress  MX  lookups.   This
+#        prevents  mail  routing loops when your machine is primary
 #        MX host for example.com.
 # 
-#        In  the  case  of delivery via SMTP, one may specify host-
+#        In the case of delivery via SMTP, one  may  specify  host-
 #        name:service instead of just a host:
 # 
 #             example.com      smtp:bar.example:2025
 # 
 #        The error mailer can be used to bounce mail:
 # 
-#             .example.com      error:mail for *.example.com is not
+#             .example.com     error:mail for *.example.com is  not
 #        deliverable
 # 
-#        This causes all mail for user@anything.example.com  to  be
+#        This  causes  all mail for user@anything.example.com to be
 #        bounced.
 # 
 # REGULAR EXPRESSION TABLES
-#        This  section  describes how the table lookups change when
+#        This section describes how the table lookups  change  when
 #        the table is given in the form of regular expressions. For
-#        a  description  of regular expression lookup table syntax,
+#        a description of regular expression lookup  table  syntax,
 #        see regexp_table(5) or pcre_table(5).
 # 
-#        Each pattern is a regular expression that  is  applied  to
-#        the    entire    address    being    looked    up.   Thus,
-#        some.domain.hierarchy is not  looked  up  via  its  parent
-#        domains,  nor is user+foo@domain looked up as user@domain.
+#        Each  pattern  is  a regular expression that is applied to
+#        the   entire    address    being    looked    up.    Thus,
+#        some.domain.hierarchy  is  not  looked  up  via its parent
+#        domains, nor is user+foo@domain looked up as  user@domain.
 # 
-#        Patterns are applied in the  order  as  specified  in  the
-#        table,  until  a  pattern is found that matches the search
+#        Patterns  are  applied  in  the  order as specified in the
+#        table, until a pattern is found that  matches  the  search
 #        string.
 # 
-#        Results are the same as with indexed  file  lookups,  with
-#        the  additional feature that parenthesized substrings from
+#        Results  are  the  same as with indexed file lookups, with
+#        the additional feature that parenthesized substrings  from
 #        the pattern can be interpolated as $1, $2 and so on.
 # 
 # TCP-BASED TABLES
-#        This section describes how the table lookups  change  when
+#        This  section  describes how the table lookups change when
 #        lookups are directed to a TCP-based server. For a descrip-
-#        tion  of  the  TCP  client/server  lookup  protocol,   see
-#        tcp_table(5).   This  feature  is not available in Postfix
+#        tion   of  the  TCP  client/server  lookup  protocol,  see
+#        tcp_table(5).  This feature is not  available  in  Postfix
 #        version 2.1.
 # 
-#        Each lookup operation uses the  entire  recipient  address
-#        once.   Thus,  some.domain.hierarchy  is not looked up via
-#        its parent domains, nor is user+foo@domain  looked  up  as
+#        Each  lookup  operation  uses the entire recipient address
+#        once.  Thus, some.domain.hierarchy is not  looked  up  via
+#        its  parent  domains,  nor is user+foo@domain looked up as
 #        user@domain.
 # 
 #        Results are the same as with indexed file lookups.
 # 
 # CONFIGURATION PARAMETERS
-#        The  following main.cf parameters are especially relevant.
-#        The text below provides  only  a  parameter  summary.  See
+#        The following main.cf parameters are especially  relevant.
+#        The  text  below  provides  only  a parameter summary. See
 #        postconf(5) for more details including examples.
 # 
 #        empty_address_recipient
-#               The  address  that is looked up instead of the null
+#               The address that is looked up instead of  the  null
 #               sender address.
 # 
 #        parent_domain_matches_subdomains
-#               List of Postfix features that use  domain.tld  pat-
-#               terns   to  match  sub.domain.tld  (as  opposed  to
+#               List  of  Postfix features that use domain.tld pat-
+#               terns  to  match  sub.domain.tld  (as  opposed   to
 #               requiring .domain.tld patterns).
 # 
 #        transport_maps
 #        postmap(1), Postfix lookup table manager
 # 
 # README FILES
-#        Use "postconf readme_directory" or  "postconf  html_direc-
+#        Use  "postconf  readme_directory" or "postconf html_direc-
 #        tory" to locate this information.
 #        DATABASE_README, Postfix lookup table overview
 #        FILTER_README, external content filter
 # 
 # LICENSE
-#        The  Secure  Mailer  license must be distributed with this
+#        The Secure Mailer license must be  distributed  with  this
 #        software.
 # 
 # AUTHOR(S)
index e08eb7bb301fa623003561622c5e2d7ea6f30d8f..f2889feaf4b59e0a52440df62a45422b970fa187 100644 (file)
@@ -229,8 +229,10 @@ and is very easy to stop.
 reality, my patterns list multiple email addresses as
 "<tt>(user1@domain1\.tld|user2@domain2\.tld)</tt>".  </p>
 
-<li> <p> The <tt>[[:&lt;:]]</tt> matches the beginning of a word,
-and the <tt>[[:&gt;:]]</tt> matches the end. </p>
+<li> <p> The "<tt>[[:&lt;:]]</tt>" and "<tt>[[:&gt;:]]</tt>" match
+the beginning and end of a word, respectively. On some systems you
+should specify "<tt>\&lt;</tt>" and "<tt>\&gt;</tt>" instead. For
+details see your system documentation.
 
 <li> <p> The "<tt>\.</tt>" matches "<tt>.</tt>" literally. Without
 the "<tt>\</tt>", the "<tt>.</tt>" would match any character. </p>
@@ -261,7 +263,8 @@ above techniques to recognize forgeries.  </p>
 because there is a lot of variation in report formats.  The following
 is only a small example of message header patterns.  For a large
 collection of header and body patterns that recognize virus
-notification email, see <a href="http://www.dkuug.dk/keld/virus/">http://www.dkuug.dk/keld/virus/</a>.  </p>
+notification email, see <a href="http://www.dkuug.dk/keld/virus/">http://www.dkuug.dk/keld/virus/</a>
+or <a href="http://www.t29.dk/antiantivirus.txt">http://www.t29.dk/antiantivirus.txt</a>.  </p>
 
 <blockquote>
 <pre>
index a45f8745bdc0b0fefbdc1d9d7b0b635fea27e6d7..0c08aa00a61872511b618ade14111eb6d1c12fe1 100644 (file)
@@ -952,9 +952,23 @@ systems. </p>
 so that it listens on a socket inside the Postfix queue directory.
 Examples for specific systems: </p>
 
-<p> FreeBSD: <tt>syslogd -l /var/spool/postfix/var/run/log</tt> </p>
+<dl>
 
-<p> Linux, OpenBSD: <tt>syslogd -a /var/spool/postfix/dev/log</tt> </p>
+<dt> FreeBSD: </dt>
+
+<dd> <pre>
+# mkdir -p /var/spool/postfix/var/run
+# syslogd -l /var/spool/postfix/var/run/log
+</pre> </dd>
+
+<dt> Linux, OpenBSD: </dt>
+
+<dd> <pre>
+# mkdir -p /var/spool/postfix/dev
+# syslogd -a /var/spool/postfix/dev/log
+</pre> </dd>
+
+</dl>
 
 <h2><a name="care">12 - Care and feeding of the Postfix system</a></h2>
 
index 6fdb5733481c36e8ec80469fe5172e9f6842e444..0ca93411d7bdf1a05279192ca80913f1caa4c03f 100644 (file)
@@ -107,9 +107,9 @@ LOCAL(8)                                                 LOCAL(8)
        Mailbox  delivery  can be delegated to an external command
        specified with the <b><a href="postconf.5.html#mailbox_command">mailbox_command</a></b>  configuration  parame-
        ter.  The  command  executes  with  the  privileges of the
-       recipient user (exception: in case of  delivery  as  root,
-       the    command    executes    with   the   privileges   of
-       <b><a href="postconf.5.html#default_privs">default_privs</a></b>).
+       recipient  user  (exceptions:  secondary  groups  are  not
+       enabled; in case of delivery as root, the command executes
+       with the privileges of <b><a href="postconf.5.html#default_privs">default_privs</a></b>).
 
        Mailbox delivery can be delegated to  alternative  message
        transports  specified  in  the  <b>master.cf</b> file.  The <b><a href="postconf.5.html#mailbox_transport">mail</a>-</b>
@@ -144,6 +144,24 @@ LOCAL(8)                                                 LOCAL(8)
        ting  (<b>alias,  forward</b>)  forbids  command  destinations in
        <b>:include:</b> files.
 
+       Optionally, the process working directory  is  changed  to
+       the path specified with <b><a href="postconf.5.html#command_execution_directory">command_execution_directory</a></b> (Post-
+       fix 2.2 and later). Failure  to  change  directory  causes
+       mail to be deferred.
+
+       The <b><a href="postconf.5.html#command_execution_directory">command_execution_directory</a></b> parameter value is subject
+       to interpolation  of  <b>$user</b>  (recipient  username),  <b>$home</b>
+       (recipient  home  directory),  <b>$shell</b>  (recipient  shell),
+       <b>$recipient</b>  (complete   recipient   address),   <b>$extension</b>
+       (recipient address extension), <b>$domain</b> (recipient domain),
+       <b>local</b> (entire recipient address  localpart)  and  <b>$recipi-</b>
+       <b>ent_delimiter.</b>   The forms <i>${name?value}</i> and <i>${name:value}</i>
+       expand conditionally to  <i>value</i>  when  <i>$name</i>  is  (is  not)
+       defined.   Characters that may have special meaning to the
+       shell or file system are  replaced  by  underscores.   The
+       list of acceptable characters is specified with the <b><a href="postconf.5.html#execution_directory_expansion_filter">execu</a>-</b>
+       <b><a href="postconf.5.html#execution_directory_expansion_filter">tion_directory_expansion_filter</a></b> configuration parameter.
+
        The command is executed directly  where  possible.  Assis-
        tance  by the shell (<b>/bin/sh</b> on UNIX systems) is used only
        when the command contains shell magic characters, or  when
@@ -349,21 +367,27 @@ LOCAL(8)                                                 LOCAL(8)
               Optional catch-all destination for unknown <a href="local.8.html">local(8)</a>
               recipients.
 
+       Available in Postfix version 2.2 and later:
+
+       <b><a href="postconf.5.html#command_execution_directory">command_execution_directory</a> (empty)</b>
+              The <a href="local.8.html">local(8)</a> delivery agent working  directory  for
+              delivery to external command.
+
 <b>MAILBOX LOCKING CONTROLS</b>
        <b><a href="postconf.5.html#deliver_lock_attempts">deliver_lock_attempts</a> (20)</b>
               The maximal number of attempts to acquire an exclu-
               sive lock on a mailbox file or <a href="bounce.8.html">bounce(8)</a> logfile.
 
        <b><a href="postconf.5.html#deliver_lock_delay">deliver_lock_delay</a> (1s)</b>
-              The  time  between attempts to acquire an exclusive
+              The time between attempts to acquire  an  exclusive
               lock on a mailbox file or <a href="bounce.8.html">bounce(8)</a> logfile.
 
        <b><a href="postconf.5.html#stale_lock_time">stale_lock_time</a> (500s)</b>
-              The time after  which  a  stale  exclusive  mailbox
+              The  time  after  which  a  stale exclusive mailbox
               lockfile is removed.
 
        <b><a href="postconf.5.html#mailbox_delivery_lock">mailbox_delivery_lock</a> (see 'postconf -d' output)</b>
-              How  to  lock  a UNIX-style <a href="local.8.html">local(8)</a> mailbox before
+              How to lock a UNIX-style  <a href="local.8.html">local(8)</a>  mailbox  before
               attempting delivery.
 
 <b>RESOURCE AND RATE CONTROLS</b>
@@ -371,17 +395,17 @@ LOCAL(8)                                                 LOCAL(8)
               Time limit for delivery to external commands.
 
        <b><a href="postconf.5.html#duplicate_filter_limit">duplicate_filter_limit</a> (1000)</b>
-              The maximal number of addresses remembered  by  the
-              address  duplicate  filter  for  <a href="aliases.5.html">aliases(5)</a> or vir-
+              The  maximal  number of addresses remembered by the
+              address duplicate filter  for  <a href="aliases.5.html">aliases(5)</a>  or  vir-
               tual(5) alias expansion, or for <a href="showq.8.html">showq(8)</a> queue dis-
               plays.
 
        <b><a href="postconf.5.html#local_destination_concurrency_limit">local_destination_concurrency_limit</a> (2)</b>
-              The  maximal  number of parallel deliveries via the
+              The maximal number of parallel deliveries  via  the
               local mail delivery transport to the same recipient
-              (when  "<a href="postconf.5.html#local_destination_recipient_limit">local_destination_recipient_limit</a>  = 1") or
-              the maximal number of parallel  deliveries  to  the
-              same  <a href="ADDRESS_CLASS_README.html#local_domain_class">local domain</a> (when "local_destination_recipi-
+              (when "<a href="postconf.5.html#local_destination_recipient_limit">local_destination_recipient_limit</a> =  1")  or
+              the  maximal  number  of parallel deliveries to the
+              same <a href="ADDRESS_CLASS_README.html#local_domain_class">local domain</a> (when  "local_destination_recipi-
               ent_limit &gt; 1").
 
        <b><a href="postconf.5.html#local_destination_recipient_limit">local_destination_recipient_limit</a> (1)</b>
@@ -394,37 +418,45 @@ LOCAL(8)                                                 LOCAL(8)
 
 <b>SECURITY CONTROLS</b>
        <b><a href="postconf.5.html#allow_mail_to_commands">allow_mail_to_commands</a> (alias, forward)</b>
-              Restrict <a href="local.8.html">local(8)</a> mail delivery  to  external  com-
+              Restrict  <a href="local.8.html">local(8)</a>  mail  delivery to external com-
               mands.
 
        <b><a href="postconf.5.html#allow_mail_to_files">allow_mail_to_files</a> (alias, forward)</b>
-              Restrict  <a href="local.8.html">local(8)</a> mail delivery to external files.
+              Restrict <a href="local.8.html">local(8)</a> mail delivery to external  files.
 
        <b><a href="postconf.5.html#command_expansion_filter">command_expansion_filter</a> (see 'postconf -d' output)</b>
-              Restrict the characters that the <a href="local.8.html">local(8)</a>  delivery
-              agent  allows  in $name expansions of $mailbox_com-
+              Restrict  the characters that the <a href="local.8.html">local(8)</a> delivery
+              agent allows in $name expansions  of  $mailbox_com-
               mand.
 
        <b><a href="postconf.5.html#default_privs">default_privs</a> (nobody)</b>
-              The default rights used by  the  <a href="local.8.html">local(8)</a>  delivery
+              The  default  rights  used by the <a href="local.8.html">local(8)</a> delivery
               agent for delivery to external file or command.
 
        <b><a href="postconf.5.html#forward_expansion_filter">forward_expansion_filter</a> (see 'postconf -d' output)</b>
-              Restrict  the characters that the <a href="local.8.html">local(8)</a> delivery
-              agent allows in $name expansions of  $<a href="postconf.5.html#forward_path">forward_path</a>.
+              Restrict the characters that the <a href="local.8.html">local(8)</a>  delivery
+              agent  allows in $name expansions of $<a href="postconf.5.html#forward_path">forward_path</a>.
+
+       Available in Postfix version 2.2 and later:
+
+       <b><a href="postconf.5.html#execution_directory_expansion_filter">execution_directory_expansion_filter</a>  (see  'postconf  -d'</b>
+       <b>output)</b>
+              Restrict the characters that the <a href="local.8.html">local(8)</a>  delivery
+              agent allows in $name expansions of $<a href="postconf.5.html#command_execution_directory">command_execu</a>-
+              <a href="postconf.5.html#command_execution_directory">tion_directory</a>.
 
 <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 main.cf and
+              The default location of  the  Postfix  main.cf  and
               master.cf configuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              How much time a Postfix daemon process may take  to
-              handle  a  request  before  it  is  terminated by a
+              How  much time a Postfix daemon process may take to
+              handle a request  before  it  is  terminated  by  a
               built-in watchdog timer.
 
        <b><a href="postconf.5.html#export_environment">export_environment</a> (see 'postconf -d' output)</b>
-              The list of environment variables  that  a  Postfix
+              The  list  of  environment variables that a Postfix
               process will export to non-Postfix processes.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@@ -432,37 +464,37 @@ LOCAL(8)                                                 LOCAL(8)
               over an internal communication channel.
 
        <b><a href="postconf.5.html#local_command_shell">local_command_shell</a> (empty)</b>
-              Optional shell program  for  <a href="local.8.html">local(8)</a>  delivery  to
+              Optional  shell  program  for  <a href="local.8.html">local(8)</a> delivery to
               non-Postfix command.
 
        <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 the next  service  request
+              The maximum amount of time  that  an  idle  Postfix
+              daemon  process  waits for the next service request
               before exiting.
 
        <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
-              The  maximal number of connection requests before a
+              The maximal number of connection requests before  a
               Postfix daemon process terminates.
 
        <b><a href="postconf.5.html#prepend_delivered_header">prepend_delivered_header</a> (command, file, forward)</b>
-              The message delivery  contexts  where  the  Postfix
-              <a href="local.8.html">local(8)</a>  delivery  agent  prepends a Delivered-To:
+              The  message  delivery  contexts  where the Postfix
+              <a href="local.8.html">local(8)</a> delivery agent  prepends  a  Delivered-To:
               message header.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
-              The process ID of a Postfix command or daemon  pro-
+              The  process ID of a Postfix command or daemon pro-
               cess.
 
        <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#propagate_unmatched_extensions">propagate_unmatched_extensions</a> (canonical, virtual)</b>
-              What address lookup tables copy an  address  exten-
+              What  address  lookup tables copy an address exten-
               sion from the lookup key to the lookup result.
 
        <b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
-              The  location of the Postfix top-level queue direc-
+              The location of the Postfix top-level queue  direc-
               tory.
 
        <b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
@@ -470,14 +502,14 @@ LOCAL(8)                                                 LOCAL(8)
               sions (user+foo).
 
        <b><a href="postconf.5.html#require_home_directory">require_home_directory</a> (no)</b>
-              Whether  or  not a <a href="local.8.html">local(8)</a> recipient's home direc-
-              tory must exist before mail delivery is  attempted.
+              Whether or not a <a href="local.8.html">local(8)</a> recipient's  home  direc-
+              tory  must exist before mail delivery is attempted.
 
        <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> (postfix)</b>
-              The  mail system name that is prepended to the pro-
+              The mail system name that is prepended to the  pro-
               cess  name  in  syslog  records,  so  that  "smtpd"
               becomes, for example, "postfix/smtpd".
 
@@ -497,14 +529,14 @@ LOCAL(8)                                                 LOCAL(8)
        syslogd(8), system logging
 
 <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>
        The <b>Delivered-To:</b> message header appears in the <b>qmail</b> sys-
        tem by Daniel Bernstein.
 
-       The  <i>maildir</i>  structure  appears  in  the  <b>qmail</b> system by
+       The <i>maildir</i> structure  appears  in  the  <b>qmail</b>  system  by
        Daniel Bernstein.
 
 <b>AUTHOR(S)</b>
index c40584f700f71d4f918ebeabd48a6a766e06b08f..6bf9ef68717a8c8e322d50995a373d6cbcd33eb7 100644 (file)
@@ -48,70 +48,80 @@ PIPE(8)                                                   PIPE(8)
        file at the end of a service definition.  The syntax is as
        follows:
 
+       <b>eol=string</b> (optional, default: <b>\n</b>)
+              The output record delimiter.  Typically  one  would
+              use  either <b>\r\n</b> or <b>\n</b>. The usual C-style backslash
+              escape sequences are recognized: <b>\a \b \f \n \r  \t</b>
+              <b>\v \</b><i>octal</i> and <b>\\</b>.
+
        <b>flags=BDFORhqu.</b>&gt; (optional)
-              Optional message processing flags.  By  default,  a
+              Optional  message  processing  flags. By default, a
               message is copied unchanged.
 
-              <b>B</b>      Append  a blank line at the end of each mes-
-                     sage. This is required  by  some  mail  user
-                     agents  that  recognize  "<b>From</b>  " lines only
+              <b>B</b>      Append a blank line at the end of each  mes-
+                     sage.  This  is  required  by some mail user
+                     agents that recognize  "<b>From</b>  "  lines  only
                      when preceded by a blank line.
 
-              <b>D</b>      Prepend a "<b>Delivered-To:</b> <i>recipient</i>"  message
-                     header  with the envelope recipient address.
+              <b>D</b>      Prepend  a "<b>Delivered-To:</b> <i>recipient</i>" message
+                     header with the envelope recipient  address.
                      Note: for this to work, the <i>transport</i><b>_desti-</b>
                      <b>nation_recipient_limit</b> must be 1.
 
                      This feature is available as of Postfix 2.0.
 
-              <b>F</b>      Prepend a "<b>From</b> <i>sender time</i><b>_</b><i>stamp</i>"  envelope
-                     header  to  the  message  content.   This is
+              <b>F</b>      Prepend  a "<b>From</b> <i>sender time</i><b>_</b><i>stamp</i>" envelope
+                     header to  the  message  content.   This  is
                      expected by, for example, <b>UUCP</b> software.
 
-              <b>O</b>      Prepend an "<b>X-Original-To:</b>  <i>recipient</i>"  mes-
-                     sage  header  with  the recipient address as
-                     given to Postfix. Note: for  this  to  work,
+              <b>O</b>      Prepend  an  "<b>X-Original-To:</b> <i>recipient</i>" mes-
+                     sage header with the  recipient  address  as
+                     given  to  Postfix.  Note: for this to work,
                      the    <i>transport</i><b>_destination_recipient_limit</b>
                      must be 1.
 
                      This feature is available as of Postfix 2.0.
 
-              <b>R</b>      Prepend  a  <b>Return-Path:</b> message header with
+              <b>R</b>      Prepend a <b>Return-Path:</b> message  header  with
                      the envelope sender address.
 
               <b>h</b>      Fold the command-line <b>$recipient</b> domain name
-                     and  <b>$nexthop</b> host name to lower case.  This
+                     and <b>$nexthop</b> host name to lower case.   This
                      is recommended for delivery via <b>UUCP</b>.
 
-              <b>q</b>      Quote white space and other special  charac-
+              <b>q</b>      Quote  white space and other special charac-
                      ters in the command-line <b>$sender</b> and <b>$recip-</b>
                      <b>ient</b> address localparts (text to the left of
                      the right-most <b>@</b> character), according to an
-                     8-bit transparent version of <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a>.   This
-                     is  recommended  for  delivery  via  <b>UUCP</b> or
+                     8-bit  transparent version of <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a>.  This
+                     is recommended  for  delivery  via  <b>UUCP</b>  or
                      <b>BSMTP</b>.
 
-                     The result is compatible  with  the  address
-                     parsing  of  command-line  recipients by the
+                     The  result  is  compatible with the address
+                     parsing of command-line  recipients  by  the
                      Postfix <b>sendmail</b> mail submission command.
 
-                     The <b>q</b> flag affects  only  entire  addresses,
+                     The  <b>q</b>  flag  affects only entire addresses,
                      not the partial address information from the
-                     <b>$user</b>, <b>$extension</b> or  <b>$mailbox</b>  command-line
+                     <b>$user</b>,  <b>$extension</b>  or <b>$mailbox</b> command-line
                      macros.
 
               <b>u</b>      Fold  the  command-line  <b>$recipient</b>  address
-                     localpart (text to the left  of  the  right-
-                     most  <b>@</b>  character)  to lower case.  This is
+                     localpart  (text  to  the left of the right-
+                     most <b>@</b> character) to lower  case.   This  is
                      recommended for delivery via <b>UUCP</b>.
 
-              <b>.</b>      Prepend <b>.</b> to lines starting with  "<b>.</b>".  This
+              <b>.</b>      Prepend  <b>.</b>  to lines starting with "<b>.</b>". This
                      is needed by, for example, <b>BSMTP</b> software.
 
-              &gt;      Prepend  &gt;  to  lines starting with "<b>From</b> ".
+              &gt;      Prepend &gt; to lines starting  with  "<b>From</b>  ".
                      This is expected by, for example, <b>UUCP</b> soft-
                      ware.
 
+       <b>size</b>=<i>size</i><b>_</b><i>limit</i> (optional)
+              Messages greater in size than this limit (in bytes)
+              will be bounced back to the sender.
+
        <b>user</b>=<i>username</i> (required)
 
        <b>user</b>=<i>username</i>:<i>groupname</i>
@@ -122,16 +132,6 @@ PIPE(8)                                                   PIPE(8)
               is  specified,  the  corresponding group ID is used
               instead of the group ID of <i>username</i>.
 
-       <b>eol=string</b> (optional, default: <b>\n</b>)
-              The output record delimiter.  Typically  one  would
-              use  either <b>\r\n</b> or <b>\n</b>. The usual C-style backslash
-              escape sequences are recognized: <b>\a \b \f \n \r  \t</b>
-              <b>\v \</b><i>octal</i> and <b>\\</b>.
-
-       <b>size</b>=<i>size</i><b>_</b><i>limit</i> (optional)
-              Messages greater in size than this limit (in bytes)
-              will be bounced back to the sender.
-
        <b>argv</b>=<i>command</i>... (required)
               The command to be executed. This must be  specified
               as the last command attribute.  The command is exe-
@@ -216,6 +216,13 @@ PIPE(8)                                                   PIPE(8)
        $(<i>name</i>) are also recognized.  Specify <b>$$</b> where a single  <b>$</b>
        is wanted.
 
+       Available in Postfix 2.2 and later:
+
+       <b>directory=</b><i>pathname</i> (optional)
+              Change  to the specified directory before executing
+              the command.  Failure causes mail  delivery  to  be
+              deferred.
+
 <b>DIAGNOSTICS</b>
        Command  exit status codes are expected to follow the con-
        ventions defined in &lt;<b>sysexits.h</b>&gt;.
index ec6ac71ed8a81f810cbf222e865f44df00b8ede8..e91f7492462ff322dc8668b23cd56ee70443f9bc 100644 (file)
@@ -997,6 +997,72 @@ The location of all postfix administrative commands.
 </p>
 
 
+</DD>
+
+<DT><b><a name="command_execution_directory">command_execution_directory</a>
+(default: empty)</b></DT><DD>
+
+<p> The <a href="local.8.html">local(8)</a> delivery agent working directory for delivery to
+external command.  Failure to change directory causes the delivery
+to be deferred. </p>
+
+<p> The following $name expansions are done on <a href="postconf.5.html#command_execution_directory">command_execution_directory</a>
+before the directory is changed. Expansion happens in the context
+of the delivery request.  The result of $name expansion is filtered
+with the character set that is specified with the
+<a href="postconf.5.html#execution_directory_expansion_filter">execution_directory_expansion_filter</a> parameter.  </p>
+
+<dl>
+
+<dt><b>$user</b></dt>
+
+<dd>The recipient's username. </dd>
+
+<dt><b>$shell</b></dt>
+
+<dd>The recipient's login shell pathname. </dd>
+
+<dt><b>$home</b></dt>
+
+<dd>The recipient's home directory. </dd>
+
+<dt><b>$recipient</b></dt>
+
+<dd>The full recipient address. </dd>
+
+<dt><b>$extension</b></dt>
+
+<dd>The optional recipient address extension. </dd>
+
+<dt><b>$domain</b></dt>
+
+<dd>The recipient domain. </dd>
+
+<dt><b>$local</b></dt>
+
+<dd>The entire recipient localpart. </dd>
+
+<dt><b>$<a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a></b></dt>
+
+<dd>The system-wide recipient address extension delimiter. </dd>
+
+<dt><b>${name?value}</b></dt>
+
+<dd>Expands to <i>value</i> when <i>$name</i> is non-empty. </dd>
+
+<dt><b>${name:value}</b></dt>
+
+<dd>Expands to <i>value</i> when <i>$name</i> is empty. </dd>
+
+</dl>
+
+<p>
+Instead of $name you can also specify ${name} or $(name).
+</p>
+
+<p> This feature is available in Postfix 2.2 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="command_expansion_filter">command_expansion_filter</a>
@@ -1817,6 +1883,18 @@ This feature is available in Postfix 2.0 and later.
 </p>
 
 
+</DD>
+
+<DT><b><a name="execution_directory_expansion_filter">execution_directory_expansion_filter</a>
+(default: see "postconf -d" output)</b></DT><DD>
+
+<p> Restrict the characters that the <a href="local.8.html">local(8)</a> delivery agent allows
+in $name expansions of $<a href="postconf.5.html#command_execution_directory">command_execution_directory</a>.  Characters
+outside the allowed set are replaced by underscores.  </p>
+
+<p> This feature is available in Postfix 2.2 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="expand_owner_alias">expand_owner_alias</a>
@@ -2026,10 +2104,6 @@ $name expansions of $<a href="postconf.5.html#forward_path">forward_path</a>.  C
 allowed set are replaced by underscores.
 </p>
 
-<p>
-Characters outside the allowed set are replaced by underscores.
-</p>
-
 
 </DD>
 
@@ -2040,10 +2114,10 @@ Characters outside the allowed set are replaced by underscores.
 file with user-specified delivery methods. The first file that is
 found is used.  </p>
 
-<p>
-The following expansions are done on <a href="postconf.5.html#forward_path">forward_path</a> before
-the search actually happens:
-</p>
+<p> The following $name expansions are done on <a href="postconf.5.html#forward_path">forward_path</a> before
+the search actually happens. The result of $name expansion is
+filtered with the character set that is specified with the
+<a href="postconf.5.html#forward_expansion_filter">forward_expansion_filter</a> parameter.  </p>
 
 <dl>
 
index 024f2add13bef66b861108dd3a961a11eedf17d1..9dbf93cdbfa828285f2ba973faa6061b8e4dbfa1 100644 (file)
@@ -68,7 +68,7 @@ REGEXP_TABLE(5)                                   REGEXP_TABLE(5)
 
        Each  pattern  is a POSIX regular expression enclosed by a
        pair of delimiters. The regular expression syntax is docu-
-       mented  in  re_format(7)  with 4.4BSD, in regcomp(3C) with
+       mented  in  re_format(7)  with  4.4BSD,  in  regex(5) with
        Solaris, and in regex(7) with Linux. Other systems may use
        other document names.
 
index a6609d7b81dbbf275b5919c78250ef43759c2166..ea57c1e117a1f29bbfc6ede58115b830ff1c060d 100644 (file)
@@ -117,73 +117,76 @@ TRANSPORT(5)                                         TRANSPORT(5)
        <b>$<a href="postconf.5.html#empty_address_recipient">empty_address_recipient</a></b>@<b>$<a href="postconf.5.html#myhostname">myhostname</a></b> (default: mailer-dae-
        mon@hostname).
 
+       Note  3:  <i>user@domain</i>  or  <i>user+extension@domain</i> lookup is
+       available in Postfix 2.0 and later.
+
 <b>RESULT FORMAT</b>
-       The  lookup  result is of the form <i>transport</i><b>:</b><i>nexthop</i>.  The
-       <i>transport</i> field specifies a mail delivery  transport  such
-       as  <b>smtp</b>  or  <b>local</b>. The <i>nexthop</i> field specifies where and
+       The lookup result is of the form  <i>transport</i><b>:</b><i>nexthop</i>.   The
+       <i>transport</i>  field  specifies a mail delivery transport such
+       as <b>smtp</b> or <b>local</b>. The <i>nexthop</i> field  specifies  where  and
        how to deliver mail.
 
-       The transport field specifies the name of a mail  delivery
+       The  transport field specifies the name of a mail delivery
        transport (the first name of a mail delivery service entry
        in the Postfix <b>master.cf</b> file).
 
-       The interpretation  of  the  nexthop  field  is  transport
-       dependent.  In  the  case  of SMTP, specify a service on a
-       non-default port as <i>host</i>:<i>service</i>,  and  disable  MX  (mail
-       exchanger)  DNS lookups with [<i>host</i>] or [<i>host</i>]:<i>port</i>. The []
+       The  interpretation  of  the  nexthop  field  is transport
+       dependent. In the case of SMTP, specify  a  service  on  a
+       non-default  port  as  <i>host</i>:<i>service</i>,  and disable MX (mail
+       exchanger) DNS lookups with [<i>host</i>] or [<i>host</i>]:<i>port</i>. The  []
        form is required when you specify an IP address instead of
        a hostname.
 
-       A  null  <i>transport</i>  and  null <i>nexthop</i> result means "do not
-       change": use the delivery transport and  nexthop  informa-
-       tion  that  would  be used when the entire transport table
+       A null <i>transport</i> and null <i>nexthop</i>  result  means  "do  not
+       change":  use  the delivery transport and nexthop informa-
+       tion that would be used when the  entire  transport  table
        did not exist.
 
-       A non-null <i>transport</i>  field  with  a  null  <i>nexthop</i>  field
+       A  non-null  <i>transport</i>  field  with  a  null <i>nexthop</i> field
        resets the nexthop information to the recipient domain.
 
-       A  null  <i>transport</i>  field with non-null <i>nexthop</i> field does
+       A null <i>transport</i> field with non-null  <i>nexthop</i>  field  does
        not modify the transport information.
 
 <b>EXAMPLES</b>
-       In order to deliver internal mail directly, while using  a
-       mail  relay  for  all other mail, specify a null entry for
-       internal destinations (do not change the  delivery  trans-
-       port  or  the  nexthop information) and specify a wildcard
+       In  order to deliver internal mail directly, while using a
+       mail relay for all other mail, specify a  null  entry  for
+       internal  destinations  (do not change the delivery trans-
+       port or the nexthop information) and  specify  a  wildcard
        for all other destinations.
 
             <b>my.domain    :</b>
             <b>.my.domain   :</b>
             <b>*         <a href="smtp.8.html">smtp</a>:outbound-relay.my.domain</b>
 
-       In order to send mail for <b>example.com</b> and  its  subdomains
+       In  order  to send mail for <b>example.com</b> and its subdomains
        via the <b>uucp</b> transport to the UUCP host named <b>example</b>:
 
             <b>example.com      uucp:example</b>
             <b>.example.com     uucp:example</b>
 
-       When  no  nexthop  host name is specified, the destination
-       domain name is used instead. For  example,  the  following
-       directs  mail  for <i>user</i>@<b>example.com</b> via the <b>slow</b> transport
-       to a mail exchanger for <b>example.com</b>.  The  <b>slow</b>  transport
+       When no nexthop host name is  specified,  the  destination
+       domain  name  is  used instead. For example, the following
+       directs mail for <i>user</i>@<b>example.com</b> via the  <b>slow</b>  transport
+       to  a  mail exchanger for <b>example.com</b>.  The <b>slow</b> transport
        could be configured to run at most one delivery process at
        a time:
 
             <b>example.com      slow:</b>
 
        When no transport is specified, Postfix uses the transport
-       that  matches  the  address  domain class (see DESCRIPTION
-       above).  The following sends all mail for <b>example.com</b>  and
+       that matches the address  domain  class  (see  DESCRIPTION
+       above).   The following sends all mail for <b>example.com</b> and
        its subdomains to host <b>gateway.example.com</b>:
 
             <b>example.com      :[gateway.example.com]</b>
             <b>.example.com     :[gateway.example.com]</b>
 
-       In  the  above  example, the [] suppress MX lookups.  This
-       prevents mail routing loops when your machine  is  primary
+       In the above example, the [] suppress  MX  lookups.   This
+       prevents  mail  routing loops when your machine is primary
        MX host for <b>example.com</b>.
 
-       In  the  case  of delivery via SMTP, one may specify <i>host-</i>
+       In the case of delivery via SMTP, one  may  specify  <i>host-</i>
        <i>name</i>:<i>service</i> instead of just a host:
 
             <b>example.com      <a href="smtp.8.html">smtp</a>:bar.example:2025</b>
@@ -195,57 +198,57 @@ TRANSPORT(5)                                         TRANSPORT(5)
 
        The error mailer can be used to bounce mail:
 
-            <b>.example.com      <a href="error.8.html">error</a>:mail for *.example.com is not</b>
+            <b>.example.com     <a href="error.8.html">error</a>:mail for *.example.com is  not</b>
        <b>deliverable</b>
 
-       This causes all mail for <i>user</i>@<i>anything</i><b>.example.com</b>  to  be
+       This  causes  all mail for <i>user</i>@<i>anything</i><b>.example.com</b> to be
        bounced.
 
 <b>REGULAR EXPRESSION TABLES</b>
-       This  section  describes how the table lookups change when
+       This section describes how the table lookups  change  when
        the table is given in the form of regular expressions. For
-       a  description  of regular expression lookup table syntax,
+       a description of regular expression lookup  table  syntax,
        see <a href="regexp_table.5.html"><b>regexp_table</b>(5)</a> or <a href="pcre_table.5.html"><b>pcre_table</b>(5)</a>.
 
-       Each pattern is a regular expression that  is  applied  to
-       the    entire    address    being    looked    up.   Thus,
-       <i>some.domain.hierarchy</i> is not  looked  up  via  its  parent
-       domains,  nor is <i>user+foo@domain</i> looked up as <i>user@domain</i>.
+       Each  pattern  is  a regular expression that is applied to
+       the   entire    address    being    looked    up.    Thus,
+       <i>some.domain.hierarchy</i>  is  not  looked  up  via its parent
+       domains, nor is <i>user+foo@domain</i> looked up as  <i>user@domain</i>.
 
-       Patterns are applied in the  order  as  specified  in  the
-       table,  until  a  pattern is found that matches the search
+       Patterns  are  applied  in  the  order as specified in the
+       table, until a pattern is found that  matches  the  search
        string.
 
-       Results are the same as with indexed  file  lookups,  with
-       the  additional feature that parenthesized substrings from
+       Results  are  the  same as with indexed file lookups, with
+       the additional feature that parenthesized substrings  from
        the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on.
 
 <b>TCP-BASED TABLES</b>
-       This section describes how the table lookups  change  when
+       This  section  describes how the table lookups change when
        lookups are directed to a TCP-based server. For a descrip-
-       tion  of  the  TCP  client/server  lookup  protocol,   see
-       <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>.   This  feature  is not available in Postfix
+       tion   of  the  TCP  client/server  lookup  protocol,  see
+       <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>.  This feature is not  available  in  Postfix
        version 2.1.
 
-       Each lookup operation uses the  entire  recipient  address
-       once.   Thus,  <i>some.domain.hierarchy</i>  is not looked up via
-       its parent domains, nor is <i>user+foo@domain</i>  looked  up  as
+       Each  lookup  operation  uses the entire recipient address
+       once.  Thus, <i>some.domain.hierarchy</i> is not  looked  up  via
+       its  parent  domains,  nor is <i>user+foo@domain</i> looked up as
        <i>user@domain</i>.
 
        Results are the same as with indexed file lookups.
 
 <b>CONFIGURATION PARAMETERS</b>
-       The  following <b>main.cf</b> parameters are especially relevant.
-       The text below provides  only  a  parameter  summary.  See
+       The following <b>main.cf</b> parameters are especially  relevant.
+       The  text  below  provides  only  a parameter summary. See
        <a href="postconf.5.html">postconf(5)</a> for more details including examples.
 
        <b><a href="postconf.5.html#empty_address_recipient">empty_address_recipient</a></b>
-              The  address  that is looked up instead of the null
+              The address that is looked up instead of  the  null
               sender address.
 
        <b><a href="postconf.5.html#parent_domain_matches_subdomains">parent_domain_matches_subdomains</a></b>
-              List of Postfix features that use  <i>domain.tld</i>  pat-
-              terns   to  match  <i>sub.domain.tld</i>  (as  opposed  to
+              List  of  Postfix features that use <i>domain.tld</i> pat-
+              terns  to  match  <i>sub.domain.tld</i>  (as  opposed   to
               requiring <i>.domain.tld</i> patterns).
 
        <b><a href="postconf.5.html#transport_maps">transport_maps</a></b>
@@ -261,7 +264,7 @@ TRANSPORT(5)                                         TRANSPORT(5)
        <a href="FILTER_README.html">FILTER_README</a>, external content filter
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>AUTHOR(S)</b>
index 3c0ebc2438339891df1088a4d6a809cf1b168c38..a60c2b9b1bc4149641443dc1e1985a69e06ce468 100644 (file)
@@ -507,6 +507,40 @@ and virtual(5) aliasing.
 This feature is available in Postfix 2.0 and later.
 .SH command_directory (default: see "postconf -d" output)
 The location of all postfix administrative commands.
+.SH command_execution_directory (default: empty)
+The local(8) delivery agent working directory for delivery to
+external command.  Failure to change directory causes the delivery
+to be deferred.
+.PP
+The following $name expansions are done on command_execution_directory
+before the directory is changed. Expansion happens in the context
+of the delivery request.  The result of $name expansion is filtered
+with the character set that is specified with the
+execution_directory_expansion_filter parameter.
+.IP "\fB$user\fR"
+The recipient's username.
+.IP "\fB$shell\fR"
+The recipient's login shell pathname.
+.IP "\fB$home\fR"
+The recipient's home directory.
+.IP "\fB$recipient\fR"
+The full recipient address.
+.IP "\fB$extension\fR"
+The optional recipient address extension.
+.IP "\fB$domain\fR"
+The recipient domain.
+.IP "\fB$local\fR"
+The entire recipient localpart.
+.IP "\fB$recipient_delimiter\fR"
+The system-wide recipient address extension delimiter.
+.IP "\fB${name?value}\fR"
+Expands to \fIvalue\fR when \fI$name\fR is non-empty.
+.IP "\fB${name:value}\fR"
+Expands to \fIvalue\fR when \fI$name\fR is empty.
+.PP
+Instead of $name you can also specify ${name} or $(name).
+.PP
+This feature is available in Postfix 2.2 and later.
 .SH command_expansion_filter (default: see "postconf -d" output)
 Restrict the characters that the local(8) delivery agent allows in
 $name expansions of $mailbox_command.  Characters outside the
@@ -920,6 +954,12 @@ The name of the error(8) pseudo delivery agent. This service always
 returns mail as undeliverable.
 .PP
 This feature is available in Postfix 2.0 and later.
+.SH execution_directory_expansion_filter (default: see "postconf -d" output)
+Restrict the characters that the local(8) delivery agent allows
+in $name expansions of $command_execution_directory.  Characters
+outside the allowed set are replaced by underscores.
+.PP
+This feature is available in Postfix 2.2 and later.
 .SH expand_owner_alias (default: no)
 When delivering to an alias "aliasname" that has an "owner-aliasname"
 companion alias, set the envelope sender address to the expansion
@@ -1015,15 +1055,15 @@ Time units: s (seconds), m (minutes), h (hours), d (days), w
 Restrict the characters that the local(8) delivery agent allows in
 $name expansions of $forward_path.  Characters outside the
 allowed set are replaced by underscores.
-.PP
-Characters outside the allowed set are replaced by underscores.
 .SH forward_path (default: see "postconf -d" output)
 The local(8) delivery agent search list for finding a .forward
 file with user-specified delivery methods. The first file that is
 found is used.
 .PP
-The following expansions are done on forward_path before
-the search actually happens:
+The following $name expansions are done on forward_path before
+the search actually happens. The result of $name expansion is
+filtered with the character set that is specified with the
+forward_expansion_filter parameter.
 .IP "\fB$user\fR"
 The recipient's username.
 .IP "\fB$shell\fR"
index 4f7907d9d3219fa3d73bd64716b1aa1f9fb5b44c..cb43347e7d8425a508ab80e3ae7ace46c1337a1c 100644 (file)
@@ -62,7 +62,7 @@ starts with whitespace continues a logical line.
 .PP
 Each pattern is a POSIX regular expression enclosed by a pair of
 delimiters. The regular expression syntax is documented in
-re_format(7) with 4.4BSD, in regcomp(3C) with Solaris, and in
+re_format(7) with 4.4BSD, in regex(5) with Solaris, and in
 regex(7) with Linux. Other systems may use other document names.
 
 The expression delimiter can be any character, except whitespace
index 094a75bed7960b409e463a7b29a46efdcf2714ef..9a6ba14ddc1d3feac321e5b7e34c41f644a9c7f3 100644 (file)
@@ -104,6 +104,9 @@ functions as the wild-card pattern).
 Note 2: the null recipient address is looked up as
 \fB$empty_address_recipient\fR@\fB$myhostname\fR (default:
 mailer-daemon@hostname).
+
+Note 3: \fIuser@domain\fR or \fIuser+extension@domain\fR
+lookup is available in Postfix 2.0 and later.
 .SH "RESULT FORMAT"
 .na
 .nf
index a01ccce7061f7b00c07c65668e1c5808827f2b69..a7c20e36432515bd29925830bf16f2d1db4c0ada 100644 (file)
@@ -114,9 +114,9 @@ ending in \fB/\fR for \fBqmail\fR-compatible \fBmaildir\fR delivery.
 
 Mailbox delivery can be delegated to an external command specified
 with the \fBmailbox_command\fR configuration parameter. The command
-executes with the privileges of the recipient user (exception: in
-case of delivery as root, the command executes with the privileges
-of \fBdefault_privs\fR).
+executes with the privileges of the recipient user (exceptions:
+secondary groups are not enabled; in case of delivery as root,
+the command executes with the privileges of \fBdefault_privs\fR).
 
 Mailbox delivery can be delegated to alternative message transports
 specified in the \fBmaster.cf\fR file.
@@ -156,6 +156,25 @@ The \fBallow_mail_to_commands\fR configuration parameter restricts
 delivery to external commands. The default setting (\fBalias,
 forward\fR) forbids command destinations in \fB:include:\fR files.
 
+Optionally, the process working directory is changed to the path
+specified with \fBcommand_execution_directory\fR (Postfix 2.2 and
+later). Failure to change directory causes mail to be deferred.
+
+The \fBcommand_execution_directory\fR parameter value is subject
+to interpolation of \fB$user\fR (recipient username),
+\fB$home\fR (recipient home directory), \fB$shell\fR
+(recipient shell), \fB$recipient\fR (complete recipient
+address), \fB$extension\fR (recipient address extension),
+\fB$domain\fR (recipient domain), \fBlocal\fR (entire
+recipient address localpart) and \fB$recipient_delimiter.\fR
+The forms \fI${name?value}\fR and \fI${name:value}\fR expand
+conditionally to \fIvalue\fR when \fI$name\fR is (is not)
+defined.  Characters that may have special meaning to the
+shell or file system are replaced by underscores.  The list
+of acceptable characters is specified with the
+\fBexecution_directory_expansion_filter\fR configuration
+parameter.
+
 The command is executed directly where possible. Assistance by the
 shell (\fB/bin/sh\fR on UNIX systems) is used only when the command
 contains shell magic characters, or when the command invokes a shell
@@ -361,6 +380,11 @@ agent should use for names that are not found in the aliases(5)
 database or in the UNIX passwd database.
 .IP "\fBluser_relay (empty)\fR"
 Optional catch-all destination for unknown local(8) recipients.
+.PP
+Available in Postfix version 2.2 and later:
+.IP "\fBcommand_execution_directory (empty)\fR"
+The local(8) delivery agent working directory for delivery to
+external command.
 .SH "MAILBOX LOCKING CONTROLS"
 .na
 .nf
@@ -417,6 +441,11 @@ to external file or command.
 .IP "\fBforward_expansion_filter (see 'postconf -d' output)\fR"
 Restrict the characters that the local(8) delivery agent allows in
 $name expansions of $forward_path.
+.PP
+Available in Postfix version 2.2 and later:
+.IP "\fBexecution_directory_expansion_filter (see 'postconf -d' output)\fR"
+Restrict the characters that the local(8) delivery agent allows
+in $name expansions of $command_execution_directory.
 .SH "MISCELLANEOUS CONTROLS"
 .na
 .nf
index ebb14d046e6b3f3733937340aeec69cd822c8ce1..8dc1369df0751bda55359eb5839bdd5baa45f25f 100644 (file)
@@ -51,6 +51,11 @@ entry for the pipe-based delivery transport.
 .fi
 The external command attributes are given in the \fBmaster.cf\fR
 file at the end of a service definition.  The syntax is as follows:
+.IP "\fBeol=string\fR (optional, default: \fB\en\fR)"
+The output record delimiter. Typically one would use either
+\fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape
+sequences are recognized: \fB\ea \eb \ef \en \er \et \ev
+\e\fIoctal\fR and \fB\e\e\fR.
 .IP "\fBflags=BDFORhqu.>\fR (optional)"
 Optional message processing flags. By default, a message is
 copied unchanged.
@@ -106,6 +111,9 @@ by, for example, \fBBSMTP\fR software.
 Prepend \fB>\fR to lines starting with "\fBFrom \fR". This is expected
 by, for example, \fBUUCP\fR software.
 .RE
+.IP "\fBsize\fR=\fIsize_limit\fR (optional)"
+Messages greater in size than this limit (in bytes) will be bounced
+back to the sender.
 .IP "\fBuser\fR=\fIusername\fR (required)"
 .IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR"
 The external command is executed with the rights of the
@@ -114,14 +122,6 @@ commands with root privileges, or with the privileges of the
 mail system owner. If \fIgroupname\fR is specified, the
 corresponding group ID is used instead of the group ID of
 \fIusername\fR.
-.IP "\fBeol=string\fR (optional, default: \fB\en\fR)"
-The output record delimiter. Typically one would use either
-\fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape
-sequences are recognized: \fB\ea \eb \ef \en \er \et \ev
-\e\fIoctal\fR and \fB\e\e\fR.
-.IP "\fBsize\fR=\fIsize_limit\fR (optional)"
-Messages greater in size than this limit (in bytes) will be bounced
-back to the sender.
 .IP "\fBargv\fR=\fIcommand\fR... (required)"
 The command to be executed. This must be specified as the
 last command attribute.
@@ -183,6 +183,11 @@ This information is modified by the \fBu\fR flag for case folding.
 In addition to the form ${\fIname\fR}, the forms $\fIname\fR and
 $(\fIname\fR) are also recognized.  Specify \fB$$\fR where a single
 \fB$\fR is wanted.
+.PP
+Available in Postfix 2.2 and later:
+.IP "\fBdirectory=\fIpathname\fR (optional)"
+Change to the specified directory before executing the command.
+Failure causes mail delivery to be deferred.
 .SH DIAGNOSTICS
 .ad
 .fi
index 785c0e2b8e103753b88b97b4bb3eeeb17a70ebd5..bcbb1f05bbb45d98fe5809a2408ac9e375cb466c 100755 (executable)
@@ -106,6 +106,8 @@ while (<>) {
     s;\bbroken_sasl_auth_clients\b;<a href="postconf.5.html#broken_sasl_auth_clients">$&</a>;g;
     s;\bcanonical_maps\b;<a href="postconf.5.html#canonical_maps">$&</a>;g;
     s;\bcleanup_service_name\b;<a href="postconf.5.html#cleanup_service_name">$&</a>;g;
+    s;\bcommand_execu[-</bB>]*\n* *[<bB>]*tion_direc[-</bB>]*\n* *[<bB>]*tory\b;<a href="postconf.5.html#command_execution_directory">$&</a>;g;
+    s;\bexecu[-</bB>]*\n* *[<bB>]*tion_directory_expansion_filter\b;<a href="postconf.5.html#execution_directory_expansion_filter">$&</a>;g;
     s;\banvil_status_update_time\b;<a href="postconf.5.html#anvil_status_update_time">$&</a>;g;
     s;\bcommand_directory\b;<a href="postconf.5.html#command_directory">$&</a>;g;
     s;\bcommand_expan[-</bB>]*\n* *[<bB>]*sion_filter\b;<a href="postconf.5.html#command_expansion_filter">$&</a>;g;
index 77fd202bf88c166017d1a4cd73bf61d196832dff..05361073422d6914bc1439aaf686b8849922a123 100755 (executable)
@@ -36,6 +36,7 @@ config_directory
 daemon_directory
 default_database_type
 default_rbl_reply
+execution_directory_expansion_filter
 export_environment
 forward_expansion_filter
 forward_path
index 15f7dadfb076e232501cbc4baa2a57e8478ff6dc..069bf60e1b0e501c31ca4f9ef70b703a8c51263f 100644 (file)
@@ -229,8 +229,10 @@ and is very easy to stop.
 reality, my patterns list multiple email addresses as
 "<tt>(user1@domain1\.tld|user2@domain2\.tld)</tt>".  </p>
 
-<li> <p> The <tt>[[:&lt;:]]</tt> matches the beginning of a word,
-and the <tt>[[:&gt;:]]</tt> matches the end. </p>
+<li> <p> The "<tt>[[:&lt;:]]</tt>" and "<tt>[[:&gt;:]]</tt>" match
+the beginning and end of a word, respectively. On some systems you
+should specify "<tt>\&lt;</tt>" and "<tt>\&gt;</tt>" instead. For
+details see your system documentation.
 
 <li> <p> The "<tt>\.</tt>" matches "<tt>.</tt>" literally. Without
 the "<tt>\</tt>", the "<tt>.</tt>" would match any character. </p>
@@ -261,7 +263,8 @@ above techniques to recognize forgeries.  </p>
 because there is a lot of variation in report formats.  The following
 is only a small example of message header patterns.  For a large
 collection of header and body patterns that recognize virus
-notification email, see http://www.dkuug.dk/keld/virus/.  </p>
+notification email, see http://www.dkuug.dk/keld/virus/
+or http://www.t29.dk/antiantivirus.txt.  </p>
 
 <blockquote>
 <pre>
index da821a27bc6d1fae080495629455c985dd4f82c4..40fb4bf569c8f0be676184079a8ad50decea2f52 100644 (file)
@@ -952,9 +952,23 @@ systems. </p>
 so that it listens on a socket inside the Postfix queue directory.
 Examples for specific systems: </p>
 
-<p> FreeBSD: <tt>syslogd -l /var/spool/postfix/var/run/log</tt> </p>
+<dl>
 
-<p> Linux, OpenBSD: <tt>syslogd -a /var/spool/postfix/dev/log</tt> </p>
+<dt> FreeBSD: </dt>
+
+<dd> <pre>
+# mkdir -p /var/spool/postfix/var/run
+# syslogd -l /var/spool/postfix/var/run/log
+</pre> </dd>
+
+<dt> Linux, OpenBSD: </dt>
+
+<dd> <pre>
+# mkdir -p /var/spool/postfix/dev
+# syslogd -a /var/spool/postfix/dev/log
+</pre> </dd>
+
+</dl>
 
 <h2><a name="care">12 - Care and feeding of the Postfix system</a></h2>
 
index fa132d941ca2b036076a00ecc8b2667b0968b6ef..80dfd2a39e4179f309d31f377828c3600eee8c95 100644 (file)
@@ -1189,16 +1189,86 @@ d=days, w=weeks.  The default time unit is hours.
 <p> Time units: s (seconds), m (minutes), h (hours), d (days), w
 (weeks).  The default time unit is s (seconds).  </p>
 
+%PARAM execution_directory_expansion_filter see "postconf -d" output
+
+<p> Restrict the characters that the local(8) delivery agent allows
+in $name expansions of $command_execution_directory.  Characters
+outside the allowed set are replaced by underscores.  </p>
+
+<p> This feature is available in Postfix 2.2 and later. </p>
+
+%PARAM command_execution_directory
+
+<p> The local(8) delivery agent working directory for delivery to
+external command.  Failure to change directory causes the delivery
+to be deferred. </p>
+
+<p> The following $name expansions are done on command_execution_directory
+before the directory is changed. Expansion happens in the context
+of the delivery request.  The result of $name expansion is filtered
+with the character set that is specified with the
+execution_directory_expansion_filter parameter.  </p>
+
+<dl>
+
+<dt><b>$user</b></dt>
+
+<dd>The recipient's username. </dd>
+
+<dt><b>$shell</b></dt>
+
+<dd>The recipient's login shell pathname. </dd>
+
+<dt><b>$home</b></dt>
+
+<dd>The recipient's home directory. </dd>
+
+<dt><b>$recipient</b></dt>
+
+<dd>The full recipient address. </dd>
+
+<dt><b>$extension</b></dt>
+
+<dd>The optional recipient address extension. </dd>
+
+<dt><b>$domain</b></dt>
+
+<dd>The recipient domain. </dd>
+
+<dt><b>$local</b></dt>
+
+<dd>The entire recipient localpart. </dd>
+
+<dt><b>$recipient_delimiter</b></dt>
+
+<dd>The system-wide recipient address extension delimiter. </dd>
+
+<dt><b>${name?value}</b></dt>
+
+<dd>Expands to <i>value</i> when <i>$name</i> is non-empty. </dd>
+
+<dt><b>${name:value}</b></dt>
+
+<dd>Expands to <i>value</i> when <i>$name</i> is empty. </dd>
+
+</dl>
+
+<p>
+Instead of $name you can also specify ${name} or $(name).
+</p>
+
+<p> This feature is available in Postfix 2.2 and later. </p>
+
 %PARAM forward_path see "postconf -d" output
 
 <p> The local(8) delivery agent search list for finding a .forward
 file with user-specified delivery methods. The first file that is
 found is used.  </p>
 
-<p>
-The following expansions are done on forward_path before
-the search actually happens:
-</p>
+<p> The following $name expansions are done on forward_path before
+the search actually happens. The result of $name expansion is
+filtered with the character set that is specified with the
+forward_expansion_filter parameter.  </p>
 
 <dl>
 
@@ -5648,10 +5718,6 @@ $name expansions of $forward_path.  Characters outside the
 allowed set are replaced by underscores.
 </p>
 
-<p>
-Characters outside the allowed set are replaced by underscores.
-</p>
-
 %PARAM header_address_token_limit 10240
 
 <p>
index 92c8d782035d3ff93012751f0539e6198d4d78ae..3dcd43b2605104e32fe23664afdc1367f86b0ffe 100644 (file)
@@ -54,7 +54,7 @@
 # .PP
 #      Each pattern is a POSIX regular expression enclosed by a pair of
 #      delimiters. The regular expression syntax is documented in
-#      re_format(7) with 4.4BSD, in regcomp(3C) with Solaris, and in
+#      re_format(7) with 4.4BSD, in regex(5) with Solaris, and in
 #      regex(7) with Linux. Other systems may use other document names.
 #
 #      The expression delimiter can be any character, except whitespace
index 23c95642162b104d72d5bee105d53b3a3d005e71..c16d0a878aa9ff09ee41b202b7ecb214067b1ede 100644 (file)
@@ -94,6 +94,9 @@
 #      Note 2: the null recipient address is looked up as
 #      \fB$empty_address_recipient\fR@\fB$myhostname\fR (default:
 #      mailer-daemon@hostname).
+#
+#      Note 3: \fIuser@domain\fR or \fIuser+extension@domain\fR
+#      lookup is available in Postfix 2.0 and later.
 # RESULT FORMAT
 # .ad
 # .fi
index afcfac163c0e7d31f0248eb54f4606439094eb69..b3f91f51d1d3430c3ed3161630738461db47f48a 100644 (file)
@@ -448,6 +448,19 @@ extern char *var_fallback_transport;
 #define DEF_FORWARD_PATH       "$home/.forward${recipient_delimiter}${extension}, $home/.forward"
 extern char *var_forward_path;
 
+ /*
+  * Local delivery: external command execution directory.
+  */
+#define VAR_EXEC_DIRECTORY     "command_execution_directory"
+#define DEF_EXEC_DIRECTORY     ""
+extern char *var_exec_directory;
+
+#define VAR_EXEC_EXP_FILTER    "execution_directory_expansion_filter"
+#define DEF_EXEC_EXP_FILTER    "1234567890!@%-_=+:,./\
+abcdefghijklmnopqrstuvwxyz\
+ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+extern char *var_exec_exp_filter;
+
  /*
   * Mailbox locking. DEF_MAILBOX_LOCK is defined in sys_defs.h.
   */
index 891c2fca5f0e438c83fc0fa32af79bc27e75a8bd..23b74218431f433e1bee106ec5bc53a12d5d0b2f 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change the patchlevel and the release date. Snapshots change the
   * release date only.
   */
-#define MAIL_RELEASE_DATE      "20040616"
+#define MAIL_RELEASE_DATE      "20040621"
 #define MAIL_VERSION_NUMBER    "2.2"
 
 #define VAR_MAIL_VERSION       "mail_version"
index 7cbd9795c041b4112aa6e850cf28ca1f11877e78..e091b6e77af552de1fce802c9680acb95b201785 100644 (file)
 /*     The command is specified as an argument vector. This vector is
 /*     passed without further inspection to the \fIexecvp\fR() routine.
 /*     One of PIPE_CMD_COMMAND or PIPE_CMD_ARGV must be specified.
+/* .IP "PIPE_CMD_CWD (char *)"
+/*     Working directory for command execution. A null pointer means
+/*     don't change directory anyway. Failure to change directory
+/*     causes mail delivery to be deferred.
 /* .IP "PIPE_CMD_ENV (char **)"
 /*     Additional environment information, in the form of a null-terminated
 /*     list of name, value, name, value, ... elements. By default only the
@@ -159,6 +163,7 @@ struct pipe_args {
     char  **env;                       /* extra environment */
     char  **export;                    /* exportable environment */
     char   *shell;                     /* command shell */
+    char   *cwd;                       /* preferred working directory */
 };
 
 static int pipe_command_timeout;       /* command has timed out */
@@ -186,6 +191,7 @@ static void get_pipe_args(struct pipe_args * args, va_list ap)
     args->env = 0;
     args->export = 0;
     args->shell = 0;
+    args->cwd = 0;
 
     pipe_command_maxtime = var_command_maxtime;
 
@@ -237,6 +243,9 @@ static void get_pipe_args(struct pipe_args * args, va_list ap)
        case PIPE_CMD_SHELL:
            args->shell = va_arg(ap, char *);
            break;
+       case PIPE_CMD_CWD:
+           args->cwd = va_arg(ap, char *);
+           break;
        default:
            msg_panic("%s: unknown key: %d", myname, key);
        }
@@ -428,6 +437,16 @@ int     pipe_command(VSTREAM *src, VSTRING *why,...)
        close(cmd_in_pipe[0]);
        close(cmd_out_pipe[1]);
 
+       /*
+        * Working directory plumbing.
+        */
+       if (args.cwd && chdir(args.cwd) < 0) {
+           msg_warn("cannot change directory to \"%s\" for uid=%lu gid=%lu: %m",
+                    args.cwd, (unsigned long) args.uid,
+                    (unsigned long) args.gid);
+           exit(EX_TEMPFAIL);
+       }
+
        /*
         * Environment plumbing. Always reset the command search path. XXX
         * That should probably be done by clean_env().
index 9a36832cb8843119ea78d925fe1d8235c54d1e77..a500e8440da5f88ddb5d29f75804b091dd585344 100644 (file)
@@ -39,6 +39,7 @@
 #define PIPE_CMD_EOL           11      /* record delimiter */
 #define PIPE_CMD_EXPORT                12      /* exportable environment */
 #define PIPE_CMD_ORIG_RCPT     13      /* mail_copy() original recipient */
+#define PIPE_CMD_CWD           14      /* working directory */
 
  /*
   * Command completion status.
index 50f8f9d85bb8f9af5cb63ec0e6163e117c95731f..6bb68db8b02993513349aece4052e45103c0c408 100644 (file)
@@ -62,6 +62,7 @@
 #include <vstring.h>
 #include <vstream.h>
 #include <argv.h>
+#include <mac_parse.h>
 
 /* Global library. */
 
@@ -90,6 +91,8 @@ int     deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, const char *comma
     char  **cpp;
     char   *cp;
     ARGV   *export_env;
+    VSTRING *exec_dir;
+    int     expand_status;
 
     /*
      * Make verbose logging easier to understand.
@@ -168,22 +171,38 @@ int     deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, const char *comma
        for (cp = cpp[1]; *(cp += strspn(cp, var_cmd_exp_filter)) != 0;)
            *cp++ = '_';
 
+    /*
+     * Evaluate the command execution directory. Defer delivery if expansion
+     * fails.
+     */
     export_env = argv_split(var_export_environ, ", \t\r\n");
-
-    cmd_status = pipe_command(state.msg_attr.fp, why,
-                             PIPE_CMD_UID, usr_attr.uid,
-                             PIPE_CMD_GID, usr_attr.gid,
-                             PIPE_CMD_COMMAND, command,
-                             PIPE_CMD_COPY_FLAGS, copy_flags,
-                             PIPE_CMD_SENDER, state.msg_attr.sender,
-                             PIPE_CMD_ORIG_RCPT, state.msg_attr.orig_rcpt,
-                             PIPE_CMD_DELIVERED, state.msg_attr.delivered,
-                             PIPE_CMD_TIME_LIMIT, var_command_maxtime,
-                             PIPE_CMD_ENV, env->argv,
-                             PIPE_CMD_EXPORT, export_env->argv,
-                             PIPE_CMD_SHELL, var_local_cmd_shell,
-                             PIPE_CMD_END);
-
+    exec_dir = vstring_alloc(10);
+    expand_status = local_expand(exec_dir, var_exec_directory,
+                                &state, &usr_attr, var_exec_exp_filter);
+
+    if (expand_status & MAC_PARSE_ERROR) {
+       cmd_status = PIPE_STAT_DEFER;
+       vstring_strcpy(why, "Server configuration error");
+       msg_warn("bad parameter value syntax for %s: %s",
+                VAR_EXEC_DIRECTORY, var_exec_directory);
+    } else {
+       cmd_status = pipe_command(state.msg_attr.fp, why,
+                                 PIPE_CMD_UID, usr_attr.uid,
+                                 PIPE_CMD_GID, usr_attr.gid,
+                                 PIPE_CMD_COMMAND, command,
+                                 PIPE_CMD_COPY_FLAGS, copy_flags,
+                                 PIPE_CMD_SENDER, state.msg_attr.sender,
+                              PIPE_CMD_ORIG_RCPT, state.msg_attr.orig_rcpt,
+                              PIPE_CMD_DELIVERED, state.msg_attr.delivered,
+                                 PIPE_CMD_TIME_LIMIT, var_command_maxtime,
+                                 PIPE_CMD_ENV, env->argv,
+                                 PIPE_CMD_EXPORT, export_env->argv,
+                                 PIPE_CMD_SHELL, var_local_cmd_shell,
+                                 PIPE_CMD_CWD, *vstring_str(exec_dir) ?
+                                 vstring_str(exec_dir) : (char *) 0,
+                                 PIPE_CMD_END);
+    }
+    vstring_free(exec_dir);
     argv_free(export_env);
     argv_free(env);
 
index 69eb905a8ac7cd942cc1ce8b5ce8603d6fc83b47..4fb88a99d2227552eb5dd8e903a8369b1768bc50 100644 (file)
 /*
 /*     Mailbox delivery can be delegated to an external command specified
 /*     with the \fBmailbox_command\fR configuration parameter. The command
-/*     executes with the privileges of the recipient user (exception: in
-/*     case of delivery as root, the command executes with the privileges
-/*     of \fBdefault_privs\fR).
+/*     executes with the privileges of the recipient user (exceptions: 
+/*     secondary groups are not enabled; in case of delivery as root, 
+/*     the command executes with the privileges of \fBdefault_privs\fR).
 /*
 /*     Mailbox delivery can be delegated to alternative message transports
 /*     specified in the \fBmaster.cf\fR file.
 /*     delivery to external commands. The default setting (\fBalias,
 /*     forward\fR) forbids command destinations in \fB:include:\fR files.
 /*
+/*     Optionally, the process working directory is changed to the path
+/*     specified with \fBcommand_execution_directory\fR (Postfix 2.2 and
+/*     later). Failure to change directory causes mail to be deferred.
+/*
+/*     The \fBcommand_execution_directory\fR parameter value is subject
+/*     to interpolation of \fB$user\fR (recipient username),
+/*     \fB$home\fR (recipient home directory), \fB$shell\fR
+/*     (recipient shell), \fB$recipient\fR (complete recipient
+/*     address), \fB$extension\fR (recipient address extension),
+/*     \fB$domain\fR (recipient domain), \fBlocal\fR (entire
+/*     recipient address localpart) and \fB$recipient_delimiter.\fR
+/*     The forms \fI${name?value}\fR and \fI${name:value}\fR expand
+/*     conditionally to \fIvalue\fR when \fI$name\fR is (is not)
+/*     defined.  Characters that may have special meaning to the
+/*     shell or file system are replaced by underscores.  The list
+/*     of acceptable characters is specified with the
+/*     \fBexecution_directory_expansion_filter\fR configuration
+/*     parameter.
+/*
 /*     The command is executed directly where possible. Assistance by the
 /*     shell (\fB/bin/sh\fR on UNIX systems) is used only when the command
 /*     contains shell magic characters, or when the command invokes a shell
 /*     database or in the UNIX passwd database.
 /* .IP "\fBluser_relay (empty)\fR"
 /*     Optional catch-all destination for unknown local(8) recipients.
+/* .PP
+/*     Available in Postfix version 2.2 and later:
+/* .IP "\fBcommand_execution_directory (empty)\fR"
+/*     The local(8) delivery agent working directory for delivery to
+/*     external command.
 /* MAILBOX LOCKING CONTROLS
 /* .ad
 /* .fi
 /* .IP "\fBforward_expansion_filter (see 'postconf -d' output)\fR"
 /*     Restrict the characters that the local(8) delivery agent allows in
 /*     $name expansions of $forward_path.
+/* .PP
+/*     Available in Postfix version 2.2 and later:
+/* .IP "\fBexecution_directory_expansion_filter (see 'postconf -d' output)\fR"
+/*     Restrict the characters that the local(8) delivery agent allows
+/*     in $name expansions of $command_execution_directory.
 /* MISCELLANEOUS CONTROLS
 /* .ad
 /* .fi
@@ -519,6 +548,8 @@ int     var_biff;
 char   *var_mail_spool_dir;
 char   *var_mailbox_transport;
 char   *var_fallback_transport;
+char   *var_exec_directory;
+char   *var_exec_exp_filter;
 char   *var_forward_path;
 char   *var_cmd_exp_filter;
 char   *var_fwd_exp_filter;
@@ -755,6 +786,7 @@ int     main(int argc, char **argv)
        VAR_FALLBACK_TRANSP, DEF_FALLBACK_TRANSP, &var_fallback_transport, 0, 0,
        VAR_CMD_EXP_FILTER, DEF_CMD_EXP_FILTER, &var_cmd_exp_filter, 1, 0,
        VAR_FWD_EXP_FILTER, DEF_FWD_EXP_FILTER, &var_fwd_exp_filter, 1, 0,
+       VAR_EXEC_EXP_FILTER, DEF_EXEC_EXP_FILTER, &var_exec_exp_filter, 1, 0,
        VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0,
        VAR_DELIVER_HDR, DEF_DELIVER_HDR, &var_deliver_hdr, 0, 0,
        VAR_MAILBOX_LOCK, DEF_MAILBOX_LOCK, &var_mailbox_lock, 1, 0,
@@ -770,6 +802,7 @@ int     main(int argc, char **argv)
 
     /* Suppress $name expansion upon loading. */
     static CONFIG_RAW_TABLE raw_table[] = {
+       VAR_EXEC_DIRECTORY, DEF_EXEC_DIRECTORY, &var_exec_directory, 0, 0,
        VAR_FORWARD_PATH, DEF_FORWARD_PATH, &var_forward_path, 0, 0,
        VAR_MAILBOX_COMMAND, DEF_MAILBOX_COMMAND, &var_mailbox_command, 0, 0,
        VAR_MAILBOX_CMD_MAPS, DEF_MAILBOX_CMD_MAPS, &var_mailbox_cmd_maps, 0, 0,
index 20491d377c65c9b839c7eddc9d2e67540f590a7c..dcb52da65168477cfad6c84f81d1f1a5cccfc05c 100644 (file)
 /* .fi
 /*     The external command attributes are given in the \fBmaster.cf\fR
 /*     file at the end of a service definition.  The syntax is as follows:
+/* .IP "\fBeol=string\fR (optional, default: \fB\en\fR)"
+/*     The output record delimiter. Typically one would use either
+/*     \fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape
+/*     sequences are recognized: \fB\ea \eb \ef \en \er \et \ev
+/*     \e\fIoctal\fR and \fB\e\e\fR.
 /* .IP "\fBflags=BDFORhqu.>\fR (optional)"
 /*     Optional message processing flags. By default, a message is
 /*     copied unchanged.
 /*     Prepend \fB>\fR to lines starting with "\fBFrom \fR". This is expected
 /*     by, for example, \fBUUCP\fR software.
 /* .RE
+/* .IP "\fBsize\fR=\fIsize_limit\fR (optional)"
+/*     Messages greater in size than this limit (in bytes) will be bounced
+/*     back to the sender.
 /* .IP "\fBuser\fR=\fIusername\fR (required)"
 /* .IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR"
 /*     The external command is executed with the rights of the
 /*     mail system owner. If \fIgroupname\fR is specified, the
 /*     corresponding group ID is used instead of the group ID of
 /*     \fIusername\fR.
-/* .IP "\fBeol=string\fR (optional, default: \fB\en\fR)"
-/*     The output record delimiter. Typically one would use either
-/*     \fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape
-/*     sequences are recognized: \fB\ea \eb \ef \en \er \et \ev
-/*     \e\fIoctal\fR and \fB\e\e\fR.
-/* .IP "\fBsize\fR=\fIsize_limit\fR (optional)"
-/*     Messages greater in size than this limit (in bytes) will be bounced
-/*     back to the sender.
 /* .IP "\fBargv\fR=\fIcommand\fR... (required)"
 /*     The command to be executed. This must be specified as the
 /*     last command attribute.
 /*     In addition to the form ${\fIname\fR}, the forms $\fIname\fR and
 /*     $(\fIname\fR) are also recognized.  Specify \fB$$\fR where a single
 /*     \fB$\fR is wanted.
+/* .PP
+/*     Available in Postfix 2.2 and later:
+/* .IP "\fBdirectory=\fIpathname\fR (optional)"
+/*     Change to the specified directory before executing the command.
+/*     Failure causes mail delivery to be deferred.
 /* DIAGNOSTICS
 /*     Command exit status codes are expected to
 /*     follow the conventions defined in <\fBsysexits.h\fR>.
@@ -382,6 +387,7 @@ typedef struct {
     uid_t   uid;                       /* command privileges */
     gid_t   gid;                       /* command privileges */
     int     flags;                     /* mail_copy() flags */
+    char   *exec_dir;                  /* working directory */
     VSTRING *eol;                      /* output record delimiter */
     off_t   size_limit;                        /* max size in bytes we will accept */
 } PIPE_ATTR;
@@ -626,6 +632,7 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
     group = 0;
     attr->command = 0;
     attr->flags = 0;
+    attr->exec_dir = 0;
     attr->eol = vstring_strcpy(vstring_alloc(1), "\n");
     attr->size_limit = 0;
 
@@ -697,6 +704,13 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
            }
        }
 
+       /*
+        * directory=string
+        */
+       else if (strncasecmp("directory=", *argv, sizeof("directory=") - 1) == 0) {
+           attr->exec_dir = mystrdup(*argv + sizeof("directory=") - 1);
+       }
+
        /*
         * eol=string
         */
@@ -977,6 +991,7 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
                                  PIPE_CMD_TIME_LIMIT, conf.time_limit,
                                  PIPE_CMD_EOL, STR(attr.eol),
                                  PIPE_CMD_EXPORT, export_env->argv,
+                                 PIPE_CMD_CWD, attr.exec_dir,
                           PIPE_CMD_ORIG_RCPT, rcpt_list->info[0].orig_addr,
                             PIPE_CMD_DELIVERED, rcpt_list->info[0].address,
                                  PIPE_CMD_END);
index 72be1d83338f615ff459748f7e80b20e598a0316..dbcb0c1d2f00feb49d8dbbdc51f58df04504ef3f 100644 (file)
@@ -382,7 +382,6 @@ static int deliver_message(DELIVER_REQUEST *request)
     /*
      * Clean up.
      */
-    smtp_chat_reset(state);
     smtp_state_free(state);
 
     return (result);
index 8133098031b4299177ef00fc31213c5a905dfcbd..c965c25e7d288e0908fa75da5b95c3d4777ffd47 100644 (file)
@@ -36,25 +36,8 @@ typedef struct SMTP_STATE {
     VSTREAM *src;                      /* queue file stream */
     DELIVER_REQUEST *request;          /* envelope info, offsets */
     struct SMTP_SESSION *session;      /* network connection */
-    VSTRING *buffer;                   /* I/O buffer */
-    VSTRING *scratch;                  /* scratch buffer */
-    VSTRING *scratch2;                 /* scratch buffer */
     int     status;                    /* delivery status */
-    int     features;                  /* server features */
-    ARGV   *history;                   /* transaction log */
-    int     error_mask;                        /* error classes */
-#ifdef USE_SASL_AUTH
-    char   *sasl_mechanism_list;       /* server mechanism list */
-    char   *sasl_username;             /* client username */
-    char   *sasl_passwd;               /* client password */
-    sasl_conn_t *sasl_conn;            /* SASL internal state */
-    VSTRING *sasl_encoded;             /* encoding buffer */
-    VSTRING *sasl_decoded;             /* decoding buffer */
-    sasl_callback_t *sasl_callbacks;   /* stateful callbacks */
-#endif
-    off_t   size_limit;                        /* server limit or unknown */
     int     space_left;                        /* output length control */
-    struct MIME_STATE *mime_state;     /* mime state machine */
 
     /*
      * Flags and counters to control the handling of mail delivery errors.
@@ -81,6 +64,7 @@ typedef struct SMTP_STATE {
 #define SMTP_FEATURE_XFORWARD_ADDR     (1<<8)
 #define SMTP_FEATURE_XFORWARD_PROTO    (1<<9)
 #define SMTP_FEATURE_XFORWARD_HELO     (1<<10)
+#define SMTP_FEATURE_CACHE_SESSION     (1<<11)
 
  /*
   * Misc flags.
@@ -109,13 +93,37 @@ extern int smtp_host_lookup_mask;  /* host lookup methods to use */
   */
 typedef struct SMTP_SESSION {
     VSTREAM *stream;                   /* network connection */
+    char   *dest;                      /* nexthop[:port] or fallback relay */
     char   *host;                      /* mail exchanger */
     char   *addr;                      /* mail exchanger */
     char   *namaddr;                   /* mail exchanger */
     int     best;                      /* most preferred host */
+
+    VSTRING *buffer;                   /* I/O buffer */
+    VSTRING *scratch;                  /* scratch buffer */
+    VSTRING *scratch2;                 /* scratch buffer */
+
+    int     features;                  /* server features */
+    off_t   size_limit;                        /* server limit or unknown */
+
+    ARGV   *history;                   /* transaction log */
+    int     error_mask;                        /* error classes */
+    struct MIME_STATE *mime_state;     /* mime state machine */
+
+#ifdef USE_SASL_AUTH
+    char   *sasl_mechanism_list;       /* server mechanism list */
+    char   *sasl_username;             /* client username */
+    char   *sasl_passwd;               /* client password */
+    sasl_conn_t *sasl_conn;            /* SASL internal state */
+    VSTRING *sasl_encoded;             /* encoding buffer */
+    VSTRING *sasl_decoded;             /* decoding buffer */
+    sasl_callback_t *sasl_callbacks;   /* stateful callbacks */
+#endif
+
 } SMTP_SESSION;
 
-extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, char *, char *);
+extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, char *, char *, char *);
+extern void smtp_session_reuse(SMTP_SESSION *);
 extern void smtp_session_free(SMTP_SESSION *);
 
  /*
@@ -128,7 +136,6 @@ extern int smtp_connect(SMTP_STATE *);
   */
 extern int smtp_helo(SMTP_STATE *, int);
 extern int smtp_xfer(SMTP_STATE *);
-extern void smtp_quit(SMTP_STATE *);
 
  /*
   * smtp_chat.c
@@ -139,10 +146,11 @@ typedef struct SMTP_RESP {                /* server response */
     VSTRING *buf;                      /* origin of text */
 } SMTP_RESP;
 
-extern void PRINTFLIKE(2, 3) smtp_chat_cmd(SMTP_STATE *, char *,...);
-extern SMTP_RESP *smtp_chat_resp(SMTP_STATE *);
-extern void smtp_chat_reset(SMTP_STATE *);
-extern void smtp_chat_notify(SMTP_STATE *);
+extern void PRINTFLIKE(2, 3) smtp_chat_cmd(SMTP_SESSION *, char *,...);
+extern SMTP_RESP *smtp_chat_resp(SMTP_SESSION *);
+extern void smtp_chat_init(SMTP_SESSION *);
+extern void smtp_chat_reset(SMTP_SESSION *);
+extern void smtp_chat_notify(SMTP_SESSION *);
 
  /*
   * These operations implement a redundant mark-and-sweep algorithm that
index e3d0367655efabab9f3750cd4e007030867fac95..06a21273c606cfe04950199e4832f8f242e1e81e 100644 (file)
 /* .in -4
 /*     } SMTP_RESP;
 /*
-/*     void    smtp_chat_cmd(state, format, ...)
-/*     SMTP_STATE *state;
+/*     void    smtp_chat_cmd(session, format, ...)
+/*     SMTP_SESSION *session;
 /*     char    *format;
 /*
-/*     SMTP_RESP *smtp_chat_resp(state)
-/*     SMTP_STATE *state;
+/*     SMTP_RESP *smtp_chat_resp(session)
+/*     SMTP_SESSION *session;
 /*
-/*     void    smtp_chat_notify(state)
-/*     SMTP_STATE *state;
+/*     void    smtp_chat_notify(session)
+/*     SMTP_SESSION *session;
 /*
-/*     void    smtp_chat_reset(state)
-/*     SMTP_STATE *state;
+/*     void    smtp_chat_init(session)
+/*     SMTP_SESSION *session;
+/*
+/*     void    smtp_chat_reset(session)
+/*     SMTP_SESSION *session;
 /* DESCRIPTION
 /*     This module implements SMTP client support for request/reply
 /*     conversations, and maintains a limited SMTP transaction log.
@@ -43,6 +46,9 @@
 /*     when delivery is possible immediately. It is an error to call
 /*     smtp_chat_notify() when no SMTP transaction log exists.
 /*
+/*     smtp_chat_init() initializes the per-session transaction log.
+/*     This must be done at the beginning of a new SMTP session.
+/*
 /*     smtp_chat_reset() resets the transaction log. This is
 /*     typically done at the beginning or end of an SMTP session,
 /*     or within a session to discard non-error information.
 #define STR(x) ((char *) vstring_str(x))
 #define LEN    VSTRING_LEN
 
+/* smtp_chat_init - initialize SMTP transaction log */
+
+void    smtp_chat_init(SMTP_SESSION *session)
+{
+    session->history = 0;
+}
+
 /* smtp_chat_reset - reset SMTP transaction log */
 
-void    smtp_chat_reset(SMTP_STATE *state)
+void    smtp_chat_reset(SMTP_SESSION *session)
 {
-    if (state->history) {
-       argv_free(state->history);
-       state->history = 0;
+
+    if (session->history) {
+       argv_free(session->history);
+       session->history = 0;
     }
 }
 
 /* smtp_chat_append - append record to SMTP transaction log */
 
-static void smtp_chat_append(SMTP_STATE *state, char *direction, char *data)
+static void smtp_chat_append(SMTP_SESSION *session, char *direction, char *data)
 {
     char   *line;
 
-    if (state->history == 0)
-       state->history = argv_alloc(10);
+    if (session->history == 0)
+       session->history = argv_alloc(10);
     line = concatenate(direction, data, (char *) 0);
-    argv_add(state->history, line, (char *) 0);
+    argv_add(session->history, line, (char *) 0);
     myfree(line);
 }
 
 /* smtp_chat_cmd - send an SMTP command */
 
-void    smtp_chat_cmd(SMTP_STATE *state, char *fmt,...)
+void    smtp_chat_cmd(SMTP_SESSION *session, char *fmt,...)
 {
-    SMTP_SESSION *session = state->session;
     va_list ap;
 
     /*
      * Format the command, and update the transaction log.
      */
     va_start(ap, fmt);
-    vstring_vsprintf(state->buffer, fmt, ap);
+    vstring_vsprintf(session->buffer, fmt, ap);
     va_end(ap);
-    smtp_chat_append(state, "Out: ", STR(state->buffer));
+    smtp_chat_append(session, "Out: ", STR(session->buffer));
 
     /*
      * Optionally log the command first, so we can see in the log what the
      * program is trying to do.
      */
     if (msg_verbose)
-       msg_info("> %s: %s", session->namaddr, STR(state->buffer));
+       msg_info("> %s: %s", session->namaddr, STR(session->buffer));
 
     /*
      * Send the command to the SMTP server.
      */
-    smtp_fputs(STR(state->buffer), LEN(state->buffer), session->stream);
+    smtp_fputs(STR(session->buffer), LEN(session->buffer), session->stream);
 
     /*
      * Flush unsent data to avoid timeouts after slow DNS lookups.
@@ -167,9 +180,8 @@ void    smtp_chat_cmd(SMTP_STATE *state, char *fmt,...)
 
 /* smtp_chat_resp - read and process SMTP server response */
 
-SMTP_RESP *smtp_chat_resp(SMTP_STATE *state)
+SMTP_RESP *smtp_chat_resp(SMTP_SESSION *session)
 {
-    SMTP_SESSION *session = state->session;
     static SMTP_RESP rdata;
     char   *cp;
     int     last_char;
@@ -187,13 +199,13 @@ SMTP_RESP *smtp_chat_resp(SMTP_STATE *state)
      */
     VSTRING_RESET(rdata.buf);
     for (;;) {
-       last_char = smtp_get(state->buffer, session->stream, var_line_limit);
-       printable(STR(state->buffer), '?');
+       last_char = smtp_get(session->buffer, session->stream, var_line_limit);
+       printable(STR(session->buffer), '?');
        if (last_char != '\n')
            msg_warn("%s: response longer than %d: %.30s...",
-                    session->namaddr, var_line_limit, STR(state->buffer));
+                    session->namaddr, var_line_limit, STR(session->buffer));
        if (msg_verbose)
-           msg_info("< %s: %.100s", session->namaddr, STR(state->buffer));
+           msg_info("< %s: %.100s", session->namaddr, STR(session->buffer));
 
        /*
         * Defend against a denial of service attack by limiting the amount
@@ -202,8 +214,8 @@ SMTP_RESP *smtp_chat_resp(SMTP_STATE *state)
        if (LEN(rdata.buf) < var_line_limit) {
            if (VSTRING_LEN(rdata.buf))
                VSTRING_ADDCH(rdata.buf, '\n');
-           vstring_strcat(rdata.buf, STR(state->buffer));
-           smtp_chat_append(state, "In:  ", STR(state->buffer));
+           vstring_strcat(rdata.buf, STR(session->buffer));
+           smtp_chat_append(session, "In:  ", STR(session->buffer));
        }
 
        /*
@@ -211,17 +223,17 @@ SMTP_RESP *smtp_chat_resp(SMTP_STATE *state)
         * that any character except space (or end of line) will have the
         * same effect as the '-' line continuation character.
         */
-       for (cp = STR(state->buffer); *cp && ISDIGIT(*cp); cp++)
+       for (cp = STR(session->buffer); *cp && ISDIGIT(*cp); cp++)
             /* void */ ;
-       if (cp - STR(state->buffer) == 3) {
+       if (cp - STR(session->buffer) == 3) {
            if (*cp == '-')
                continue;
            if (*cp == ' ' || *cp == 0)
                break;
        }
-       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       session->error_mask |= MAIL_ERROR_PROTOCOL;
     }
-    rdata.code = atoi(STR(state->buffer));
+    rdata.code = atoi(STR(session->buffer));
     VSTRING_TERMINATE(rdata.buf);
     rdata.str = STR(rdata.buf);
     return (&rdata);
@@ -238,17 +250,16 @@ static void print_line(const char *str, int len, int indent, char *context)
 
 /* smtp_chat_notify - notify postmaster */
 
-void    smtp_chat_notify(SMTP_STATE *state)
+void    smtp_chat_notify(SMTP_SESSION *session)
 {
     char   *myname = "smtp_chat_notify";
-    SMTP_SESSION *session = state->session;
     VSTREAM *notice;
     char  **cpp;
 
     /*
      * Sanity checks.
      */
-    if (state->history == 0)
+    if (session->history == 0)
        msg_panic("%s: no conversation history", myname);
     if (msg_verbose)
        msg_info("%s: notify postmaster", myname);
@@ -282,8 +293,8 @@ void    smtp_chat_notify(SMTP_STATE *state)
     post_mail_fputs(notice, "");
     post_mail_fputs(notice, "Transcript of session follows.");
     post_mail_fputs(notice, "");
-    argv_terminate(state->history);
-    for (cpp = state->history->argv; *cpp; cpp++)
+    argv_terminate(session->history);
+    for (cpp = session->history->argv; *cpp; cpp++)
        line_wrap(printable(*cpp, '?'), LENGTH, INDENT, print_line,
                  (char *) notice);
     (void) post_mail_fclose(notice);
index 604c90c64b52475e8fbd59440ebcb25fa9c841a9..c81120adfa73eba16065e636e5f236b725fcc62f 100644 (file)
@@ -98,7 +98,7 @@
 
 /* smtp_connect_addr - connect to explicit address */
 
-static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
+static SMTP_SESSION *smtp_connect_addr(char *dest, DNS_RR *addr, unsigned port,
                                               VSTRING *why)
 {
     char   *myname = "smtp_connect_addr";
@@ -212,7 +212,8 @@ static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
        return (0);
     }
     vstream_ungetc(stream, ch);
-    return (smtp_session_alloc(stream, addr->name, inet_ntoa(sin.sin_addr)));
+    return (smtp_session_alloc(stream, dest, addr->name,
+                              inet_ntoa(sin.sin_addr)));
 }
 
 /* smtp_parse_destination - parse destination */
@@ -269,6 +270,7 @@ int     smtp_connect(SMTP_STATE *state)
     int     addr_count;
     int     sess_count;
     int     misc_flags = SMTP_MISC_FLAG_DEFAULT;
+    SMTP_SESSION *session;
 
     /*
      * First try to deliver to the indicated destination, then try to deliver
@@ -348,27 +350,23 @@ int     smtp_connect(SMTP_STATE *state)
            next = addr->next;
            if (++addr_count == var_smtp_mxaddr_limit)
                next = 0;
-           if ((state->session = smtp_connect_addr(addr, port, why)) != 0) {
-               state->features = 0;            /* XXX should be SESSION info */
+           session = state->session = smtp_connect_addr(dest, addr, port, why);
+           if (session != 0) {
                if (++sess_count == var_smtp_mxsess_limit)
                    next = 0;
                state->final_server = (cpp[1] == 0 && next == 0);
-               state->session->best = (addr->pref == addr_list->pref);
-               debug_peer_check(state->session->host, state->session->addr);
+               session->best = (addr->pref == addr_list->pref);
+               debug_peer_check(session->host, session->addr);
                if (smtp_helo(state, misc_flags) == 0)
                    smtp_xfer(state);
-               if (state->history != 0) {
-                   if (state->error_mask & name_mask(VAR_NOTIFY_CLASSES,
+               if (session->history != 0) {
+                   if (session->error_mask & name_mask(VAR_NOTIFY_CLASSES,
                                      mail_error_masks, var_notify_classes))
-                       smtp_chat_notify(state);
-                   smtp_chat_reset(state);
+                       smtp_chat_notify(session);
                }
                /* XXX smtp_xfer() may abort in the middle of DATA. */
-               smtp_session_free(state->session);
+               smtp_session_free(session);
                state->session = 0;
-#ifdef USE_SASL_AUTH
-               smtp_sasl_cleanup(state);
-#endif
                debug_peer_restore();
                smtp_rcpt_cleanup(state);
            } else {
index 71369a19ddfd5503978cf400a88596a1c7af4343..18fcb3ea1fa11fef9d51b2fd317b49a0e7c25b5c 100644 (file)
@@ -196,7 +196,7 @@ int     smtp_helo(SMTP_STATE *state, int misc_flags)
     /*
      * Read and parse the server's SMTP greeting banner.
      */
-    switch ((resp = smtp_chat_resp(state))->code / 100) {
+    switch ((resp = smtp_chat_resp(session))->code / 100) {
     case 2:
        break;
     case 5:
@@ -215,7 +215,7 @@ int     smtp_helo(SMTP_STATE *state, int misc_flags)
      * on by default.
      */
     if (resp->str[strspn(resp->str, "20 *\t\n")] == 0)
-       state->features |= SMTP_FEATURE_MAYBEPIX;
+       session->features |= SMTP_FEATURE_MAYBEPIX;
 
     /*
      * See if we are talking to ourself. This should not be possible with the
@@ -231,25 +231,27 @@ int     smtp_helo(SMTP_STATE *state, int misc_flags)
                msg_warn("host %s greeted me with my own hostname %s",
                         session->namaddr, var_myhostname);
        } else if (strcasecmp(word, "ESMTP") == 0)
-           state->features |= SMTP_FEATURE_ESMTP;
+           session->features |= SMTP_FEATURE_ESMTP;
     }
-    if (var_smtp_always_ehlo && (state->features & SMTP_FEATURE_MAYBEPIX) == 0)
-       state->features |= SMTP_FEATURE_ESMTP;
-    if (var_smtp_never_ehlo || (state->features & SMTP_FEATURE_MAYBEPIX) != 0)
-       state->features &= ~SMTP_FEATURE_ESMTP;
+    if (var_smtp_always_ehlo
+        && (session->features & SMTP_FEATURE_MAYBEPIX) == 0)
+       session->features |= SMTP_FEATURE_ESMTP;
+    if (var_smtp_never_ehlo
+       || (session->features & SMTP_FEATURE_MAYBEPIX) != 0)
+       session->features &= ~SMTP_FEATURE_ESMTP;
 
     /*
      * Return the compliment. Fall back to SMTP if our ESMTP recognition
      * heuristic failed.
      */
-    if (state->features & SMTP_FEATURE_ESMTP) {
-       smtp_chat_cmd(state, "EHLO %s", var_smtp_helo_name);
-       if ((resp = smtp_chat_resp(state))->code / 100 != 2)
-           state->features &= ~SMTP_FEATURE_ESMTP;
+    if (session->features & SMTP_FEATURE_ESMTP) {
+       smtp_chat_cmd(session, "EHLO %s", var_smtp_helo_name);
+       if ((resp = smtp_chat_resp(session))->code / 100 != 2)
+           session->features &= ~SMTP_FEATURE_ESMTP;
     }
-    if ((state->features & SMTP_FEATURE_ESMTP) == 0) {
-       smtp_chat_cmd(state, "HELO %s", var_smtp_helo_name);
-       if ((resp = smtp_chat_resp(state))->code / 100 != 2)
+    if ((session->features & SMTP_FEATURE_ESMTP) == 0) {
+       smtp_chat_cmd(session, "HELO %s", var_smtp_helo_name);
+       if ((resp = smtp_chat_resp(session))->code / 100 != 2)
            return (smtp_site_fail(state, resp->code,
                                   "host %s refused to talk to me: %s",
                                   session->namaddr,
@@ -271,26 +273,26 @@ int     smtp_helo(SMTP_STATE *state, int misc_flags)
     while ((words = mystrtok(&lines, "\n")) != 0) {
        if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t=")) != 0) {
            if (strcasecmp(word, "8BITMIME") == 0)
-               state->features |= SMTP_FEATURE_8BITMIME;
+               session->features |= SMTP_FEATURE_8BITMIME;
            else if (strcasecmp(word, "PIPELINING") == 0)
-               state->features |= SMTP_FEATURE_PIPELINING;
+               session->features |= SMTP_FEATURE_PIPELINING;
            else if (strcasecmp(word, "XFORWARD") == 0)
                while ((word = mystrtok(&words, " \t")) != 0)
-                   state->features |= name_code(xforward_features,
-                                                NAME_CODE_FLAG_NONE, word);
+                   session->features |= name_code(xforward_features,
+                                                  NAME_CODE_FLAG_NONE, word);
            else if (strcasecmp(word, "SIZE") == 0) {
-               state->features |= SMTP_FEATURE_SIZE;
+               session->features |= SMTP_FEATURE_SIZE;
                if ((word = mystrtok(&words, " \t")) != 0) {
                    if (!alldig(word))
                        msg_warn("bad size limit \"%s\" in EHLO reply from %s",
                                 word, session->namaddr);
                    else
-                       state->size_limit = off_cvt_string(word);
+                       session->size_limit = off_cvt_string(word);
                }
            }
 #ifdef USE_SASL_AUTH
            else if (var_smtp_sasl_enable && strcasecmp(word, "AUTH") == 0)
-               smtp_sasl_helo_auth(state, words);
+               smtp_sasl_helo_auth(session, words);
 #endif
            else if (strcasecmp(word, var_myhostname) == 0) {
                if (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT) {
@@ -305,10 +307,10 @@ int     smtp_helo(SMTP_STATE *state, int misc_flags)
     }
     if (msg_verbose)
        msg_info("server features: 0x%x size %.0f",
-                state->features, (double) state->size_limit);
+                session->features, (double) session->size_limit);
 
 #ifdef USE_SASL_AUTH
-    if (var_smtp_sasl_enable && (state->features & SMTP_FEATURE_AUTH))
+    if (var_smtp_sasl_enable && (session->features & SMTP_FEATURE_AUTH))
        return (smtp_sasl_helo_login(state));
 #endif
 
@@ -429,8 +431,8 @@ int     smtp_xfer(SMTP_STATE *state)
 
 #define RETURN(x) do { \
        vstring_free(next_command); \
-       if (state->mime_state) \
-           state->mime_state = mime_state_free(state->mime_state); \
+       if (session->mime_state) \
+           session->mime_state = mime_state_free(session->mime_state); \
        return (x); \
     } while (0)
 
@@ -458,10 +460,10 @@ int     smtp_xfer(SMTP_STATE *state)
      * here rather than in the EHLO processing code, because of future SMTP
      * connection caching.
      */
-    if (state->size_limit > 0 && state->size_limit < request->data_size) {
+    if (session->size_limit > 0 && session->size_limit < request->data_size) {
        smtp_mesg_fail(state, 552,
                    "message size %lu exceeds size limit %.0f of server %s",
-                      request->data_size, (double) state->size_limit,
+                      request->data_size, (double) session->size_limit,
                       session->namaddr);
        RETURN(0);
     }
@@ -479,15 +481,15 @@ int     smtp_xfer(SMTP_STATE *state)
      * to be aware of application-level buffering by the vstream module,
      * which is limited to a couple kbytes.
      */
-    if (state->features & SMTP_FEATURE_PIPELINING) {
-       if (getsockopt(vstream_fileno(state->session->stream), SOL_SOCKET,
+    if (session->features & SMTP_FEATURE_PIPELINING) {
+       if (getsockopt(vstream_fileno(session->stream), SOL_SOCKET,
                       SO_SNDBUF, (char *) &sndbufsize, &optlen) < 0)
            msg_fatal("%s: getsockopt: %m", myname);
        if (sndbufsize > VSTREAM_BUFSIZE)
            sndbufsize = VSTREAM_BUFSIZE;
        if (sndbufsize == 0) {
            sndbufsize = VSTREAM_BUFSIZE;
-           if (setsockopt(vstream_fileno(state->session->stream), SOL_SOCKET,
+           if (setsockopt(vstream_fileno(session->stream), SOL_SOCKET,
                           SO_SNDBUF, (char *) &sndbufsize, optlen) < 0)
                msg_fatal("%s: setsockopt: %m", myname);
        }
@@ -521,15 +523,15 @@ int     smtp_xfer(SMTP_STATE *state)
     nrcpt = 0;
     send_name_addr =
        var_smtp_send_xforward
-       && (((state->features & SMTP_FEATURE_XFORWARD_NAME)
+       && (((session->features & SMTP_FEATURE_XFORWARD_NAME)
             && DEL_REQ_ATTR_AVAIL(request->client_name))
-           || ((state->features & SMTP_FEATURE_XFORWARD_ADDR)
+           || ((session->features & SMTP_FEATURE_XFORWARD_ADDR)
                && DEL_REQ_ATTR_AVAIL(request->client_addr)));
     send_proto_helo =
        var_smtp_send_xforward
-       && (((state->features & SMTP_FEATURE_XFORWARD_PROTO)
+       && (((session->features & SMTP_FEATURE_XFORWARD_PROTO)
             && DEL_REQ_ATTR_AVAIL(request->client_proto))
-           || ((state->features & SMTP_FEATURE_XFORWARD_HELO)
+           || ((session->features & SMTP_FEATURE_XFORWARD_HELO)
                && DEL_REQ_ATTR_AVAIL(request->client_helo)));
     if (send_name_addr)
        recv_state = send_state = SMTP_STATE_XFORWARD_NAME_ADDR;
@@ -560,11 +562,11 @@ int     smtp_xfer(SMTP_STATE *state)
             */
        case SMTP_STATE_XFORWARD_NAME_ADDR:
            vstring_strcpy(next_command, XFORWARD_CMD);
-           if (state->features & SMTP_FEATURE_XFORWARD_NAME)
+           if (session->features & SMTP_FEATURE_XFORWARD_NAME)
                vstring_sprintf_append(next_command, " %s=%s",
                   XFORWARD_NAME, DEL_REQ_ATTR_AVAIL(request->client_name) ?
                               request->client_name : XFORWARD_UNAVAILABLE);
-           if (state->features & SMTP_FEATURE_XFORWARD_ADDR)
+           if (session->features & SMTP_FEATURE_XFORWARD_ADDR)
                vstring_sprintf_append(next_command, " %s=%s",
                   XFORWARD_ADDR, DEL_REQ_ATTR_AVAIL(request->client_addr) ?
                               request->client_addr : XFORWARD_UNAVAILABLE);
@@ -576,11 +578,11 @@ int     smtp_xfer(SMTP_STATE *state)
 
        case SMTP_STATE_XFORWARD_PROTO_HELO:
            vstring_strcpy(next_command, XFORWARD_CMD);
-           if (state->features & SMTP_FEATURE_XFORWARD_PROTO)
+           if (session->features & SMTP_FEATURE_XFORWARD_PROTO)
                vstring_sprintf_append(next_command, " %s=%s",
                 XFORWARD_PROTO, DEL_REQ_ATTR_AVAIL(request->client_proto) ?
                              request->client_proto : XFORWARD_UNAVAILABLE);
-           if (state->features & SMTP_FEATURE_XFORWARD_HELO)
+           if (session->features & SMTP_FEATURE_XFORWARD_HELO)
                vstring_sprintf_append(next_command, " %s=%s",
                   XFORWARD_HELO, DEL_REQ_ATTR_AVAIL(request->client_helo) ?
                               request->client_helo : XFORWARD_UNAVAILABLE);
@@ -591,13 +593,13 @@ int     smtp_xfer(SMTP_STATE *state)
             * Build the MAIL FROM command.
             */
        case SMTP_STATE_MAIL:
-           QUOTE_ADDRESS(state->scratch, request->sender);
+           QUOTE_ADDRESS(session->scratch, request->sender);
            vstring_sprintf(next_command, "MAIL FROM:<%s>",
-                           vstring_str(state->scratch));
-           if (state->features & SMTP_FEATURE_SIZE)    /* RFC 1870 */
+                           vstring_str(session->scratch));
+           if (session->features & SMTP_FEATURE_SIZE)  /* RFC 1870 */
                vstring_sprintf_append(next_command, " SIZE=%lu",
                                       request->data_size);
-           if (state->features & SMTP_FEATURE_8BITMIME) {      /* RFC 1652 */
+           if (session->features & SMTP_FEATURE_8BITMIME) {    /* RFC 1652 */
                if (strcmp(request->encoding, MAIL_ATTR_ENC_8BIT) == 0)
                    vstring_strcat(next_command, " BODY=8BITMIME");
                else if (strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) == 0)
@@ -612,8 +614,7 @@ int     smtp_xfer(SMTP_STATE *state)
             */
 #ifdef USE_SASL_AUTH
            if (var_smtp_sasl_enable
-               && (state->features & SMTP_FEATURE_AUTH)
-               && state->sasl_passwd)
+               && (session->features & SMTP_FEATURE_AUTH))
                vstring_strcat(next_command, " AUTH=<>");
 #endif
            next_state = SMTP_STATE_RCPT;
@@ -625,9 +626,9 @@ int     smtp_xfer(SMTP_STATE *state)
             */
        case SMTP_STATE_RCPT:
            rcpt = request->rcpt_list.info + send_rcpt;
-           QUOTE_ADDRESS(state->scratch, rcpt->address);
+           QUOTE_ADDRESS(session->scratch, rcpt->address);
            vstring_sprintf(next_command, "RCPT TO:<%s>",
-                           vstring_str(state->scratch));
+                           vstring_str(session->scratch));
            if ((next_rcpt = send_rcpt + 1) == SMTP_RCPT_LEFT(state))
                next_state = DEL_REQ_TRACE_ONLY(request->flags) ?
                    SMTP_STATE_ABORT : SMTP_STATE_DATA;
@@ -705,12 +706,12 @@ int     smtp_xfer(SMTP_STATE *state)
                 * Receive the next server response. Use the proper timeout,
                 * and log the proper client state in case of trouble.
                 */
-               smtp_timeout_setup(state->session->stream,
+               smtp_timeout_setup(session->stream,
                                   *xfer_timeouts[recv_state]);
-               if ((except = vstream_setjmp(state->session->stream)) != 0)
+               if ((except = vstream_setjmp(session->stream)) != 0)
                    RETURN(SENDING_MAIL ? smtp_stream_except(state, except,
                                             xfer_states[recv_state]) : -1);
-               resp = smtp_chat_resp(state);
+               resp = smtp_chat_resp(session);
 
                /*
                 * Process the response.
@@ -902,10 +903,10 @@ int     smtp_xfer(SMTP_STATE *state)
        if (send_state == SMTP_STATE_DOT && nrcpt > 0) {
            downgrading =
                (var_disable_mime_oconv == 0
-                && (state->features & SMTP_FEATURE_8BITMIME) == 0
+                && (session->features & SMTP_FEATURE_8BITMIME) == 0
                 && strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) != 0);
            if (downgrading)
-               state->mime_state = mime_state_alloc(MIME_OPT_DOWNGRADE
+               session->mime_state = mime_state_alloc(MIME_OPT_DOWNGRADE
                                                  | MIME_OPT_REPORT_NESTING,
                                                     smtp_header_out,
                                                     (MIME_STATE_ANY_END) 0,
@@ -914,28 +915,28 @@ int     smtp_xfer(SMTP_STATE *state)
                                                   (MIME_STATE_ERR_PRINT) 0,
                                                     (void *) state);
            state->space_left = var_smtp_line_limit;
-           smtp_timeout_setup(state->session->stream,
+           smtp_timeout_setup(session->stream,
                               var_smtp_data1_tmout);
-           if ((except = vstream_setjmp(state->session->stream)) != 0)
+           if ((except = vstream_setjmp(session->stream)) != 0)
                RETURN(smtp_stream_except(state, except,
                                          "sending message body"));
 
            if (vstream_fseek(state->src, request->data_offset, SEEK_SET) < 0)
                msg_fatal("seek queue file: %m");
 
-           while ((rec_type = rec_get(state->src, state->scratch, 0)) > 0) {
+           while ((rec_type = rec_get(state->src, session->scratch, 0)) > 0) {
                if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
                    break;
                if (downgrading == 0) {
                    smtp_text_out((void *) state, rec_type,
-                                 vstring_str(state->scratch),
-                                 VSTRING_LEN(state->scratch),
+                                 vstring_str(session->scratch),
+                                 VSTRING_LEN(session->scratch),
                                  (off_t) 0);
                } else {
                    mime_errs =
-                       mime_state_update(state->mime_state, rec_type,
-                                         vstring_str(state->scratch),
-                                         VSTRING_LEN(state->scratch));
+                       mime_state_update(session->mime_state, rec_type,
+                                         vstring_str(session->scratch),
+                                         VSTRING_LEN(session->scratch));
                    if (mime_errs) {
                        smtp_mesg_fail(state, 554,
                                       "MIME 7-bit conversion failed: %s",
@@ -946,7 +947,7 @@ int     smtp_xfer(SMTP_STATE *state)
                prev_type = rec_type;
            }
 
-           if (state->mime_state) {
+           if (session->mime_state) {
 
                /*
                 * The cleanup server normally ends MIME content with a
@@ -957,7 +958,7 @@ int     smtp_xfer(SMTP_STATE *state)
                 * is requested upon delivery.
                 */
                mime_errs =
-                   mime_state_update(state->mime_state, rec_type, "", 0);
+                   mime_state_update(session->mime_state, rec_type, "", 0);
                if (mime_errs) {
                    smtp_mesg_fail(state, 554,
                                   "MIME 7-bit conversion failed: %s",
@@ -966,7 +967,7 @@ int     smtp_xfer(SMTP_STATE *state)
                }
            } else if (prev_type == REC_TYPE_CONT)      /* missing newline */
                smtp_fputs("", 0, session->stream);
-           if ((state->features & SMTP_FEATURE_MAYBEPIX) != 0
+           if ((session->features & SMTP_FEATURE_MAYBEPIX) != 0
                && request->arrival_time < vstream_ftime(session->stream)
                - var_smtp_pix_thresh) {
                msg_info("%s: enabling PIX <CRLF>.<CRLF> workaround for %s",
@@ -985,7 +986,7 @@ int     smtp_xfer(SMTP_STATE *state)
         */
        if (sndbuffree > 0)
            sndbuffree -= VSTRING_LEN(next_command) + 2;
-       smtp_chat_cmd(state, "%s", vstring_str(next_command));
+       smtp_chat_cmd(session, "%s", vstring_str(next_command));
        send_state = next_state;
        send_rcpt = next_rcpt;
     }
index 35f9e1c4d2b152c1120ff5bcd85ebd2b2c21af23..c7550aae207b2a10057d740df8a37965918d78fa 100644 (file)
  * SASL protocol functions
  */
 extern void smtp_sasl_initialize(void);
-extern void smtp_sasl_connect(SMTP_STATE *);
-extern int smtp_sasl_passwd_lookup(SMTP_STATE *);
-extern void smtp_sasl_start(SMTP_STATE *, const char *, const char *);
-extern int smtp_sasl_authenticate(SMTP_STATE *, VSTRING *);
-extern void smtp_sasl_cleanup(SMTP_STATE *);
+extern void smtp_sasl_connect(SMTP_SESSION *);
+extern int smtp_sasl_passwd_lookup(SMTP_SESSION *);
+extern void smtp_sasl_start(SMTP_SESSION *, const char *, const char *);
+extern int smtp_sasl_authenticate(SMTP_SESSION *, VSTRING *);
+extern void smtp_sasl_cleanup(SMTP_SESSION *);
 
-extern void smtp_sasl_helo_auth(SMTP_STATE *, const char *);
+extern void smtp_sasl_helo_auth(SMTP_SESSION *, const char *);
 extern int smtp_sasl_helo_login(SMTP_STATE *);
 
 /* LICENSE
index 211a30a4e0f76e0648128e1844038468a5f7c149..30251c8d37c744c0f32c56587c39ae2ad28651f5 100644 (file)
@@ -8,21 +8,21 @@
 /*
 /*     void    smtp_sasl_initialize()
 /*
-/*     void    smtp_sasl_connect(state)
-/*     SMTP_STATE *state;
+/*     void    smtp_sasl_connect(session)
+/*     SMTP_SESSION *session;
 /*
-/*     void    smtp_sasl_start(state, sasl_opts_name, sasl_opts_val)
-/*     SMTP_STATE *state;
+/*     void    smtp_sasl_start(session, sasl_opts_name, sasl_opts_val)
+/*     SMTP_SESSION *session;
 /*
-/*     int     smtp_sasl_passwd_lookup(state)
-/*     SMTP_STATE *state;
+/*     int     smtp_sasl_passwd_lookup(session)
+/*     SMTP_SESSION *session;
 /*
-/*     int     smtp_sasl_authenticate(state, why)
-/*     SMTP_STATE *state;
+/*     int     smtp_sasl_authenticate(session, why)
+/*     SMTP_SESSION *session;
 /*     VSTRING *why;
 /*
-/*     void    smtp_sasl_cleanup(state)
-/*     SMTP_STATE *state;
+/*     void    smtp_sasl_cleanup(session)
+/*     SMTP_SESSION *session;
 /* DESCRIPTION
 /*     smtp_sasl_initialize() initializes the SASL library. This
 /*     routine must be called once at process startup, before any
@@ -53,7 +53,7 @@
 /*     This routine is a noop for non-SASL sessions.
 /*
 /*     Arguments:
-/* .IP state
+/* .IP session
 /*     Session context.
 /* .IP mech_list
 /*     String of SASL mechanisms (separated by blanks)
@@ -203,20 +203,20 @@ static int smtp_sasl_get_user(void *context, int unused_id, const char **result,
                                      unsigned *len)
 {
     char   *myname = "smtp_sasl_get_user";
-    SMTP_STATE *state = (SMTP_STATE *) context;
+    SMTP_SESSION *session = (SMTP_SESSION *) context;
 
     if (msg_verbose)
-       msg_info("%s: %s", myname, state->sasl_username);
+       msg_info("%s: %s", myname, session->sasl_username);
 
     /*
      * Sanity check.
      */
-    if (state->sasl_passwd == 0)
+    if (session->sasl_passwd == 0)
        msg_panic("%s: no username looked up", myname);
 
-    *result = state->sasl_username;
+    *result = session->sasl_username;
     if (len)
-       *len = strlen(state->sasl_username);
+       *len = strlen(session->sasl_username);
     return (SASL_OK);
 }
 
@@ -226,35 +226,35 @@ static int smtp_sasl_get_passwd(sasl_conn_t *conn, void *context,
                                        int id, sasl_secret_t **psecret)
 {
     char   *myname = "smtp_sasl_get_passwd";
-    SMTP_STATE *state = (SMTP_STATE *) context;
+    SMTP_SESSION *session = (SMTP_SESSION *) context;
     int     len;
 
     if (msg_verbose)
-       msg_info("%s: %s", myname, state->sasl_passwd);
+       msg_info("%s: %s", myname, session->sasl_passwd);
 
     /*
      * Sanity check.
      */
     if (!conn || !psecret || id != SASL_CB_PASS)
        return (SASL_BADPARAM);
-    if (state->sasl_passwd == 0)
+    if (session->sasl_passwd == 0)
        msg_panic("%s: no password looked up", myname);
 
     /*
      * Convert the password into a counted string.
      */
-    len = strlen(state->sasl_passwd);
+    len = strlen(session->sasl_passwd);
     if ((*psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len)) == 0)
        return (SASL_NOMEM);
     (*psecret)->len = len;
-    memcpy((*psecret)->data, state->sasl_passwd, len + 1);
+    memcpy((*psecret)->data, session->sasl_passwd, len + 1);
 
     return (SASL_OK);
 }
 
 /* smtp_sasl_passwd_lookup - password lookup routine */
 
-int     smtp_sasl_passwd_lookup(SMTP_STATE *state)
+int     smtp_sasl_passwd_lookup(SMTP_SESSION *session)
 {
     char   *myname = "smtp_sasl_passwd_lookup";
     const char *value;
@@ -269,21 +269,24 @@ int     smtp_sasl_passwd_lookup(SMTP_STATE *state)
     /*
      * Look up the per-server password information. Try the hostname first,
      * then try the destination.
+     * 
+     * XXX Instead of using nexthop (the intended destination) we use dest
+     * (either the intended destination, or a fall-back destination).
      */
-    if ((value = maps_find(smtp_sasl_passwd_map, state->session->host, 0)) != 0
-       || (value = maps_find(smtp_sasl_passwd_map, state->request->nexthop, 0)) != 0) {
-       state->sasl_username = mystrdup(value);
-       passwd = split_at(state->sasl_username, ':');
-       state->sasl_passwd = mystrdup(passwd ? passwd : "");
+    if ((value = maps_find(smtp_sasl_passwd_map, session->host, 0)) != 0
+      || (value = maps_find(smtp_sasl_passwd_map, session->dest, 0)) != 0) {
+       session->sasl_username = mystrdup(value);
+       passwd = split_at(session->sasl_username, ':');
+       session->sasl_passwd = mystrdup(passwd ? passwd : "");
        if (msg_verbose)
            msg_info("%s: host `%s' user `%s' pass `%s'",
-                    myname, state->session->host,
-                    state->sasl_username, state->sasl_passwd);
+                    myname, session->host,
+                    session->sasl_username, session->sasl_passwd);
        return (1);
     } else {
        if (msg_verbose)
            msg_info("%s: host `%s' no auth info found",
-                    myname, state->session->host);
+                    myname, session->host);
        return (0);
     }
 }
@@ -323,20 +326,20 @@ void    smtp_sasl_initialize(void)
 
 /* smtp_sasl_connect - per-session client initialization */
 
-void    smtp_sasl_connect(SMTP_STATE *state)
+void    smtp_sasl_connect(SMTP_SESSION *session)
 {
-    state->sasl_mechanism_list = 0;
-    state->sasl_username = 0;
-    state->sasl_passwd = 0;
-    state->sasl_conn = 0;
-    state->sasl_encoded = 0;
-    state->sasl_decoded = 0;
-    state->sasl_callbacks = 0;
+    session->sasl_mechanism_list = 0;
+    session->sasl_username = 0;
+    session->sasl_passwd = 0;
+    session->sasl_conn = 0;
+    session->sasl_encoded = 0;
+    session->sasl_decoded = 0;
+    session->sasl_callbacks = 0;
 }
 
 /* smtp_sasl_start - per-session SASL initialization */
 
-void    smtp_sasl_start(SMTP_STATE *state, const char *sasl_opts_name,
+void    smtp_sasl_start(SMTP_SESSION *session, const char *sasl_opts_name,
                                const char *sasl_opts_val)
 {
     static sasl_callback_t callbacks[] = {
@@ -357,18 +360,18 @@ void    smtp_sasl_start(SMTP_STATE *state, const char *sasl_opts_name,
      */
 #define NULL_SECFLAGS          0
 
-    state->sasl_callbacks = (sasl_callback_t *) mymalloc(sizeof(callbacks));
-    memcpy((char *) state->sasl_callbacks, callbacks, sizeof(callbacks));
-    for (cp = state->sasl_callbacks; cp->id != SASL_CB_LIST_END; cp++)
-       cp->context = (void *) state;
+    session->sasl_callbacks = (sasl_callback_t *) mymalloc(sizeof(callbacks));
+    memcpy((char *) session->sasl_callbacks, callbacks, sizeof(callbacks));
+    for (cp = session->sasl_callbacks; cp->id != SASL_CB_LIST_END; cp++)
+       cp->context = (void *) session;
 
 #define NULL_SERVER_ADDR       ((char *) 0)
 #define NULL_CLIENT_ADDR       ((char *) 0)
 
-    if (SASL_CLIENT_NEW("smtp", state->session->host,
+    if (SASL_CLIENT_NEW("smtp", session->host,
                        NULL_CLIENT_ADDR, NULL_SERVER_ADDR,
-                       state->sasl_callbacks, NULL_SECFLAGS,
-                       (sasl_conn_t **) &state->sasl_conn) != SASL_OK)
+                       session->sasl_callbacks, NULL_SECFLAGS,
+                       (sasl_conn_t **) &session->sasl_conn) != SASL_OK)
        msg_fatal("per-session SASL client initialization");
 
     /*
@@ -384,7 +387,7 @@ void    smtp_sasl_start(SMTP_STATE *state, const char *sasl_opts_name,
     sec_props.maxbufsize = 0;
     sec_props.property_names = 0;
     sec_props.property_values = 0;
-    if (sasl_setprop(state->sasl_conn, SASL_SEC_PROPS,
+    if (sasl_setprop(session->sasl_conn, SASL_SEC_PROPS,
                     &sec_props) != SASL_OK)
        msg_fatal("set per-session SASL security properties");
 
@@ -393,13 +396,13 @@ void    smtp_sasl_start(SMTP_STATE *state, const char *sasl_opts_name,
      * order to avoid memory leaks in case of read/write timeout or I/O
      * error.
      */
-    state->sasl_encoded = vstring_alloc(10);
-    state->sasl_decoded = vstring_alloc(10);
+    session->sasl_encoded = vstring_alloc(10);
+    session->sasl_decoded = vstring_alloc(10);
 }
 
 /* smtp_sasl_authenticate - run authentication protocol */
 
-int     smtp_sasl_authenticate(SMTP_STATE *state, VSTRING *why)
+int     smtp_sasl_authenticate(SMTP_SESSION *session, VSTRING *why)
 {
     char   *myname = "smtp_sasl_authenticate";
     unsigned enc_length;
@@ -426,18 +429,18 @@ int     smtp_sasl_authenticate(SMTP_STATE *state, VSTRING *why)
 
     if (msg_verbose)
        msg_info("%s: %s: SASL mechanisms %s",
-              myname, state->session->namaddr, state->sasl_mechanism_list);
+                myname, session->namaddr, session->sasl_mechanism_list);
 
     /*
      * Start the client side authentication protocol.
      */
-    result = SASL_CLIENT_START((sasl_conn_t *) state->sasl_conn,
-                              state->sasl_mechanism_list,
+    result = SASL_CLIENT_START((sasl_conn_t *) session->sasl_conn,
+                              session->sasl_mechanism_list,
                               NO_SASL_SECRET, NO_SASL_INTERACTION,
                               &clientout, &clientoutlen, &mechanism);
     if (result != SASL_OK && result != SASL_CONTINUE) {
        vstring_sprintf(why, "cannot SASL authenticate to server %s: %s",
-                       state->session->namaddr,
+                       session->namaddr,
                        sasl_errstring(result, NO_SASL_LANGLIST,
                                       NO_SASL_OUTLANG));
        return (-1);
@@ -453,28 +456,28 @@ int     smtp_sasl_authenticate(SMTP_STATE *state, VSTRING *why)
     if (clientoutlen > 0) {
        if (msg_verbose)
            msg_info("%s: %s: uncoded initial reply: %.*s",
-                    myname, state->session->namaddr,
-                    (int) clientoutlen, clientout);
+                  myname, session->namaddr, (int) clientoutlen, clientout);
        enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
-       VSTRING_SPACE(state->sasl_encoded, enc_length);
+       VSTRING_SPACE(session->sasl_encoded, enc_length);
        if (sasl_encode64(clientout, clientoutlen,
-                         STR(state->sasl_encoded), enc_length,
+                         STR(session->sasl_encoded), enc_length,
                          &enc_length_out) != SASL_OK)
            msg_panic("%s: sasl_encode64 botch", myname);
 #if SASL_VERSION_MAJOR < 2
        /* SASL version 1 doesn't free memory that it allocates. */
        free(clientout);
 #endif
-       smtp_chat_cmd(state, "AUTH %s %s", mechanism, STR(state->sasl_encoded));
+       smtp_chat_cmd(session, "AUTH %s %s", mechanism,
+                     STR(session->sasl_encoded));
     } else {
-       smtp_chat_cmd(state, "AUTH %s", mechanism);
+       smtp_chat_cmd(session, "AUTH %s", mechanism);
     }
 
     /*
      * Step through the authentication protocol until the server tells us
      * that we are done.
      */
-    while ((resp = smtp_chat_resp(state))->code / 100 == 3) {
+    while ((resp = smtp_chat_resp(session))->code / 100 == 3) {
 
        /*
         * Process a server challenge.
@@ -482,25 +485,24 @@ int     smtp_sasl_authenticate(SMTP_STATE *state, VSTRING *why)
        line = resp->str;
        (void) mystrtok(&line, "- \t\n");       /* skip over result code */
        serverinlen = strlen(line);
-       VSTRING_SPACE(state->sasl_decoded, serverinlen);
-       if (SASL_DECODE64(line, serverinlen, STR(state->sasl_decoded),
+       VSTRING_SPACE(session->sasl_decoded, serverinlen);
+       if (SASL_DECODE64(line, serverinlen, STR(session->sasl_decoded),
                          serverinlen, &enc_length) != SASL_OK) {
            vstring_sprintf(why, "malformed SASL challenge from server %s",
-                           state->session->namaddr);
+                           session->namaddr);
            return (-1);
        }
        if (msg_verbose)
            msg_info("%s: %s: decoded challenge: %.*s",
-                    myname, state->session->namaddr,
-                    (int) enc_length, STR(state->sasl_decoded));
-       result = sasl_client_step((sasl_conn_t *) state->sasl_conn,
-                                 STR(state->sasl_decoded), enc_length,
+                    myname, session->namaddr, (int) enc_length,
+                    STR(session->sasl_decoded));
+       result = sasl_client_step((sasl_conn_t *) session->sasl_conn,
+                                 STR(session->sasl_decoded), enc_length,
                            NO_SASL_INTERACTION, &clientout, &clientoutlen);
        if (result != SASL_OK && result != SASL_CONTINUE)
            msg_warn("SASL authentication failed to server %s: %s",
-                    state->session->namaddr,
-                    sasl_errstring(result, NO_SASL_LANGLIST,
-                                   NO_SASL_OUTLANG));
+                 session->namaddr, sasl_errstring(result, NO_SASL_LANGLIST,
+                                                  NO_SASL_OUTLANG));
 
        /*
         * Send a client response.
@@ -508,12 +510,12 @@ int     smtp_sasl_authenticate(SMTP_STATE *state, VSTRING *why)
        if (clientoutlen > 0) {
            if (msg_verbose)
                msg_info("%s: %s: uncoded client response %.*s",
-                        myname, state->session->namaddr,
+                        myname, session->namaddr,
                         (int) clientoutlen, clientout);
            enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
-           VSTRING_SPACE(state->sasl_encoded, enc_length);
+           VSTRING_SPACE(session->sasl_encoded, enc_length);
            if (sasl_encode64(clientout, clientoutlen,
-                             STR(state->sasl_encoded), enc_length,
+                             STR(session->sasl_encoded), enc_length,
                              &enc_length_out) != SASL_OK)
                msg_panic("%s: sasl_encode64 botch", myname);
 #if SASL_VERSION_MAJOR < 2
@@ -521,9 +523,9 @@ int     smtp_sasl_authenticate(SMTP_STATE *state, VSTRING *why)
            free(clientout);
 #endif
        } else {
-           vstring_strcat(state->sasl_encoded, "");
+           vstring_strcat(session->sasl_encoded, "");
        }
-       smtp_chat_cmd(state, "%s", STR(state->sasl_encoded));
+       smtp_chat_cmd(session, "%s", STR(session->sasl_encoded));
     }
 
     /*
@@ -531,7 +533,7 @@ int     smtp_sasl_authenticate(SMTP_STATE *state, VSTRING *why)
      */
     if (resp->code / 100 != 2) {
        vstring_sprintf(why, "SASL authentication failed; server %s said: %s",
-                       state->session->namaddr, resp->str);
+                       session->namaddr, resp->str);
        return (0);
     }
     return (1);
@@ -539,37 +541,37 @@ int     smtp_sasl_authenticate(SMTP_STATE *state, VSTRING *why)
 
 /* smtp_sasl_cleanup - per-session cleanup */
 
-void    smtp_sasl_cleanup(SMTP_STATE *state)
+void    smtp_sasl_cleanup(SMTP_SESSION *session)
 {
-    if (state->sasl_username) {
-       myfree(state->sasl_username);
-       state->sasl_username = 0;
+    if (session->sasl_username) {
+       myfree(session->sasl_username);
+       session->sasl_username = 0;
     }
-    if (state->sasl_passwd) {
-       myfree(state->sasl_passwd);
-       state->sasl_passwd = 0;
+    if (session->sasl_passwd) {
+       myfree(session->sasl_passwd);
+       session->sasl_passwd = 0;
     }
-    if (state->sasl_mechanism_list) {
+    if (session->sasl_mechanism_list) {
        /* allocated in smtp_sasl_helo_auth */
-       myfree(state->sasl_mechanism_list);
-       state->sasl_mechanism_list = 0;
+       myfree(session->sasl_mechanism_list);
+       session->sasl_mechanism_list = 0;
     }
-    if (state->sasl_conn) {
+    if (session->sasl_conn) {
        if (msg_verbose)
            msg_info("disposing SASL state information");
-       sasl_dispose(&state->sasl_conn);
+       sasl_dispose(&session->sasl_conn);
     }
-    if (state->sasl_callbacks) {
-       myfree((char *) state->sasl_callbacks);
-       state->sasl_callbacks = 0;
+    if (session->sasl_callbacks) {
+       myfree((char *) session->sasl_callbacks);
+       session->sasl_callbacks = 0;
     }
-    if (state->sasl_encoded) {
-       vstring_free(state->sasl_encoded);
-       state->sasl_encoded = 0;
+    if (session->sasl_encoded) {
+       vstring_free(session->sasl_encoded);
+       session->sasl_encoded = 0;
     }
-    if (state->sasl_decoded) {
-       vstring_free(state->sasl_decoded);
-       state->sasl_decoded = 0;
+    if (session->sasl_decoded) {
+       vstring_free(session->sasl_decoded);
+       session->sasl_decoded = 0;
     }
 }
 
index 30cf0ab58e52de674919b611762b3616c913bd39..bcd87cb465b421990882dcccb7d113337ff4ed8b 100644 (file)
 
 /* smtp_sasl_helo_auth - handle AUTH option in EHLO reply */
 
-void    smtp_sasl_helo_auth(SMTP_STATE *state, const char *words)
+void    smtp_sasl_helo_auth(SMTP_SESSION *session, const char *words)
 {
 
     /*
      * XXX If the server offers a null list of authentication mechanisms,
      * then pretend that the server doesn't support SASL authentication.
      */
-    if (state->sasl_mechanism_list) {
-       if (strcasecmp(state->sasl_mechanism_list, words) == 0)
+    if (session->sasl_mechanism_list) {
+       if (strcasecmp(session->sasl_mechanism_list, words) == 0)
            return;
-       myfree(state->sasl_mechanism_list);
-       msg_warn("%s offered AUTH option multiple times",
-                state->session->namaddr);
-       state->sasl_mechanism_list = 0;
-       state->features &= ~SMTP_FEATURE_AUTH;
+       myfree(session->sasl_mechanism_list);
+       msg_warn("%s offered AUTH option multiple times", session->namaddr);
+       session->sasl_mechanism_list = 0;
+       session->features &= ~SMTP_FEATURE_AUTH;
     }
     if (strlen(words) > 0) {
-       state->sasl_mechanism_list = mystrdup(words);
-       state->features |= SMTP_FEATURE_AUTH;
+       session->sasl_mechanism_list = mystrdup(words);
+       session->features |= SMTP_FEATURE_AUTH;
     } else {
-       msg_warn("%s offered null AUTH mechanism list",
-                state->session->namaddr);
+       msg_warn("%s offered null AUTH mechanism list", session->namaddr);
     }
 }
 
@@ -104,20 +102,33 @@ void    smtp_sasl_helo_auth(SMTP_STATE *state, const char *words)
 
 int     smtp_sasl_helo_login(SMTP_STATE *state)
 {
-    VSTRING *why = vstring_alloc(10);
-    int     ret = 0;
+    SMTP_SESSION *session = state->session;
+    VSTRING *why;
+    int     ret;
 
     /*
      * Skip authentication when no authentication info exists for this
-     * server, so that we talk to each other like strangers. Otherwise, if
-     * authentication information exists, assume that authentication is
-     * required, and assume that an authentication error is recoverable.
+     * server, so that we talk to each other like strangers.
      */
-    if (smtp_sasl_passwd_lookup(state) != 0) {
-       smtp_sasl_start(state, VAR_SMTP_SASL_OPTS, var_smtp_sasl_opts);
-       if (smtp_sasl_authenticate(state, why) <= 0)
-           ret = smtp_site_fail(state, 450, "Authentication failed: %s",
-                                vstring_str(why));
+    if (smtp_sasl_passwd_lookup(session) == 0) {
+       session->features &= ~SMTP_FEATURE_AUTH;
+       return 0;
+    }
+
+    /*
+     * Otherwise, if authentication information exists, assume that
+     * authentication is required, and assume that an authentication error is
+     * recoverable from the message delivery point of view. An authentication
+     * error is unrecoverable from a session point of view - the session will
+     * not be reused.
+     */
+    why = vstring_alloc(10);
+    ret = 0;
+    smtp_sasl_start(session, VAR_SMTP_SASL_OPTS, var_smtp_sasl_opts);
+    if (smtp_sasl_authenticate(session, why) <= 0) {
+       ret = smtp_site_fail(state, 450, "Authentication failed: %s",
+                            vstring_str(why));
+       /* Session reuse is disabled. */
     }
     vstring_free(why);
     return (ret);
index 7f913d2dfdb9e2119cf3a178e61b9d63cee45c73..8ac687a2df755b8777e044f86ec00cbf4c3a64f8 100644 (file)
@@ -6,8 +6,9 @@
 /* SYNOPSIS
 /*     #include "smtp.h"
 /*
-/*     SMTP_SESSION *smtp_session_alloc(stream, host, addr)
+/*     SMTP_SESSION *smtp_session_alloc(stream, dest, host, addr)
 /*     VSTREAM *stream;
+/*     char    *dest;
 /*     char    *host;
 /*     char    *addr;
 /*
 /*     SMTP_SESSION *session;
 /* DESCRIPTION
 /*     smtp_session_alloc() allocates memory for an SMTP_SESSION structure
-/*     and initializes it with the given stream and host name and address
-/*     information.  The host name and address strings are copied. The code
-/*     assumes that the stream is connected to the "best" alternative.
+/*     and initializes it with the given stream and destination, host name
+/*     and address information.  The host name and address strings are
+/*     copied. The code assumes that the stream is connected to the "best"
+/*     alternative.
 /*
 /*     smtp_session_free() destroys an SMTP_SESSION structure and its
 /*     members, making memory available for reuse.
 #include <vstream.h>
 #include <stringops.h>
 
+/* Global library. */
+
+#include <mime_state.h>
+
 /* Application-specific. */
 
 #include "smtp.h"
 
 /* smtp_session_alloc - allocate and initialize SMTP_SESSION structure */
 
-SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, char *host, char *addr)
+SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, char *dest, char *host,
+                                        char *addr)
 {
     SMTP_SESSION *session;
 
     session = (SMTP_SESSION *) mymalloc(sizeof(*session));
     session->stream = stream;
+    session->dest = mystrdup(dest);
     session->host = mystrdup(host);
     session->addr = mystrdup(addr);
     session->namaddr = concatenate(host, "[", addr, "]", (char *) 0);
     session->best = 1;
+
+    session->size_limit = 0;
+    session->error_mask = 0;
+    session->buffer = vstring_alloc(100);
+    session->scratch = vstring_alloc(100);
+    session->scratch2 = vstring_alloc(100);
+    smtp_chat_init(session);
+    session->features = SMTP_FEATURE_CACHE_SESSION;
+    session->mime_state = 0;
+
+#ifdef USE_SASL_AUTH
+    smtp_sasl_connect(session);
+#endif
+
     return (session);
 }
 
@@ -65,9 +87,25 @@ SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, char *host, char *addr)
 
 void    smtp_session_free(SMTP_SESSION *session)
 {
-    vstream_fclose(session->stream);
+    if (session->stream)
+       vstream_fclose(session->stream);
+    myfree(session->dest);
     myfree(session->host);
     myfree(session->addr);
     myfree(session->namaddr);
+
+    vstring_free(session->buffer);
+    vstring_free(session->scratch);
+    vstring_free(session->scratch2);
+
+    if (session->history)
+       smtp_chat_reset(session);
+    if (session->mime_state)
+       mime_state_free(session->mime_state);
+
+#ifdef USE_SASL_AUTH
+    smtp_sasl_cleanup(session);
+#endif
+
     myfree((char *) session);
 }
index 8b14f0c1dac73124b9607ec60700eea584dc0e1a..f871a391a3111e3b45ad2d3c390470b94e2f4ebf 100644 (file)
@@ -59,19 +59,8 @@ SMTP_STATE *smtp_state_alloc(void)
     state->src = 0;
     state->request = 0;
     state->session = 0;
-    state->buffer = vstring_alloc(100);
-    state->scratch = vstring_alloc(100);
-    state->scratch2 = vstring_alloc(100);
     state->status = 0;
-    state->features = 0;
-    state->history = 0;
-    state->error_mask = 0;
-#ifdef USE_SASL_AUTH
-    smtp_sasl_connect(state);
-#endif
-    state->size_limit = 0;
     state->space_left = 0;
-    state->mime_state = 0;
     return (state);
 }
 
@@ -79,13 +68,5 @@ SMTP_STATE *smtp_state_alloc(void)
 
 void    smtp_state_free(SMTP_STATE *state)
 {
-    vstring_free(state->buffer);
-    vstring_free(state->scratch);
-    vstring_free(state->scratch2);
-#ifdef USE_SASL_AUTH
-    smtp_sasl_cleanup(state);
-#endif
-    if (state->mime_state)
-       mime_state_free(state->mime_state);
     myfree((char *) state);
 }
index ea98fb54f71b680c63c5c0d44d0a308e0bc367ff..f323dfb9296f8e8e571899cb709ab4f0d4461e7c 100644 (file)
@@ -60,6 +60,7 @@
 /*     record why the host is being skipped; soft error, final server:
 /*     defer delivery of all remaining recipients and mark the destination
 /*     as problematic; hard error: bounce all remaining recipients.
+/*     The session is marked as "do not cache".
 /*     The result is non-zero.
 /*
 /*     smtp_mesg_fail() handles the case where the smtp server
@@ -86,6 +87,7 @@
 /*     The policy is: non-final server: log an informational record
 /*     with the reason why the host is being skipped; final server:
 /*     defer delivery of all remaining recipients.
+/*     The session is marked as "do not cache".
 /*     The result is non-zero.
 /* DIAGNOSTICS
 /*     Panic: unknown exception code.
 
 /* smtp_check_code - check response code */
 
-static void smtp_check_code(SMTP_STATE *state, int code)
+static void smtp_check_code(SMTP_SESSION *session, int code)
 {
 
     /*
@@ -152,7 +154,7 @@ static void smtp_check_code(SMTP_STATE *state, int code)
     if ((!SMTP_SOFT(code) && !SMTP_HARD(code))
        || code == 555                  /* RFC 1869, section 6.1. */
        || (code >= 500 && code < 510))
-       state->error_mask |= MAIL_ERROR_PROTOCOL;
+       session->error_mask |= MAIL_ERROR_PROTOCOL;
 }
 
 /* smtp_site_fail - skip site, defer or bounce all recipients */
@@ -214,7 +216,14 @@ int     smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
        if (soft_error && request->hop_status == 0)
            request->hop_status = mystrdup(vstring_str(why));
     }
-    smtp_check_code(state, code);
+    if (session)
+       smtp_check_code(session, code);
+
+    /*
+     * Don't cache this session. We can't talk to this server.
+     */
+    if (session)
+       session->features &= ~SMTP_FEATURE_CACHE_SESSION;
 
     /*
      * Cleanup.
@@ -271,15 +280,16 @@ int     smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
            status = (soft_error ? defer_append : bounce_append)
                (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
                 rcpt->orig_addr, rcpt->address, rcpt->offset,
-                session->namaddr, request->arrival_time,
-                "%s", vstring_str(why));
+                session ? session->namaddr : "none",
+                request->arrival_time, "%s", vstring_str(why));
            if (status == 0)
                deliver_completed(state->src, rcpt->offset);
            SMTP_RCPT_DROP(state, rcpt);
            state->status |= status;
        }
     }
-    smtp_check_code(state, code);
+    if (session)
+       smtp_check_code(session, code);
 
     /*
      * Cleanup.
@@ -334,14 +344,16 @@ void    smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
        status = (soft_error ? vdefer_append : vbounce_append)
            (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
             rcpt->orig_addr, rcpt->address, rcpt->offset,
-            session->namaddr, request->arrival_time, format, ap);
+            session ? session->namaddr : "none",
+            request->arrival_time, format, ap);
        va_end(ap);
        if (status == 0)
            deliver_completed(state->src, rcpt->offset);
        SMTP_RCPT_DROP(state, rcpt);
        state->status |= status;
     }
-    smtp_check_code(state, code);
+    if (session)
+       smtp_check_code(session, code);
 }
 
 /* smtp_stream_except - defer domain after I/O problem */
@@ -354,6 +366,12 @@ int     smtp_stream_except(SMTP_STATE *state, int code, char *description)
     int     nrcpt;
     VSTRING *why = vstring_alloc(100);
 
+    /*
+     * Sanity check.
+     */
+    if (session == 0)
+       msg_panic("smtp_stream_except: no session");
+
     /*
      * Initialize.
      */
@@ -404,6 +422,11 @@ int     smtp_stream_except(SMTP_STATE *state, int code, char *description)
        }
     }
 
+    /*
+     * Don't attempt to cache this session.
+     */
+    session->features &= ~SMTP_FEATURE_CACHE_SESSION;
+
     /*
      * Cleanup.
      */