]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-1.1.12-20021217
authorWietse Venema <wietse@porcupine.org>
Tue, 17 Dec 2002 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:28:34 +0000 (06:28 +0000)
40 files changed:
postfix/HISTORY
postfix/conf/main.cf
postfix/conf/post-install
postfix/conf/sample-misc.cf
postfix/conf/sample-smtpd.cf
postfix/conf/transport
postfix/html/smtpd.8.html
postfix/html/transport.5.html
postfix/html/trivial-rewrite.8.html
postfix/man/man5/transport.5
postfix/man/man8/smtpd.8
postfix/man/man8/trivial-rewrite.8
postfix/proto/transport
postfix/src/global/Makefile.in
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/quote_821_local.c
postfix/src/global/quote_822_local.c
postfix/src/global/resolve_clnt.c
postfix/src/global/resolve_clnt.in [new file with mode: 0644]
postfix/src/global/resolve_clnt.ref [new file with mode: 0644]
postfix/src/global/rewrite_clnt.c
postfix/src/global/rewrite_clnt.in [new file with mode: 0644]
postfix/src/global/rewrite_clnt.ref [new file with mode: 0644]
postfix/src/nqmgr/Makefile.in
postfix/src/nqmgr/qmgr_message.c
postfix/src/qmgr/Makefile.in
postfix/src/qmgr/qmgr_message.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_check.c
postfix/src/trivial-rewrite/Makefile.in
postfix/src/trivial-rewrite/resolve.c
postfix/src/trivial-rewrite/rewrite.c
postfix/src/trivial-rewrite/transport.c
postfix/src/trivial-rewrite/transport.h
postfix/src/trivial-rewrite/trivial-rewrite.c
postfix/src/util/valid_hostname.c
postfix/src/util/valid_hostname.h
postfix/src/util/valid_hostname.in
postfix/src/util/valid_hostname.ref

index 61c98c0b8031abe993b8994c0d029b8f63b22741..d855304058cbe3a43a9a5740082705a60a1b9394 100644 (file)
@@ -7426,8 +7426,58 @@ Apologies for any names omitted.
        File:  trivial-rewrite/resolve.c.
 
        Performance: don't do UCE checks (which may result in 4xx
-       SMTP reply codes) when we already know that the recipient
-       is undeliverable. Files:  smtpd/smtpd.c, smtpd/smtpd_check.c.
+       SMTP reply codes, and thus, repeated delivery attempts)
+       when we already know that the recipient does not exist.
+       Files:  smtpd/smtpd.c, smtpd/smtpd_check.c.
+
+20021215
+
+       Cleanup: further simplification of transport map handling
+       after some really fine hair splitting with Victor Duchovni.
+       Files: trivial-rewrite/resolve.c, trivial-rewrite/transport.c.
+
+20021216
+
+       Workaround:  transform the address local-part into unquoted
+       form only when the address domain is local and the local-part
+       contains routing operators.  Otherwise, we may damage the
+       address local-part by inserting space between non-operator
+       tokens. Some people use weird addresses and expect them to
+       be handled without damage.  File: trivial-rewrite/resolve.c.
+
+       Robustness: scan the resolved recipient address for routing
+       operators in the address local-part, even when the local
+       MTA does not recognize ! and % as valid operators.  File:
+       trivial-rewrite/resolve.c.
+
+       Cleanup: the address rewriting code no longer tries to
+       rewrite broken user@ or user@. address forms into even more
+       broken forms. bother. File: trivial-rewrite/rewrite.c.
+
+       Cleanup: the address resolver code now treates forms ending
+       in @ in a more rational manner (because the address rewriting
+       code no longer messes up by appending .my.domain).
+
+       Bugfix: a null address local-part before @domain now is
+       properly quoted just like the null address. File:
+       global/quote_82[12]_local.c.
+
+
+20021217
+
+       Cleanup: more work on the trivial-rewrite address rewriting
+       and address resolving code. New regression tests for address
+       rewriting and resolving that make some assumptions about
+       main.cf settings. Files: global/Makefile.in (assumptions),
+       global/rewrite_clnt.in, global/rewrite_clnt.ref,
+       global/resolve_clnt.in, global/resolve_clnt.ref.
+
+       Safety: configurable SMTPD reject codes for recipients not
+       in {local,relay}_recipient,virtual_{alias,mailbox}}_maps,
+       aptly named unknown_mumble_reject_code.  Postfix installs
+       with unknown_local_recipient_reject_code=450, unless the
+       site already ran Postfix with local_recipient_maps enabled.
+       Files:  smtpd/smtpd.c, smtpd/smtpd_check.c, conf/post-install.
 
 Open problems:
 
index b26e358fab3b86659422e16b120c0683f580956f..adfb58fbed466c6aef920e5e58c4e47e6fb3c65c 100644 (file)
@@ -122,7 +122,9 @@ mail_owner = postfix
 # machine considers itself the final destination for.
 #
 # These domains are routed to the delivery agent specified with the
-# local_transport parameter setting.
+# local_transport parameter setting. By default, that is the UNIX
+# compatible delivery agent that lookups all recipients in /etc/passwd
+# and /etc/aliases or their equivalent.
 #
 # The default is $myhostname + localhost.$mydomain.  On a mail domain
 # gateway, you should also include $mydomain.
@@ -145,12 +147,14 @@ mail_owner = postfix
 # a name matches a lookup key (the right-hand side is ignored).
 # Continue long lines by starting the next line with whitespace.
 #
+# See also below, section "REJECTING MAIL FOR UNKNOWN LOCAL USERS".
+#
 #mydestination = $myhostname, localhost.$mydomain
 #mydestination = $myhostname, localhost.$mydomain $mydomain
 #mydestination = $myhostname, localhost.$mydomain, $mydomain,
 #      mail.$mydomain, www.$mydomain, ftp.$mydomain
 
-# REJECTING UNKNOWN LOCAL USERS
+# REJECTING MAIL FOR UNKNOWN LOCAL USERS
 #
 # The local_recipient_maps parameter specifies optional lookup tables
 # with all names or addresses of users that are local with respect
@@ -159,6 +163,9 @@ mail_owner = postfix
 # If this parameter is defined, then the SMTP server will reject
 # mail for unknown local users. This parameter is defined by default.
 #
+# To turn off local recipient checking in the SMTP server, specify
+# local_recipient_maps = (i.e. empty).
+#
 # The default setting assumes that you use the default Postfix local
 # delivery agent for local delivery. You need to update the
 # local_recipient_maps setting if:
@@ -175,11 +182,24 @@ mail_owner = postfix
 # - You use the "luser_relay", "mailbox_transport", or "fallback_transport"
 #   feature of the Postfix local delivery agent (see sample-local.cf).
 #
-# Beware: if the Postfix SMTP server runs chrooted, you may have to
-# copy the passwd (not shadow) database into the jail. This is
-# system dependent.
+# Beware: if the Postfix SMTP server runs chrooted, you probably have
+# to copy the passwd (not shadow) database into the jail, and perhaps
+# other files. This is system dependent.
 # 
-local_recipient_maps = unix:passwd.byname $alias_maps
+#local_recipient_maps = unix:passwd.byname $alias_maps
+#local_recipient_maps =
+
+# The unknown_local_recipient_reject_code specifies the SMTP server
+# response code when a recipient domain matches $mydestination or
+# $inet_interfaces, while $local_recipient_maps is non-empty and the
+# recipient address or address local-part is not found.
+#
+# The default setting is 550 (reject mail) but it is safer to start
+# with 450 (try again later) until you are certain that your
+# local_recipient_maps settings are OK.
+#
+#unknown_local_recipient_reject_code = 550
+unknown_local_recipient_reject_code = 450
 
 # TRUST AND RELAY CONTROL
 
@@ -282,7 +302,7 @@ local_recipient_maps = unix:passwd.byname $alias_maps
 # with all addresses in the domains that match $relay_domains.
 #
 # If this parameter is defined, then the SMTP server will reject
-# mail for unknown relay users.
+# mail for unknown relay users. This feature is off by default.
 # 
 #relay_recipient_maps = hash:/etc/postfix/relay_recipients
 
index ccdfc0fb5645d334887d1317a65546ccacaf70ce..88fae3a76b04177c150178662ff28e5bdbb6eb77 100644 (file)
@@ -498,7 +498,7 @@ EOF
        }
     done
 
-    # With 10000 active queue files, the active queue directory should
+    # With 20000 active queue files, the active queue directory should
     # be hashed, and so should the other directories, because they
     # can contain even more mail.
     #
@@ -520,6 +520,21 @@ EOF
        $POSTCONF -c $config_directory -e hash_queue_names="$found$missing" ||
            exit 1
     }
+
+    # Turn on safety nets for new features that could bounce mail that
+    # would be accepted by a previous Postfix version.
+
+    unknown_local=unknown_local_recipient_reject_code
+    has_lrm=`$POSTCONF -n local_recipient_maps`
+    has_lrjc=`$POSTCONF -n $unknown_local`
+
+    if [ -z "$has_lrm" -a -z "$has_lrjc" ]
+    then
+       echo SAFETY: editing main.cf, setting $unknown_local=450.
+       echo See the RELEASE_NOTES and $config_directory/main.cf for details.
+       $POSTCONF -e "$unknown_local = 450" || exit 1
+    fi
+
 }
 
 # A reminder if this is the first time Postfix is being installed.
index 44042f6bf6a2e83dd78bdf61335068807d323268..6d671287c83e8eacf6bb929ab4d564ab9016c82c 100644 (file)
@@ -200,7 +200,9 @@ max_use = 100
 # machine considers itself the final destination for.
 #
 # These domains are routed to the delivery agent specified with the 
-# local_transport parameter setting.
+# local_transport parameter setting. By default, that is the UNIX
+# compatible delivery agent that lookups all recipients in /etc/passwd
+# and /etc/aliases or their equivalent.
 #
 # The default is $myhostname + localhost.$mydomain.  On a mail domain
 # gateway, you should also include $mydomain. 
@@ -223,6 +225,11 @@ max_use = 100
 # a name matches a lookup key.  Continue long lines by starting the
 # next line with whitespace.
 #
+# See sample-local.cf for a description of the local_recipient_maps
+# and unknown_local_recipient_reject_code parameters. By default,
+# the SMTP server rejects mail for recipients not listed with the
+# local_recipient_maps parameter.
+#
 #mydestination = $myhostname, localhost.$mydomain $mydomain
 #mydestination = $myhostname, localhost.$mydomain www.$mydomain, ftp.$mydomain
 mydestination = $myhostname, localhost.$mydomain
index 9a82c179e46ad13e297d57e55f51e55824e19179..da140faf9a6c879daa558c258fb634809bd00b56 100644 (file)
@@ -434,6 +434,14 @@ allow_untrusted_routing = no
 #
 relay_domains = $mydestination
 
+# The relay_recipient_maps parameter specifies optional lookup tables
+# with all addresses in the domains that match $relay_domains.
+#
+# If this parameter is defined, then the SMTP server will reject
+# mail to unknown relay users. This feature is off by default.
+# 
+#relay_recipient_maps = hash:/etc/postfix/relay_recipients
+
 #
 # RESPONSE CODES
 #
index 2b36e7c4dd588241d729f05b916d3fcc93ca0cd0..65be2041040350b6c23edc60a1612ea52ae80697 100644 (file)
 #        Alternatively,  the  table  can  be provided as a regular-
 #        expression map where patterns are given as regular expres-
 #        sions.  In  that  case, the lookups are done in a slightly
-#        different way as described in the section titled  "REGULAR
-#        EXPRESSION TABLES".
+#        different way as described in section "REGULAR  EXPRESSION
+#        TABLES".
 # 
 # TABLE FORMAT
 #        The format of the transport table is as follows:
 # 
 #        pattern result
-#               When  pattern  matches  the  domain, use the corre-
-#               sponding result.
+#               When  pattern  matches  the  recipient  address  or
+#               domain, use the corresponding result.
 # 
 #        blank lines and comments
 #               Empty lines and whitespace-only lines are  ignored,
 #               line  that starts with whitespace continues a logi-
 #               cal line.
 # 
-#        In an indexed file, a pattern of `*' matches everything.
+#        The pattern specifies an email address, a domain name,  or
+#        a  domain  name  hierarchy, as described in section "TABLE
+#        LOOKUP".
 # 
 #        The result is of the form transport:nexthop.   The  trans-
 #        port  field  specifies  a  mail delivery transport such as
 #        smtp or local. The nexthop field specifies where  and  how
-#        to  deliver  mail. A null transport or nexthop field means
-#        "do not change": use the delivery  transport  and  nexthop
-#        information that would be used if no match were found.
+#        to deliver mail. More details are given in section "RESULT
+#        FORMAT".
 # 
-# TRANSPORT FIELD
-#        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).
-# 
-#        When a null transport field is specified, Postfix uses one
-#        of the following transports:
-# 
-#        $local_transport
-#               The domain matches $mydestination  or  $inet_inter-
-#               faces.
-# 
-#        $virtual_transport
-#               The domain matches $virtual_mailbox_domains.
-# 
-#        $relay_transport
-#               The domain matches $relay_transport.
-# 
-#        $default_transport
-#               All other non-local, non-virtual destinations.
-# 
-# NEXTHOP FIELD
-#        The  interpretation  of  the  nexthop  field  is transport
-#        dependent. In the case of SMTP, specify host:service for a
-#        non-default  server port, and use [host] or [host]:port in
-#        order to disable MX (mail exchanger) DNS lookups.  The  []
-#        form  can  also be used with IP addresses instead of host-
-#        names.
-# 
-# LOOKUP ORDER
+# TABLE LOOKUP
 #        With lookups from indexed files such as DB or DBM, or from
 #        networked  tables  such  as NIS, LDAP or SQL, patterns are
 #        tried in the order as listed below:
 #               ting.   Otherwise, a domain name matches itself and
 #               its subdomains.
 # 
-# NOTE
-#        The special pattern <> represents the  null  address,  and
-#        the  special  pattern  *  represents  any address (i.e. it
-#        functions as the wild-card pattern).
+#        Note 1: the special pattern * represents any address (i.e.
+#        it functions as the wild-card pattern).
+# 
+#        Note  2:  the  null  recipient address is looked up as the
+#        local  mailer-daemon  address  (mailer-daemon@fully-quali-
+#        fied-domain-name).
+# 
+# RESULT FORMAT
+#        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
+#        resets the nexthop information to the recipient domain.
+# 
+#        A  null  transport  field with non-null nexthop field does
+#        not modify the transport information.
+# 
+# TRANSPORT FIELD
+#        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).
+# 
+#        When a null transport field is specified, Postfix uses one
+#        of the following transports:
+# 
+#        $local_transport
+#               The  domain  matches $mydestination or $inet_inter-
+#               faces.
+# 
+#        $virtual_transport
+#               The domain matches $virtual_mailbox_domains.
+# 
+#        $relay_transport
+#               The domain matches $relay_transport.
+# 
+#        $default_transport
+#               All other non-local, non-virtual destinations.
+# 
+# NEXTHOP FIELD
+#        The interpretation  of  the  nexthop  field  is  transport
+#        dependent. In the case of SMTP, specify host:service for a
+#        non-default server port, and use [host] or [host]:port  in
+#        order  to  disable MX (mail exchanger) DNS lookups. The []
+#        form can also be used with IP addresses instead  of  host-
+#        names.
 # 
 # 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
-#        for all other destinations. Note that for  this  trick  to
-#        work  you  should  not  specify a relayhost in the main.cf
+#        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. Note that for this trick to
+#        work you should not specify a  relayhost  in  the  main.cf
 #        file.
 # 
 #             my.domain    :
 #             .my.domain   :
 #             *            smtp:outbound-relay.my.domain
 # 
-#        In order to send mail for foo.org and its  subdomains  via
+#        In  order  to send mail for foo.org and its subdomains via
 #        the uucp transport to the UUCP host named foo:
 # 
 #             foo.org      uucp:foo
 #             .foo.org     uucp:foo
 # 
-#        When  no  nexthop  host name is specified, the destination
-#        domain name is used instead. For  example,  the  following
-#        directs  mail for user@foo.org via the slow transport to a
-#        mail exchanger for foo.org.  The slow transport  could  be
-#        something  that  runs  at  most  one delivery process at a
+#        When no nexthop host name is  specified,  the  destination
+#        domain  name  is  used instead. For example, the following
+#        directs mail for user@foo.org via the slow transport to  a
+#        mail  exchanger  for foo.org.  The slow transport could be
+#        something that runs at most  one  delivery  process  at  a
 #        time:
 # 
 #             foo.org      slow:
 # 
 #        When no transport is specified, Postfix uses the transport
 #        that matches the address domain class (see TRANSPORT FIELD
-#        discussion above).   The  following  sends  all  mail  for
+#        discussion  above).   The  following  sends  all  mail for
 #        foo.org and its subdomains to host gateway.foo.org:
 # 
 #             foo.org      :[gateway.foo.org]
 #             .foo.org     :[gateway.foo.org]
 # 
-#        In  the  above  example,  the  []  are used to suppress MX
-#        lookups.  The result would  likely  point  to  your  local
+#        In the above example, the  []  are  used  to  suppress  MX
+#        lookups.   The  result  would  likely  point to your local
 #        machine.
 # 
-#        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:
 # 
 #             foo.org      smtp:bar.org:2025
 # 
-#        This directs mail for user@foo.org to  host  bar.org  port
-#        2025.  Instead  of a numerical port a symbolic name may be
-#        used. Specify [] around the hostname in order  to  disable
+#        This  directs  mail  for user@foo.org to host bar.org port
+#        2025. Instead of a numerical port a symbolic name  may  be
+#        used.  Specify  [] around the hostname in order to disable
 #        MX lookups.
 # 
 #        The error mailer can be used to bounce mail:
 # 
-#             .foo.org       error:mail for *.foo.org is not deliv-
+#             .foo.org      error:mail for *.foo.org is not  deliv-
 #        erable
 # 
-#        This causes  all  mail  for  user@anything.foo.org  to  be
+#        This  causes  all  mail  for  user@anything.foo.org  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
+#        Each  pattern  is  a regular expression that is applied to
 #        the entire domain being looked up. Thus, some.domain.hier-
 #        archy is not broken up into parent domains.
 # 
-#        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.
 # 
 # CONFIGURATION PARAMETERS
-#        The following main.cf parameters are  especially  relevant
-#        to  this  topic.  See  the Postfix main.cf file for syntax
-#        details and for default values.  Use  the  postfix  reload
+#        The  following  main.cf parameters are especially relevant
+#        to this topic. See the Postfix  main.cf  file  for  syntax
+#        details  and  for  default  values. Use the postfix reload
 #        command after a configuration change.
 # 
 #        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
 # 
 #        local_transport
 #               The default mail delivery transport when the desti-
-#               nation matches $mydestination or  $inet_interfaces.
+#               nation  matches $mydestination or $inet_interfaces.
 # 
 #        virtual_transport
 #               The default mail delivery transport when the desti-
 # 
 #        default_transport
 #               The default mail delivery transport when the desti-
-#               nation does not match a  local,  virtual  or  relay
+#               nation  does  not  match  a local, virtual or relay
 #               destination.
 # 
 #        mydestination
 #        regexp_table(5) format of POSIX regular expression tables
 # 
 # LICENSE
-#        The Secure Mailer license must be  distributed  with  this
+#        The  Secure  Mailer  license must be distributed with this
 #        software.
 # 
 # AUTHOR(S)
index 7d1221af64de1e6a88b24c95701d9f2435af4af7..cc416b07fa60a091118e3e7e0827db83d67c57ef 100644 (file)
@@ -145,18 +145,6 @@ SMTPD(8)                                                 SMTPD(8)
        <b>hopcount</b><i>_</i><b>limit</b>
               Limit the number of <b>Received:</b> message headers.
 
-       <b>local</b><i>_</i><b>recipient</b><i>_</i><b>maps</b>
-              List of maps with user  names  that  are  local  to
-              <b>$myorigin</b> or <b>$inet</b><i>_</i><b>interfaces</b>. If this parameter is
-              defined, then the  SMTP  server  rejects  mail  for
-              unknown local users.
-
-       <b>relay</b><i>_</i><b>recipient</b><i>_</i><b>maps</b>
-              List of maps that define all the email addresses in
-              the domains that  match  <b>$relay</b><i>_</i><b>domains</b>.   If  this
-              parameter  is defined, then the SMTP server rejects
-              mail for unknown relay recipients.
-
        <b>notify</b><i>_</i><b>classes</b>
               List of error classes. Of special interest are:
 
@@ -195,9 +183,35 @@ SMTPD(8)                                                 SMTPD(8)
               The characters that Postfix accepts as VERP  delim-
               iter characters.
 
+<b>Known</b> <b>versus</b> <b>unknown</b> <b>recipients</b>
+       <b>unknown</b><i>_</i><b>local</b><i>_</i><b>recipient</b><i>_</i><b>reject</b><i>_</i><b>code</b>
+              The response code when a client specifies a recipi-
+              ent  whose   domain   matches   <b>$mydestination</b>   or
+              <b>$inet</b><i>_</i><b>interfaces</b>,  while  <b>$local</b><i>_</i><b>recipient</b><i>_</i><b>maps</b>  is
+              non-empty and does not list the  recipient  address
+              or address local-part.
+
+       <b>unknown</b><i>_</i><b>relay</b><i>_</i><b>recipient</b><i>_</i><b>reject</b><i>_</i><b>code</b>
+              The response code when a client specifies a recipi-
+              ent  whose  domain  matches  <b>$relay</b><i>_</i><b>domains</b>,  while
+              <b>$relay</b><i>_</i><b>recipient</b><i>_</i><b>maps</b>  is  non-empty  and  does not
+              list the recipient address.
+
+       <b>unknown</b><i>_</i><b>virtual</b><i>_</i><b>alias</b><i>_</i><b>reject</b><i>_</i><b>code</b>
+              The response code when a client specifies a recipi-
+              ent  whose  domain  matches <b>$virtual</b><i>_</i><b>alias</b><i>_</i><b>domains</b>,
+              while  the  recipient  is  not  listed   in   <b>$vir-</b>
+              <b>tual</b><i>_</i><b>alias</b><i>_</i><b>maps</b>.
+
+       <b>unknown</b><i>_</i><b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>reject</b><i>_</i><b>code</b>
+              The response code when a client specifies a recipi-
+              ent whose domain matches  <b>$virtual</b><i>_</i><b>mailbox</b><i>_</i><b>domains</b>,
+              while the recipient is not listed in <b>$virtual</b><i>_</i><b>mail-</b>
+              <b>box</b><i>_</i><b>maps</b>.
+
 <b>Resource</b> <b>controls</b>
        <b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>
-              Limit  the  amount  of memory in bytes used for the
+              Limit the amount of memory in bytes  used  for  the
               handling of partial input lines.
 
        <b>message</b><i>_</i><b>size</b><i>_</i><b>limit</b>
@@ -205,8 +219,8 @@ SMTPD(8)                                                 SMTPD(8)
               ing on-disk storage for envelope information.
 
        <b>queue</b><i>_</i><b>minfree</b>
-              Minimal  amount of free space in bytes in the queue
-              file system for the SMTP server to accept any  mail
+              Minimal amount of free space in bytes in the  queue
+              file  system for the SMTP server to accept any mail
               at all.
 
        <b>smtpd</b><i>_</i><b>history</b><i>_</i><b>flush</b><i>_</i><b>threshold</b>
@@ -221,23 +235,23 @@ SMTPD(8)                                                 SMTPD(8)
 
        <b>smtpd</b><i>_</i><b>soft</b><i>_</i><b>error</b><i>_</i><b>limit</b>
               When an SMTP client has made this number of errors,
-              wait  <i>error_count</i>  seconds before responding to any
+              wait <i>error_count</i> seconds before responding  to  any
               client request.
 
        <b>smtpd</b><i>_</i><b>hard</b><i>_</i><b>error</b><i>_</i><b>limit</b>
-              Disconnect after a client has made this  number  of
+              Disconnect  after  a client has made this number of
               errors.
 
        <b>smtpd</b><i>_</i><b>junk</b><i>_</i><b>command</b><i>_</i><b>limit</b>
               Limit the number of times a client can issue a junk
-              command such as NOOP, VRFY, ETRN  or  RSET  in  one
-              SMTP  session  before  it  is penalized with tarpit
+              command  such  as  NOOP,  VRFY, ETRN or RSET in one
+              SMTP session before it  is  penalized  with  tarpit
               delays.
 
 <b>UCE</b> <b>control</b> <b>restrictions</b>
        <b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdomains</b>
-              List of Postfix features that use  <i>domain.tld</i>  pat-
-              terns   to  match  <i>sub.domain.tld</i>  (as  opposed  to
+              List  of  Postfix features that use <i>domain.tld</i> pat-
+              terns  to  match  <i>sub.domain.tld</i>  (as  opposed   to
               requiring <i>.domain.tld</i> patterns).
 
        <b>smtpd</b><i>_</i><b>client</b><i>_</i><b>restrictions</b>
@@ -245,19 +259,19 @@ SMTPD(8)                                                 SMTPD(8)
               tem.
 
        <b>smtpd</b><i>_</i><b>helo</b><i>_</i><b>required</b>
-              Require  that  clients  introduce themselves at the
+              Require that clients introduce  themselves  at  the
               beginning of an SMTP session.
 
        <b>smtpd</b><i>_</i><b>helo</b><i>_</i><b>restrictions</b>
-              Restrict what client hostnames are allowed in  <b>HELO</b>
+              Restrict  what client hostnames are allowed in <b>HELO</b>
               and <b>EHLO</b> commands.
 
        <b>smtpd</b><i>_</i><b>sender</b><i>_</i><b>restrictions</b>
-              Restrict  what sender addresses are allowed in <b>MAIL</b>
+              Restrict what sender addresses are allowed in  <b>MAIL</b>
               <b>FROM</b> commands.
 
        <b>smtpd</b><i>_</i><b>recipient</b><i>_</i><b>restrictions</b>
-              Restrict what recipient addresses  are  allowed  in
+              Restrict  what  recipient  addresses are allowed in
               <b>RCPT</b> <b>TO</b> commands.
 
        <b>smtpd</b><i>_</i><b>etrn</b><i>_</i><b>restrictions</b>
@@ -265,73 +279,73 @@ SMTPD(8)                                                 SMTPD(8)
               mands, and what clients may issue <b>ETRN</b> commands.
 
        <b>smtpd</b><i>_</i><b>data</b><i>_</i><b>restrictions</b>
-              Restrictions on the <b>DATA</b>  command.  Currently,  the
-              only   restriction   that   makes   sense  here  is
+              Restrictions  on  the  <b>DATA</b> command. Currently, the
+              only  restriction  that   makes   sense   here   is
               <b>reject</b><i>_</i><b>unauth</b><i>_</i><b>pipelining</b>.
 
        <b>allow</b><i>_</i><b>untrusted</b><i>_</i><b>routing</b>
-              Allow untrusted clients to specify  addresses  with
-              sender-specified  routing.   Enabling this opens up
-              nasty relay loopholes involving trusted  backup  MX
+              Allow  untrusted  clients to specify addresses with
+              sender-specified routing.  Enabling this  opens  up
+              nasty  relay  loopholes involving trusted backup MX
               hosts.
 
        <b>smtpd</b><i>_</i><b>restriction</b><i>_</i><b>classes</b>
-              Declares  the  name of zero or more parameters that
-              contain a list of UCE restrictions.  The  names  of
-              these  parameters  can  then be used instead of the
+              Declares the name of zero or more  parameters  that
+              contain  a  list  of UCE restrictions. The names of
+              these parameters can then be used  instead  of  the
               restriction lists that they represent.
 
        <b>smtpd</b><i>_</i><b>null</b><i>_</i><b>access</b><i>_</i><b>lookup</b><i>_</i><b>key</b>
-              The lookup key to be used in  SMTPD  access  tables
-              instead  of  the null sender address. A null sender
+              The  lookup  key  to be used in SMTPD access tables
+              instead of the null sender address. A  null  sender
               address cannot be looked up.
 
        <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b> (deprecated)
-              List of DNS domains that publish the  addresses  of
+              List  of  DNS domains that publish the addresses of
               blacklisted hosts. This is used with the deprecated
               <b>reject</b><i>_</i><b>maps</b><i>_</i><b>rbl</b> restriction.
 
        <b>permit</b><i>_</i><b>mx</b><i>_</i><b>backup</b><i>_</i><b>networks</b>
-              Only domains  whose  primary  MX  hosts  match  the
-              listed   networks   are   eligible   for  the  <b>per-</b>
+              Only  domains  whose  primary  MX  hosts  match the
+              listed  networks  are   eligible   for   the   <b>per-</b>
               <b>mit</b><i>_</i><b>mx</b><i>_</i><b>backup</b> feature.
 
        <b>relay</b><i>_</i><b>domains</b>
-              Restrict what domains this mail system  will  relay
-              mail  to.  The  domains  are routed to the delivery
+              Restrict  what  domains this mail system will relay
+              mail to. The domains are  routed  to  the  delivery
               agent specified with the <b>relay</b><i>_</i><b>transport</b> setting.
 
 <b>UCE</b> <b>control</b> <b>responses</b>
        <b>access</b><i>_</i><b>map</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Response code when  a  client  violates  an  access
+              Response  code  when  a  client  violates an access
               database restriction.
 
        <b>default</b><i>_</i><b>rbl</b><i>_</i><b>reply</b>
               Default template reply when a request is RBL black-
-              listed.  This template is used by the  <b>reject</b><i>_</i><b>rbl</b><i>_</i><b>*</b>
-              and    <b>reject</b><i>_</i><b>rhsbl</b><i>_</i><b>*</b>   restrictions.   See   also:
+              listed.   This template is used by the <b>reject</b><i>_</i><b>rbl</b><i>_</i><b>*</b>
+              and   <b>reject</b><i>_</i><b>rhsbl</b><i>_</i><b>*</b>   restrictions.   See    also:
               <b>rbl</b><i>_</i><b>reply</b><i>_</i><b>maps</b> and <b>smtpd</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>.
 
        <b>defer</b><i>_</i><b>code</b>
-              Response code when a client request is rejected  by
+              Response  code when a client request is rejected by
               the <b>defer</b> restriction.
 
        <b>invalid</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Response   code   when   a   client   violates  the
+              Response  code   when   a   client   violates   the
               <b>reject</b><i>_</i><b>invalid</b><i>_</i><b>hostname</b> restriction.
 
        <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>reject</b><i>_</i><b>code</b>
               Response code when a request is RBL blacklisted.
 
        <b>rbl</b><i>_</i><b>reply</b><i>_</i><b>maps</b>
-              Table with template responses for  RBL  blacklisted
-              requests,  indexed  by  RBL domain name. These tem-
+              Table  with  template responses for RBL blacklisted
+              requests, indexed by RBL domain  name.  These  tem-
               plates   are   used   by   the   <b>reject</b><i>_</i><b>rbl</b><i>_</i><b>*</b>   and
-              <b>reject</b><i>_</i><b>rhsbl</b><i>_</i><b>*</b>      restrictions.     See     also:
+              <b>reject</b><i>_</i><b>rhsbl</b><i>_</i><b>*</b>     restrictions.     See      also:
               <b>default</b><i>_</i><b>rbl</b><i>_</i><b>reply</b> and <b>smtpd</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>.
 
        <b>reject</b><i>_</i><b>code</b>
-              Response code when  the  client  matches  a  <b>reject</b>
+              Response  code  when  the  client  matches a <b>reject</b>
               restriction.
 
        <b>relay</b><i>_</i><b>domains</b><i>_</i><b>reject</b><i>_</i><b>code</b>
@@ -339,7 +353,7 @@ SMTPD(8)                                                 SMTPD(8)
               mail relay policy.
 
        <b>unknown</b><i>_</i><b>address</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Response  code   when   a   client   violates   the
+              Response   code   when   a   client   violates  the
               <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>address</b> restriction.
 
        <b>unknown</b><i>_</i><b>client</b><i>_</i><b>reject</b><i>_</i><b>code</b>
@@ -348,7 +362,7 @@ SMTPD(8)                                                 SMTPD(8)
               tion.
 
        <b>unknown</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b>
-              Response   code   when   a   client   violates  the
+              Response  code   when   a   client   violates   the
               <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>hostname</b> restriction.
 
 <b>SEE</b> <b>ALSO</b>
@@ -358,7 +372,7 @@ SMTPD(8)                                                 SMTPD(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>AUTHOR(S)</b>
index 613240673b55adf8b1de0dcdf4be30c7ccde7b83..58543b89302998fda8408089f83da5b25ea85643 100644 (file)
@@ -31,15 +31,15 @@ TRANSPORT(5)                                         TRANSPORT(5)
        Alternatively,  the  table  can  be provided as a regular-
        expression map where patterns are given as regular expres-
        sions.  In  that  case, the lookups are done in a slightly
-       different way as described in the section titled  "REGULAR
-       EXPRESSION TABLES".
+       different way as described in section "REGULAR  EXPRESSION
+       TABLES".
 
 <b>TABLE</b> <b>FORMAT</b>
        The format of the transport table is as follows:
 
        <i>pattern</i> <i>result</i>
-              When  <i>pattern</i>  matches  the  domain, use the corre-
-              sponding <i>result</i>.
+              When  <i>pattern</i>  matches  the  recipient  address  or
+              domain, use the corresponding <i>result</i>.
 
        blank lines and comments
               Empty lines and whitespace-only lines are  ignored,
@@ -51,45 +51,17 @@ TRANSPORT(5)                                         TRANSPORT(5)
               line  that starts with whitespace continues a logi-
               cal line.
 
-       In an indexed file, a pattern of `<b>*</b>' matches everything.
+       The <i>pattern</i> specifies an email address, a domain name,  or
+       a  domain  name  hierarchy, as described in section "TABLE
+       LOOKUP".
 
        The <i>result</i> is of the form <i>transport</i><b>:</b><i>nexthop</i>.   The  <i>trans-</i>
        <i>port</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. A null <i>transport</i> or <i>nexthop</i> field means
-       "do not change": use the delivery  transport  and  nexthop
-       information that would be used if no match were found.
+       to deliver mail. More details are given in section "RESULT
+       FORMAT".
 
-<b>TRANSPORT</b> <b>FIELD</b>
-       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).
-
-       When a null transport field is specified, Postfix uses one
-       of the following transports:
-
-       <b>$local</b><i>_</i><b>transport</b>
-              The domain matches <b>$mydestination</b>  or  <b>$inet</b><i>_</i><b>inter-</b>
-              <b>faces</b>.
-
-       <b>$virtual</b><i>_</i><b>transport</b>
-              The domain matches <b>$virtual</b><i>_</i><b>mailbox</b><i>_</i><b>domains</b>.
-
-       <b>$relay</b><i>_</i><b>transport</b>
-              The domain matches <b>$relay</b><i>_</i><b>transport</b>.
-
-       <b>$default</b><i>_</i><b>transport</b>
-              All other non-local, non-virtual destinations.
-
-<b>NEXTHOP</b> <b>FIELD</b>
-       The  interpretation  of  the  nexthop  field  is transport
-       dependent. In the case of SMTP, specify <i>host</i>:<i>service</i> for a
-       non-default  server port, and use [<i>host</i>] or [<i>host</i>]:<i>port</i> in
-       order to disable MX (mail exchanger) DNS lookups.  The  []
-       form  can  also be used with IP addresses instead of host-
-       names.
-
-<b>LOOKUP</b> <b>ORDER</b>
+<b>TABLE</b> <b>LOOKUP</b>
        With lookups from indexed files such as DB or DBM, or from
        networked  tables  such  as NIS, LDAP or SQL, patterns are
        tried in the order as listed below:
@@ -114,96 +86,139 @@ TRANSPORT(5)                                         TRANSPORT(5)
               ting.   Otherwise, a domain name matches itself and
               its subdomains.
 
-<b>NOTE</b>
-       The special pattern &lt;&gt; represents the  null  address,  and
-       the  special  pattern  <b>*</b>  represents  any address (i.e. it
-       functions as the wild-card pattern).
+       Note 1: the special pattern <b>*</b> represents any address (i.e.
+       it functions as the wild-card pattern).
+
+       Note  2:  the  null  recipient address is looked up as the
+       local  mailer-daemon  address  (mailer-daemon@fully-quali-
+       fied-domain-name).
+
+<b>RESULT</b> <b>FORMAT</b>
+       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
+       resets the nexthop information to the recipient domain.
+
+       A  null  <i>transport</i>  field with non-null <i>nexthop</i> field does
+       not modify the transport information.
+
+<b>TRANSPORT</b> <b>FIELD</b>
+       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).
+
+       When a null transport field is specified, Postfix uses one
+       of the following transports:
+
+       <b>$local</b><i>_</i><b>transport</b>
+              The  domain  matches <b>$mydestination</b> or <b>$inet</b><i>_</i><b>inter-</b>
+              <b>faces</b>.
+
+       <b>$virtual</b><i>_</i><b>transport</b>
+              The domain matches <b>$virtual</b><i>_</i><b>mailbox</b><i>_</i><b>domains</b>.
+
+       <b>$relay</b><i>_</i><b>transport</b>
+              The domain matches <b>$relay</b><i>_</i><b>transport</b>.
+
+       <b>$default</b><i>_</i><b>transport</b>
+              All other non-local, non-virtual destinations.
+
+<b>NEXTHOP</b> <b>FIELD</b>
+       The interpretation  of  the  nexthop  field  is  transport
+       dependent. In the case of SMTP, specify <i>host</i>:<i>service</i> for a
+       non-default server port, and use [<i>host</i>] or [<i>host</i>]:<i>port</i>  in
+       order  to  disable MX (mail exchanger) DNS lookups. The []
+       form can also be used with IP addresses instead  of  host-
+       names.
 
 <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
-       for all other destinations. Note that for  this  trick  to
-       work  you  should  not  specify a <b>relayhost</b> in the <b>main.cf</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
+       for  all  other  destinations. Note that for this trick to
+       work you should not specify a  <b>relayhost</b>  in  the  <b>main.cf</b>
        file.
 
             <b>my.domain</b>    <b>:</b>
             <b>.my.domain</b>   <b>:</b>
             <b>*</b>            <b>smtp:outbound-relay.my.domain</b>
 
-       In order to send mail for <b>foo.org</b> and its  subdomains  via
+       In  order  to send mail for <b>foo.org</b> and its subdomains via
        the <b>uucp</b> transport to the UUCP host named <b>foo</b>:
 
             <b>foo.org</b>      <b>uucp:foo</b>
             <b>.foo.org</b>     <b>uucp:foo</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>foo.org</b> via the <b>slow</b> transport to a
-       mail exchanger for <b>foo.org</b>.  The <b>slow</b> transport  could  be
-       something  that  runs  at  most  one delivery process at a
+       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>foo.org</b> via the <b>slow</b> transport to  a
+       mail  exchanger  for <b>foo.org</b>.  The <b>slow</b> transport could be
+       something that runs at most  one  delivery  process  at  a
        time:
 
             <b>foo.org</b>      <b>slow:</b>
 
        When no transport is specified, Postfix uses the transport
        that matches the address domain class (see TRANSPORT FIELD
-       discussion above).   The  following  sends  all  mail  for
+       discussion  above).   The  following  sends  all  mail for
        <b>foo.org</b> and its subdomains to host <b>gateway.foo.org</b>:
 
             <b>foo.org</b>      <b>:[gateway.foo.org]</b>
             <b>.foo.org</b>     <b>:[gateway.foo.org]</b>
 
-       In  the  above  example,  the  []  are used to suppress MX
-       lookups.  The result would  likely  point  to  your  local
+       In the above example, the  []  are  used  to  suppress  MX
+       lookups.   The  result  would  likely  point to your local
        machine.
 
-       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>foo.org</b>      <b>smtp:bar.org:2025</b>
 
-       This directs mail for <i>user</i>@<b>foo.org</b> to  host  <b>bar.org</b>  port
-       <b>2025</b>.  Instead  of a numerical port a symbolic name may be
-       used. Specify [] around the hostname in order  to  disable
+       This  directs  mail  for <i>user</i>@<b>foo.org</b> to host <b>bar.org</b> port
+       <b>2025</b>. Instead of a numerical port a symbolic name  may  be
+       used.  Specify  [] around the hostname in order to disable
        MX lookups.
 
        The error mailer can be used to bounce mail:
 
-            <b>.foo.org</b>       <b>error:mail</b> <b>for</b> <b>*.foo.org</b> <b>is</b> <b>not</b> <b>deliv-</b>
+            <b>.foo.org</b>      <b>error:mail</b> <b>for</b> <b>*.foo.org</b> <b>is</b> <b>not</b>  <b>deliv-</b>
        <b>erable</b>
 
-       This causes  all  mail  for  <i>user</i>@<i>anything</i><b>.foo.org</b>  to  be
+       This  causes  all  mail  for  <i>user</i>@<i>anything</i><b>.foo.org</b>  to be
        bounced.
 
 <b>REGULAR</b> <b>EXPRESSION</b> <b>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</b><i>_</i><b>table</b>(5)</a> or <a href="pcre_table.5.html"><b>pcre</b><i>_</i><b>table</b>(5)</a>.
 
-       Each pattern is a regular expression that  is  applied  to
+       Each  pattern  is  a regular expression that is applied to
        the entire domain being looked up. Thus, <i>some.domain.hier-</i>
        <i>archy</i> is not broken up into parent domains.
 
-       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>CONFIGURATION</b> <b>PARAMETERS</b>
-       The following <b>main.cf</b> parameters are  especially  relevant
-       to  this  topic.  See  the Postfix <b>main.cf</b> file for syntax
-       details and for default values.  Use  the  <b>postfix</b>  <b>reload</b>
+       The  following  <b>main.cf</b> parameters are especially relevant
+       to this topic. See the Postfix  <b>main.cf</b>  file  for  syntax
+       details  and  for  default  values. Use the <b>postfix</b> <b>reload</b>
        command after a configuration change.
 
        <b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdomains</b>
-              List  of  Postfix features that use <i>domain.tld</i> pat-
-              terns  to  match  <i>sub.domain.tld</i>  (as  opposed   to
+              List of Postfix features that use  <i>domain.tld</i>  pat-
+              terns   to  match  <i>sub.domain.tld</i>  (as  opposed  to
               requiring <i>.domain.tld</i> patterns).
 
        <b>transport</b><i>_</i><b>maps</b>
@@ -213,7 +228,7 @@ TRANSPORT(5)                                         TRANSPORT(5)
 
        <b>local</b><i>_</i><b>transport</b>
               The default mail delivery transport when the desti-
-              nation matches <b>$mydestination</b> or  <b>$inet</b><i>_</i><b>interfaces</b>.
+              nation  matches <b>$mydestination</b> or <b>$inet</b><i>_</i><b>interfaces</b>.
 
        <b>virtual</b><i>_</i><b>transport</b>
               The default mail delivery transport when the desti-
@@ -225,7 +240,7 @@ TRANSPORT(5)                                         TRANSPORT(5)
 
        <b>default</b><i>_</i><b>transport</b>
               The default mail delivery transport when the desti-
-              nation does not match a  local,  virtual  or  relay
+              nation  does  not  match  a local, virtual or relay
               destination.
 
        <b>mydestination</b>
@@ -244,7 +259,7 @@ TRANSPORT(5)                                         TRANSPORT(5)
        <a href="regexp_table.5.html">regexp_table(5)</a> format of POSIX regular expression tables
 
 <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 b1c3d48364df6327ef8d21ad3a77b8376f97cef5..508bfca2b9709d72609598babb0f38f13838d336 100644 (file)
@@ -127,17 +127,6 @@ TRIVIAL-REWRITE(8)                             TRIVIAL-REWRITE(8)
               Syntax  is  <i>transport</i>:<i>nexthop</i>; see <a href="transport.5.html"><b>transport</b>(5)</a> for
               details. The :<i>nexthop</i> part is optional.
 
-       <b>error</b><i>_</i><b>transport</b>
-              Where to deliver mail for  non-existent  recipients
-              in  domains  that  match <b>virtual</b><i>_</i><b>alias</b><i>_</i><b>domains</b> (all
-              recipients in simulated  virtual  domains  must  be
-              aliased  to  some other local or remote domain), or
-              for recipients that have moved.  The default trans-
-              port is <b>error</b>.
-
-              Syntax  is  <i>transport</i>:<i>nexthop</i>; see <a href="transport.5.html"><b>transport</b>(5)</a> for
-              details. The :<i>nexthop</i> part is optional.
-
        <b>virtual</b><i>_</i><b>transport</b>
               Where to deliver mail for  non-local  domains  that
               match <b>$virtual</b><i>_</i><b>mailbox</b><i>_</i><b>domains</b>.  The default trans-
@@ -178,9 +167,6 @@ TRIVIAL-REWRITE(8)                             TRIVIAL-REWRITE(8)
               List  of tables with <i>domain</i> to (<i>transport,</i> <i>nexthop</i>)
               mappings.
 
-       <b>transport</b><i>_</i><b>null</b><i>_</i><b>address</b><i>_</i><b>lookup</b><i>_</i><b>key</b>
-              Lookup key to be used for the null address.
-
 <b>SEE</b> <b>ALSO</b>
        <a href="master.8.html">master(8)</a> process manager
        syslogd(8) system logging
index 24e9487c3576824ea70d6976768230fff31b4e3d..c35b35420381df2d3dd13b7ff759d18f2fd411ee 100644 (file)
@@ -33,7 +33,7 @@ or SQL, the same lookups are done as for ordinary indexed files.
 Alternatively, the table can be provided as a regular-expression
 map where patterns are given as regular expressions. In that case,
 the lookups are done in a slightly different way as described
-in the section titled "REGULAR EXPRESSION TABLES".
+in section "REGULAR EXPRESSION TABLES".
 .SH TABLE FORMAT
 .na
 .nf
@@ -41,8 +41,8 @@ in the section titled "REGULAR EXPRESSION TABLES".
 .fi
 The format of the transport table is as follows:
 .IP "\fIpattern result\fR"
-When \fIpattern\fR matches the domain, use the corresponding
-\fIresult\fR.
+When \fIpattern\fR matches the recipient address or domain, use the
+corresponding \fIresult\fR.
 .IP "blank lines and comments"
 Empty lines and whitespace-only lines are ignored, as
 are lines whose first non-whitespace character is a `#'.
@@ -50,15 +50,55 @@ are lines whose first non-whitespace character is a `#'.
 A logical line starts with non-whitespace text. A line that
 starts with whitespace continues a logical line.
 .PP
-In an indexed file, a pattern of `\fB*\fR' matches everything.
-.PP
+The \fIpattern\fR specifies an email address, a domain name, or
+a domain name hierarchy, as described in section "TABLE LOOKUP".
+
 The \fIresult\fR is of the form \fItransport\fB:\fInexthop\fR.
 The \fItransport\fR field specifies a mail delivery transport
 such as \fBsmtp\fR or \fBlocal\fR. The \fInexthop\fR field
-specifies where and how to deliver mail. A null \fItransport\fR
-or \fInexthop\fR field means "do not change": use the delivery
-transport and nexthop information that would be used if no
-match were found.
+specifies where and how to deliver mail. More details are given
+in section "RESULT FORMAT".
+.SH TABLE LOOKUP
+.ad
+.fi
+With lookups from indexed files such as DB or DBM, or from networked
+tables such as NIS, LDAP or SQL, patterns are tried in the order as
+listed below:
+.IP "\fIuser+extension@domain transport\fR:\fInexthop\fR"
+Mail for \fIuser+extension@domain\fR is delivered through
+\fItransport\fR to
+\fInexthop\fR.
+.IP "\fIuser@domain transport\fR:\fInexthop\fR"
+Mail for \fIuser@domain\fR is delivered through \fItransport\fR to
+\fInexthop\fR.
+.IP "\fIdomain transport\fR:\fInexthop\fR"
+Mail for \fIdomain\fR is delivered through \fItransport\fR to
+\fInexthop\fR.
+.IP "\fI.domain transport\fR:\fInexthop\fR"
+Mail for any subdomain of \fIdomain\fR is delivered through
+\fItransport\fR to \fInexthop\fR. This applies only when the
+string \fBtransport_maps\fR is not listed in the
+\fBparent_domain_matches_subdomains\fR configuration setting.
+Otherwise, a domain name matches itself and its subdomains.
+.PP
+Note 1: the special pattern \fB*\fR represents any address (i.e. it
+functions as the wild-card pattern).
+
+Note 2: the null recipient address is looked up as the local
+mailer-daemon address (mailer-daemon@fully-qualified-domain-name).
+.SH RESULT FORMAT
+.ad
+.fi
+
+A null \fItransport\fR and null \fInexthop\fR result means "do
+not change": use the delivery transport and nexthop information
+that would be used when the entire transport table did not exist.
+
+A non-null \fItransport\fR field with a null \fInexthop\fR field
+resets the nexthop information to the recipient domain.
+
+A null \fItransport\fR field with non-null \fInexthop\fR field
+does not modify the transport information.
 .SH TRANSPORT FIELD
 .ad
 .fi
@@ -84,37 +124,6 @@ dependent. In the case of SMTP, specify \fIhost\fR:\fIservice\fR for a
 non-default server port, and use [\fIhost\fR] or [\fIhost\fR]:\fIport\fR
 in order to disable MX (mail exchanger) DNS lookups. The [] form
 can also be used with IP addresses instead of hostnames.
-.SH LOOKUP ORDER
-.ad
-.fi
-With lookups from indexed files such as DB or DBM, or from networked
-tables such as NIS, LDAP or SQL, patterns are tried in the order as
-listed below:
-.IP "\fIuser+extension@domain transport\fR:\fInexthop\fR"
-Mail for \fIuser+extension@domain\fR is delivered through
-\fItransport\fR to
-\fInexthop\fR.
-.IP "\fIuser@domain transport\fR:\fInexthop\fR"
-Mail for \fIuser@domain\fR is delivered through \fItransport\fR to
-\fInexthop\fR.
-.IP "\fIdomain transport\fR:\fInexthop\fR"
-Mail for \fIdomain\fR is delivered through \fItransport\fR to
-\fInexthop\fR.
-.IP "\fI.domain transport\fR:\fInexthop\fR"
-Mail for any subdomain of \fIdomain\fR is delivered through
-\fItransport\fR to \fInexthop\fR. This applies only when the
-string \fBtransport_maps\fR is not listed in the
-\fBparent_domain_matches_subdomains\fR configuration setting.
-Otherwise, a domain name matches itself and its subdomains.
-.PP
-.SH NOTE
-.na
-.nf
-.ad
-.fi
-The special pattern \fB<>\fR represents the null address, and the
-special pattern \fB*\fR represents any address (i.e. it functions
-as the wild-card pattern).
 .SH EXAMPLES
 .na
 .nf
index 8914156c03867709481883fbcf05b923032c9cc2..7136742668ac315598a87b254c7167fb3456f62d 100644 (file)
@@ -132,14 +132,6 @@ XVERP command is specified without explicit delimiters.
 Recipient of protocol/policy/resource/software error notices.
 .IP \fBhopcount_limit\fR
 Limit the number of \fBReceived:\fR message headers.
-.IP \fBlocal_recipient_maps\fR
-List of maps with user names that are local to \fB$myorigin\fR
-or \fB$inet_interfaces\fR. If this parameter is defined,
-then the SMTP server rejects mail for unknown local users.
-.IP \fBrelay_recipient_maps\fR
-List of maps that define all the email addresses in the domains
-that match \fB$relay_domains\fR.  If this parameter is defined,
-then the SMTP server rejects mail for unknown relay recipients.
 .IP \fBnotify_classes\fR
 List of error classes. Of special interest are:
 .RS
@@ -167,6 +159,26 @@ Change hard (5xx) reject responses into soft (4xx) reject responses.
 This can be useful for testing purposes.
 .IP \fBverp_delimiter_filter\fR
 The characters that Postfix accepts as VERP delimiter characters.
+.SH "Known versus unknown recipients"
+.ad
+.fi
+.IP \fBunknown_local_recipient_reject_code\fR
+The response code when a client specifies a recipient whose domain
+matches \fB$mydestination\fR or \fB$inet_interfaces\fR, while
+\fB$local_recipient_maps\fR is non-empty and does not list
+the recipient address or address local-part.
+.IP \fBunknown_relay_recipient_reject_code\fR
+The response code when a client specifies a recipient whose domain
+matches \fB$relay_domains\fR, while \fB$relay_recipient_maps\fR
+is non-empty and does not list the recipient address.
+.IP \fBunknown_virtual_alias_reject_code\fR
+The response code when a client specifies a recipient whose domain
+matches \fB$virtual_alias_domains\fR, while the recipient is not
+listed in \fB$virtual_alias_maps\fR.
+.IP \fBunknown_virtual_mailbox_reject_code\fR
+The response code when a client specifies a recipient whose domain
+matches \fB$virtual_mailbox_domains\fR, while the recipient is not
+listed in \fB$virtual_mailbox_maps\fR.
 .SH "Resource controls"
 .ad
 .fi
index 2bf08c72d6f95d8acd95e881712c094301e36009..b299a9c96ddeaf6fbbaf0d54e183ee4e15e6244a 100644 (file)
@@ -117,15 +117,6 @@ The default transport is \fBlocal\fR.
 .sp
 Syntax is \fItransport\fR:\fInexthop\fR; see \fBtransport\fR(5)
 for details. The :\fInexthop\fR part is optional.
-.IP \fBerror_transport\fR
-Where to deliver mail for non-existent recipients in domains
-that match \fBvirtual_alias_domains\fR (all recipients
-in simulated virtual domains must be aliased to some other
-local or remote domain), or for recipients that have moved.
-The default transport is \fBerror\fR.
-.sp
-Syntax is \fItransport\fR:\fInexthop\fR; see \fBtransport\fR(5)
-for details. The :\fInexthop\fR part is optional.
 .IP \fBvirtual_transport\fR
 Where to deliver mail for non-local domains that match
 \fB$virtual_mailbox_domains\fR.
@@ -160,8 +151,6 @@ to the destination's mail exchanger.
 .IP \fBtransport_maps\fR
 List of tables with \fIdomain\fR to (\fItransport, nexthop\fR)
 mappings.
-.IP \fBtransport_null_address_lookup_key\fR
-Lookup key to be used for the null address.
 .SH SEE ALSO
 .na
 .nf
index 0ebd73bbf32eb384a684dd86b6c5a829f1b0d72a..c8634c45bb82a198edaf9feedfb1ab0d99d9706d 100644 (file)
 #      Alternatively, the table can be provided as a regular-expression
 #      map where patterns are given as regular expressions. In that case,
 #      the lookups are done in a slightly different way as described
-#      in the section titled "REGULAR EXPRESSION TABLES".
+#      in section "REGULAR EXPRESSION TABLES".
 # TABLE FORMAT
 # .ad
 # .fi
 #      The format of the transport table is as follows:
 # .IP "\fIpattern result\fR"
-#      When \fIpattern\fR matches the domain, use the corresponding
-#       \fIresult\fR.
+#      When \fIpattern\fR matches the recipient address or domain, use the
+#      corresponding \fIresult\fR.
 # .IP "blank lines and comments"
 #      Empty lines and whitespace-only lines are ignored, as
 #      are lines whose first non-whitespace character is a `#'.
 #      A logical line starts with non-whitespace text. A line that
 #      starts with whitespace continues a logical line.
 # .PP
-#      In an indexed file, a pattern of `\fB*\fR' matches everything.
-# .PP
+#      The \fIpattern\fR specifies an email address, a domain name, or
+#      a domain name hierarchy, as described in section "TABLE LOOKUP".
+#
 #      The \fIresult\fR is of the form \fItransport\fB:\fInexthop\fR.
 #      The \fItransport\fR field specifies a mail delivery transport
 #      such as \fBsmtp\fR or \fBlocal\fR. The \fInexthop\fR field
-#      specifies where and how to deliver mail. A null \fItransport\fR
-#      or \fInexthop\fR field means "do not change": use the delivery
-#      transport and nexthop information that would be used if no
-#      match were found.
+#      specifies where and how to deliver mail. More details are given
+#      in section "RESULT FORMAT".
+# .SH TABLE LOOKUP
+# .ad
+# .fi
+#      With lookups from indexed files such as DB or DBM, or from networked
+#      tables such as NIS, LDAP or SQL, patterns are tried in the order as
+#      listed below:
+# .IP "\fIuser+extension@domain transport\fR:\fInexthop\fR"
+#      Mail for \fIuser+extension@domain\fR is delivered through
+#      \fItransport\fR to
+#      \fInexthop\fR.
+# .IP "\fIuser@domain transport\fR:\fInexthop\fR"
+#      Mail for \fIuser@domain\fR is delivered through \fItransport\fR to
+#      \fInexthop\fR.
+# .IP "\fIdomain transport\fR:\fInexthop\fR"
+#      Mail for \fIdomain\fR is delivered through \fItransport\fR to
+#      \fInexthop\fR.
+# .IP "\fI.domain transport\fR:\fInexthop\fR"
+#      Mail for any subdomain of \fIdomain\fR is delivered through
+#      \fItransport\fR to \fInexthop\fR. This applies only when the
+#      string \fBtransport_maps\fR is not listed in the
+#      \fBparent_domain_matches_subdomains\fR configuration setting.
+#      Otherwise, a domain name matches itself and its subdomains.
+# .PP
+#      Note 1: the special pattern \fB*\fR represents any address (i.e. it
+#      functions as the wild-card pattern).
+#
+#      Note 2: the null recipient address is looked up as the local
+#      mailer-daemon address (mailer-daemon@fully-qualified-domain-name).
+# .SH RESULT FORMAT
+# .ad
+# .fi
+#
+#      A null \fItransport\fR and null \fInexthop\fR result means "do
+#      not change": use the delivery transport and nexthop information
+#      that would be used when the entire transport table did not exist.
+#
+#      A non-null \fItransport\fR field with a null \fInexthop\fR field
+#      resets the nexthop information to the recipient domain.
+#
+#      A null \fItransport\fR field with non-null \fInexthop\fR field
+#      does not modify the transport information.
 # .SH TRANSPORT FIELD
 # .ad
 # .fi
 #      non-default server port, and use [\fIhost\fR] or [\fIhost\fR]:\fIport\fR
 #      in order to disable MX (mail exchanger) DNS lookups. The [] form
 #      can also be used with IP addresses instead of hostnames.
-# .SH LOOKUP ORDER
-# .ad
-# .fi
-#      With lookups from indexed files such as DB or DBM, or from networked
-#      tables such as NIS, LDAP or SQL, patterns are tried in the order as
-#      listed below:
-# .IP "\fIuser+extension@domain transport\fR:\fInexthop\fR"
-#      Mail for \fIuser+extension@domain\fR is delivered through
-#      \fItransport\fR to
-#      \fInexthop\fR.
-# .IP "\fIuser@domain transport\fR:\fInexthop\fR"
-#      Mail for \fIuser@domain\fR is delivered through \fItransport\fR to
-#      \fInexthop\fR.
-# .IP "\fIdomain transport\fR:\fInexthop\fR"
-#      Mail for \fIdomain\fR is delivered through \fItransport\fR to
-#      \fInexthop\fR.
-# .IP "\fI.domain transport\fR:\fInexthop\fR"
-#      Mail for any subdomain of \fIdomain\fR is delivered through
-#      \fItransport\fR to \fInexthop\fR. This applies only when the
-#      string \fBtransport_maps\fR is not listed in the
-#      \fBparent_domain_matches_subdomains\fR configuration setting.
-#      Otherwise, a domain name matches itself and its subdomains.
-# .PP
-# NOTE
-# .ad
-# .fi
-#      The special pattern \fB<>\fR represents the null address, and the
-#      special pattern \fB*\fR represents any address (i.e. it functions
-#      as the wild-card pattern).
 # EXAMPLES
 # .ad
 # .fi
index 2be94cdcd531fdda801aed79fba0eb4836036e95..5a5a430eb7d0272523f4bc8d0d02f6171b6c0a54 100644 (file)
@@ -298,6 +298,27 @@ virtual8_test: virtual8_maps virtual8_map virtual8.in virtual8.ref \
        diff virtual8.ref virtual8.tmp
        rm -f virtual8.tmp virtual8_map.db
 
+# Requires: Postfix running, root privileges
+
+rewrite_clnt_test: rewrite_clnt rewrite_clnt.in rewrite_clnt.ref
+       ./rewrite_clnt <rewrite_clnt.in >rewrite_clnt.tmp
+       sed "s/MYDOMAIN/`postconf -h mydomain`/" rewrite_clnt.ref | \
+           diff - rewrite_clnt.tmp
+       rm -f rewrite_clnt.tmp
+
+# Requires: Postfix, root, myorigin=$myhostname, relayhost=$mydomain,
+# no transport map
+
+resolve_clnt_test: resolve_clnt resolve_clnt.in resolve_clnt.ref
+       sed -e "s/MYDOMAIN/`postconf -h mydomain`/g" \
+           -e "s/MYHOSTNAME/`postconf -h myhostname`/g" \
+           resolve_clnt.in | ./resolve_clnt >resolve_clnt.tmp
+       sed -e "s/MYDOMAIN/`postconf -h mydomain`/g" \
+           -e "s/MYHOSTNAME/`postconf -h myhostname`/g" \
+           -e "s/RELAYHOST/`postconf -h mydomain`/g" \
+           resolve_clnt.ref | diff - resolve_clnt.tmp
+       rm -f resolve_clnt.tmp
+
 printfck: $(OBJS) $(PROG)
        rm -rf printfck
        mkdir printfck
index 937224a27cd0fc0d873274a29dd82ffa708aaffb..db32eae477c7a534adcf9d1e3f7b8abad10d1edc 100644 (file)
@@ -96,7 +96,7 @@ extern char *var_mydomain;
   * The default local delivery transport.
   */
 #define VAR_LOCAL_TRANSPORT    "local_transport"
-#define DEF_LOCAL_TRANSPORT    "local"
+#define DEF_LOCAL_TRANSPORT    MAIL_SERVICE_LOCAL ":$myhostname"
 extern char *var_local_transport;
 
  /*
@@ -293,10 +293,6 @@ extern bool var_disable_vrfy_cmd;
  /*
   * trivial rewrite/resolve service: mapping tables.
   */
-#define VAR_ERROR_TRANSPORT            "error_transport"
-#define DEF_ERROR_TRANSPORT            MAIL_SERVICE_ERROR
-extern char *var_error_transport;
-
 #define VAR_VIRT_ALIAS_MAPS    "virtual_alias_maps"
 #define DEF_VIRT_ALIAS_MAPS    "$virtual_maps" /* Compatibility! */
 extern char *var_virt_alias_maps;
@@ -305,6 +301,10 @@ extern char *var_virt_alias_maps;
 #define DEF_VIRT_ALIAS_DOMS    "$virtual_alias_maps"
 extern char *var_virt_alias_doms;
 
+#define VAR_VIRT_ALIAS_CODE    "unknown_virtual_alias_reject_code"
+#define DEF_VIRT_ALIAS_CODE    550
+extern int var_virt_alias_code;
+
 #define VAR_CANONICAL_MAPS     "canonical_maps"
 #define DEF_CANONICAL_MAPS     ""
 extern char *var_canonical_maps;
@@ -1126,6 +1126,10 @@ extern char *var_relay_transport;
 #define DEF_RELAY_RCPT_MAPS    ""
 extern char *var_relay_rcpt_maps;
 
+#define VAR_RELAY_RCPT_CODE    "unknown_relay_recipient_reject_code"
+#define DEF_RELAY_RCPT_CODE    550
+extern int var_relay_rcpt_code;
+
 #define VAR_CLIENT_CHECKS      "smtpd_client_restrictions"
 #define DEF_CLIENT_CHECKS      ""
 extern char *var_client_checks;
@@ -1279,12 +1283,16 @@ abcdefghijklmnopqrstuvwxyz{|}~"
 extern char *var_smtpd_exp_filter;
 
  /*
-  * Heuristic to reject most unknown recipients at the SMTP port.
+  * Heuristic to reject unknown local recipients at the SMTP port.
   */
 #define VAR_LOCAL_RCPT_MAPS    "local_recipient_maps"
 #define DEF_LOCAL_RCPT_MAPS    "unix:passwd.byname $alias_maps"
 extern char *var_local_rcpt_maps;
 
+#define VAR_LOCAL_RCPT_CODE    "unknown_local_recipient_reject_code"
+#define DEF_LOCAL_RCPT_CODE    550
+extern int var_local_rcpt_code;
+
  /*
   * Other.
   */
@@ -1375,6 +1383,10 @@ extern char *var_virt_mailbox_maps;
 #define DEF_VIRT_MAILBOX_DOMS          "$virtual_mailbox_maps"
 extern char *var_virt_mailbox_doms;
 
+#define VAR_VIRT_MAILBOX_CODE          "unknown_virtual_mailbox_reject_code"
+#define DEF_VIRT_MAILBOX_CODE          550
+extern int var_virt_mailbox_code;
+
 #define VAR_VIRT_UID_MAPS              "virtual_uid_maps"
 #define DEF_VIRT_UID_MAPS              ""
 extern char *var_virt_uid_maps;
index 156eb251e49b40114a8c1b5ab8bfa325ce87b983..3dc150f1e6eb9e50f3f8b5e55fb7d0babb773595 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change the patchlevel and the release date. Snapshots change the
   * release date only, unless they include the same bugfix as a patch release.
   */
-#define MAIL_RELEASE_DATE      "20021214"
+#define MAIL_RELEASE_DATE      "20021217"
 
 #define VAR_MAIL_VERSION       "mail_version"
 #define DEF_MAIL_VERSION       "1.1.12-" MAIL_RELEASE_DATE
index b87cf7eb10ea38c5391dd9fc9673eb058836dce4..b13605294371b7740a4b36c07afdc94728896223 100644 (file)
@@ -82,7 +82,7 @@ static int is_821_dot_string(char *local_part, char *end, int flags)
      * lookup tables to speed up some of the work, but hey, how large can a
      * local-part be anyway?
      */
-    if (local_part[0] == 0 || local_part[0] == '.')
+    if (local_part == end || local_part[0] == 0 || local_part[0] == '.')
        return (NO);
     for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) {
        if (ch == '.' && cp[1] == '.')
index 5f4672f742394221833e246414834c6f372f36ae..bf18059d3be9ba53995706fda02fcd6c920833e7 100644 (file)
@@ -95,7 +95,7 @@ static int is_822_dot_string(const char *local_part, const char *end, int flags)
      * RFC 822 expects 7-bit data. Rather than quoting every 8-bit character
      * (and still passing it on as 8-bit data) we leave 8-bit data alone.
      */
-    if (local_part[0] == 0 || local_part[0] == '.')
+    if (local_part == end || local_part[0] == 0 || local_part[0] == '.')
        return (NO);
     for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) {
        if (ch == '.' && (cp + 1) < end && cp[1] == '.')
index 219f678bdd6a9502544182fe3fe45cff7cdd6709..4d739609f2899e00efdd2bbfa613b8d959507bee 100644 (file)
@@ -70,7 +70,7 @@
 /*     authorized mail relay destination.
 /* .IP RESOLVE_CLASS_DEFAULT
 /*     The address matches none of the above. Access to this domain
-/*     should be limited to authorized senders only. 
+/*     should be limited to authorized senders only.
 /* .PP
 /*     For convenience, the constant RESOLVE_CLASS_FINAL includes all
 /*     cases where the local machine is the final destination.
@@ -178,7 +178,7 @@ void    resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
      */
     if (rewrite_clnt_stream == 0)
        rewrite_clnt_stream = clnt_stream_create(MAIL_CLASS_PRIVATE,
-                                 var_rewrite_service, var_ipc_idle_limit);
+                                  var_rewrite_service, var_ipc_idle_limit);
 
     for (;;) {
        stream = clnt_stream_access(rewrite_clnt_stream);
@@ -247,6 +247,24 @@ static NORETURN usage(char *myname)
 
 static void resolve(char *addr, RESOLVE_REPLY *reply)
 {
+    struct RESOLVE_FLAG_TABLE {
+       int     flag;
+       const char *name;
+    };
+    struct RESOLVE_FLAG_TABLE resolve_flag_table[] = {
+       RESOLVE_FLAG_FINAL, "FLAG_FINAL",
+       RESOLVE_FLAG_ROUTED, "FLAG_ROUTED",
+       RESOLVE_FLAG_ERROR, "FLAG_ERROR",
+       RESOLVE_FLAG_FAIL, "FLAG_FAIL",
+       RESOLVE_CLASS_LOCAL, "CLASS_LOCAL",
+       RESOLVE_CLASS_ALIAS, "CLASS_ALIAS",
+       RESOLVE_CLASS_VIRTUAL, "CLASS_VIRTUAL",
+       RESOLVE_CLASS_RELAY, "CLASS_RELAY",
+       RESOLVE_CLASS_DEFAULT, "CLASS_DEFAULT",
+       0,
+    };
+    struct RESOLVE_FLAG_TABLE *fp;
+
     resolve_clnt_query(addr, reply);
     if (reply->flags & RESOLVE_FLAG_FAIL) {
        vstream_printf("request failed\n");
@@ -256,6 +274,16 @@ static void resolve(char *addr, RESOLVE_REPLY *reply)
        vstream_printf("%-10s %s\n", "nexthop", *STR(reply->nexthop) ?
                       STR(reply->nexthop) : "[none]");
        vstream_printf("%-10s %s\n", "recipient", STR(reply->recipient));
+       vstream_printf("%-10s ", "flags");
+       for (fp = resolve_flag_table; fp->name; fp++) {
+           if (reply->flags & fp->flag) {
+               vstream_printf("%s ", fp->name);
+               reply->flags &= ~fp->flag;
+           }
+       }
+       if (reply->flags != 0)
+           vstream_printf("Unknown flag 0x%x", reply->flags);
+       vstream_printf("\n");
        vstream_fflush(VSTREAM_OUT);
     }
 }
@@ -297,6 +325,7 @@ int     main(int argc, char **argv)
        vstring_free(buffer);
     }
     resolve_clnt_free(&reply);
+    exit(0);
 }
 
 #endif
diff --git a/postfix/src/global/resolve_clnt.in b/postfix/src/global/resolve_clnt.in
new file mode 100644 (file)
index 0000000..d44aa3d
--- /dev/null
@@ -0,0 +1,45 @@
+
+@
+@@
+@a.
+@..
+@.@.
+!
+a!
+!b
+a!b
+!@
+a!@
+!b@
+a!b@
+%
+a%
+%b
+a%b
+%@
+a%@
+%b@
+@@
+a@@
+@b@
+a@b@
+a%b@
+a%b@MYHOSTNAME
+a!b@MYHOSTNAME
+a@b@MYHOSTNAME
+a[b]@MYHOSTNAME@MYHOSTNAME
+a[b]%MYHOSTNAME@MYHOSTNAME
+a[b]%MYHOSTNAME%MYHOSTNAME
+MYHOSTNAME!a[b]@MYHOSTNAME
+MYHOSTNAME!a[b]%MYHOSTNAME
+MYHOSTNAME!MYHOSTNAME!a[b]
+user@dom.ain1@dom.ain2
+user%dom.ain1@dom.ain2
+dom.ain1!user@dom.ain2
+user@[1.2.3.4]@dom.ain2
+user%[1.2.3.4]@dom.ain2
+[1.2.3.4]!user@dom.ain2
+user@localhost.MYDOMAIN
+user@[321.1.2.3]
+user@1.2.3
+user@host:port
diff --git a/postfix/src/global/resolve_clnt.ref b/postfix/src/global/resolve_clnt.ref
new file mode 100644 (file)
index 0000000..c7b55a1
--- /dev/null
@@ -0,0 +1,225 @@
+address    
+transport  local
+nexthop    MYHOSTNAME
+recipient  MAILER-DAEMON@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    @
+transport  local
+nexthop    MYHOSTNAME
+recipient  MAILER-DAEMON@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    @@
+transport  local
+nexthop    MYHOSTNAME
+recipient  MAILER-DAEMON@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    @a.
+transport  smtp
+nexthop    RELAYHOST
+recipient  @a
+flags      CLASS_DEFAULT 
+address    @..
+transport  smtp
+nexthop    RELAYHOST
+recipient  @..
+flags      FLAG_ERROR CLASS_DEFAULT 
+address    @.@.
+transport  local
+nexthop    MYHOSTNAME
+recipient  MAILER-DAEMON@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    !
+transport  local
+nexthop    MYHOSTNAME
+recipient  MAILER-DAEMON@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    a!
+transport  smtp
+nexthop    RELAYHOST
+recipient  @a.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    !b
+transport  local
+nexthop    MYHOSTNAME
+recipient  b@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    a!b
+transport  smtp
+nexthop    RELAYHOST
+recipient  b@a.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    !@
+transport  local
+nexthop    MYHOSTNAME
+recipient  MAILER-DAEMON@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    a!@
+transport  smtp
+nexthop    RELAYHOST
+recipient  @a.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    !b@
+transport  local
+nexthop    MYHOSTNAME
+recipient  b@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    a!b@
+transport  smtp
+nexthop    RELAYHOST
+recipient  b@a.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    %
+transport  local
+nexthop    MYHOSTNAME
+recipient  MAILER-DAEMON@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    a%
+transport  local
+nexthop    MYHOSTNAME
+recipient  a@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    %b
+transport  smtp
+nexthop    RELAYHOST
+recipient  @b.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    a%b
+transport  smtp
+nexthop    RELAYHOST
+recipient  a@b.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    %@
+transport  local
+nexthop    MYHOSTNAME
+recipient  MAILER-DAEMON@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    a%@
+transport  local
+nexthop    MYHOSTNAME
+recipient  a@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    %b@
+transport  smtp
+nexthop    RELAYHOST
+recipient  @b.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    @@
+transport  local
+nexthop    MYHOSTNAME
+recipient  MAILER-DAEMON@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    a@@
+transport  local
+nexthop    MYHOSTNAME
+recipient  a@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    @b@
+transport  smtp
+nexthop    RELAYHOST
+recipient  @b.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    a@b@
+transport  smtp
+nexthop    RELAYHOST
+recipient  a@b.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    a%b@
+transport  smtp
+nexthop    RELAYHOST
+recipient  a@b.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    a%b@MYHOSTNAME
+transport  smtp
+nexthop    RELAYHOST
+recipient  a@b.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    a!b@MYHOSTNAME
+transport  smtp
+nexthop    RELAYHOST
+recipient  b@a.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    a@b@MYHOSTNAME
+transport  smtp
+nexthop    RELAYHOST
+recipient  a@b.MYDOMAIN
+flags      CLASS_DEFAULT 
+address    a[b]@MYHOSTNAME@MYHOSTNAME
+transport  local
+nexthop    MYHOSTNAME
+recipient  a[b]@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    a[b]%MYHOSTNAME@MYHOSTNAME
+transport  local
+nexthop    MYHOSTNAME
+recipient  a[b]@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    a[b]%MYHOSTNAME%MYHOSTNAME
+transport  local
+nexthop    MYHOSTNAME
+recipient  a[b]@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    MYHOSTNAME!a[b]@MYHOSTNAME
+transport  local
+nexthop    MYHOSTNAME
+recipient  a [b]@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    MYHOSTNAME!a[b]%MYHOSTNAME
+transport  local
+nexthop    MYHOSTNAME
+recipient  a [b]@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    MYHOSTNAME!MYHOSTNAME!a[b]
+transport  local
+nexthop    MYHOSTNAME
+recipient  a [b]@MYHOSTNAME
+flags      CLASS_LOCAL 
+address    user@dom.ain1@dom.ain2
+transport  smtp
+nexthop    RELAYHOST
+recipient  user@dom.ain1@dom.ain2
+flags      FLAG_ROUTED CLASS_DEFAULT 
+address    user%dom.ain1@dom.ain2
+transport  smtp
+nexthop    RELAYHOST
+recipient  user%dom.ain1@dom.ain2
+flags      FLAG_ROUTED CLASS_DEFAULT 
+address    dom.ain1!user@dom.ain2
+transport  smtp
+nexthop    RELAYHOST
+recipient  dom.ain1!user@dom.ain2
+flags      FLAG_ROUTED CLASS_DEFAULT 
+address    user@[1.2.3.4]@dom.ain2
+transport  smtp
+nexthop    RELAYHOST
+recipient  user@[1.2.3.4]@dom.ain2
+flags      FLAG_ROUTED CLASS_DEFAULT 
+address    user%[1.2.3.4]@dom.ain2
+transport  smtp
+nexthop    RELAYHOST
+recipient  user%[1.2.3.4]@dom.ain2
+flags      FLAG_ROUTED CLASS_DEFAULT 
+address    [1.2.3.4]!user@dom.ain2
+transport  smtp
+nexthop    RELAYHOST
+recipient  [1.2.3.4]!user@dom.ain2
+flags      FLAG_ROUTED CLASS_DEFAULT 
+address    user@localhost.MYDOMAIN
+transport  local
+nexthop    MYHOSTNAME
+recipient  user@localhost.MYDOMAIN
+flags      CLASS_LOCAL 
+address    user@[321.1.2.3]
+transport  smtp
+nexthop    RELAYHOST
+recipient  user@[321.1.2.3]
+flags      FLAG_ERROR CLASS_DEFAULT 
+address    user@1.2.3
+transport  smtp
+nexthop    RELAYHOST
+recipient  user@1.2.3
+flags      CLASS_DEFAULT 
+address    user@host:port
+transport  smtp
+nexthop    RELAYHOST
+recipient  user@host:port
+flags      FLAG_ERROR CLASS_DEFAULT 
index c02375b44b715e0995bafec7891974955d2d964e..8e07dba78548981f0308075c785622ed88a47ad4 100644 (file)
@@ -242,6 +242,7 @@ int     main(int argc, char **argv)
        vstring_free(buffer);
     }
     vstring_free(reply);
+    exit(0);
 }
 
 #endif
diff --git a/postfix/src/global/rewrite_clnt.in b/postfix/src/global/rewrite_clnt.in
new file mode 100644 (file)
index 0000000..4f79ebc
--- /dev/null
@@ -0,0 +1,13 @@
+x !
+x a!
+x !b
+x a!b
+x %
+x a%
+x %b
+x a%b
+x @
+x a@
+x a@.
+x a@b
+x a@b.
diff --git a/postfix/src/global/rewrite_clnt.ref b/postfix/src/global/rewrite_clnt.ref
new file mode 100644 (file)
index 0000000..40d2faf
--- /dev/null
@@ -0,0 +1,39 @@
+rule       x
+address    !
+result     ""@
+rule       x
+address    a!
+result     ""@a.MYDOMAIN
+rule       x
+address    !b
+result     b@
+rule       x
+address    a!b
+result     b@a.MYDOMAIN
+rule       x
+address    %
+result     ""@
+rule       x
+address    a%
+result     a@
+rule       x
+address    %b
+result     ""@b.MYDOMAIN
+rule       x
+address    a%b
+result     a@b.MYDOMAIN
+rule       x
+address    @
+result     ""
+rule       x
+address    a@
+result     a@
+rule       x
+address    a@.
+result     a@.
+rule       x
+address    a@b
+result     a@b.MYDOMAIN
+rule       x
+address    a@b.
+result     a@b.
index f2b846ea475a8eaf1599799bc8b493bd60f32452..771cac5079b338905444a7656ab9f5ab082956b4 100644 (file)
@@ -185,7 +185,6 @@ qmgr_message.o: ../../include/rec_type.h
 qmgr_message.o: ../../include/sent.h
 qmgr_message.o: ../../include/deliver_completed.h
 qmgr_message.o: ../../include/opened.h
-qmgr_message.o: ../../include/resolve_local.h
 qmgr_message.o: ../../include/verp_sender.h
 qmgr_message.o: ../../include/mail_proto.h
 qmgr_message.o: ../../include/iostuff.h
index 31420c70dc156f2a0c9cfb3147786fc81a7f373c..83b7d5c9e7b23a2e87bb8cc7203e5f888fc6dcbd 100644 (file)
 #include <sent.h>
 #include <deliver_completed.h>
 #include <opened.h>
-#include <resolve_local.h>
 #include <verp_sender.h>
 #include <mail_proto.h>
 
@@ -768,8 +767,11 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
         * system can run without a local delivery agent. They'd still have
         * to configure something for mail directed to the local postmaster,
         * though, but that is an RFC requirement anyway.
+        * 
+        * XXX This lookup should be done in the resolver, and the mail should
+        * be directed to a general-purpose null delivery agent.
         */
-       if (at == 0 || resolve_local(at + 1)) {
+       if (reply.flags & RESOLVE_CLASS_LOCAL) {
            if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
                            len) == 0
                && !var_double_bounce_sender[len]) {
index f3cd4c2c64d55d03f28d5c07b4f8baa9e2c48c13..35212640b4d0c1b6a8f4898a8fbe43b171a99945 100644 (file)
@@ -172,7 +172,6 @@ qmgr_message.o: ../../include/rec_type.h
 qmgr_message.o: ../../include/sent.h
 qmgr_message.o: ../../include/deliver_completed.h
 qmgr_message.o: ../../include/opened.h
-qmgr_message.o: ../../include/resolve_local.h
 qmgr_message.o: ../../include/verp_sender.h
 qmgr_message.o: ../../include/mail_proto.h
 qmgr_message.o: ../../include/iostuff.h
index 534f2bc5692e440d0b995db433f43816548bc293..011f6020a51bba90ccfc5be1b959786a27b2a385 100644 (file)
 #include <sent.h>
 #include <deliver_completed.h>
 #include <opened.h>
-#include <resolve_local.h>
 #include <verp_sender.h>
 #include <mail_proto.h>
 
@@ -648,8 +647,11 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
         * system can run without a local delivery agent. They'd still have
         * to configure something for mail directed to the local postmaster,
         * though, but that is an RFC requirement anyway.
+        * 
+        * XXX This lookup should be done in the resolver, and the mail should
+        * be directed to a general-purpose null delivery agent.
         */
-       if (at == 0 || resolve_local(at + 1)) {
+       if (reply.flags & RESOLVE_CLASS_LOCAL) {
            if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
                            len) == 0
                && !var_double_bounce_sender[len]) {
index 5d757afd428a4281c1314b46692bbcb17ce67396..fa965759927e936d82c8c98702eaeb59c8080c80 100644 (file)
 /*     Recipient of protocol/policy/resource/software error notices.
 /* .IP \fBhopcount_limit\fR
 /*     Limit the number of \fBReceived:\fR message headers.
-/* .IP \fBlocal_recipient_maps\fR
-/*     List of maps with user names that are local to \fB$myorigin\fR
-/*     or \fB$inet_interfaces\fR. If this parameter is defined,
-/*     then the SMTP server rejects mail for unknown local users.
-/* .IP \fBrelay_recipient_maps\fR
-/*     List of maps that define all the email addresses in the domains
-/*     that match \fB$relay_domains\fR.  If this parameter is defined,
-/*     then the SMTP server rejects mail for unknown relay recipients.
 /* .IP \fBnotify_classes\fR
 /*     List of error classes. Of special interest are:
 /* .RS
 /*     This can be useful for testing purposes.
 /* .IP \fBverp_delimiter_filter\fR
 /*     The characters that Postfix accepts as VERP delimiter characters.
+/* .SH "Known versus unknown recipients"
+/* .ad
+/* .fi
+/* .IP \fBunknown_local_recipient_reject_code\fR
+/*     The response code when a client specifies a recipient whose domain
+/*     matches \fB$mydestination\fR or \fB$inet_interfaces\fR, while
+/*     \fB$local_recipient_maps\fR is non-empty and does not list
+/*     the recipient address or address local-part.
+/* .IP \fBunknown_relay_recipient_reject_code\fR
+/*     The response code when a client specifies a recipient whose domain
+/*     matches \fB$relay_domains\fR, while \fB$relay_recipient_maps\fR
+/*     is non-empty and does not list the recipient address.
+/* .IP \fBunknown_virtual_alias_reject_code\fR
+/*     The response code when a client specifies a recipient whose domain
+/*     matches \fB$virtual_alias_domains\fR, while the recipient is not
+/*     listed in \fB$virtual_alias_maps\fR.
+/* .IP \fBunknown_virtual_mailbox_reject_code\fR
+/*     The response code when a client specifies a recipient whose domain
+/*     matches \fB$virtual_mailbox_domains\fR, while the recipient is not
+/*     listed in \fB$virtual_mailbox_maps\fR.
 /* .SH "Resource controls"
 /* .ad
 /* .fi
@@ -413,12 +425,11 @@ char   *var_smtpd_null_key;
 int     var_smtpd_hist_thrsh;
 char   *var_smtpd_exp_filter;
 char   *var_def_rbl_reply;
-char   *var_def_transport;
-char   *var_error_transport;
-char   *var_local_transport;
-char   *var_relay_transport;
-char   *var_virt_transport;
 char   *var_relay_rcpt_maps;
+int     var_local_rcpt_code;
+int     var_virt_alias_code;
+int     var_virt_mailbox_code;
+int     var_relay_rcpt_code;
 
  /*
   * Silly little macros.
@@ -1619,6 +1630,10 @@ int     main(int argc, char **argv)
        VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code, 0, 0,
        VAR_SMTPD_JUNK_CMD, DEF_SMTPD_JUNK_CMD, &var_smtpd_junk_cmd_limit, 1, 0,
        VAR_SMTPD_HIST_THRSH, DEF_SMTPD_HIST_THRSH, &var_smtpd_hist_thrsh, 1, 0,
+       VAR_LOCAL_RCPT_CODE, DEF_LOCAL_RCPT_CODE, &var_local_rcpt_code, 0, 0,
+       VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code, 0, 0,
+       VAR_VIRT_MAILBOX_CODE, DEF_VIRT_MAILBOX_CODE, &var_virt_mailbox_code, 0, 0,
+       VAR_RELAY_RCPT_CODE, DEF_RELAY_RCPT_CODE, &var_relay_rcpt_code, 0, 0,
        0,
     };
     static CONFIG_TIME_TABLE time_table[] = {
@@ -1663,11 +1678,6 @@ int     main(int argc, char **argv)
        VAR_SMTPD_SND_AUTH_MAPS, DEF_SMTPD_SND_AUTH_MAPS, &var_smtpd_snd_auth_maps, 0, 0,
        VAR_SMTPD_NOOP_CMDS, DEF_SMTPD_NOOP_CMDS, &var_smtpd_noop_cmds, 0, 0,
        VAR_SMTPD_NULL_KEY, DEF_SMTPD_NULL_KEY, &var_smtpd_null_key, 0, 0,
-       VAR_DEF_TRANSPORT, DEF_DEF_TRANSPORT, &var_def_transport, 1, 0,
-       VAR_ERROR_TRANSPORT, DEF_ERROR_TRANSPORT, &var_error_transport, 1, 0,
-       VAR_LOCAL_TRANSPORT, DEF_LOCAL_TRANSPORT, &var_local_transport, 1, 0,
-       VAR_RELAY_TRANSPORT, DEF_RELAY_TRANSPORT, &var_relay_transport, 1, 0,
-       VAR_VIRT_TRANSPORT, DEF_VIRT_TRANSPORT, &var_virt_transport, 1, 0,
        VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0,
        0,
     };
index 346eb70e4c3c3a19f65178295ca9ba2a004618e8..7d9949c96bc377e5fee220591fe1b19f6903990d 100644 (file)
@@ -3149,9 +3149,11 @@ char   *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
      * unknown recipients in simulated virtual domains will both resolve to
      * "error:user unknown".
      */
-    if (strcmp(STR(reply->transport), var_error_transport) == 0) {
+    if (strcmp(STR(reply->transport), MAIL_SERVICE_ERROR) == 0) {
        (void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
-                                 "%d <%s>: %s", 550,
+                                 "%d <%s>: %s",
+                                 (reply->flags & RESOLVE_CLASS_ALIAS) ?
+                                 var_virt_alias_code : 550,
                                  recipient, STR(reply->nexthop));
        SMTPD_CHECK_RCPT_RETURN(STR(error_text));
     }
@@ -3170,13 +3172,10 @@ char   *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
      */
     if ((reply->flags & RESOLVE_CLASS_LOCAL)
        && *var_local_rcpt_maps
-#if 0
-       && strcmp(STR(reply->transport), var_local_transport) == 0
-#endif
        && NOMATCH(local_rcpt_maps, CONST_STR(reply->recipient))) {
        (void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
                           "%d <%s>: User unknown in local recipient table",
-                                 550, recipient);
+                                 var_local_rcpt_code, recipient);
        SMTPD_CHECK_RCPT_RETURN(STR(error_text));
     }
 
@@ -3184,13 +3183,10 @@ char   *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
      * Reject mail to unknown addresses in virtual mailbox domains.
      */
     if ((reply->flags & RESOLVE_CLASS_VIRTUAL)
-#if 0
-       && strcmp(STR(reply->transport), var_virt_transport) == 0
-#endif
        && NOMATCHV8(virt_mailbox_maps, CONST_STR(reply->recipient))) {
        (void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
                           "%d <%s>: User unknown in virtual mailbox table",
-                                 550, recipient);
+                                 var_virt_mailbox_code, recipient);
        SMTPD_CHECK_RCPT_RETURN(STR(error_text));
     }
 
@@ -3199,13 +3195,10 @@ char   *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
      */
     if ((reply->flags & RESOLVE_CLASS_RELAY)
        && *var_relay_rcpt_maps
-#if 0
-       && strcmp(STR(reply->transport), var_relay_transport) == 0
-#endif
        && NOMATCH(relay_rcpt_maps, CONST_STR(reply->recipient))) {
        (void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
                           "%d <%s>: User unknown in relay recipient table",
-                                 550, recipient);
+                                 var_relay_rcpt_code, recipient);
        SMTPD_CHECK_RCPT_RETURN(STR(error_text));
     }
 
@@ -3365,11 +3358,6 @@ char   *var_double_bounce_sender;
 char   *var_rbl_reply_maps;
 char   *var_smtpd_exp_filter;
 char   *var_def_rbl_reply;
-char   *var_local_transport;
-char   *var_error_transport;
-char   *var_virt_transport;
-char   *var_relay_transport;
-char   *var_def_transport;
 char   *var_relay_rcpt_maps;
 
 typedef struct {
@@ -3408,11 +3396,6 @@ static STRING_TABLE string_table[] = {
     VAR_RBL_REPLY_MAPS, DEF_RBL_REPLY_MAPS, &var_rbl_reply_maps,
     VAR_SMTPD_EXP_FILTER, DEF_SMTPD_EXP_FILTER, &var_smtpd_exp_filter,
     VAR_DEF_RBL_REPLY, DEF_DEF_RBL_REPLY, &var_def_rbl_reply,
-    VAR_LOCAL_TRANSPORT, DEF_LOCAL_TRANSPORT, &var_local_transport,
-    VAR_ERROR_TRANSPORT, DEF_ERROR_TRANSPORT, &var_error_transport,
-    VAR_VIRT_TRANSPORT, DEF_VIRT_TRANSPORT, &var_virt_transport,
-    VAR_RELAY_TRANSPORT, DEF_RELAY_TRANSPORT, &var_relay_transport,
-    VAR_DEF_TRANSPORT, DEF_DEF_TRANSPORT, &var_def_transport,
     VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps,
     0,
 };
@@ -3465,6 +3448,10 @@ int     var_defer_code;
 int     var_non_fqdn_code;
 int     var_smtpd_delay_reject;
 int     var_allow_untrust_route;
+int     var_local_rcpt_code;
+int     var_relay_rcpt_code;
+int     var_virt_mailbox_code;
+int     var_virt_alias_code;
 
 static INT_TABLE int_table[] = {
     "msg_verbose", 0, &msg_verbose,
@@ -3480,6 +3467,10 @@ static INT_TABLE int_table[] = {
     VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code,
     VAR_SMTPD_DELAY_REJECT, DEF_SMTPD_DELAY_REJECT, &var_smtpd_delay_reject,
     VAR_ALLOW_UNTRUST_ROUTE, DEF_ALLOW_UNTRUST_ROUTE, &var_allow_untrust_route,
+    VAR_LOCAL_RCPT_CODE, DEF_LOCAL_RCPT_CODE, &var_local_rcpt_code,
+    VAR_RELAY_RCPT_CODE, DEF_RELAY_RCPT_CODE, &var_relay_rcpt_code,
+    VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code,
+    VAR_VIRT_MAILBOX_CODE, DEF_VIRT_MAILBOX_CODE, &var_virt_mailbox_code,
     0,
 };
 
@@ -3633,23 +3624,23 @@ void    resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
     domain += 1;
     if (resolve_local(domain)) {
        reply->flags = RESOLVE_CLASS_LOCAL;
-       vstring_strcpy(reply->transport, var_local_transport);
+       vstring_strcpy(reply->transport, MAIL_SERVICE_LOCAL);
        vstring_strcpy(reply->nexthop, domain);
     } else if (string_list_match(virt_alias_doms, domain)) {
        reply->flags = RESOLVE_CLASS_ALIAS;
-       vstring_strcpy(reply->transport, var_error_transport);
+       vstring_strcpy(reply->transport, MAIL_SERVICE_ERROR);
        vstring_strcpy(reply->nexthop, "user unknown");
     } else if (string_list_match(virt_mailbox_doms, domain)) {
        reply->flags = RESOLVE_CLASS_VIRTUAL;
-       vstring_strcpy(reply->transport, var_virt_transport);
+       vstring_strcpy(reply->transport, MAIL_SERVICE_VIRTUAL);
        vstring_strcpy(reply->nexthop, domain);
     } else if (domain_list_match(relay_domains, domain)) {
        reply->flags = RESOLVE_CLASS_RELAY;
-       vstring_strcpy(reply->transport, var_relay_transport);
+       vstring_strcpy(reply->transport, MAIL_SERVICE_RELAY);
        vstring_strcpy(reply->nexthop, domain);
     } else {
        reply->flags = RESOLVE_CLASS_DEFAULT;
-       vstring_strcpy(reply->transport, var_def_transport);
+       vstring_strcpy(reply->transport, MAIL_SERVICE_SMTP);
        vstring_strcpy(reply->nexthop, domain);
     }
     vstring_strcpy(reply->recipient, addr);
index 3ff0eb8e6d3e01f8c2ad2e3bc90efab9cd93bc5b..36d30660ed5e9e883ff69d381e01029d39126e7b 100644 (file)
@@ -71,6 +71,7 @@ resolve.o: ../../include/vstring_vstream.h
 resolve.o: ../../include/split_at.h
 resolve.o: ../../include/valid_hostname.h
 resolve.o: ../../include/stringops.h
+resolve.o: ../../include/mymalloc.h
 resolve.o: ../../include/mail_params.h
 resolve.o: ../../include/mail_proto.h
 resolve.o: ../../include/iostuff.h
@@ -127,6 +128,9 @@ transport.o: ../../include/mail_params.h
 transport.o: ../../include/maps.h
 transport.o: ../../include/match_parent_style.h
 transport.o: ../../include/match_ops.h
+transport.o: ../../include/mail_proto.h
+transport.o: ../../include/iostuff.h
+transport.o: ../../include/attr.h
 transport.o: transport.h
 trivial-rewrite.o: trivial-rewrite.c
 trivial-rewrite.o: ../../include/sys_defs.h
index 8e55123c80d7261e2e52bd93a90ffa3733b4c794..53fdd5b30f412e0e8bbad37e48e7becb9fb5ad13 100644 (file)
@@ -63,6 +63,7 @@
 #include <split_at.h>
 #include <valid_hostname.h>
 #include <stringops.h>
+#include <mymalloc.h>
 
 /* Global library. */
 
   * nexthop information (or vice versa) may produce surprising results. In
   * particular, the free text nexthop information for the error transport is
   * likely to confuse regular delivery agents; and conversely, a hostname or
-  * socket pathname is not a useful reason for non-delivery.
+  * socket pathname is not an adequate text as reason for non-delivery.
   * 
-  * In the code below, the class_domain variable specifies the domain name that
-  * we will use when (the class transport is the error transport and the
-  * class transport is replaced by a transport map lookup result) but the
-  * nexthop information is not updated.
-  * 
-  * For the sake of completeness, we also take action when the reverse happens:
-  * replacing the class transport by the error transport without updating the
-  * nexthop information.
-  * 
-  * The ability to specify "error:reason for non-delivery" in main.cf and in
-  * transport maps is just too convenient to take it away.
+  * In the code below, rcpt_domain specifies the domain name that we will use
+  * when the transport table specifies a non-default channel but no nexthop
+  * information (we use a generic text when that non-default channel is the
+  * error transport).
   */
 
 #define STR    vstring_str
@@ -141,13 +135,6 @@ static DOMAIN_LIST *relay_domains;
 static STRING_LIST *virt_alias_doms;
 static STRING_LIST *virt_mailbox_doms;
 
- /*
-  * Saved address domain class information.
-  */
-static VSTRING *saved_class_channel;
-static VSTRING *saved_class_nexthop;
-static VSTRING *saved_class_domain;
-
 static MAPS *relocated_maps;
 
 /* resolve_addr - resolve address according to rule set */
@@ -157,50 +144,109 @@ void    resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop,
 {
     char   *myname = "resolve_addr";
     VSTRING *addr_buf = vstring_alloc(100);
-    TOK822 *tree;
+    TOK822 *tree = 0;
     TOK822 *saved_domain = 0;
     TOK822 *domain = 0;
     char   *destination;
     const char *blame = 0;
     const char *rcpt_domain;
+    int     addr_len;
+    int     loop_count;
+    int     loop_max;
+    char   *local;
+    char   *oper;
+    char   *junk;
 
-    vstring_strcpy(saved_class_domain, "UNINITIALIZED SAVED_CLASS_DOMAIN");
     *flags = 0;
+    vstring_strcpy(channel, "CHANNEL NOT UPDATED");
+    vstring_strcpy(nexthop, "NEXTHOP NOT UPDATED");
+    vstring_strcpy(nextrcpt, "NEXTRCPT NOT UPDATED");
 
     /*
-     * The address is in internalized (unquoted) form, so we must externalize
-     * it first before we can parse it.
+     * The address is in internalized (unquoted) form.
+     * 
+     * In an ideal world we would parse the externalized address form as given
+     * to us by the sender.
+     * 
+     * However, in the real world we have to look for routing characters like
+     * %@! in the address local-part, even when that information is quoted
+     * due to the presence of special characters or whitespace. Although
+     * technically incorrect, this is needed to stop user@domain@domain relay
+     * attempts when forwarding mail to a Sendmail MX host.
      * 
-     * While quoting the address local part, do not treat @ as a special
-     * character. This allows us to detect extra @ characters and block
-     * source routed relay attempts.
+     * This suggests that we parse the address in internalized (unquoted) form.
+     * Unfortunately, if we do that, the unparser generates incorrect white
+     * space between adjacent non-operator tokens. Example: ``first last''
+     * needs white space, but ``stuff[stuff]'' does not. This is is not a
+     * problem when unparsing the result from parsing externalized forms,
+     * because the parser/unparser were designed for valid externalized forms
+     * where ``stuff[stuff]'' does not happen.
      * 
-     * But practically, we have to look at the unquoted form so that routing
-     * characters like @ remain visible, in order to stop user@domain@domain
-     * relay attempts when forwarding mail to a primary Sendmail MX host.
+     * As a workaround we start with the quoted form and then dequote the
+     * local-part only where needed. This will do the right thing in most
+     * (but not all) cases.
      */
-    if (var_resolve_dequoted) {
-       tree = tok822_scan_addr(addr);
-    } else {
-       quote_822_local(addr_buf, addr);
-       tree = tok822_scan_addr(vstring_str(addr_buf));
+    addr_len = strlen(addr);
+    quote_822_local(addr_buf, addr);
+    tree = tok822_scan_addr(vstring_str(addr_buf));
+
+    /*
+     * Let the optimizer replace multiple expansions of this macro by a GOTO
+     * to a single instance.
+     */
+#define FREE_MEMORY_AND_RETURN { \
+       if (saved_domain) \
+           tok822_free_tree(saved_domain); \
+       if(tree) \
+           tok822_free_tree(tree); \
+       if (addr_buf) \
+           vstring_free(addr_buf); \
     }
 
     /*
      * Preliminary resolver: strip off all instances of the local domain.
      * Terminate when no destination domain is left over, or when the
      * destination domain is remote.
+     * 
+     * XXX To whom it may concern. If you change the resolver loop below, or
+     * quote_822_local.c, or tok822_parse.c, be sure to re-run the tests
+     * under "make resolve_clnt_test" in the global directory.
      */
 #define RESOLVE_LOCAL(domain) \
     resolve_local(STR(tok822_internalize(addr_buf, domain, TOK822_STR_DEFL)))
 
-    while (tree->head) {
+    dict_errno = 0;
+
+    for (loop_count = 0, loop_max = addr_len + 100; /* void */ ; loop_count++) {
+
+       /*
+        * Grr. resolve_local() table lookups may fail. It may be OK for
+        * local file lookup code to abort upon failure, but with
+        * network-based tables it is preferable to return an error
+        * indication to the requestor.
+        */
+       if (dict_errno) {
+           *flags |= RESOLVE_FLAG_FAIL;
+           FREE_MEMORY_AND_RETURN;
+       }
+
+       /*
+        * XXX Should never happen, but if this happens with some
+        * pathological address, then that is not sufficient reason to
+        * disrupt the operation of an MTA.
+        */
+       if (loop_count > loop_max) {
+           msg_warn("resolve_addr: <%s>: giving up after %d iterations",
+                    addr, loop_count);
+           break;
+       }
 
        /*
         * Strip trailing dot at end of domain, but not dot-dot. This merely
         * makes diagnostics more accurate by leaving bogus addresses alone.
         */
-       if (tree->tail->type == '.'
+       if (tree->tail
+           && tree->tail->type == '.'
            && tok822_rfind_type(tree->tail, '@') != 0
            && tree->tail->prev->type != '.')
            tok822_free_tree(tok822_sub_keep_before(tree, tree->tail));
@@ -208,26 +254,15 @@ void    resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop,
        /*
         * Strip trailing @.
         */
-       if (tree->tail->type == '@') {
+       if (tree->tail
+           && tree->tail->type == '@')
            tok822_free_tree(tok822_sub_keep_before(tree, tree->tail));
-           continue;
-       }
-
-       /*
-        * A lone empty string becomes the postmaster.
-        */
-       if (tree->head == tree->tail && tree->head->type == TOK822_QSTRING
-           && VSTRING_LEN(tree->head->vstr) == 0) {
-           tok822_free(tree->head);
-           tree->head = tok822_scan(MAIL_ADDR_POSTMASTER, &tree->tail);
-           rewrite_tree(REWRITE_CANON, tree);
-       }
 
        /*
         * Strip (and save) @domain if local.
         */
        if ((domain = tok822_rfind_type(tree->tail, '@')) != 0) {
-           if (RESOLVE_LOCAL(domain->next) == 0)
+           if (domain->next && RESOLVE_LOCAL(domain->next) == 0)
                break;
            tok822_sub_keep_before(tree, domain);
            if (saved_domain)
@@ -239,32 +274,65 @@ void    resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop,
         * After stripping the local domain, if any, replace foo%bar by
         * foo@bar, site!user by user@site, rewrite to canonical form, and
         * retry.
-        * 
-        * Otherwise we're done.
         */
        if (tok822_rfind_type(tree->tail, '@')
            || (var_swap_bangpath && tok822_rfind_type(tree->tail, '!'))
            || (var_percent_hack && tok822_rfind_type(tree->tail, '%'))) {
            rewrite_tree(REWRITE_CANON, tree);
-       } else {
-           domain = 0;
-           break;
+           continue;
+       }
+
+       /*
+        * If the local-part is a quoted string, crack it open when we're
+        * permitted to do so and look for routing operators. This is
+        * technically incorrect, but is needed to stop relaying problems.
+        * 
+        * XXX Do another feeble attempt to keep local-part info quoted.
+        */
+       if (var_resolve_dequoted
+           && tree->head && tree->head == tree->tail
+           && tree->head->type == TOK822_QSTRING
+           && ((oper = strrchr(local = STR(tree->head->vstr), '@')) != 0
+               || (var_percent_hack && (oper = strrchr(local, '%')) != 0)
+            || (var_swap_bangpath && (oper = strrchr(local, '!')) != 0))) {
+           if (*oper == '%')
+               *oper = '@';
+           tok822_internalize(addr_buf, tree->head, TOK822_STR_DEFL);
+           if (*oper == '@') {
+               junk = mystrdup(STR(addr_buf));
+               quote_822_local(addr_buf, junk);
+               myfree(junk);
+           }
+           tok822_free(tree->head);
+           tree->head = tok822_scan(STR(addr_buf), &tree->tail);
+           rewrite_tree(REWRITE_CANON, tree);
+           continue;
+       }
+
+       /*
+        * An empty local-part or an empty quoted string local-part becomes
+        * the local MAILER-DAEMON, for consistency with our own From:
+        * message headers.
+        */
+       if (tree->head && tree->head == tree->tail
+           && tree->head->type == TOK822_QSTRING
+           && VSTRING_LEN(tree->head->vstr) == 0) {
+           tok822_free(tree->head);
+           tree->head = 0;
        }
+       if (tree->head == 0)
+           tree->head = tok822_scan(MAIL_ADDR_MAIL_DAEMON, &tree->tail);
+
+       /*
+        * We're done. There are no domains left to strip off the address,
+        * and all null local-part information is sanitized.
+        */
+       domain = 0;
+       break;
     }
 
-    /*
-     * If the destination is non-local, recognize routing operators in the
-     * address localpart. This is needed to prevent backup MX hosts from
-     * relaying third-party destinations through primary MX hosts, otherwise
-     * the backup host could end up on black lists. Ignore local
-     * swap_bangpath and percent_hack settings because we can't know how the
-     * primary MX host is set up.
-     */
-    if (domain && domain->prev)
-       if (tok822_rfind_type(domain->prev, '@') != 0
-           || tok822_rfind_type(domain->prev, '!') != 0
-           || tok822_rfind_type(domain->prev, '%') != 0)
-           *flags |= RESOLVE_FLAG_ROUTED;
+    vstring_free(addr_buf);
+    addr_buf = 0;
 
     /*
      * Make sure the resolved envelope recipient has the user@domain form. If
@@ -275,105 +343,134 @@ void    resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop,
        if (saved_domain) {
            tok822_sub_append(tree, saved_domain);
            saved_domain = 0;
-       } else {                                /* Aargh! Always! */
+       } else {
            tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
            tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0));
        }
     }
+
+    /*
+     * Transform the recipient address back to internal form.
+     * 
+     * XXX This may produce incorrect results if we cracked open a quoted
+     * local-part with routing operators; see discussion above at the top of
+     * the big loop.
+     */
     tok822_internalize(nextrcpt, tree, TOK822_STR_DEFL);
+    rcpt_domain = strrchr(STR(nextrcpt), '@') + 1;
+    if (*rcpt_domain == '[' ? !valid_hostliteral(rcpt_domain, DONT_GRIPE) :
+       !valid_hostname(rcpt_domain, DONT_GRIPE))
+       *flags |= RESOLVE_FLAG_ERROR;
+    tok822_free_tree(tree);
+    tree = 0;
+
+    /*
+     * Recognize routing operators in the local-part, even when we do not
+     * recognize ! or % as valid routing operators locally. This is needed to
+     * prevent backup MX hosts from relaying third-party destinations through
+     * primary MX hosts, otherwise the backup host could end up on black
+     * lists. Ignore local swap_bangpath and percent_hack settings because we
+     * can't know how the next MX host is set up.
+     */
+    if (strcmp(STR(nextrcpt) + strcspn(STR(nextrcpt), "@!%") + 1, rcpt_domain))
+       *flags |= RESOLVE_FLAG_ROUTED;
 
     /*
-     * With relay or other non-local destinations, the relayhost setting
-     * overrides the destination domain name.
+     * With local, virtual, relay, or other non-local destinations, give the
+     * highest precedence to transport associated nexthop information.
      * 
-     * With virtual, relay, or other non-local destinations, give the highest
-     * precedence to delivery transport associated next-hop information.
+     * Otherwise, with relay or other non-local destinations, the relayhost
+     * setting overrides the destination domain name.
      * 
-     * XXX With the virtual mailbox transport, set the nexthop information to
-     * $myhostname, so that in default configurations the virtual delivery
-     * agent will not use separate queues for every $virtual_mailbox_domains
-     * domain name. That prevents anomalies where many low-traffic domains
-     * starve a high-traffic domain.
+     * XXX Nag if the recipient domain is listed in multiple domain lists. The
+     * result is implementation defined, and may break when internals change.
      * 
-     * XXX Nag if the domain is listed in multiple domain lists. The effect is
-     * implementation defined, and may break when internals change.
+     * For now, we distinguish only a fixed number of address classes.
+     * Eventually this may become extensible, so that new classes can be
+     * configured with their own domain list, delivery transport, and
+     * recipient table.
      */
 #define STREQ(x,y) (strcmp((x), (y)) == 0)
 
     dict_errno = 0;
     if (domain != 0) {
-       tok822_internalize(nexthop, domain->next, TOK822_STR_DEFL);
-       vstring_strcpy(saved_class_domain, STR(nexthop));
-       if (STR(nexthop)[strspn(STR(nexthop), "[]0123456789.")] != 0
-           && valid_hostname(STR(nexthop), DONT_GRIPE) == 0)
-           *flags |= RESOLVE_FLAG_ERROR;
+
+       /*
+        * Virtual alias domain.
+        */
        if (virt_alias_doms
-           && string_list_match(virt_alias_doms, STR(nexthop))) {
+           && string_list_match(virt_alias_doms, rcpt_domain)) {
            if (var_helpful_warnings
                && virt_mailbox_doms
-               && string_list_match(virt_mailbox_doms, STR(nexthop)))
+               && string_list_match(virt_mailbox_doms, rcpt_domain))
                msg_warn("do not list domain %s in BOTH %s and %s",
-                 STR(nexthop), VAR_VIRT_ALIAS_DOMS, VAR_VIRT_MAILBOX_DOMS);
-           vstring_strcpy(channel, var_error_transport);
+                        rcpt_domain, VAR_VIRT_ALIAS_DOMS,
+                        VAR_VIRT_MAILBOX_DOMS);
+           vstring_strcpy(channel, MAIL_SERVICE_ERROR);
            vstring_strcpy(nexthop, "User unknown in virtual alias table");
-           vstring_strcpy(saved_class_domain, var_myhostname);
-           blame = VAR_ERROR_TRANSPORT;
            *flags |= RESOLVE_CLASS_ALIAS;
        } else if (dict_errno != 0) {
            msg_warn("%s lookup failure", VAR_VIRT_ALIAS_DOMS);
            *flags |= RESOLVE_FLAG_FAIL;
-       } else if (virt_mailbox_doms
-                  && string_list_match(virt_mailbox_doms, STR(nexthop))) {
+           FREE_MEMORY_AND_RETURN;
+       }
+
+       /*
+        * Virtual mailbox domain.
+        */
+       else if (virt_mailbox_doms
+                && string_list_match(virt_mailbox_doms, rcpt_domain)) {
            vstring_strcpy(channel, var_virt_transport);
-           vstring_strcpy(nexthop, var_myhostname);
-           vstring_strcpy(saved_class_domain, var_myhostname);
+           vstring_strcpy(nexthop, rcpt_domain);
            blame = VAR_VIRT_TRANSPORT;
            *flags |= RESOLVE_CLASS_VIRTUAL;
        } else if (dict_errno != 0) {
            msg_warn("%s lookup failure", VAR_VIRT_MAILBOX_DOMS);
            *flags |= RESOLVE_FLAG_FAIL;
+           FREE_MEMORY_AND_RETURN;
        } else {
+
+           /*
+            * Off-host relay destination.
+            */
            if (relay_domains
-               && domain_list_match(relay_domains, STR(nexthop))) {
+               && domain_list_match(relay_domains, rcpt_domain)) {
                vstring_strcpy(channel, var_relay_transport);
                blame = VAR_RELAY_TRANSPORT;
                *flags |= RESOLVE_CLASS_RELAY;
            } else if (dict_errno != 0) {
                msg_warn("%s lookup failure", VAR_RELAY_DOMAINS);
                *flags |= RESOLVE_FLAG_FAIL;
-           } else {
+               FREE_MEMORY_AND_RETURN;
+           }
+
+           /*
+            * Other off-host destination.
+            */
+           else {
                vstring_strcpy(channel, var_def_transport);
                blame = VAR_DEF_TRANSPORT;
                *flags |= RESOLVE_CLASS_DEFAULT;
            }
-           if (*var_relayhost) {
+
+           /*
+            * With off-host delivery, relayhost overrides recipient domain.
+            */
+           if (*var_relayhost)
                vstring_strcpy(nexthop, var_relayhost);
-               if (!STREQ(STR(channel), var_error_transport))
-                   vstring_strcpy(saved_class_domain, STR(nexthop));
-           }
-       }
-       if ((destination = split_at(STR(channel), ':')) != 0 && *destination) {
-           vstring_strcpy(nexthop, destination);
-           if (!STREQ(STR(channel), var_error_transport))
-               vstring_strcpy(saved_class_domain, STR(nexthop));
+           else
+               vstring_strcpy(nexthop, rcpt_domain);
        }
     }
 
     /*
-     * Local delivery. Set up the default local transport and the default
-     * next-hop hostname (myself).
-     * 
-     * XXX Set the nexthop information to myhostname, so that the local delivery
-     * agent does not get a queue for every domain name in $mydestination or
-     * for every network address in $inet_interfaces.
+     * Local delivery.
      * 
      * XXX Nag if the domain is listed in multiple domain lists. The effect is
      * implementation defined, and may break when internals change.
      */
     else {
-       if (var_helpful_warnings
-           && (rcpt_domain = strrchr(STR(nextrcpt), '@')) != 0) {
-           rcpt_domain++;
+       if (var_helpful_warnings) {
            if (virt_alias_doms
                && string_list_match(virt_alias_doms, rcpt_domain))
                msg_warn("do not list domain %s in BOTH %s and %s",
@@ -384,56 +481,67 @@ void    resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop,
                         rcpt_domain, VAR_MYDEST, VAR_VIRT_MAILBOX_DOMS);
        }
        vstring_strcpy(channel, var_local_transport);
+       vstring_strcpy(nexthop, rcpt_domain);
        blame = VAR_LOCAL_TRANSPORT;
-       if ((destination = split_at(STR(channel), ':')) == 0
-           || *destination == 0)
-           destination = var_myhostname;
-       vstring_strcpy(nexthop, destination);
-       if (!STREQ(STR(channel), var_error_transport))
-           vstring_strcpy(saved_class_domain, STR(nexthop));
-       else
-           vstring_strcpy(saved_class_domain, var_myhostname);
        *flags |= RESOLVE_CLASS_LOCAL;
     }
 
+    /*
+     * An explicit main.cf transport:nexthop setting overrides the nexthop.
+     * 
+     * XXX We depend on this mechanism to enforce per-recipient concurrencies
+     * for local recipients. With "local_transport = local:$myhostname" we
+     * force mail for any domain in $mydestination/$inet_interfaces to share
+     * the same queue.
+     */
+    if ((destination = split_at(STR(channel), ':')) != 0 && *destination)
+       vstring_strcpy(nexthop, destination);
+
     /*
      * Sanity checks.
      */
-    if ((*flags & RESOLVE_FLAG_FAIL) == 0) {
-       if (*STR(channel) == 0) {
-           if (blame == 0)
-               msg_panic("%s: null blame", myname);
-           msg_warn("file %s/%s: parameter %s: null transport is not allowed",
-                    var_config_dir, MAIN_CONF_FILE, blame);
-           *flags |= RESOLVE_FLAG_FAIL;
-       }
-       if (*STR(nexthop) == 0)
-           msg_panic("%s: null nexthop", myname);
+    if (*STR(channel) == 0) {
+       if (blame == 0)
+           msg_panic("%s: null blame", myname);
+       msg_warn("file %s/%s: parameter %s: null transport is not allowed",
+                var_config_dir, MAIN_CONF_FILE, blame);
+       *flags |= RESOLVE_FLAG_FAIL;
+       FREE_MEMORY_AND_RETURN;
     }
+    if (*STR(nexthop) == 0)
+       msg_panic("%s: null nexthop", myname);
 
     /*
-     * The transport map overrides any transport and next-hop host info that
-     * is set up above.
+     * The transport map can selectively override any transport and/or
+     * nexthop host info that is set up above. Unfortunately, the syntax for
+     * nexthop information is transport specific. We therefore need sane and
+     * intuitive semantics for transport map entries that specify a channel
+     * but no nexthop.
+     * 
+     * With non-error transports, the initial nexthop information is the
+     * recipient domain. However, specific main.cf transport definitions may
+     * specify a transport-specific destination, such as a host + TCP socket,
+     * or the pathname of a UNIX-domain socket. With less precedence than
+     * main.cf transport definitions, a main.cf relayhost definition may also
+     * override nexthop information for off-host deliveries.
      * 
-     * With error transports, the nexthop info is arbitrary text that must not
-     * be passed on to regular delivery agents. When the transport map
-     * overrides an error transport without overriding the nexthop
-     * information, or vice versa, update the nexthop information
-     * appropriately.
+     * With the error transport, the nexthop information is free text that
+     * specifies the reason for non-delivery.
+     * 
+     * Because nexthop syntax is transport specific we reset the nexthop
+     * information to the recipient domain when the transport table specifies
+     * a transport without also specifying the nexthop information.
+     * 
+     * Subtle note: reset nexthop even when the transport table does not change
+     * the transport. Otherwise it is hard to get rid of main.cf specified
+     * nexthop information.
      */
-    if ((*flags & RESOLVE_FLAG_FAIL) == 0 && *var_transport_maps) {
-       vstring_strcpy(saved_class_channel, STR(channel));
-       vstring_strcpy(saved_class_nexthop, STR(nexthop));
-
-       if (transport_lookup(STR(nextrcpt), channel, nexthop) != 0) {
-           if (!STREQ(STR(saved_class_channel), STR(channel))
-               && STREQ(STR(saved_class_nexthop), STR(nexthop))) {
-               vstring_strcpy(nexthop, STREQ(STR(channel), var_error_transport) ?
-                   "Address is not deliverable" : STR(saved_class_domain));
-           }
-       } else if (dict_errno != 0) {
+    if (*var_transport_maps) {
+       if (transport_lookup(STR(nextrcpt), rcpt_domain, channel, nexthop) == 0
+           && dict_errno != 0) {
            msg_warn("%s lookup failure", VAR_TRANSPORT_MAPS);
            *flags |= RESOLVE_FLAG_FAIL;
+           FREE_MEMORY_AND_RETURN;
        }
     }
 
@@ -448,26 +556,24 @@ void    resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop,
      */
 #define IGNORE_ADDR_EXTENSION   ((char **) 0)
 
-    if ((*flags & RESOLVE_FLAG_FAIL) == 0 && relocated_maps != 0) {
+    if (relocated_maps != 0) {
        const char *newloc;
 
        if ((newloc = mail_addr_find(relocated_maps, STR(nextrcpt),
                                     IGNORE_ADDR_EXTENSION)) != 0) {
-           vstring_strcpy(channel, var_error_transport);
+           vstring_strcpy(channel, MAIL_SERVICE_ERROR);
            vstring_sprintf(nexthop, "User has moved to %s", newloc);
        } else if (dict_errno != 0) {
            msg_warn("%s lookup failure", VAR_RELOCATED_MAPS);
            *flags |= RESOLVE_FLAG_FAIL;
+           FREE_MEMORY_AND_RETURN;
        }
     }
 
     /*
      * Clean up.
      */
-    if (saved_domain)
-       tok822_free_tree(saved_domain);
-    tok822_free_tree(tree);
-    vstring_free(addr_buf);
+    FREE_MEMORY_AND_RETURN;
 }
 
 /* Static, so they can be used by the network protocol interface only. */
@@ -516,9 +622,6 @@ void    resolve_init(void)
     channel = vstring_alloc(100);
     nexthop = vstring_alloc(100);
     nextrcpt = vstring_alloc(100);
-    saved_class_channel = vstring_alloc(100);
-    saved_class_nexthop = vstring_alloc(100);
-    saved_class_domain = vstring_alloc(100);
 
     if (*var_virt_alias_doms)
        virt_alias_doms =
index d34a464822f3f1651fbfd15c6d896c43aeeae717..f551ecd1eb80ff3a05071ade2ef2c57df35dccb8 100644 (file)
@@ -90,6 +90,12 @@ void    rewrite_tree(char *unused_ruleset, TOK822 *tree)
     TOK822 *bang;
     TOK822 *local;
 
+    /*
+     * XXX If you change this module, quote_822_local.c, or tok822_parse.c,
+     * be sure to re-run the tests under "make rewrite_clnt_test" and "make
+     * resolve_clnt_test" in the global directory.
+     */
+
     /*
      * Sanity check.
      */
@@ -158,10 +164,13 @@ void    rewrite_tree(char *unused_ruleset, TOK822 *tree)
     }
 
     /*
-     * Append missing .domain
+     * Append missing .domain, but leave broken forms ending in @ alone. This
+     * merely makes diagnostics more accurate by leaving bogus addresses
+     * alone.
      */
     if (var_append_dot_mydomain != 0
        && (domain = tok822_rfind_type(tree->tail, '@')) != 0
+       && domain != tree->tail
        && tok822_find_type(domain, TOK822_DOMLIT) == 0
        && tok822_find_type(domain, '.') == 0) {
        tok822_sub_append(tree, tok822_alloc('.', (char *) 0));
@@ -169,13 +178,17 @@ void    rewrite_tree(char *unused_ruleset, TOK822 *tree)
     }
 
     /*
-     * Strip trailing dot at end of domain, but not dot-dot. This merely
-     * makes diagnostics more accurate by leaving bogus addresses alone.
+     * Strip trailing dot at end of domain, but not dot-dot or @-dot. This
+     * merely makes diagnostics more accurate by leaving bogus addresses
+     * alone.
      */
+#if 0
     if (tree->tail->type == '.'
-       && tok822_rfind_type(tree->tail, '@') != 0
-       && tree->tail->prev->type != '.')
+       && tree->tail->prev
+       && tree->tail->prev->type != '.'
+       && tree->tail->prev->type != '@')
        tok822_free_tree(tok822_sub_keep_before(tree, tree->tail));
+#endif
 }
 
 /* rewrite_addr - rewrite address according to rule set */
index 0ac8a4fe33c9a2acd46f2c708e4a10ac105114d8..fa608025835cf1fc2c6500e09688f4928b365764 100644 (file)
@@ -8,8 +8,9 @@
 /*
 /*     void    transport_init()
 /*
-/*     int     transport_lookup(address, channel, nexthop)
+/*     int     transport_lookup(address, rcpt_domain, channel, nexthop)
 /*     const char *address;
+/*     const char *rcpt_domain;
 /*     VSTRING *channel;
 /*     VSTRING *nexthop;
 /* DESCRIPTION
@@ -65,6 +66,7 @@
 #include <mail_params.h>
 #include <maps.h>
 #include <match_parent_style.h>
+#include <mail_proto.h>
 
 /* Application-specific. */
 
@@ -77,13 +79,6 @@ static VSTRING *wildcard_nexthop;
 
 #define STR(x) vstring_str(x)
 
- /*
-  * Macro for consistent updates of the transport and nexthop results.
-  */
-#define UPDATE_IF_SPECIFIED(dst, src) do { \
-       if ((src) && *(src)) vstring_strcpy((dst), (src)); \
-    } while (0)
-
 /* transport_init - pre-jail initialization */
 
 void    transport_init(void)
@@ -95,15 +90,52 @@ void    transport_init(void)
     transport_match_parent_style = match_parent_style(VAR_TRANSPORT_MAPS);
 }
 
+/* update_entry - update from transport table entry */
+
+static void update_entry(const char *new_channel, const char *new_nexthop,
+                                const char *rcpt_domain, VSTRING *channel,
+                                VSTRING *nexthop)
+{
+
+    /*
+     * :[nexthop] means don't change the channel, and don't change the
+     * nexthop unless a non-default nexthop is specified. Thus, a right-hand
+     * side of ":" is the transport table equivalent of a NOOP.
+     */
+    if (*new_channel == 0) {                   /* :[nexthop] */
+       if (*new_nexthop != 0)
+           vstring_strcpy(nexthop, new_nexthop);
+    }
+
+    /*
+     * transport[:[nexthop]] means change the channel, and reset the nexthop
+     * to the default unless a non-default nexthop is specified.
+     */
+    else {
+       vstring_strcpy(channel, new_channel);
+       if (*new_nexthop != 0)
+           vstring_strcpy(nexthop, new_nexthop);
+       else if (strcmp(STR(channel), MAIL_SERVICE_ERROR) != 0)
+           vstring_strcpy(nexthop, rcpt_domain);
+       else
+           vstring_strcpy(nexthop, "Address is undeliverable");
+    }
+}
+
 /* find_transport_entry - look up and parse transport table entry */
 
-static int find_transport_entry(const char *key, int flags,
-                                       VSTRING *channel, VSTRING *nexthop)
+static int find_transport_entry(const char *key, const char *rcpt_domain,
+                             int flags, VSTRING *channel, VSTRING *nexthop)
 {
     char   *saved_value;
     const char *host;
     const char *value;
 
+    /*
+     * Reset previous error history.
+     */
+    dict_errno = 0;
+
 #define FOUND          1
 #define NOTFOUND       0
 
@@ -115,11 +147,8 @@ static int find_transport_entry(const char *key, int flags,
      * 
      * XXX Should report lookup failure status to caller instead of aborting.
      */
-    if ((value = maps_find(transport_path, key, flags)) == 0) {
-       if (dict_errno != 0)
-           msg_fatal("transport table lookup problem.");
+    if ((value = maps_find(transport_path, key, flags)) == 0)
        return (NOTFOUND);
-    }
 
     /*
      * It would be great if we could specify a recipient address in the
@@ -131,8 +160,8 @@ static int find_transport_entry(const char *key, int flags,
     else {
        saved_value = mystrdup(value);
        host = split_at(saved_value, ':');
-       UPDATE_IF_SPECIFIED(nexthop, host);
-       UPDATE_IF_SPECIFIED(channel, saved_value);
+       update_entry(saved_value, host ? host : "", rcpt_domain,
+                    channel, nexthop);
        myfree(saved_value);
        return (FOUND);
     }
@@ -159,13 +188,15 @@ void    transport_wildcard_init(void)
 #define FULL           0
 #define PARTIAL                DICT_FLAG_FIXED
 
-    if (find_transport_entry(WILDCARD, FULL, channel, nexthop)) {
+    if (find_transport_entry(WILDCARD, "", FULL, channel, nexthop)) {
        wildcard_channel = channel;
        wildcard_nexthop = nexthop;
        if (msg_verbose)
            msg_info("wildcard_{chan:hop}={%s:%s}",
              vstring_str(wildcard_channel), vstring_str(wildcard_nexthop));
     } else {
+       if (dict_errno != 0)
+           msg_fatal("transport table initialization problem.");
        vstring_free(channel);
        vstring_free(nexthop);
     }
@@ -173,9 +204,10 @@ void    transport_wildcard_init(void)
 
 /* transport_lookup - map a transport domain */
 
-int     transport_lookup(const char *addr, VSTRING *channel, VSTRING *nexthop)
+int     transport_lookup(const char *addr, const char *rcpt_domain,
+                                VSTRING *channel, VSTRING *nexthop)
 {
-    char   *full_addr = lowercase(mystrdup(*addr ? addr : var_xport_null_key));
+    char   *full_addr;
     char   *stripped_addr;
     char   *ratsign = 0;
     const char *name;
@@ -185,6 +217,15 @@ int     transport_lookup(const char *addr, VSTRING *channel, VSTRING *nexthop)
 #define STREQ(x,y)     (strcmp((x), (y)) == 0)
 #define DISCARD_EXTENSION ((char **) 0)
 
+    /*
+     * The null recipient is rewritten to the local mailer daemon address.
+     */
+    if (*addr == 0) {
+       msg_warn("transport_lookup: null address - skipping table lookup");
+       return (NOTFOUND);
+    }
+    full_addr = lowercase(mystrdup(addr));
+
     /*
      * The optimizer will replace multiple instances of this macro expansion
      * by gotos to a single instance that does the same thing.
@@ -194,16 +235,6 @@ int     transport_lookup(const char *addr, VSTRING *channel, VSTRING *nexthop)
        return (x); \
     }
 
-    /*
-     * If this is a special address such as <> do only one lookup of the full
-     * string. Specify the FULL flag to include regexp maps in the query.
-     */
-    if (STREQ(full_addr, var_xport_null_key)) {
-       if (find_transport_entry(full_addr, FULL, channel, nexthop))
-           RETURN_FREE(FOUND);
-       RETURN_FREE(NOTFOUND);
-    }
-
     /*
      * Look up the full address with the FULL flag to include regexp maps in
      * the query.
@@ -211,8 +242,10 @@ int     transport_lookup(const char *addr, VSTRING *channel, VSTRING *nexthop)
     if ((ratsign = strrchr(full_addr, '@')) == 0 || ratsign[1] == 0)
        msg_panic("transport_lookup: bad address: \"%s\"", full_addr);
 
-    if (find_transport_entry(full_addr, FULL, channel, nexthop))
+    if (find_transport_entry(full_addr, rcpt_domain, FULL, channel, nexthop))
        RETURN_FREE(FOUND);
+    if (dict_errno != 0)
+       RETURN_FREE(NOTFOUND);
 
     /*
      * If the full address did not match, and there is an address extension,
@@ -221,13 +254,14 @@ int     transport_lookup(const char *addr, VSTRING *channel, VSTRING *nexthop)
      */
     if ((stripped_addr = strip_addr(full_addr, DISCARD_EXTENSION,
                                    *var_rcpt_delim)) != 0) {
-       if (find_transport_entry(stripped_addr, PARTIAL,
-                                channel, nexthop)) {
-           myfree(stripped_addr);
+       found = find_transport_entry(stripped_addr, rcpt_domain, PARTIAL,
+                                    channel, nexthop);
+
+       myfree(stripped_addr);
+       if (found)
            RETURN_FREE(FOUND);
-       } else {
-           myfree(stripped_addr);
-       }
+       if (dict_errno != 0)
+           RETURN_FREE(NOTFOUND);
     }
 
     /*
@@ -246,9 +280,11 @@ int     transport_lookup(const char *addr, VSTRING *channel, VSTRING *nexthop)
      * Specify that the lookup key is partial, to avoid matching partial keys
      * with regular expressions.
      */
-    for (found = 0, name = ratsign + 1; /* void */ ; name = next) {
-       if (find_transport_entry(name, PARTIAL, channel, nexthop))
+    for (name = ratsign + 1; /* void */ ; name = next) {
+       if (find_transport_entry(name, rcpt_domain, PARTIAL, channel, nexthop))
            RETURN_FREE(FOUND);
+       if (dict_errno != 0)
+           RETURN_FREE(NOTFOUND);
        if ((next = strchr(name + 1, '.')) == 0)
            break;
        if (transport_match_parent_style == MATCH_FLAG_PARENT)
@@ -259,8 +295,8 @@ int     transport_lookup(const char *addr, VSTRING *channel, VSTRING *nexthop)
      * Fall back to the wild-card entry.
      */
     if (wildcard_channel) {
-       UPDATE_IF_SPECIFIED(channel, STR(wildcard_channel));
-       UPDATE_IF_SPECIFIED(nexthop, STR(wildcard_nexthop));
+       update_entry(STR(wildcard_channel), STR(wildcard_nexthop),
+                    rcpt_domain, channel, nexthop);
        RETURN_FREE(FOUND);
     }
 
index 2ebe3def400cfb791dbc7a6aafed2f6c670c4fdc..0884eb291dbf85895c48503ca20b8a059e9f8793 100644 (file)
@@ -18,7 +18,7 @@
   */
 extern void transport_init(void);
 extern void transport_wildcard_init(void);
-extern int transport_lookup(const char *, VSTRING *, VSTRING *);
+extern int transport_lookup(const char *, const char *, VSTRING *, VSTRING *);
 
 /* LICENSE
 /* .ad
index d5ca7a17715ffb4c7ff5786dedb185fbde7d2471..2a7f0233fa521cfeacecca02dbd092b1e3add658 100644 (file)
 /* .sp
 /*     Syntax is \fItransport\fR:\fInexthop\fR; see \fBtransport\fR(5)
 /*     for details. The :\fInexthop\fR part is optional.
-/* .IP \fBerror_transport\fR
-/*     Where to deliver mail for non-existent recipients in domains
-/*     that match \fBvirtual_alias_domains\fR (all recipients
-/*     in simulated virtual domains must be aliased to some other 
-/*     local or remote domain), or for recipients that have moved.
-/*     The default transport is \fBerror\fR.
-/* .sp
-/*     Syntax is \fItransport\fR:\fInexthop\fR; see \fBtransport\fR(5)
-/*     for details. The :\fInexthop\fR part is optional.
 /* .IP \fBvirtual_transport\fR
 /*     Where to deliver mail for non-local domains that match
 /*     \fB$virtual_mailbox_domains\fR.
 /* .IP \fBtransport_maps\fR
 /*     List of tables with \fIdomain\fR to (\fItransport, nexthop\fR)
 /*     mappings.
-/* .IP \fBtransport_null_address_lookup_key\fR
-/*     Lookup key to be used for the null address.
 /* SEE ALSO
 /*     master(8) process manager
 /*     syslogd(8) system logging
@@ -208,11 +197,9 @@ bool    var_append_dot_mydomain;
 bool    var_append_at_myorigin;
 bool    var_percent_hack;
 char   *var_local_transport;
-char   *var_error_transport;
 char   *var_virt_transport;
 char   *var_relay_transport;
 int     var_resolve_dequoted;
-char   *var_xport_null_key;
 char   *var_virt_alias_maps;           /* XXX virtual_alias_domains */
 char   *var_virt_mailbox_maps;         /* XXX virtual_mailbox_domains */
 char   *var_virt_alias_doms;
@@ -284,10 +271,8 @@ int     main(int argc, char **argv)
     static CONFIG_STR_TABLE str_table[] = {
        VAR_TRANSPORT_MAPS, DEF_TRANSPORT_MAPS, &var_transport_maps, 0, 0,
        VAR_LOCAL_TRANSPORT, DEF_LOCAL_TRANSPORT, &var_local_transport, 1, 0,
-       VAR_ERROR_TRANSPORT, DEF_ERROR_TRANSPORT, &var_error_transport, 1, 0,
        VAR_VIRT_TRANSPORT, DEF_VIRT_TRANSPORT, &var_virt_transport, 1, 0,
        VAR_RELAY_TRANSPORT, DEF_RELAY_TRANSPORT, &var_relay_transport, 1, 0,
-       VAR_XPORT_NULL_KEY, DEF_XPORT_NULL_KEY, &var_xport_null_key, 1, 0,
        VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0,
        VAR_VIRT_ALIAS_DOMS, DEF_VIRT_ALIAS_DOMS, &var_virt_alias_doms, 0, 0,
        VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
index fa628c4881c28d4c14929e450bdd5f21c1f13b29..9a63fe53c3be9b7ac26f9a4b9bc47b2b25d22713 100644 (file)
 /*     int     valid_hostaddr(addr, gripe)
 /*     const char *addr;
 /*     int     gripe;
+/*
+/*     int     valid_hostliteral(addr, gripe)
+/*     const char *addr;
+/*     int     gripe;
 /* DESCRIPTION
 /*     valid_hostname() scrutinizes a hostname: the name should be no
 /*     longer than VALID_HOSTNAME_LEN characters, should contain only
 /*     no leading or trailing dots or hyphens, no labels longer than
 /*     VALID_LABEL_LEN characters, and no numeric top-level domain.
 /*
-/*     valid_hostaddr() requirs that the input is a valid string
+/*     valid_hostaddr() requires that the input is a valid string
 /*     representation of an internet network address.
 /*
+/*     valid_hostliteral() requires an address enclosed in [].
+/*
 /*     These routines operate silently unless the gripe parameter
 /*     specifies a non-zero value. The macros DO_GRIPE and DONT_GRIPE
 /*     provide suitable constants.
@@ -192,6 +198,39 @@ int     valid_hostaddr(const char *addr, int gripe)
     return (1);
 }
 
+/* valid_hostliteral - validate address literal */
+
+int     valid_hostliteral(const char *addr, int gripe)
+{
+    const char *myname = "valid_hostliteral";
+    char    buf[100];
+    const char *last;
+
+    if (*addr != '[') {
+       if (gripe)
+           msg_warn("%s: '[' expected at start: %.100s", myname, addr);
+       return (0);
+    }
+    if ((last = strchr(addr, ']')) == 0) {
+       if (gripe)
+           msg_warn("%s: ']' expected at end: %.100s", myname, addr);
+       return (0);
+    }
+    if (last[1]) {
+       if (gripe)
+           msg_warn("%s: unexpected text after ']': %.100s", myname, addr);
+       return (0);
+    }
+    if (last - addr >= sizeof(buf)) {
+       if (gripe)
+           msg_warn("%s: too much text: %.100s", myname, addr);
+       return (0);
+    }
+    strncpy(buf, addr + 1, last - addr - 1);
+    buf[last - addr - 1] = 0;
+    return (valid_hostaddr(buf, gripe));
+}
+
 #ifdef TEST
 
  /*
@@ -216,6 +255,7 @@ int     main(int unused_argc, char **argv)
        msg_info("testing: \"%s\"", vstring_str(buffer));
        valid_hostname(vstring_str(buffer), DO_GRIPE);
        valid_hostaddr(vstring_str(buffer), DO_GRIPE);
+       valid_hostliteral(vstring_str(buffer), DO_GRIPE);
     }
     exit(0);
 }
index 8de21619e2624d9b9cb6012c7b897c6a94366af0..e66bbc53d7c87f98a7f35fe46e8cdcf6ae1d360d 100644 (file)
@@ -21,6 +21,7 @@
 
 extern int valid_hostname(const char *, int);
 extern int valid_hostaddr(const char *, int);
+extern int valid_hostliteral(const char *, int);
 
 /* LICENSE
 /* .ad
index 9d48f5db0e9c7d555c3c0aa19529262b5085860b..bb50ec0268c3d9927e2e80273aac2f562a536a74 100644 (file)
@@ -36,3 +36,8 @@ a.bb-.b
 a.b.-bb
 a.b.bb-
 a-a.b-b
+[1.2.3.4]
+[321.255.255.255]
+[1.2.3.4
+[1.2.3.4]foo
+[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
index 28e2e737c5d18b96842469ad31fc11023db6d281..7b093805332c1dd4bee68bd27a62a91272044a23 100644 (file)
 ./valid_hostname: testing: "123456789012345678901234567890123456789012345678901234567890123"
 ./valid_hostname: warning: valid_hostname: numeric hostname: 123456789012345678901234567890123456789012345678901234567890123
 ./valid_hostname: warning: valid_hostaddr: invalid octet value: 123456789012345678901234567890123456789012345678901234567890123
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 123456789012345678901234567890123456789012345678901234567890123
 ./valid_hostname: testing: "1234567890123456789012345678901234567890123456789012345678901234"
 ./valid_hostname: warning: valid_hostname: hostname label too long: 1234567890123456789012345678901234567890123456789012345678901234
 ./valid_hostname: warning: valid_hostaddr: invalid octet value: 1234567890123456789012345678901234567890123456789012345678901234
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1234567890123456789012345678901234567890123456789012345678901234
 ./valid_hostname: testing: "a.123456789012345678901234567890123456789012345678901234567890123.b"
 ./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.123456789012345678901234567890123456789012345678901234567890123.b
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.123456789012345678901234567890123456789012345678901234567890123.b
 ./valid_hostname: testing: "a.1234567890123456789012345678901234567890123456789012345678901234.b"
 ./valid_hostname: warning: valid_hostname: hostname label too long: a.1234567890123456789012345678901234567890123456789012345678901234.b
 ./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.1234567890123456789012345678901234567890123456789012345678901234.b
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.1234567890123456789012345678901234567890123456789012345678901234.b
 ./valid_hostname: testing: "1.2.3.4"
 ./valid_hostname: warning: valid_hostname: numeric hostname: 1.2.3.4
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.4
 ./valid_hostname: testing: "321.255.255.255"
 ./valid_hostname: warning: valid_hostname: numeric hostname: 321.255.255.255
 ./valid_hostname: warning: valid_hostaddr: invalid octet value: 321.255.255.255
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 321.255.255.255
 ./valid_hostname: testing: "0.0.0.0"
 ./valid_hostname: warning: valid_hostname: numeric hostname: 0.0.0.0
 ./valid_hostname: warning: valid_hostaddr: bad initial octet value: 0.0.0.0
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 0.0.0.0
 ./valid_hostname: testing: "255.255.255.255"
 ./valid_hostname: warning: valid_hostname: numeric hostname: 255.255.255.255
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 255.255.255.255
 ./valid_hostname: testing: "0.255.255.255"
 ./valid_hostname: warning: valid_hostname: numeric hostname: 0.255.255.255
 ./valid_hostname: warning: valid_hostaddr: bad initial octet value: 0.255.255.255
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 0.255.255.255
 ./valid_hostname: testing: "1.2.3.321"
 ./valid_hostname: warning: valid_hostname: numeric hostname: 1.2.3.321
 ./valid_hostname: warning: valid_hostaddr: invalid octet value: 1.2.3.321
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.321
 ./valid_hostname: testing: "1.2.3"
 ./valid_hostname: warning: valid_hostname: numeric hostname: 1.2.3
 ./valid_hostname: warning: valid_hostaddr: invalid octet count: 1.2.3
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3
 ./valid_hostname: testing: "1.2.3.4.5"
 ./valid_hostname: warning: valid_hostname: numeric hostname: 1.2.3.4.5
 ./valid_hostname: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.4.5
 ./valid_hostname: testing: "1..2.3.4"
 ./valid_hostname: warning: valid_hostname: misplaced delimiter: 1..2.3.4
 ./valid_hostname: warning: valid_hostaddr: misplaced dot: 1..2.3.4
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1..2.3.4
 ./valid_hostname: testing: ".1.2.3.4"
 ./valid_hostname: warning: valid_hostname: misplaced delimiter: .1.2.3.4
 ./valid_hostname: warning: valid_hostaddr: misplaced dot: .1.2.3.4
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: .1.2.3.4
 ./valid_hostname: testing: "1.2.3.4.5."
 ./valid_hostname: warning: valid_hostname: misplaced delimiter: 1.2.3.4.5.
 ./valid_hostname: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5.
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.4.5.
 ./valid_hostname: testing: "1"
 ./valid_hostname: warning: valid_hostname: numeric hostname: 1
 ./valid_hostname: warning: valid_hostaddr: invalid octet count: 1
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1
 ./valid_hostname: testing: "."
 ./valid_hostname: warning: valid_hostname: misplaced delimiter: .
 ./valid_hostname: warning: valid_hostaddr: misplaced dot: .
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: .
 ./valid_hostname: testing: ""
 ./valid_hostname: warning: valid_hostname: empty hostname
 ./valid_hostname: warning: valid_hostaddr: empty address
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 
 ./valid_hostname: testing: "321"
 ./valid_hostname: warning: valid_hostname: numeric hostname: 321
 ./valid_hostname: warning: valid_hostaddr: invalid octet value: 321
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 321
 ./valid_hostname: testing: "f"
 ./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): f
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: f
 ./valid_hostname: testing: "f.2.3.4"
 ./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): f.2.3.4
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: f.2.3.4
 ./valid_hostname: testing: "1f.2.3.4"
 ./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1f.2.3.4
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1f.2.3.4
 ./valid_hostname: testing: "f1.2.3.4"
 ./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): f1.2.3.4
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: f1.2.3.4
 ./valid_hostname: testing: "1.2f.3.4"
 ./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2f.3.4
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2f.3.4
 ./valid_hostname: testing: "1.f2.3.4"
 ./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.f2.3.4
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.f2.3.4
 ./valid_hostname: testing: "1.2.3.4f"
 ./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.4f
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.4f
 ./valid_hostname: testing: "1.2.3.f4"
 ./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.f4
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.f4
 ./valid_hostname: testing: "1.2.3.f"
 ./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.f
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.f
 ./valid_hostname: testing: "-.a.b"
 ./valid_hostname: warning: valid_hostname: misplaced hyphen: -.a.b
 ./valid_hostname: warning: valid_hostaddr: invalid character 45(decimal): -.a.b
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: -.a.b
 ./valid_hostname: testing: "a.-.b"
 ./valid_hostname: warning: valid_hostname: misplaced hyphen: a.-.b
 ./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.-.b
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.-.b
 ./valid_hostname: testing: "a.b.-"
 ./valid_hostname: warning: valid_hostname: misplaced hyphen: a.b.-
 ./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.b.-
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.b.-
 ./valid_hostname: testing: "-aa.b.b"
 ./valid_hostname: warning: valid_hostname: misplaced hyphen: -aa.b.b
 ./valid_hostname: warning: valid_hostaddr: invalid character 45(decimal): -aa.b.b
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: -aa.b.b
 ./valid_hostname: testing: "aa-.b.b"
 ./valid_hostname: warning: valid_hostname: misplaced hyphen: aa-.b.b
 ./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): aa-.b.b
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: aa-.b.b
 ./valid_hostname: testing: "a.-bb.b"
 ./valid_hostname: warning: valid_hostname: misplaced hyphen: a.-bb.b
 ./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.-bb.b
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.-bb.b
 ./valid_hostname: testing: "a.bb-.b"
 ./valid_hostname: warning: valid_hostname: misplaced hyphen: a.bb-.b
 ./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.bb-.b
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.bb-.b
 ./valid_hostname: testing: "a.b.-bb"
 ./valid_hostname: warning: valid_hostname: misplaced hyphen: a.b.-bb
 ./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.b.-bb
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.b.-bb
 ./valid_hostname: testing: "a.b.bb-"
 ./valid_hostname: warning: valid_hostname: misplaced hyphen: a.b.bb-
 ./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.b.bb-
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.b.bb-
 ./valid_hostname: testing: "a-a.b-b"
 ./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a-a.b-b
+./valid_hostname: warning: valid_hostliteral: '[' expected at start: a-a.b-b
+./valid_hostname: testing: "[1.2.3.4]"
+./valid_hostname: warning: valid_hostname: invalid character 91(decimal): [1.2.3.4]
+./valid_hostname: warning: valid_hostaddr: invalid character 91(decimal): [1.2.3.4]
+./valid_hostname: testing: "[321.255.255.255]"
+./valid_hostname: warning: valid_hostname: invalid character 91(decimal): [321.255.255.255]
+./valid_hostname: warning: valid_hostaddr: invalid character 91(decimal): [321.255.255.255]
+./valid_hostname: warning: valid_hostaddr: invalid octet value: 321.255.255.255
+./valid_hostname: testing: "[1.2.3.4"
+./valid_hostname: warning: valid_hostname: invalid character 91(decimal): [1.2.3.4
+./valid_hostname: warning: valid_hostaddr: invalid character 91(decimal): [1.2.3.4
+./valid_hostname: warning: valid_hostliteral: ']' expected at end: [1.2.3.4
+./valid_hostname: testing: "[1.2.3.4]foo"
+./valid_hostname: warning: valid_hostname: invalid character 91(decimal): [1.2.3.4]foo
+./valid_hostname: warning: valid_hostaddr: invalid character 91(decimal): [1.2.3.4]foo
+./valid_hostname: warning: valid_hostliteral: unexpected text after ']': [1.2.3.4]foo
+./valid_hostname: testing: "[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]"
+./valid_hostname: warning: valid_hostname: invalid character 91(decimal): [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+./valid_hostname: warning: valid_hostaddr: invalid character 91(decimal): [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+./valid_hostname: warning: valid_hostliteral: too much text: [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx