]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.0.13-20030702
authorWietse Venema <wietse@porcupine.org>
Wed, 2 Jul 2003 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:28:57 +0000 (06:28 +0000)
101 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/README_FILES/LDAP_README
postfix/README_FILES/SMTPD_PROXY_README [new file with mode: 0644]
postfix/README_FILES/VIRTUAL_README
postfix/RELEASE_NOTES
postfix/conf/access
postfix/conf/cidr_table [new file with mode: 0644]
postfix/conf/pcre_table
postfix/conf/postfix-files
postfix/conf/postfix-script
postfix/conf/regexp_table
postfix/conf/sample-ldap.cf
postfix/conf/sample-misc.cf
postfix/conf/sample-smtpd.cf
postfix/conf/sample-verify.cf
postfix/conf/tcp_table [new file with mode: 0644]
postfix/conf/transport
postfix/html/access.5.html
postfix/html/cleanup.8.html
postfix/html/faq.html
postfix/html/pcre_table.5.html
postfix/html/regexp_table.5.html
postfix/html/rewrite.html
postfix/html/smtp.8.html
postfix/html/smtpd.8.html
postfix/html/transport.5.html
postfix/html/verify.8.html
postfix/man/Makefile.in
postfix/man/man5/access.5
postfix/man/man5/cidr_table.5 [new file with mode: 0644]
postfix/man/man5/pcre_table.5
postfix/man/man5/regexp_table.5
postfix/man/man5/tcp_table.5 [new file with mode: 0644]
postfix/man/man5/transport.5
postfix/man/man8/cleanup.8
postfix/man/man8/smtp.8
postfix/man/man8/smtpd.8
postfix/man/man8/verify.8
postfix/proto/Makefile.in
postfix/proto/access
postfix/proto/cidr_table [new file with mode: 0644]
postfix/proto/pcre_table
postfix/proto/regexp_table
postfix/proto/tcp_table [new file with mode: 0644]
postfix/proto/transport
postfix/src/bounce/Makefile.in
postfix/src/bounce/bounce_notify_util.c
postfix/src/bounce/bounce_service.h
postfix/src/cleanup/cleanup.c
postfix/src/cleanup/cleanup.h
postfix/src/cleanup/cleanup_init.c
postfix/src/cleanup/cleanup_out_recipient.c
postfix/src/global/Makefile.in
postfix/src/global/cleanup_user.h
postfix/src/global/header_token.c
postfix/src/global/log_adhoc.c
postfix/src/global/mail_conf_int.c
postfix/src/global/mail_conf_str.c
postfix/src/global/mail_copy.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/resolve_clnt.c
postfix/src/global/verify_clnt.h
postfix/src/global/xtext.c
postfix/src/global/xtext.h
postfix/src/nqmgr/qmgr_message.c
postfix/src/postcat/postcat.c
postfix/src/qmgr/qmgr_message.c
postfix/src/showq/showq.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd.h
postfix/src/smtpd/smtpd_check.c
postfix/src/smtpd/smtpd_proxy.c [new file with mode: 0644]
postfix/src/smtpd/smtpd_proxy.h [new file with mode: 0644]
postfix/src/smtpd/smtpd_state.c
postfix/src/util/Makefile.in
postfix/src/util/dict_cidr.c [new file with mode: 0644]
postfix/src/util/dict_cidr.h [new file with mode: 0644]
postfix/src/util/dict_cidr.in [new file with mode: 0644]
postfix/src/util/dict_cidr.map [new file with mode: 0644]
postfix/src/util/dict_cidr.ref [new file with mode: 0644]
postfix/src/util/dict_ldap.c
postfix/src/util/dict_open.c
postfix/src/util/dict_pcre.c
postfix/src/util/dict_pcre.in
postfix/src/util/dict_pcre.map
postfix/src/util/dict_pcre.ref
postfix/src/util/dict_regexp.c
postfix/src/util/dict_regexp.in
postfix/src/util/dict_regexp.map
postfix/src/util/dict_regexp.ref
postfix/src/util/dict_tcp.c
postfix/src/util/hex_quote.c
postfix/src/util/match_ops.c
postfix/src/util/safe_open.c
postfix/src/util/valid_hostname.c
postfix/src/verify/verify.c

index c662f44f532da97df726907434bc035a062a5529..2388a60ed6a84b87fefba423f2ad4b3687f6c9b1 100644 (file)
@@ -26,6 +26,8 @@
 -TDELIVER_ATTR
 -TDELIVER_REQUEST
 -TDICT
+-TDICT_CIDR
+-TDICT_CIDR_ENTRY
 -TDICT_DB
 -TDICT_DBM
 -TDICT_DEBUG
index 0984941cc9823ca3db4e7bd06a8a8ad1dba3390f..6f4122a0d088e824ad8abc19af475659f2a8c197 100644 (file)
@@ -8189,8 +8189,8 @@ Apologies for any names omitted.
        of mail probes, so it will no longer block for in_flow_delay
        seconds when mail arrives faster than it is delivered.
        Still need to make mail_stream_finish() asynchronous in
-       order to avoid blocking for trigger_timeout seconds when
-       the queue manager is overwhelmed.  Files:  global/post_mail.c,
+       order to avoid blocking for trigger_timeout seconds when the
+       queue manager is overwhelmed.  Files:  global/post_mail.c,
        verify/verify.c.
 
        Bugfix: removed extraneous sleep() after the last attempt
@@ -8201,6 +8201,42 @@ Apologies for any names omitted.
        Bugfix: the stricter postdrop input filter broke "sendmail
        -bs". Found by Lutz Jaenicke. File: smtpd/smtpd.c.
 
+20030614
+
+       Portability: Dropped support for client side LDAP caching.
+       As of release 2.1.13 OpenLDAP no longer supports client
+       side caching, it has been deprecated for some time, and
+       never worked well.  Implemented by Victor Duchovni, Morgan
+       Stanley, and further enhanced by Lamont Jones, HP. Files:
+       src/util/dict_ldap.c, conf/sample-ldap.cf,
+       README_FILES/LDAP_README.
+
+       Safety: Given suitable invalid database contents, LDAP
+       lookups can produce too many results, enter an infinite
+       loop in the expansion of "special result attributes" (LDAP
+       DNs and LDAP URLs) or just consume excessive server resources
+       returning large result sets.  Three new (per LDAP map)
+       configuration parameters enable one to set limits on
+       recursive nesting, result expansion and the server response
+       "entry" count. Implemented by Victor Duchovni, Morgan
+       Stanley, further enanced by Lamont Jones, HP. Files:
+       src/util/dict_ldap.c, conf/sample-ldap.cf,
+       README_FILES/LDAP_README.
+
+20030616
+
+       Feature: in mail delivery status reports, report the sender
+       address as X-Postfix-Sender. Matthias Andree. File:
+       bounce/bounce_notify_util.c.
+
+       Cleanup: in mail delivery status reports, transform the
+       original recipient into xtext format as required by RFC
+       1891. Files: bounce/bounce_notify_util.c, util/xtext.[hc].
+
+       Cleanup: more accurate "postfix check" warning for files
+       that miss one or more of the required mode 02111 execute
+       permission bits. Matthias Andree. File: conf/postfix-script.
+
 20030618
 
        After "postfix reload", the master daemon now warns when
@@ -8208,6 +8244,20 @@ Apologies for any names omitted.
        of passing incorrect information to the smtp server. File:
        master/master_ent.c.
 
+20030619
+
+       Feature: the Postfix SMTP server can send all mail into a
+       proxy server, for example a real-time SPAM filter. This
+       proxy is supposed to send the mail into another Postfix
+       SMTP server process for normal delivery. Files: smtpd/smtpd.c
+       smtpd/smtpd_proxy.[hc].
+
+20030620
+
+       Bugfix: a cut-and-paste error caused the proxy server's
+       354 status code to be reported when a proxy connection
+       broke during the DATA phase. File: smtpd.c.
+
 20030620
 
        Bugfix: after the last change to postdrop, postcat no longer
@@ -8217,6 +8267,74 @@ Apologies for any names omitted.
        sendmail, "-t" broke multi-line recipient headers.  Victor
        Duchovni, Morgan Stanley. File: sendmail/sendmail.c.
 
+20030621
+
+       Workaround: the safe_open(O_CREAT) race condition exploit
+       avoiding code tries a little harder when it encounters a
+       race condition. File: util/safe_open.c.
+
+20030623
+
+       Non-prod operator precedence bug with detecting end of
+       DATA. Matthias Andree. File: smtpd/smtpd.c.
+
+20030624
+
+       Bugfix: reject_unverified_address() set the defer_if_reject
+       flag when the verify service was unavailable (which never
+       happens). Victor Duchovni, Morgan Stanley. File:
+       smtpd/smtpd_check.c.
+
+       New parameters address_verify_poll_{count,delay} that
+       control how often to poll the address verification service
+       for the completion of an address verification request.
+       Specify address_verify_poll_count=1 to implement a crude
+       form of greylisting, that is, always defer the first delivery
+       attempt for an unknown address.  File: smtpd/smtpd_check.c.
+
+       Bugfix: after the last change to postdrop, postcat no longer
+       recognized non-maildrop queue files as valid. File:
+       postcat/postcat.c.
+
+20030629
+
+       Cleanup: replaced references to "simulated virtual domains"
+       by "virtual alias domains". Victor Duchovni, Morgan Stanley.
+
+20030630
+
+       Feature: smtp_quote_rfc821_envelope=(yes|no) to control
+       RFC 821 style quoting of MAIL FROM and RCPT TO addresses.
+       Files: global/mail_params.h, smtp/smtp.c, smtp/smtp_proto.c.
+
+20030701
+
+       Bugfix: multi-recipient probes triggered a bug in the SMTP
+       client.  File: smtp/smtp_proto.c.
+
+       Feature: enable_original_recipient (default: yes) to control
+       whether Postfix keeps track of original recipient address
+       information. Victor Duchovni, Morgan Stanley.  Files:
+       cleanup/cleanup.c, cleanup/cleanup_init.c,
+       cleanup/cleanup_out_recipient.c, global/log_adhoc.c,
+       global/mail_copy.c, *qmgr/qmgr_message.c.
+
+       Feature: !/pattern/ support for PCRE lookup tables.  Victor
+       Duchovni, Morgan Stanley.  Files: util/dict_pcre.c.
+
+       Cleanup: allow whitespace after patterns in repexp and pcre
+       tables. Victor Duchovni, Morgan Stanley.  Files:
+       util/dict_pcre.c, util/dict_regexp.c.
+
+20030702
+
+       Feature: CIDR lookup table support, very remotely based on
+       code by Jozsef Kadlecsik. Files: proto/cidr_table,
+       util/dict_cidr.[hc].
+
+       Feature: TCP lookup table support, finally finished.  Files:
+       proto/tcp_table, proto/dict_tcp.[hc].
+
 Open problems:
 
        Low: smtp-source may block when sending large test messages.
index 02c152b3c00e387cc04d4d7630b195dee389d7d5..abf8fd5d969a4117adca62298d34bcbe0efa225c 100644 (file)
@@ -154,21 +154,41 @@ parameter below, "server_host", would be defined in main.cf as
        the Postfix user. Example:
                ldapsource_bind_pw = postfixpw
 
-    cache (no)
-        Whether to use a client-side cache for the LDAP connection. See
-       ldap_enable_cache(3). It's off by default.
-
-    cache_expiry (30 seconds)
-        If the client-side cache is enabled, cached results will expire
-       after this many seconds.
-
-    cache_size (32768 bytes)
-        If the client-side cache is enabled, this is its size in bytes.
+    cache        (IGNORED with a warning)
+    cache_expiry (IGNORED with a warning)
+    cache_size   (IGNORED with a warning)
+       The above parameters are NO LONGER SUPPORTED by Postfix.
+       Cache support has been dropped from OpenLDAP as of release 2.1.13.
+
+    recursion_limit (1000)
+       A limit on the nesting depth of DN and URL special result
+       attribute evaluation. The limit must be a non-zero positive
+       number.
+
+    expansion_limit (0)
+       A limit on the total number of result elements returned (as a
+       comma separated list) by a lookup against the map. A setting of
+       zero disables the limit. Lookups fail with a temporary error
+       if the limit is exceeded. Setting the limit to 1 ensures that
+       lookups do not return multiple values.
+
+    size_limit ($expansion_limit)
+       A limit on the number of LDAP entries returned by any single LDAP
+       query performed as part of the lookup. A setting of 0 disables
+       the limit. Expansion of DN and URL references involves nested
+       LDAP queries, each of which is separately subjected to this
+       limit.
+
+       Note: even a single LDAP entry can generate multiple lookup
+       results, via multiple result attributes and/or multi-valued
+       result attributes. This limit caps the per query resource
+       utilization on the LDAP server, not the final multiplicity of the
+       lookup result. It is analogous to the "-z" option of "ldapsearch".
 
     dereference (0)
-       When to dereference LDAP aliases. (Note that this has nothing
-       do with Postfix aliases.) The permitted values are those 
-       legal for the OpenLDAP/UM LDAP implementations:
+       When to dereference LDAP aliases. (Note that this has nothing
+       do with Postfix aliases.) The permitted values are those legal
+       for the OpenLDAP/UM LDAP implementations:
 
                0       never
                1       when searching
diff --git a/postfix/README_FILES/SMTPD_PROXY_README b/postfix/README_FILES/SMTPD_PROXY_README
new file mode 100644 (file)
index 0000000..28e1e9e
--- /dev/null
@@ -0,0 +1,81 @@
+Purpose of the SMTPD pass-through proxy feature
+===============================================
+
+The Postfix SMTP server can be configured to forward all mail to
+a proxy server, for example, a real-time SPAM filter. The proxy is
+supposed to send the mail into another Postfix SMTP server process
+for normal delivery.
+
+The proxy server receives only the commands that the Postfix SMTP
+server has approved. The proxy server should accept the same MAIL
+FROM and RCPT TO command syntax as Postfix, but does not need to
+support ESMTP command pipelining.
+
+This feature is meant to be used as follows:
+
+    Internet -> smtpd -> proxy -> smtpd -> cleanup -> queue
+               Postfix           Postfix   Postfix   Postfix
+
+Limitations
+===========
+
+When used with a real-time SPAM filter, this approach allows Postfix
+to reject mail before the SMTP mail transfer completes, so that
+Postfix does not have to send rejected mail back to the sender.
+Mail that is not accepted remains the responsibility of the client.
+
+In all other respects this content filtering approach is inferior
+to the existing content filter (see FILTER_README) which processes
+mail AFTER it is queued, because that gives you full control over
+how many filtering processes can be run in parallel.
+
+The problem with real-time content filtering is that the remote
+SMTP client expects an SMTP reply within a deadline. As the system
+load increases, fewer and fewer CPU cycles remain available to
+answer within the deadline, and eventually you either have to stop
+accepting mail or you have to accept unfiltered mail.
+
+A possible workaround is to have the proxy take special action when
+the deadline is reached: add a distinctive message header that
+triggers a Postfix header_checks FILTER action, or send the mail
+into Postfix via an alternative Postfix SMTP server that always
+turns on content filtering.
+
+Configuration parameters 
+========================
+
+Parameters that control proxying:
+
+smtpd_proxy_filter (syntax: host:port)
+
+    The host and TCP port of the SMTP proxy server.  When no host
+    or host:  is specified, localhost is assumed.
+
+smtpd_proxy_timeout (default: 100s)
+
+    Timeout for connecting to the SMTP proxy server and for sending
+    and receiving data.  All proxy errors are logged to the maillog
+    file, but the client sees "451 Error: queue file write error".
+
+smtpd_proxy_ehlo (default: $myhostname)
+
+    The hostname to use when sending an EHLO command to the SMTP
+    proxy server.
+
+Testing the SMTP pass-through proxy feature
+===========================================
+
+The following example sets up a null proxy, that is, the Postfix
+SMTP server gives the mail directly to another Postfix SMTP server
+process.
+
+/etc/postfix/master.cf
+    smtp      inet  n       -       n       -       -       smtpd 
+       -o smtpd_proxy_filter=26
+    26        inet  n       -       n       -       -       smtpd
+
+The result is as follows:
+
+    Internet -> smtpd on port 25 -> smtpd on port 26 -> cleanup -> queue
+
+This configuration is sufficient for stress testing.
index 3a4220e1232ee5c3889abfd31e2e786657fc3dfc..44f2e1407c271136699be5db11951efa3df0148d 100644 (file)
@@ -8,7 +8,7 @@ Purpose of this software
 You can use the virtual delivery agent for mailbox delivery of some
 or all domains that are handled by a machine.
 
-This mechanism is different from simulated virtual domains. Those
+This mechanism is different from virtual alias domains. Those
 are implemented by translating every recipient address into a
 different address. For that, see the virtual(5) manual page.
 
index 5dcc566866134b1b0c951c294642156118f20a10..0221d767d95bad992db0a34d52c2f6e7cac9d2dd 100644 (file)
@@ -22,6 +22,51 @@ snapshot release).  Patches change the patchlevel and the release
 date. Snapshots change only the release date, unless they include
 the same bugfixes as a patch release.
 
+Incompatible changes with Postfix snapshot 2.0.13-20030702
+==========================================================
+
+Support for client side LDAP caching is gone.  OpenLDAP 2.1.13 and
+later no longer support it, and the feature never worked well.
+Postfix now ignores cache controlling parameters in an LDAP
+configuration file and logs a warning. Credits to Victor Duchovni
+and Lamont Jones.
+
+Major changes with Postfix snapshot 2.0.13-20030702
+===================================================
+
+The Postfix SMTP server can be configured to send all mail into a
+proxy server, for example a real-time SPAM filter. This proxy is
+expected to send the mail into another Postfix SMTP server process
+for normal delivery.  See the SMTPD_PROXY_README file for details.
+
+Improved LDAP client robustness. Given suitable invalid database
+contents, LDAP lookups can produce too many results, enter an
+infinite loop in the expansion of "special result attributes" (LDAP
+DNs and LDAP URLs) or can simply consume excessive server resources.
+Credits to Victor Duchovni and Lamont Jones.
+
+New CIDR-based lookup table, remotely based on code by Jozsef
+Kadlecsik.  For details and examples, see "man cidr_table".
+
+The TCP-based client-server table lookup protocol is finished.
+For details and examples, see "man tcp_table". This will allow you
+to implement your own greylisting.
+
+Support for !/pattern/ (negative matches) in PCRE lookup tables by
+Victor Duchovni. See "man pcre_table" for more.
+
+New enable_original_recipient parameter (default: yes) to control
+whether Postfix keeps track of original recipient address information.
+If this is turned off Postfix produces no X-Original-To: headers
+and ignores the original recipient when eliminating duplicates
+after virtual alias expansion. Code by Victor Duchovni.
+
+Finer control over how long the SMTP server waits for address
+verification probes to complete. address_verify_poll_{count,delay}
+control how often to query the verify server and how long to wait
+between queries. Specify address_verify_poll_count=1 to implement
+a crude form of greylisting.
+
 Major changes with Postfix snapshot 2.0.11-20030611
 ===================================================
 
index 1f4b38ba72c21e8ae558aaa817f92b4f94007387..baacf9c4296734c4f6b63a25a7f1bc2475925b67 100644 (file)
 #               A  network  address  is  a  sequence of one or more
 #               octets separated by ".".
 # 
+#               NOTE: use the cidr lookup table type if you want to
+#               specify arbitrary network blocks.
+# 
 # ACTIONS
 #        [45]NN text
-#               Reject the address etc. that matches  the  pattern,
+#               Reject  the  address etc. that matches the pattern,
 #               and respond with the numerical code and text.
 # 
 #        REJECT
 # 
 #        REJECT optional text...
-#               Reject  the  address etc. that matches the pattern.
-#               Reply with $reject_code optional text...  when  the
-#               optional  text is specified, otherwise reply with a
+#               Reject the address etc. that matches  the  pattern.
+#               Reply  with  $reject_code optional text... when the
+#               optional text is specified, otherwise reply with  a
 #               generic error response message.
 # 
 #        OK     Accept the address etc. that matches the pattern.
 # 
 #        all-numerical
 #               An all-numerical result is treated as OK. This for-
-#               mat  is generated by address-based relay authoriza-
+#               mat is generated by address-based relay  authoriza-
 #               tion schemes.
 # 
-#        DUNNO  Pretend that the lookup key was not found  in  this
+#        DUNNO  Pretend  that  the lookup key was not found in this
 #               table. This prevents Postfix from trying substrings
-#               of the lookup key (such as a subdomain name,  or  a
+#               of  the  lookup key (such as a subdomain name, or a
 #               network address subnetwork).
 # 
 #        HOLD
 # 
 #        HOLD optional text...
-#               Place  the message on the hold queue, where it will
-#               sit until someone either deletes it or releases  it
-#               for  delivery.  Log the optional text if specified,
+#               Place the message on the hold queue, where it  will
+#               sit  until someone either deletes it or releases it
+#               for delivery.  Log the optional text if  specified,
 #               otherwise log a generic message.
 # 
-#               Mail that is placed on hold can  be  examined  with
-#               the  postcat(1)  command,  and  can be destroyed or
+#               Mail  that  is  placed on hold can be examined with
+#               the postcat(1) command, and  can  be  destroyed  or
 #               released with the postsuper(1) command.
 # 
-#               Note: this action currently affects all  recipients
+#               Note:  this action currently affects all recipients
 #               of the message.
 # 
 #        DISCARD
 # 
 #        DISCARD optional text...
-#               Claim  successful delivery and silently discard the
-#               message.  Log the optional text if specified,  oth-
+#               Claim successful delivery and silently discard  the
+#               message.   Log the optional text if specified, oth-
 #               erwise log a generic message.
 # 
-#               Note:  this action currently affects all recipients
+#               Note: this action currently affects all  recipients
 #               of the message.
 # 
 #        FILTER transport:destination
-#               After the message is queued, send the  entire  mes-
-#               sage  through  a  content filter.  More information
+#               After  the  message is queued, send the entire mes-
+#               sage through a content  filter.   More  information
 #               about  content  filters  is  in  the  Postfix  FIL-
 #               TER_README file.
 # 
-#               Note:   this  action  overrides  the  main.cf  con-
+#               Note:  this  action  overrides  the  main.cf   con-
 #               tent_filter  setting,  and  currently  affects  all
 #               recipients of the message.
 # 
 #        REDIRECT user@domain
-#               After  the  message  is queued, send the message to
+#               After the message is queued, send  the  message  to
 #               the  specified  address  instead  of  the  intended
 #               recipient(s).
 # 
-#               Note:  this action overrides the FILTER action, and
+#               Note: this action overrides the FILTER action,  and
 #               currently affects all recipients of the message.
 # 
 #        restriction...
 #               reject_unauth_destination, and so on).
 # 
 # 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 string being looked up. Depending on the appli-
-#        cation, that string  is  an  entire  client  hostname,  an
+#        cation,  that  string  is  an  entire  client hostname, an
 #        entire client IP address, or an entire mail address. Thus,
 #        no  parent  domain  or  parent  network  search  is  done,
-#        user@domain  mail  addresses  are not broken up into their
+#        user@domain mail addresses are not broken  up  into  their
 #        user@ and domain constituent parts, nor is user+foo broken
 #        up into user and foo.
 # 
-#        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.
 # 
-#        Actions  are  the  same as with indexed file lookups, with
-#        the additional feature that parenthesized substrings  from
+#        Actions 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.
 # 
 # BUGS
-#        The  table format does not understand quoting conventions.
+#        The table format does not understand quoting  conventions.
 # 
 # SEE ALSO
-#        postmap(1) create mapping table
+#        postmap(1) create lookup table
 #        smtpd(8) smtp server
+#        cidr_table(5) format of CIDR tables
 #        pcre_table(5) format of PCRE tables
 #        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)
diff --git a/postfix/conf/cidr_table b/postfix/conf/cidr_table
new file mode 100644 (file)
index 0000000..76b27d4
--- /dev/null
@@ -0,0 +1,77 @@
+# CIDR_TABLE(5)                                       CIDR_TABLE(5)
+# 
+# NAME
+#        cidr_table - format of Postfix CIDR tables
+# 
+# SYNOPSIS
+#        postmap -q "string" cidr:/etc/postfix/filename
+# 
+#        postmap -q - cidr:/etc/postfix/filename <inputfile
+# 
+# DESCRIPTION
+#        The  Postfix  mail  system  uses  optional  access control
+#        tables.  These tables are usually in  dbm  or  db  format.
+#        Alternatively,  access  control tables can be specified in
+#        CIDR form.
+# 
+#        To find out what types of lookup tables your Postfix  sys-
+#        tem supports use the postconf -m command.
+# 
+#        To   test  lookup  tables,  use  the  postmap  command  as
+#        described in the SYNOPSIS above.
+# 
+# TABLE FORMAT
+#        The general form of a Postfix CIDR table is:
+# 
+#        network_address/network_mask     result
+#               When a search string matches the specified  network
+#               block, use the corresponding result value.
+# 
+#        network_address     result
+#               When  a search string matches the specified network
+#               address, use the corresponding result value.
+# 
+#        blank lines and comments
+#               Empty lines and whitespace-only lines are  ignored,
+#               as  are  lines whose first non-whitespace character
+#               is a `#'.
+# 
+#        multi-line text
+#               A logical line starts with non-whitespace  text.  A
+#               line  that starts with whitespace continues a logi-
+#               cal line.
+# 
+#        Patterns are applied in the  order  as  specified  in  the
+#        table,  until  a  pattern is found that matches the search
+#        string.
+# 
+# EXAMPLE SMTPD ACCESS MAP
+#        /etc/postfix/main.cf:
+#            smtpd_client_restrictions = ... cidr:/etc/postfix/client_cidr ...
+# 
+#        /etc/postfix/client_cidr:
+#            # Rule order matters. Put more specific whitelist entries
+#            # before more general blacklist entries.
+#            192.168.1.1             OK
+#            192.168.0.0/16          REJECT
+# 
+# SEE ALSO
+#        regexp_table(5) format of regular expression tables
+#        pcre_table(5) format of PCRE tables
+#        tcp_table(5) TCP client/server table lookup protocol
+# 
+# AUTHOR(S)
+#        The CIDR table lookup code was originally written by:
+#        Jozsef Kadlecsik
+#        kadlec@blackhole.kfki.hu
+#        KFKI Research Institute for Particle and Nuclear Physics
+#        POB. 49
+#        1525 Budapest, Hungary
+# 
+#        Adopted and adapted by:
+#        Wietse Venema
+#        IBM T.J. Watson Research
+#        P.O. Box 704
+#        Yorktown Heights, NY 10598, USA
+# 
+#                                                     CIDR_TABLE(5)
index ad5bd0bc9d662476e4d57b74cdae9e02e5ceaafb..776bbdc342f11b58a071b507345724d1363aca05 100644 (file)
@@ -4,8 +4,6 @@
 #        pcre_table - format of Postfix PCRE tables
 # 
 # SYNOPSIS
-#        pcre:/etc/postfix/filename
-# 
 #        postmap -q "string" pcre:/etc/postfix/filename
 # 
 #        postmap -q - pcre:/etc/postfix/filename <inputfile
 #        The general form of a PCRE table is:
 # 
 #        /pattern/flags result
-#               When pattern matches a search string, use the  cor-
-#               responding result value.
+# 
+#        !/pattern/flags result
+#               When pattern matches  (does  not  match)  a  search
+#               string, use the corresponding result value.
 # 
 #        blank lines and comments
 #               Empty  lines and whitespace-only lines are ignored,
 # 
 #        if /pattern/flags
 # 
+#        if !/pattern/flags
+# 
 #        endif  Examine the lines between if..endif only if pattern
-#               matches. The if..endif can nest.   Do  not  prepend
-#               whitespace to patterns inside if..endif.
+#               matches (does not match). The if..endif  can  nest.
+#               Do   not  prepend  whitespace  to  patterns  inside
+#               if..endif.
 # 
 #        Each  pattern  is  a  perl-like  regular  expression.  The
-#        expression delimiter can be any character, except  whites-
-#        pace  or  characters that have special meaning (tradition-
-#        ally the forward slash is used).  The  regular  expression
+#        expression  delimiter can be any character, except whites-
+#        pace or characters that have special  meaning  (tradition-
+#        ally  the  forward slash is used).  The regular expression
 #        can contain whitespace.
 # 
 #        By default, matching is case-insensitive, and newlines are
-#        not treated as special characters. The  behavior  is  con-
-#        trolled  by  flags,  which are toggled by appending one or
+#        not  treated  as  special characters. The behavior is con-
+#        trolled by flags, which are toggled by  appending  one  or
 #        more of the following characters after the pattern:
 # 
 #        i (default: on)
-#               Toggles the  case  sensitivity  flag.  By  default,
+#               Toggles  the  case  sensitivity  flag.  By default,
 #               matching is case insensitive.
 # 
 #        m (default: off)
-#               Toggles  the PCRE_MULTILINE flag. When this flag is
-#               on, the ^ and $  metacharacters  match  immediately
-#               after  and  immediately before a newline character,
-#               respectively, in addition to matching at the  start
+#               Toggles the PCRE_MULTILINE flag. When this flag  is
+#               on,  the  ^  and $ metacharacters match immediately
+#               after and immediately before a  newline  character,
+#               respectively,  in addition to matching at the start
 #               and end of the subject string.
 # 
 #        s (default: on)
 #               Toggles the PCRE_DOTALL flag. When this flag is on,
 #               the .  metacharacter matches the newline character.
-#               With  Postfix  versions prior to 20020528, The flag
+#               With Postfix versions prior to 20020528,  The  flag
 #               is off by default, which is inconvenient for multi-
 #               line message header matching.
 # 
 #        x (default: off)
-#               Toggles  the  pcre extended flag. When this flag is
-#               on, whitespace in the  pattern  (other  than  in  a
+#               Toggles the pcre extended flag. When this  flag  is
+#               on,  whitespace  in  the  pattern  (other than in a
 #               character class) and characters between a # outside
-#               a character class and the  next  newline  character
-#               are  ignored.  An escaping backslash can be used to
-#               include a whitespace or # character as part of  the
+#               a  character  class  and the next newline character
+#               are ignored. An escaping backslash can be  used  to
+#               include  a whitespace or # character as part of the
 #               pattern.
 # 
 #        A (default: off)
-#               Toggles  the PCRE_ANCHORED flag.  When this flag is
-#               on, the pattern is forced to  be  "anchored",  that
+#               Toggles the PCRE_ANCHORED flag.  When this flag  is
+#               on,  the  pattern  is forced to be "anchored", that
 #               is, it is constrained to match only at the start of
-#               the string which is being  searched  (the  "subject
-#               string").  This  effect  can  also  be  achieved by
+#               the  string  which  is being searched (the "subject
+#               string"). This  effect  can  also  be  achieved  by
 #               appropriate constructs in the pattern itself.
 # 
 #        E (default: off)
-#               Toggles the  PCRE_DOLLAR_ENDONLY  flag.  When  this
-#               flag  is  on,  a  $  metacharacter  in  the pattern
-#               matches only at the  end  of  the  subject  string.
-#               Without  this  flag,  a dollar also matches immedi-
+#               Toggles  the  PCRE_DOLLAR_ENDONLY  flag.  When this
+#               flag is  on,  a  $  metacharacter  in  the  pattern
+#               matches  only  at  the  end  of the subject string.
+#               Without this flag, a dollar  also  matches  immedi-
 #               ately before the final character if it is a newline
 #               character (but not before any other newline charac-
-#               ters). This flag is ignored if PCRE_MULTILINE  flag
+#               ters).  This flag is ignored if PCRE_MULTILINE flag
 #               is set.
 # 
 #        U (default: off)
 #               Toggles the ungreedy matching flag.  When this flag
-#               is on, the  pattern  matching  engine  inverts  the
-#               "greediness"  of  the  quantifiers so that they are
-#               not greedy by default, but become  greedy  if  fol-
-#               lowed  by  "?".   This  flag can also set by a (?U)
+#               is  on,  the  pattern  matching  engine inverts the
+#               "greediness" of the quantifiers so  that  they  are
+#               not  greedy  by  default, but become greedy if fol-
+#               lowed by "?".  This flag can also  set  by  a  (?U)
 #               modifier within the pattern.
 # 
 #        X (default: off)
 #               Toggles the PCRE_EXTRA flag.  When this flag is on,
-#               any  backslash  in  a pattern that is followed by a
+#               any backslash in a pattern that is  followed  by  a
 #               letter that has no special meaning causes an error,
 #               thus reserving these combinations for future expan-
 #               sion.
 # 
-#        Each pattern is applied to the entire lookup  key  string.
-#        Depending  on  the  application,  that string is an entire
+#        Each  pattern  is applied to the entire lookup key string.
+#        Depending on the application, that  string  is  an  entire
 #        client hostname, an entire client IP address, or an entire
-#        mail  address.   Thus,  no parent domain or parent network
-#        search is done, and user@domain  mail  addresses  are  not
-#        broken  up  into  their user and domain constituent parts,
+#        mail address.  Thus, no parent domain  or  parent  network
+#        search  is  done,  and  user@domain mail addresses are not
+#        broken up into their user and  domain  constituent  parts,
 #        nor is user+foo broken up into user and foo.
 # 
-#        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.
 # 
-#        Substitution of substrings  from  the  matched  expression
-#        into  the result string is possible using the conventional
-#        perl syntax ($1, $2, etc.).   The  macros  in  the  result
-#        string  may  need  to  be  written as ${n} or $(n) if they
-#        aren't followed by whitespace.
+#        Substitution  of  substrings  from  the matched expression
+#        into the result string is possible using the  conventional
+#        perl  syntax  ($1,  $2,  etc.).   The macros in the result
+#        string may need to be written as  ${n}  or  $(n)  if  they
+#        aren't  followed  by  whitespace.  Since  negated patterns
+#        (those preceded by !) return a result when the  expression
+#        does  not  match,  substitutions  are  not  available  for
+#        negated patterns.
 # 
 # EXAMPLE SMTPD ACCESS MAP
 #        # Protect your outgoing majordomo exploders
 # 
 # SEE ALSO
 #        regexp_table(5) format of POSIX regular expression tables
+#        cidr_table(5) format of CIDR tables
+#        tcp_table(5) TCP client/server table lookup protocol
 # 
 # AUTHOR(S)
 #        The PCRE table lookup code was originally written by:
index a3aa53536c811ffc5fbad1b117786375f656f026..ce99b82941f92a39f4aecf891a1b32e8ca24e778 100644 (file)
@@ -92,6 +92,7 @@ $config_directory/LICENSE:f:root:-:644
 $config_directory/access:f:root:-:644:p
 $config_directory/aliases:f:root:-:644:p
 $config_directory/canonical:f:root:-:644:p
+$config_directory/cidr_table:f:root:-:644:p
 $config_directory/main.cf:f:root:-:644:p
 $config_directory/main.cf.default:f:root:-:644
 $config_directory/makedefs.out:f:root:-:644
@@ -100,6 +101,7 @@ $config_directory/pcre_table:f:root:-:644:p
 $config_directory/postfix-files:f:root:-:644
 $config_directory/regexp_table:f:root:-:644:p
 $config_directory/relocated:f:root:-:644:p
+$config_directory/tcp_table:f:root:-:644:p
 $config_directory/transport:f:root:-:644:p
 $config_directory/virtual:f:root:-:644:p
 $config_directory/postfix-script:f:root:-:755
@@ -121,9 +123,11 @@ $manpage_directory/man1/sendmail.1:f:root:-:644
 $manpage_directory/man5/access.5:f:root:-:644
 $manpage_directory/man5/aliases.5:f:root:-:644
 $manpage_directory/man5/canonical.5:f:root:-:644
+$manpage_directory/man5/cidr_table.5:f:root:-:644
 $manpage_directory/man5/pcre_table.5:f:root:-:644
 $manpage_directory/man5/regexp_table.5:f:root:-:644
 $manpage_directory/man5/relocated.5:f:root:-:644
+$manpage_directory/man5/tcp_table.5:f:root:-:644
 $manpage_directory/man5/transport.5:f:root:-:644
 $manpage_directory/man5/virtual.5:f:root:-:644
 $manpage_directory/man8/bounce.8:f:root:-:644
index 25b00567eb496a571eaf00ef9b4671febc0b5050..36a02efa884968bc3ceb405266fcd0c8c04922b0 100644 (file)
@@ -181,7 +181,7 @@ check)
 
        find $command_directory/postqueue $command_directory/postdrop \
            -prune ! -perm -02111 \
-           -exec $WARN not set-gid: {} \;
+           -exec $WARN not set-gid or not owner+group+world executable: {} \;
 
        for name in `ls -d $queue_directory/* | \
            egrep '/(bin|etc|lib|usr)$'` ; \
index 94bcf2f13646ace6f38818a18395ba9497ce5648..d3534b85583961c072b4bc17e9b498c78ff4d94a 100644 (file)
@@ -4,8 +4,6 @@
 #        regexp_table - format of Postfix regular expression tables
 # 
 # SYNOPSIS
-#        regexp:/etc/postfix/filename
-# 
 #        postmap -q "string" regexp:/etc/postfix/filename
 # 
 #        postmap -q - regexp:/etc/postfix/filename <inputfile
 #        Substitution  of  substrings  from  the matched expression
 #        into the result string is possible using $1, $2, etc.. The
 #        macros in the result string may need to be written as ${n}
-#        or $(n) if they aren't followed by whitespace.
+#        or $(n) if  they  aren't  followed  by  whitespace.  Since
+#        negated  patterns  (those  preceded by !)  return a result
+#        when the expression does not match, substitutions are  not
+#        available for negated patterns.
 # 
 # EXAMPLE SMTPD ACCESS MAP
 #        # Disallow sender-specified routing. This is a must if you relay mail
 # 
 # SEE ALSO
 #        pcre_table(5) format of PCRE tables
+#        cidr_table(5) format of CIDR tables
+#        tcp_table(5) TCP client/server table lookup protocol
 # 
 # AUTHOR(S)
 #        The regexp table lookup code was originally written by:
index e8bb8bccc60989dd882da34119d1ae6843914abb..2f8e564589cab7411a22475dbe548c992f4d32ca 100644 (file)
 #
 #ldap_bind_pw =
 
-# The ldap_cache parameter specifies whether or not to turn on client-side
-# caching.
-#
-#ldap_cache = no
-
-# The ldap_cache_expiry parameter specifies how many seconds to cache results
-# for (if ldap_cache=yes)
-#
-#ldap_cache_expiry = 30
-
-# The ldap_cache_size parameter specifies the cache size, in bytes.
-#
-#ldap_cache_size = 32768
+#ldap_cache        (IGNORED with a warning)
+#ldap_cache_expiry (IGNORED with a warning)
+#ldap_cache_size   (IGNORED with a warning)
+#
+# The above parameters are NO LONGER SUPPORTED by Postfix.
+# Cache support has been dropped from OpenLDAP as of release 2.1.13.
+
+# The ldap_recursion_limit parameter specifies a limit on the nesting
+# depth of DN and URL special result attribute evaluation. The limit
+# must be a non-zero positive number. The default value is 1000.
+# 
+#ldap_recursion_limit = 1000
+
+# The ldap_expansion_limit parameter specifies a limit on the total
+# number of result elements returned (as a comma separated list) by a lookup
+# against the map. A setting of 0 disables the limit. Lookups fail with a
+# temporary error if the limit is exceeded. Setting the limit to 1 ensures
+# that lookups do not return multiple values. The default value is 0.
+#
+#ldap_expansion_limit = 0
+
+# The ldap_size_limit parameter specifies a limit on the number of LDAP
+# entries returned by any single LDAP query performed as part of the
+# lookup. A setting of 0 disables the limit. Expansion of DN and URL
+# references involves nested LDAP queries, each of which is separately
+# subjected to this limit. The default value is $ldap_expansion_limit.
+# 
+# Note: even a single LDAP entry can generate multiple lookup results, via
+# multiple result attributes and/or multi-valued result attributes.
+# This limit caps the per query resource utilization on the LDAP server,
+# not the final multiplicity of the lookup result. It is analogous to the
+# "-z" option of "ldapsearch".
+#
+#ldap_size_limit = $ldap_expansion_limit
 
 # The ldap_deference parameter specifies how to handle LDAP aliases.  See the
 # ldap_open(3) man page.
index b97e9ee62decee0d48c4a65342d2f4cd3b007155..dbc5b699dcda99351c961386afd5813a93df8bc7 100644 (file)
@@ -71,6 +71,18 @@ default_transport = smtp
 #
 double_bounce_sender = double-bounce
 
+# The enable_original_recipient parameter enables support for the
+# X-Original-To message header, which is needed for multi-recipient
+# mailboxes. When this parameter is set to yes, the cleanup daemon
+# performs duplicate elimination on distinct pairs of (original
+# recipient, rewritten recipient), and generates non-empty original
+# recipient queue file records.  When this parameter is set to no,
+# the cleanup daemon performs duplicate elimination on the rewritten
+# recipient address only, and generates empty original recipient
+# queue file records.  The default value is "yes".
+# 
+enable_original_recipient = yes
+
 # The export_environment parameter specifies the names of environment
 # parameters that Postfix will export to non-Postfix processes.
 # 
index 7fc8c761fafd70dbe4694da5928b0744d0d40e3d..d3ff079dd91e5a9332a4e045992cd8accef9e058 100644 (file)
@@ -215,6 +215,41 @@ smtpd_soft_error_limit = 10
 #
 smtpd_hard_error_limit = 20
 
+#
+# PASS-THROUGH PROXY OPERATION
+#
+
+# The smtpd_proxy_filter parameter specifies the host:port of a proxy
+# filter, for example a real-time SPAM filter. The proxy receives
+# all mail from the Postfix SMTP server, and is supposed to give the
+# result to another Postfix SMTP server process.
+#
+# WARNING: the proxy filter must reply within a fixed deadline or
+# else the remote SMTP client times out and mail duplication happens.
+# This becomes a problem as mail load increases so that fewer and
+# fewer CPU cycles remain available to mead the fixed deadline.
+#
+# Specify host:port. When no host or host: are specified, the local
+# machine is assumed.
+#
+smtpd_proxy_filter =
+
+# The smtpd_proxy_timeout parameter specifies a deadline for
+# connecting to a proxy filter and for sending or receiving information.
+# When a connection fails the client gets a generic error message
+# while more detailed information is logged to the maillog file.
+#
+# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
+# The default time unit is s (seconds).
+#
+smtpd_proxy_timeout = 100s
+
+# The smtpd_proxy_ehlo parameter specifies how the Postfix SMTP
+# server announces itself to the proxy filter. By default, the
+# Postfix hostname is used.
+#
+smtpd_proxy_ehlo = $myhostname
+
 #
 # UCE RESTRICTIONS
 #
index 0d20eac2a24d84558ea14c539a8bb5b679596eee..e645f078a8ab6e1c0d601ad3223b1a5e999a007f 100644 (file)
@@ -8,8 +8,40 @@
 # ADDRESS VERIFICATION (see also: verify(8) and SENDER_VERIFICATION_README)
 #
 
+# The address_verify_sender configuration parameter specifies the
+# sender address that Postfix will use in address verification probe
+# messages.
+# 
+# By default, the probe sender address is postmaster@$myorigin.
+# 
+# Specify an empty value (address_verify_sender =) or <> if you want
+# to use the null sender address. Beware, some sites reject mail from
+# <>, even though RFCs require that such addresses to be accepted.
+# 
+#address_verify_sender = <>
+#address_verify_sender = postmaster@my.domain
+address_verify_sender = postmaster
+
+# The address_verify_poll_count parameter specifies how many times
+# to query the address verification service for completion of an
+# address verification request.  Specify 0 to implement a simple form
+# of greylisting, that is, always defer the first delivery request
+# from an unknown sender address.
+#
+#address_verify_poll_count = 0
+address_verify_poll_count = 3
+
+# The address_verify_poll_delay parameter specifies how long to wait
+# after querying the address verification service for completion of
+# an address verification request.
+#
+address_verify_poll_delay = 3
+
+#
+# CACHE CONTROL
+#
 # The address_verify_map configuration parameter specifies an optional
-# table for persistent recipient status storage. The file is opened
+# table for persistent address status storage. The file is opened
 # before the process enters a chroot jail and before it drops root
 # privileges.
 # 
 #address_verify_map = btree:/etc/postfix/verify
 address_verify_map = 
 
-# The address_verify_sender configuration parameter specifies the
-# sender address that Postfix will use in address verification probe
-# messages.
-# 
-# By default, the probe sender address is postmaster@$myorigin.
-# 
-# Specify an empty value (address_verify_sender =) or <> if you want
-# to use the null sender address. Beware, some sites reject mail from
-# <>, even though RFCs require that such addresses to be accepted.
-# 
-#address_verify_sender = <>
-#address_verify_sender = postmaster@my.domain
-address_verify_sender = postmaster
-
 # The address_verify_positive_expire_time configuration parameter
 # specifies the amount of time after which a known to be good address
 # expires.
diff --git a/postfix/conf/tcp_table b/postfix/conf/tcp_table
new file mode 100644 (file)
index 0000000..db1b385
--- /dev/null
@@ -0,0 +1,85 @@
+# TCP_TABLE(5)                                         TCP_TABLE(5)
+# 
+# NAME
+#        tcp_table - Postfix client/server table lookup protocol
+# 
+# SYNOPSIS
+#        postmap -q "string" tcp:host:port
+# 
+#        postmap -q - regexp:host:port <inputfile
+# 
+# DESCRIPTION
+#        The  Postfix  mail system uses optional tables for address
+#        rewriting or mail routing. These tables are usually in dbm
+#        or  db  format. Alternatively, lookup tables can be speci-
+#        fied as a TCP client/server pair.
+# 
+#        To find out what types of lookup tables your Postfix  sys-
+#        tem supports use the postconf -m command.
+# 
+#        To   test  lookup  tables,  use  the  postmap  command  as
+#        described in the SYNOPSIS above.
+# 
+# PROTOCOL DESCRIPTION
+#        The TCP map class implements a very simple  protocol:  the
+#        client  sends  a  request, and the server sends one reply.
+#        Requests and replies are sent as one line of  ASCII  text,
+#        terminated  by  the  ASCII  newline character. Request and
+#        reply parameters (see below) are separated by  whitespace.
+# 
+# ENCODING
+#        In  request  and reply parameters, the character % and any
+#        non-printing and whitespace characters must be replaced by
+#        %XX,  XX being the corresponding ASCII hexadecimal charac-
+#        ter value. The hexadecimal codes can be specified  in  any
+#        case (upper, lower, mixed).
+# 
+# REQUEST FORMAT
+#        Requests are strings that serve as lookup key in the simu-
+#        lated table.
+# 
+#        get SPACE key NEWLINE
+#               Look up data under the specified key.
+# 
+#        put SPACE key SPACE value NEWLINE
+#               This request is currently not implemented.
+# 
+# REPLY FORMAT
+#        Replies must be no longer than 4096  characters  including
+#        the newline terminator, and must have the following form:
+# 
+#        500 SPACE optional-text NEWLINE
+#               In  case  of  a  lookup request, the requested data
+#               does not exist.  In case of an update request,  the
+#               request was rejected.
+# 
+#        400 SPACE optional-text NEWLINE
+#               This  indicates  an error condition. The text gives
+#               the nature of the problem. The client should  retry
+#               the request later.
+# 
+#        200 SPACE text NEWLINE
+#               The request was successful. In the case of a lookup
+#               request, the text contains an  encoded  version  of
+#               the   requested   data.    Otherwise  the  text  is
+#               optional.
+# 
+# SEE ALSO
+#        regexp_table(5) format of regular expression tables
+#        pcre_table(5) format of PCRE tables
+#        cidr_table(5) format of CIDR tables
+# 
+# BUGS
+#        Only the lookup method is currently implemented.
+# 
+# LICENSE
+#        The Secure Mailer license must be  distributed  with  this
+#        software.
+# 
+# AUTHOR(S)
+#        Wietse Venema
+#        IBM T.J. Watson Research
+#        P.O. Box 704
+#        Yorktown Heights, NY 10598, USA
+# 
+#                                                      TCP_TABLE(5)
index 3ae93a7f07ae89b113c464e5aa750d23a7d45412..b6df3a3ffd233da08ab60c66a6ea7327e62a52a9 100644 (file)
 #        relay hosts. The mapping is used by the trivial-rewrite(8)
 #        daemon.
 # 
-#        Normally, the transport table is specified as a text  file
-#        that  serves  as  input  to  the  postmap(1) command.  The
-#        result, an indexed file in dbm or db format, is  used  for
-#        fast  searching  by  the  mail system. Execute the command
-#        postmap /etc/postfix/transport in  order  to  rebuild  the
+#        This mapping overrides the default routing that  is  built
+#        into Postfix:
+# 
+#        mydestination
+#               A  list of domains that is by default delivered via
+#               $local_transport.
+# 
+#        virtual_mailbox_domains
+#               A list of domains that is by default delivered  via
+#               $virtual_transport.
+# 
+#        relay_domains
+#               A  list of domains that is by default delivered via
+#               $relay_transport.
+# 
+#        any other destination
+#               Mail for any other destination is by default deliv-
+#               ered via $default_transport.
+# 
+#        Normally,  the transport table is specified as a text file
+#        that serves as  input  to  the  postmap(1)  command.   The
+#        result,  an  indexed file in dbm or db format, is used for
+#        fast searching by the mail  system.  Execute  the  command
+#        postmap  /etc/postfix/transport  in  order  to rebuild the
 #        indexed file after changing the transport table.
 # 
-#        When  the  table  is provided via other means such as NIS,
-#        LDAP or SQL, the same lookups are  done  as  for  ordinary
+#        When the table is provided via other means  such  as  NIS,
+#        LDAP  or  SQL,  the  same lookups are done as for ordinary
 #        indexed files.
 # 
-#        Alternatively,  the  table  can  be provided as a regular-
+#        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 section "REGULAR  EXPRESSION
+#        sions. In that case, the lookups are done  in  a  slightly
+#        different  way as described in section "REGULAR EXPRESSION
 #        TABLES".
 # 
 # TABLE FORMAT
 #               domain, use the corresponding result.
 # 
 #        blank lines and comments
-#               Empty lines and whitespace-only lines are  ignored,
-#               as  are  lines whose first non-whitespace character
+#               Empty  lines and whitespace-only lines are ignored,
+#               as are lines whose first  non-whitespace  character
 #               is a `#'.
 # 
 #        multi-line text
-#               A logical line starts with non-whitespace  text.  A
-#               line  that starts with whitespace continues a logi-
+#               A  logical  line starts with non-whitespace text. A
+#               line that starts with whitespace continues a  logi-
 #               cal line.
 # 
-#        The pattern specifies an email address, a domain name,  or
-#        a  domain  name  hierarchy, as described in section "TABLE
+#        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
+#        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. More details are given in section "RESULT
 #        FORMAT".
 # 
 # TABLE LOOKUP
 #        With lookups from indexed files such as DB or DBM, or from
-#        networked  tables  such  as NIS, LDAP or SQL, patterns are
+#        networked tables such as NIS, LDAP or  SQL,  patterns  are
 #        tried in the order as listed below:
 # 
 #        user+extension@domain transport:nexthop
 #               to nexthop.
 # 
 #        domain transport:nexthop
-#               Mail for domain is delivered through  transport  to
+#               Mail  for  domain is delivered through transport to
 #               nexthop.
 # 
 #        .domain transport:nexthop
-#               Mail  for  any  subdomain  of  domain  is delivered
-#               through transport to  nexthop.  This  applies  only
+#               Mail for  any  subdomain  of  domain  is  delivered
+#               through  transport  to  nexthop.  This applies only
 #               when the string transport_maps is not listed in the
 #               parent_domain_matches_subdomains configuration set-
-#               ting.   Otherwise, a domain name matches itself and
+#               ting.  Otherwise, a domain name matches itself  and
 #               its subdomains.
 # 
 #        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
+#        Note 2:  the  null  recipient  address  is  looked  up  as
 #        $empty_address_recipient@$myhostname (default: mailer-dae-
 #        mon@hostname).
 # 
 # RESULT FORMAT
-#        The  transport field specifies the name of a mail delivery
+#        The transport field specifies the name of a mail  delivery
 #        transport (the first name of a mail delivery service entry
 #        in the Postfix master.cf file).
 # 
-#        The  interpretation  of  the  nexthop  field  is transport
+#        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  []
+#        non-default server port, and use [host] or [host]:port  in
+#        order  to  disable MX (mail exchanger) DNS lookups. The []
 #        form is required when you specify an IP address instead of
 #        a hostname.
 # 
-#        A null transport and null nexthop  result  means  "do  not
-#        change":  use  the delivery transport and nexthop informa-
-#        tion that would be used when the  entire  transport  table
+#        A  null  transport  and  null nexthop result means "do not
+#        change": use the delivery transport and  nexthop  informa-
+#        tion  that  would  be used when the entire transport table
 #        did not exist.
 # 
-#        A  non-null  transport  field  with  a  null nexthop field
+#        A non-null transport  field  with  a  null  nexthop  field
 #        resets the nexthop information to the recipient domain.
 # 
-#        A null transport field with non-null  nexthop  field  does
+#        A  null  transport  field with non-null nexthop field does
 #        not modify the transport information.
 # 
 # EXAMPLES
-#        In  order to deliver internal mail directly, while using a
-#        mail relay for all other mail, specify a  null  entry  for
-#        internal  destinations  (do not change the delivery trans-
-#        port or the nexthop information) and  specify  a  wildcard
+#        In order to deliver internal mail directly, while using  a
+#        mail  relay  for  all other mail, specify a null entry for
+#        internal destinations (do not change the  delivery  trans-
+#        port  or  the  nexthop information) and specify a wildcard
 #        for all other destinations.
 # 
 #             my.domain    :
 #             .my.domain   :
 #             *            smtp:outbound-relay.my.domain
 # 
-#        In  order  to send mail for 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.
 # 
 #        empty_address_recipient
-#               The address that is looked up instead of  the  null
+#               The  address  that is looked up instead of the null
 #               sender address.
 # 
 #        parent_domain_matches_subdomains
-#               List  of  Postfix features that use domain.tld pat-
-#               terns  to  match  sub.domain.tld  (as  opposed   to
+#               List of Postfix features that use  domain.tld  pat-
+#               terns   to  match  sub.domain.tld  (as  opposed  to
 #               requiring .domain.tld patterns).
 # 
 #        transport_maps
 #        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 b841dfeab06c93582388198eb332a6ba5f88eaa9..2d57fef95c6b3164380ec9db574eb6fdfa0f36a0 100644 (file)
@@ -109,72 +109,75 @@ ACCESS(5)                                               ACCESS(5)
               A  network  address  is  a  sequence of one or more
               octets separated by ".".
 
+              NOTE: use the <b>cidr</b> lookup table type if you want to
+              specify arbitrary network blocks.
+
 <b>ACTIONS</b>
        [<b>45</b>]<i>NN</i> <i>text</i>
-              Reject the address etc. that matches  the  pattern,
+              Reject  the  address etc. that matches the pattern,
               and respond with the numerical code and text.
 
        <b>REJECT</b>
 
        <b>REJECT</b> <i>optional</i> <i>text...</i>
-              Reject  the  address etc. that matches the pattern.
-              Reply with <i>$reject_code</i> <i>optional</i> <i>text...</i>  when  the
-              optional  text is specified, otherwise reply with a
+              Reject the address etc. that matches  the  pattern.
+              Reply  with  <i>$reject_code</i> <i>optional</i> <i>text...</i> when the
+              optional text is specified, otherwise reply with  a
               generic error response message.
 
        <b>OK</b>     Accept the address etc. that matches the pattern.
 
        <i>all-numerical</i>
               An all-numerical result is treated as OK. This for-
-              mat  is generated by address-based relay authoriza-
+              mat is generated by address-based relay  authoriza-
               tion schemes.
 
-       <b>DUNNO</b>  Pretend that the lookup key was not found  in  this
+       <b>DUNNO</b>  Pretend  that  the lookup key was not found in this
               table. This prevents Postfix from trying substrings
-              of the lookup key (such as a subdomain name,  or  a
+              of  the  lookup key (such as a subdomain name, or a
               network address subnetwork).
 
        <b>HOLD</b>
 
        <b>HOLD</b> <i>optional</i> <i>text...</i>
-              Place  the message on the <b>hold</b> queue, where it will
-              sit until someone either deletes it or releases  it
-              for  delivery.  Log the optional text if specified,
+              Place the message on the <b>hold</b> queue, where it  will
+              sit  until someone either deletes it or releases it
+              for delivery.  Log the optional text if  specified,
               otherwise log a generic message.
 
-              Mail that is placed on hold can  be  examined  with
-              the  <a href="postcat.1.html"><b>postcat</b>(1)</a>  command,  and  can be destroyed or
+              Mail  that  is  placed on hold can be examined with
+              the <a href="postcat.1.html"><b>postcat</b>(1)</a> command, and  can  be  destroyed  or
               released with the <a href="postsuper.1.html"><b>postsuper</b>(1)</a> command.
 
-              Note: this action currently affects all  recipients
+              Note:  this action currently affects all recipients
               of the message.
 
        <b>DISCARD</b>
 
        <b>DISCARD</b> <i>optional</i> <i>text...</i>
-              Claim  successful delivery and silently discard the
-              message.  Log the optional text if specified,  oth-
+              Claim successful delivery and silently discard  the
+              message.   Log the optional text if specified, oth-
               erwise log a generic message.
 
-              Note:  this action currently affects all recipients
+              Note: this action currently affects all  recipients
               of the message.
 
        <b>FILTER</b> <i>transport:destination</i>
-              After the message is queued, send the  entire  mes-
-              sage  through  a  content filter.  More information
+              After  the  message is queued, send the entire mes-
+              sage through a content  filter.   More  information
               about  content  filters  is  in  the  Postfix  FIL-
               TER_README file.
 
-              Note:   this  action  overrides  the  <b>main.cf</b>  <b>con-</b>
+              Note:  this  action  overrides  the  <b>main.cf</b>   <b>con-</b>
               <b>tent</b><i>_</i><b>filter</b>  setting,  and  currently  affects  all
               recipients of the message.
 
        <b>REDIRECT</b> <i>user@domain</i>
-              After  the  message  is queued, send the message to
+              After the message is queued, send  the  message  to
               the  specified  address  instead  of  the  intended
               recipient(s).
 
-              Note:  this action overrides the FILTER action, and
+              Note: this action overrides the FILTER action,  and
               currently affects all recipients of the message.
 
        <i>restriction...</i>
@@ -182,39 +185,40 @@ ACCESS(5)                                               ACCESS(5)
               <b>reject</b><i>_</i><b>unauth</b><i>_</i><b>destination</b>, and so on).
 
 <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 string being looked up. Depending on the appli-
-       cation, that string  is  an  entire  client  hostname,  an
+       cation,  that  string  is  an  entire  client hostname, an
        entire client IP address, or an entire mail address. Thus,
        no  parent  domain  or  parent  network  search  is  done,
-       <i>user@domain</i>  mail  addresses  are not broken up into their
+       <i>user@domain</i> mail addresses are not broken  up  into  their
        <i>user@</i> and <i>domain</i> constituent parts, nor is <i>user+foo</i> broken
        up into <i>user</i> and <i>foo</i>.
 
-       Patterns  are  applied  in  the  order as specified in the
-       table, until a pattern is found that  matches  the  search
+       Patterns are applied in the  order  as  specified  in  the
+       table,  until  a  pattern is found that matches the search
        string.
 
-       Actions  are  the  same as with indexed file lookups, with
-       the additional feature that parenthesized substrings  from
+       Actions 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>BUGS</b>
-       The  table format does not understand quoting conventions.
+       The table format does not understand quoting  conventions.
 
 <b>SEE</b> <b>ALSO</b>
-       <a href="postmap.1.html">postmap(1)</a> create mapping table
+       <a href="postmap.1.html">postmap(1)</a> create lookup table
        <a href="smtpd.8.html">smtpd(8)</a> smtp server
+       cidr_table(5) format of CIDR tables
        <a href="pcre_table.5.html">pcre_table(5)</a> format of PCRE tables
        <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 d6a5eecda3897fe87627a9842640ad78dd80308a..50266a5a4e78d4d87bd052cadd8b0b3f1d46d066 100644 (file)
@@ -171,6 +171,14 @@ CLEANUP(8)                                             CLEANUP(8)
               Address mapping lookup table for sender and recipi-
               ent addresses in envelopes and headers.
 
+       <b>enable</b><i>_</i><b>original</b><i>_</i><b>recipient</b>
+              Enable  support  for  the   X-Original-To   message
+              header,  which  is needed for multi-recipient mail-
+              boxes.  When  this  is  enabled,  Postfix  performs
+              duplicate   elimination   on  (original  recipient,
+              rewritten recipient) pairs, instead of  looking  at
+              the rewritten recipient only.
+
        <b>recipient</b><i>_</i><b>canonical</b><i>_</i><b>maps</b>
               Address  mapping  lookup  table  for  envelope  and
               header recipient addresses.
@@ -180,16 +188,16 @@ CLEANUP(8)                                             CLEANUP(8)
               header sender addresses.
 
        <b>masquerade</b><i>_</i><b>classes</b>
-              List of address classes  subject  to  masquerading:
-              zero  or  more of <b>envelope</b><i>_</i><b>sender</b>, <b>envelope</b><i>_</i><b>recipi-</b>
+              List  of  address  classes subject to masquerading:
+              zero or more of  <b>envelope</b><i>_</i><b>sender</b>,  <b>envelope</b><i>_</i><b>recipi-</b>
               <b>ent</b>, <b>header</b><i>_</i><b>sender</b>, <b>header</b><i>_</i><b>recipient</b>.
 
        <b>masquerade</b><i>_</i><b>domains</b>
-              List of domains that hide  their  subdomain  struc-
+              List  of  domains  that hide their subdomain struc-
               ture.
 
        <b>masquerade</b><i>_</i><b>exceptions</b>
-              List  of user names that are not subject to address
+              List of user names that are not subject to  address
               masquerading.
 
        <b>virtual</b><i>_</i><b>alias</b><i>_</i><b>maps</b>
@@ -198,7 +206,7 @@ CLEANUP(8)                                             CLEANUP(8)
 
 <b>Resource</b> <b>controls</b>
        <b>duplicate</b><i>_</i><b>filter</b><i>_</i><b>limit</b>
-              Limits  the  number of envelope recipients that are
+              Limits the number of envelope recipients  that  are
               remembered.
 
        <b>header</b><i>_</i><b>address</b><i>_</i><b>token</b><i>_</i><b>limit</b>
@@ -206,21 +214,21 @@ CLEANUP(8)                                             CLEANUP(8)
               a message header.
 
        <b>header</b><i>_</i><b>size</b><i>_</i><b>limit</b>
-              Limits  the  amount of memory in bytes used to pro-
+              Limits the amount of memory in bytes used  to  pro-
               cess a message header.
 
        <b>in</b><i>_</i><b>flow</b><i>_</i><b>delay</b>
               Amount of time to pause before accepting a message,
-              when  the  message arrival rate exceeds the message
+              when the message arrival rate exceeds  the  message
               delivery rate.
 
        <b>virtual</b><i>_</i><b>alias</b><i>_</i><b>expansion</b><i>_</i><b>limit</b>
-              Limit the number of actual recipients  produced  by
-              virtual  alias expansion from each original recipi-
+              Limit  the  number of actual recipients produced by
+              virtual alias expansion from each original  recipi-
               ent.
 
        <b>virtual</b><i>_</i><b>alias</b><i>_</i><b>recursion</b><i>_</i><b>limit</b>
-              Limit the recursion depth of virtual  alias  expan-
+              Limit  the  recursion depth of virtual alias expan-
               sion.
 
 <b>SEE</b> <b>ALSO</b>
@@ -235,7 +243,7 @@ CLEANUP(8)                                             CLEANUP(8)
        /etc/postfix/virtual*, virtual mapping table
 
 <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 dba261f2ac0bec483d77098e1d0434e74656f346..3a81f15cebdacfd5be36f13794171b26a1f5f619 100644 (file)
@@ -2618,8 +2618,9 @@ the <b>virtual_mailbox_maps</b> parameter.
 
 <p>
 
-If you want to deliver the domain as a Postfix simulated <a
-href="virtual.8.html">virtual</a>(5) domain, then you should list
+If you want to deliver the domain as a <a href="virtual.8.html">
+virtual</a>(5) alias domain, where each address is aliased to
+a real local or remote address, then you should list
 the virtual domain name in the tables specified with the
 <b>virtual_alias_domains</b> parameter instead.
 
@@ -2638,7 +2639,7 @@ Solutions:
 
 <ul>
 
-<li>Specify a simulated virtual domain as per the
+<li>Specify a virtual alias domain as per the
 <a href="virtual.5.html">virtual(5)</a> manual page.
 
 <p>
@@ -2715,6 +2716,15 @@ that the mail was sent to.
 Answer: Postfix logs the original recipient address in the
 <b>X-Original-To:</b> message header.
 
+<p>
+
+This requires that the <b>enable_original_recipient</b> parameter
+is not changed from its default value of <b>yes</b>. With
+<b>enable_original_recipient</b> set to <b>no</b>, messages to
+multiple recipients in the domain will only be delivered to
+the first recipient, and the <b>X-Original-To:<b> header will
+not be added to the message.
+
 <hr>
 
 <a name="masquerade"><h3>Address masquerading with exceptions</h3></a>
index 6be1fd8c71f76fb70e804f6f859b38593416b0ba..629ab56e5c6fd1e5a309e2003b297b367fccc462 100644 (file)
@@ -5,8 +5,6 @@ PCRE_TABLE(5)                                       PCRE_TABLE(5)
        pcre_table - format of Postfix PCRE tables
 
 <b>SYNOPSIS</b>
-       <b>pcre:/etc/postfix/</b><i>filename</i>
-
        <b>postmap</b> <b>-q</b> <b>"</b><i>string</i><b>"</b> <b>pcre:/etc/postfix/</b><i>filename</i>
 
        <b>postmap</b> <b>-q</b> <b>-</b> <b>pcre:/etc/postfix/</b><i>filename</i> &lt;<i>inputfile</i>
@@ -26,8 +24,10 @@ PCRE_TABLE(5)                                       PCRE_TABLE(5)
        The general form of a PCRE table is:
 
        <b>/</b><i>pattern</i><b>/</b><i>flags</i> <i>result</i>
-              When <i>pattern</i> matches a search string, use the  cor-
-              responding <i>result</i> value.
+
+       <b>!/</b><i>pattern</i><b>/</b><i>flags</i> <i>result</i>
+              When <i>pattern</i> matches  (does  not  match)  a  search
+              string, use the corresponding <i>result</i> value.
 
        blank lines and comments
               Empty  lines and whitespace-only lines are ignored,
@@ -41,98 +41,104 @@ PCRE_TABLE(5)                                       PCRE_TABLE(5)
 
        <b>if</b> <b>/</b><i>pattern</i><b>/</b><i>flags</i>
 
+       <b>if</b> <b>!/</b><i>pattern</i><b>/</b><i>flags</i>
+
        <b>endif</b>  Examine the lines between <b>if</b>..<b>endif</b> only if <i>pattern</i>
-              matches. The <b>if</b>..<b>endif</b> can nest.   Do  not  prepend
-              whitespace to patterns inside <b>if</b>..<b>endif</b>.
+              matches (does not match). The <b>if</b>..<b>endif</b>  can  nest.
+              Do   not  prepend  whitespace  to  patterns  inside
+              <b>if</b>..<b>endif</b>.
 
        Each  pattern  is  a  perl-like  regular  expression.  The
-       expression delimiter can be any character, except  whites-
-       pace  or  characters that have special meaning (tradition-
-       ally the forward slash is used).  The  regular  expression
+       expression  delimiter can be any character, except whites-
+       pace or characters that have special  meaning  (tradition-
+       ally  the  forward slash is used).  The regular expression
        can contain whitespace.
 
        By default, matching is case-insensitive, and newlines are
-       not treated as special characters. The  behavior  is  con-
-       trolled  by  flags,  which are toggled by appending one or
+       not  treated  as  special characters. The behavior is con-
+       trolled by flags, which are toggled by  appending  one  or
        more of the following characters after the pattern:
 
        <b>i</b> (default: on)
-              Toggles the  case  sensitivity  flag.  By  default,
+              Toggles  the  case  sensitivity  flag.  By default,
               matching is case insensitive.
 
        <b>m</b> (default: off)
-              Toggles  the PCRE_MULTILINE flag. When this flag is
-              on, the <b>^</b> and <b>$</b>  metacharacters  match  immediately
-              after  and  immediately before a newline character,
-              respectively, in addition to matching at the  start
+              Toggles the PCRE_MULTILINE flag. When this flag  is
+              on,  the  <b>^</b>  and <b>$</b> metacharacters match immediately
+              after and immediately before a  newline  character,
+              respectively,  in addition to matching at the start
               and end of the subject string.
 
        <b>s</b> (default: on)
               Toggles the PCRE_DOTALL flag. When this flag is on,
               the <b>.</b>  metacharacter matches the newline character.
-              With  Postfix  versions prior to 20020528, The flag
+              With Postfix versions prior to 20020528,  The  flag
               is off by default, which is inconvenient for multi-
               line message header matching.
 
        <b>x</b> (default: off)
-              Toggles  the  pcre extended flag. When this flag is
-              on, whitespace in the  pattern  (other  than  in  a
+              Toggles the pcre extended flag. When this  flag  is
+              on,  whitespace  in  the  pattern  (other than in a
               character class) and characters between a <b>#</b> outside
-              a character class and the  next  newline  character
-              are  ignored.  An escaping backslash can be used to
-              include a whitespace or <b>#</b> character as part of  the
+              a  character  class  and the next newline character
+              are ignored. An escaping backslash can be  used  to
+              include  a whitespace or <b>#</b> character as part of the
               pattern.
 
        <b>A</b> (default: off)
-              Toggles  the PCRE_ANCHORED flag.  When this flag is
-              on, the pattern is forced to  be  "anchored",  that
+              Toggles the PCRE_ANCHORED flag.  When this flag  is
+              on,  the  pattern  is forced to be "anchored", that
               is, it is constrained to match only at the start of
-              the string which is being  searched  (the  "subject
-              string").  This  effect  can  also  be  achieved by
+              the  string  which  is being searched (the "subject
+              string"). This  effect  can  also  be  achieved  by
               appropriate constructs in the pattern itself.
 
        <b>E</b> (default: off)
-              Toggles the  PCRE_DOLLAR_ENDONLY  flag.  When  this
-              flag  is  on,  a  <b>$</b>  metacharacter  in  the pattern
-              matches only at the  end  of  the  subject  string.
-              Without  this  flag,  a dollar also matches immedi-
+              Toggles  the  PCRE_DOLLAR_ENDONLY  flag.  When this
+              flag is  on,  a  <b>$</b>  metacharacter  in  the  pattern
+              matches  only  at  the  end  of the subject string.
+              Without this flag, a dollar  also  matches  immedi-
               ately before the final character if it is a newline
               character (but not before any other newline charac-
-              ters). This flag is ignored if PCRE_MULTILINE  flag
+              ters).  This flag is ignored if PCRE_MULTILINE flag
               is set.
 
        <b>U</b> (default: off)
               Toggles the ungreedy matching flag.  When this flag
-              is on, the  pattern  matching  engine  inverts  the
-              "greediness"  of  the  quantifiers so that they are
-              not greedy by default, but become  greedy  if  fol-
-              lowed  by  "?".   This  flag can also set by a (?U)
+              is  on,  the  pattern  matching  engine inverts the
+              "greediness" of the quantifiers so  that  they  are
+              not  greedy  by  default, but become greedy if fol-
+              lowed by "?".  This flag can also  set  by  a  (?U)
               modifier within the pattern.
 
        <b>X</b> (default: off)
               Toggles the PCRE_EXTRA flag.  When this flag is on,
-              any  backslash  in  a pattern that is followed by a
+              any backslash in a pattern that is  followed  by  a
               letter that has no special meaning causes an error,
               thus reserving these combinations for future expan-
               sion.
 
-       Each pattern is applied to the entire lookup  key  string.
-       Depending  on  the  application,  that string is an entire
+       Each  pattern  is applied to the entire lookup key string.
+       Depending on the application, that  string  is  an  entire
        client hostname, an entire client IP address, or an entire
-       mail  address.   Thus,  no parent domain or parent network
-       search is done, and <i>user@domain</i>  mail  addresses  are  not
-       broken  up  into  their <i>user</i> and <i>domain</i> constituent parts,
+       mail address.  Thus, no parent domain  or  parent  network
+       search  is  done,  and  <i>user@domain</i> mail addresses are not
+       broken up into their <i>user</i> and  <i>domain</i>  constituent  parts,
        nor is <i>user+foo</i> broken up into <i>user</i> and <i>foo</i>.
 
-       Patterns are applied in the  order  as  specified  in  the
-       table,  until  a  pattern is found that matches the search
+       Patterns  are  applied  in  the  order as specified in the
+       table, until a pattern is found that  matches  the  search
        string.
 
-       Substitution of substrings  from  the  matched  expression
-       into  the result string is possible using the conventional
-       perl syntax ($1, $2, etc.).   The  macros  in  the  result
-       string  may  need  to  be  written as ${n} or $(n) if they
-       aren't followed by whitespace.
+       Substitution  of  substrings  from  the matched expression
+       into the result string is possible using the  conventional
+       perl  syntax  ($1,  $2,  etc.).   The macros in the result
+       string may need to be written as  ${n}  or  $(n)  if  they
+       aren't  followed  by  whitespace.  Since  negated patterns
+       (those preceded by <b>!</b>) return a result when the  expression
+       does  not  match,  substitutions  are  not  available  for
+       negated patterns.
 
 <b>EXAMPLE</b> <b>SMTPD</b> <b>ACCESS</b> <b>MAP</b>
        # Protect your outgoing majordomo exploders
@@ -161,6 +167,8 @@ PCRE_TABLE(5)                                       PCRE_TABLE(5)
 
 <b>SEE</b> <b>ALSO</b>
        <a href="regexp_table.5.html">regexp_table(5)</a> format of POSIX regular expression tables
+       cidr_table(5) format of CIDR tables
+       tcp_table(5) TCP client/server table lookup protocol
 
 <b>AUTHOR(S)</b>
        The PCRE table lookup code was originally written by:
index 624820adbc4756ad275c47fa001605cc05efb5b0..60e8097eac0127bff7c16e07e5f23777f5a01ef5 100644 (file)
@@ -5,8 +5,6 @@ REGEXP_TABLE(5)                                   REGEXP_TABLE(5)
        regexp_table - format of Postfix regular expression tables
 
 <b>SYNOPSIS</b>
-       <b>regexp:/etc/postfix/</b><i>filename</i>
-
        <b>postmap</b> <b>-q</b> <b>"</b><i>string</i><b>"</b> <b>regexp:/etc/postfix/</b><i>filename</i>
 
        <b>postmap</b> <b>-q</b> <b>-</b> <b>regexp:/etc/postfix/</b><i>filename</i> &lt;<i>inputfile</i>
@@ -78,7 +76,10 @@ REGEXP_TABLE(5)                                   REGEXP_TABLE(5)
        Substitution  of  substrings  from  the matched expression
        into the result string is possible using $1, $2, etc.. The
        macros in the result string may need to be written as ${n}
-       or $(n) if they aren't followed by whitespace.
+       or $(n) if  they  aren't  followed  by  whitespace.  Since
+       negated  patterns  (those  preceded by <b>!</b>)  return a result
+       when the expression does not match, substitutions are  not
+       available for negated patterns.
 
 <b>EXAMPLE</b> <b>SMTPD</b> <b>ACCESS</b> <b>MAP</b>
        # Disallow sender-specified routing. This is a must if you relay mail
@@ -107,6 +108,8 @@ REGEXP_TABLE(5)                                   REGEXP_TABLE(5)
 
 <b>SEE</b> <b>ALSO</b>
        <a href="pcre_table.5.html">pcre_table(5)</a> format of PCRE tables
+       cidr_table(5) format of CIDR tables
+       tcp_table(5) TCP client/server table lookup protocol
 
 <b>AUTHOR(S)</b>
        The regexp table lookup code was originally written by:
index a432b01947081be5b961f8cc1761bfcedb1e682a..87d8b744431c9abfaee90ec8169ec63b52f591cb 100644 (file)
@@ -318,8 +318,8 @@ href="cleanup.8.html">cleanup</a> daemon uses the <a
 href="virtual.5.html">virtual alias</a> table to redirect mail for all
 recipients, local or remote.  The mapping affects only envelope
 recipients; it has no effect on message headers or envelope senders.
-Virtual alias lookups are useful to redirect mail for simulated
-virtual domains to real user mailboxes, and to redirect mail for
+Virtual alias lookups are useful to redirect mail for virtual
+alias domains to real user mailboxes, and to redirect mail for
 domains that no longer exist.  Virtual alias lookups can also be
 used to transform <i> Firstname.Lastname </i> back into UNIX login
 names, although it seems that local <a href="#aliases">aliases</a>
index be7b18649bd4824b88925dc1729ad64cbdc693c1..167e4b3436384ea80afbd0933d2dbc34d680621a 100644 (file)
@@ -25,11 +25,6 @@ SMTP(8)                                                   SMTP(8)
        preference,  and  connects to each listed address until it
        finds a server that responds.
 
-       When the domain or host is specified as a comma/whitespace
-       separated  list, the SMTP client repeats the above process
-       for  all  destinations  until  it  finds  a  server   that
-       responds.
-
        Once the SMTP client has received the server greeting ban-
        ner, no error will cause it to proceed to the next address
        on the mail exchanger list. Instead, the message is either
@@ -37,7 +32,7 @@ SMTP(8)                                                   SMTP(8)
 
 <b>SECURITY</b>
        The SMTP client is moderately security-sensitive. It talks
-       to  SMTP  servers  and  to DNS servers on the network. The
+       to SMTP servers and to DNS servers  on  the  network.  The
        SMTP client can be run chrooted at fixed low privilege.
 
 <b>STANDARDS</b>
@@ -53,80 +48,80 @@ SMTP(8)                                                   SMTP(8)
        <a href="http://www.faqs.org/rfcs/rfc2920.html">RFC 2920</a> (SMTP Pipelining)
 
 <b>DIAGNOSTICS</b>
-       Problems and transactions are logged to <b>syslogd</b>(8).   Cor-
-       rupted  message files are marked so that the queue manager
+       Problems  and transactions are logged to <b>syslogd</b>(8).  Cor-
+       rupted message files are marked so that the queue  manager
        can move them to the <b>corrupt</b> queue for further inspection.
 
-       Depending  on the setting of the <b>notify</b><i>_</i><b>classes</b> parameter,
-       the postmaster is notified of bounces, protocol  problems,
+       Depending on the setting of the <b>notify</b><i>_</i><b>classes</b>  parameter,
+       the  postmaster is notified of bounces, protocol problems,
        and of other trouble.
 
 <b>BUGS</b>
 <b>CONFIGURATION</b> <b>PARAMETERS</b>
-       The  following  <b>main.cf</b> parameters are especially relevant
-       to this program. 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  program. 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>Miscellaneous</b>
        <b>best</b><i>_</i><b>mx</b><i>_</i><b>transport</b>
-              Name of the delivery  transport  to  use  when  the
-              local  machine is the most-preferred mail exchanger
-              (by default, a mailer loop  is  reported,  and  the
+              Name  of  the  delivery  transport  to use when the
+              local machine is the most-preferred mail  exchanger
+              (by  default,  a  mailer  loop is reported, and the
               message is bounced).
 
        <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
-              Verbose  logging  level  increment  for  hosts that
+              Verbose logging  level  increment  for  hosts  that
               match a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b> parameter.
 
        <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
-              List of domain or network patterns. When  a  remote
-              host  matches  a pattern, increase the verbose log-
-              ging  level  by  the  amount   specified   in   the
+              List  of  domain or network patterns. When a remote
+              host matches a pattern, increase the  verbose  log-
+              ging   level   by   the  amount  specified  in  the
               <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
 
        <b>disable</b><i>_</i><b>dns</b><i>_</i><b>lookups</b>
-              Disable  DNS  lookups. This means that mail must be
+              Disable DNS lookups. This means that mail  must  be
               forwarded via a smart relay host.
 
        <b>smtp</b><i>_</i><b>host</b><i>_</i><b>lookup</b>
-              What host lookup mechanism the SMTP  client  should
-              use.   Specify  <b>dns</b>  (use DNS lookup) and/or <b>native</b>
-              (use the native  naming  service  which  also  uses
-              /etc/hosts).   This  setting  is  ignored  when DNS
+              What  host  lookup mechanism the SMTP client should
+              use.  Specify <b>dns</b> (use DNS  lookup)  and/or  <b>native</b>
+              (use  the  native  naming  service  which also uses
+              /etc/hosts).  This  setting  is  ignored  when  DNS
               lookups are disabled.
 
        <b>error</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
-              Recipient   of    protocol/policy/resource/software
+              Recipient    of   protocol/policy/resource/software
               error notices.
 
        <b>fallback</b><i>_</i><b>relay</b>
-              Hosts  to hand off mail to if a message destination
+              Hosts to hand off mail to if a message  destination
               is not found or if a destination is unreachable.
 
        <b>ignore</b><i>_</i><b>mx</b><i>_</i><b>lookup</b><i>_</i><b>error</b>
               When a name server fails to respond to an MX query,
-              search  for  an  A  record  instead  deferring mail
+              search for  an  A  record  instead  deferring  mail
               delivery.
 
        <b>inet</b><i>_</i><b>interfaces</b>
               The network interface addresses that this mail sys-
-              tem  receives  mail on. When any of those addresses
+              tem receives mail on. When any of  those  addresses
               appears in the list of mail exchangers for a remote
-              destination,  the  list  is truncated to avoid mail
+              destination, the list is truncated  to  avoid  mail
               delivery  loops.   See  also  the  <b>proxy</b><i>_</i><b>interfaces</b>
               parameter.
 
        <b>notify</b><i>_</i><b>classes</b>
-              When  this  parameter  includes the <b>protocol</b> class,
-              send mail to the  postmaster  with  transcripts  of
+              When this parameter includes  the  <b>protocol</b>  class,
+              send  mail  to  the  postmaster with transcripts of
               SMTP sessions with protocol errors.
 
        <b>proxy</b><i>_</i><b>interfaces</b>
-              Network  interfaces  that this mail system receives
+              Network interfaces that this mail  system  receives
               mail on by way of a proxy or network address trans-
-              lator.  When  any of those addresses appears in the
-              list of mail exchangers for a  remote  destination,
+              lator. When any of those addresses appears  in  the
+              list  of  mail exchangers for a remote destination,
               the list is truncated to avoid mail delivery loops.
               See also the <b>inet</b><i>_</i><b>interfaces</b> parameter.
 
@@ -137,16 +132,20 @@ SMTP(8)                                                   SMTP(8)
               Never send EHLO at the start of a connection.
 
        <b>smtp</b><i>_</i><b>bind</b><i>_</i><b>address</b>
-              Numerical source network address to  bind  to  when
+              Numerical  source  network  address to bind to when
               making a connection.
 
        <b>smtp</b><i>_</i><b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>
-              Length  limit  for SMTP message content lines. Zero
-              means no limit.  Some  SMTP  servers  misbehave  on
+              Length limit for SMTP message content  lines.  Zero
+              means  no  limit.   Some  SMTP servers misbehave on
               long lines.
 
        <b>smtp</b><i>_</i><b>helo</b><i>_</i><b>name</b>
-              The  hostname to be used in HELO and EHLO commands.
+              The hostname to be used in HELO and EHLO  commands.
+
+       <b>smtp</b><i>_</i><b>quote</b><i>_</i><b>rfc821</b><i>_</i><b>envelope</b>
+              Whether  or  not  to  quote  MAIL  FROM and RCPT TO
+              addresses as per the rules laid out in <a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a>.
 
        <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>4xx</b><i>_</i><b>greeting</b>
               Skip servers that greet us with a 4xx status  code.
index 4aca9e81b79b890bb72f4d2ca008605ed0554608..9e98fba7425b1c0b412466d5198d7207d8ceaa7a 100644 (file)
@@ -114,29 +114,48 @@ SMTPD(8)                                                 SMTPD(8)
               <b>reject</b><i>_</i><b>sender</b><i>_</i><b>login</b><i>_</i><b>mismatch</b>  sender  anti-spoofing
               restriction.
 
+<b>Pass-through</b> <b>proxy</b>
+       Optionally,  the  Postfix SMTP server can be configured to
+       forward all mail to a proxy server, for  example  a  real-
+       time  content filter. This proxy server should support the
+       same MAIL FROM and RCPT TO command syntax as Postfix,  but
+       does not need to support ESMTP command pipelining.
+
+       <b>smtpd</b><i>_</i><b>proxy</b><i>_</i><b>filter</b>
+              The <i>host:port</i> of the SMTP proxy server. The <i>host</i> or
+              <i>host:</i> portion is optional.
+
+       <b>smtpd</b><i>_</i><b>proxy</b><i>_</i><b>timeout</b>
+              Timeout for connecting to, sending to and receiving
+              from the SMTP proxy server.
+
+       <b>smtpd</b><i>_</i><b>proxy</b><i>_</i><b>ehlo</b>
+              The hostname to use when sending an EHLO command to
+              the SMTP proxy server.
+
 <b>Miscellaneous</b>
        <b>authorized</b><i>_</i><b>verp</b><i>_</i><b>clients</b>
               Hostnames, domain names and/or addresses of clients
               that are authorized to use the XVERP extension.
 
        <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
-              Increment in verbose logging level  when  a  remote
+              Increment  in  verbose  logging level when a remote
               host  matches  a  pattern  in  the  <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
               parameter.
 
        <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
-              List of domain or network patterns. When  a  remote
-              host  matches  a pattern, increase the verbose log-
-              ging  level  by  the  amount   specified   in   the
+              List  of  domain or network patterns. When a remote
+              host matches a pattern, increase the  verbose  log-
+              ging   level   by   the  amount  specified  in  the
               <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
 
        <b>default</b><i>_</i><b>verp</b><i>_</i><b>delimiters</b>
               The default VERP delimiter characters that are used
-              when  the  XVERP  command  is   specified   without
+              when   the   XVERP  command  is  specified  without
               explicit delimiters.
 
        <b>error</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
-              Recipient    of   protocol/policy/resource/software
+              Recipient   of    protocol/policy/resource/software
               error notices.
 
        <b>hopcount</b><i>_</i><b>limit</b>
@@ -145,18 +164,18 @@ SMTPD(8)                                                 SMTPD(8)
        <b>notify</b><i>_</i><b>classes</b>
               List of error classes. Of special interest are:
 
-              <b>policy</b> When a client violates any  policy,  mail  a
+              <b>policy</b> When  a  client  violates any policy, mail a
                      transcript of the entire SMTP session to the
                      postmaster.
 
               <b>protocol</b>
-                     When a client violates the SMTP protocol  or
+                     When  a client violates the SMTP protocol or
                      issues  an  unimplemented  command,  mail  a
                      transcript of the entire SMTP session to the
                      postmaster.
 
        <b>smtpd</b><i>_</i><b>banner</b>
-              Text  that  follows the <b>220</b> status code in the SMTP
+              Text that follows the <b>220</b> status code in  the  SMTP
               greeting banner.
 
        <b>smtpd</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>
@@ -164,57 +183,57 @@ SMTPD(8)                                                 SMTPD(8)
               expansion of rbl template responses and other text.
 
        <b>smtpd</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
-              Restrict the number of  recipients  that  the  SMTP
+              Restrict  the  number  of  recipients that the SMTP
               server accepts per message delivery.
 
        <b>smtpd</b><i>_</i><b>timeout</b>
-              Limit  the  time  to  send a server response and to
+              Limit the time to send a  server  response  and  to
               receive a client request.
 
        <b>soft</b><i>_</i><b>bounce</b>
-              Change hard (5xx) reject responses into soft  (4xx)
-              reject  responses.   This can be useful for testing
+              Change  hard (5xx) reject responses into soft (4xx)
+              reject responses.  This can be useful  for  testing
               purposes.
 
        <b>verp</b><i>_</i><b>delimiter</b><i>_</i><b>filter</b>
-              The characters that Postfix accepts as VERP  delim-
+              The  characters that Postfix accepts as VERP delim-
               iter characters.
 
 <b>Known</b> <b>versus</b> <b>unknown</b> <b>recipients</b>
        <b>show</b><i>_</i><b>user</b><i>_</i><b>unknown</b><i>_</i><b>table</b><i>_</i><b>name</b>
-              Whether  or  not  to  reveal  the table name in the
-              "User unknown" responses. The  extra  detail  makes
-              trouble  shooting  easier but also reveals informa-
+              Whether or not to reveal  the  table  name  in  the
+              "User  unknown"  responses.  The extra detail makes
+              trouble shooting easier but also  reveals  informa-
               tion that is nobody elses business.
 
        <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
+              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
+              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
+              <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>
+              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>,
+              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>
@@ -222,8 +241,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>
@@ -238,23 +257,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>
@@ -262,19 +281,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>
@@ -282,42 +301,60 @@ 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>Sender/recipient</b> <b>address</b> <b>verification</b>
+       Address verification is implemented by sending probe email
+       messages that are not actually delivered, and  is  enabled
+       via    the   reject_unverified_{sender,recipient}   access
+       restriction.  The status of verification probes  is  main-
+       tained by the address verification service.
+
+       <b>address</b><i>_</i><b>verify</b><i>_</i><b>poll</b><i>_</i><b>count</b>
+              How  many  times  to query the address verification
+              service for completion of an  address  verification
+              request.   Specify  0 to implement a simple form of
+              greylisting.
+
+       <b>address</b><i>_</i><b>verify</b><i>_</i><b>poll</b><i>_</i><b>delay</b>
+              Time to wait after querying the  address  verifica-
+              tion service for completion of an address verifica-
+              tion request.
+
 <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
@@ -381,10 +418,11 @@ SMTPD(8)                                                 SMTPD(8)
               be undeliverable.
 
 <b>SEE</b> <b>ALSO</b>
-       <a href="trivial-rewrite.8.html">trivial-rewrite(8)</a> address resolver
        <a href="cleanup.8.html">cleanup(8)</a> message canonicalization
        <a href="master.8.html">master(8)</a> process manager
        syslogd(8) system logging
+       <a href="trivial-rewrite.8.html">trivial-rewrite(8)</a> address resolver
+       <a href="verify.8.html">verify(8)</a> address verification service
 
 <b>LICENSE</b>
        The  Secure  Mailer  license must be distributed with this
index 3d63496b84119a315a13aee61a746e913d45acaa..4d6185c8fd33a01656ad658a959edaba47a4192e 100644 (file)
@@ -17,21 +17,40 @@ TRANSPORT(5)                                         TRANSPORT(5)
        relay hosts. The mapping is used by the <a href="trivial-rewrite.8.html"><b>trivial-rewrite</b>(8)</a>
        daemon.
 
-       Normally, the <b>transport</b> table is specified as a text  file
-       that  serves  as  input  to  the  <a href="postmap.1.html"><b>postmap</b>(1)</a> command.  The
-       result, an indexed file in <b>dbm</b> or <b>db</b> format, is  used  for
-       fast  searching  by  the  mail system. Execute the command
-       <b>postmap</b> <b>/etc/postfix/transport</b> in  order  to  rebuild  the
+       This mapping overrides the default routing that  is  built
+       into Postfix:
+
+       <b>mydestination</b>
+              A  list of domains that is by default delivered via
+              <b>$local</b><i>_</i><b>transport</b>.
+
+       <b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>domains</b>
+              A list of domains that is by default delivered  via
+              <b>$virtual</b><i>_</i><b>transport</b>.
+
+       <b>relay</b><i>_</i><b>domains</b>
+              A  list of domains that is by default delivered via
+              <b>$relay</b><i>_</i><b>transport</b>.
+
+       any other destination
+              Mail for any other destination is by default deliv-
+              ered via <b>$default</b><i>_</i><b>transport</b>.
+
+       Normally,  the <b>transport</b> table is specified as a text file
+       that serves as  input  to  the  <a href="postmap.1.html"><b>postmap</b>(1)</a>  command.   The
+       result,  an  indexed file in <b>dbm</b> or <b>db</b> format, is used for
+       fast searching by the mail  system.  Execute  the  command
+       <b>postmap</b>  <b>/etc/postfix/transport</b>  in  order  to rebuild the
        indexed file after changing the transport table.
 
-       When  the  table  is provided via other means such as NIS,
-       LDAP or SQL, the same lookups are  done  as  for  ordinary
+       When the table is provided via other means  such  as  NIS,
+       LDAP  or  SQL,  the  same lookups are done as for ordinary
        indexed files.
 
-       Alternatively,  the  table  can  be provided as a regular-
+       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 section "REGULAR  EXPRESSION
+       sions. In that case, the lookups are done  in  a  slightly
+       different  way as described in section "REGULAR EXPRESSION
        TABLES".
 
 <b>TABLE</b> <b>FORMAT</b>
@@ -42,28 +61,28 @@ TRANSPORT(5)                                         TRANSPORT(5)
               domain, use the corresponding <i>result</i>.
 
        blank lines and comments
-              Empty lines and whitespace-only lines are  ignored,
-              as  are  lines whose first non-whitespace character
+              Empty  lines and whitespace-only lines are ignored,
+              as are lines whose first  non-whitespace  character
               is a `#'.
 
        multi-line text
-              A logical line starts with non-whitespace  text.  A
-              line  that starts with whitespace continues a logi-
+              A  logical  line starts with non-whitespace text. A
+              line that starts with whitespace continues a  logi-
               cal line.
 
-       The <i>pattern</i> specifies an email address, a domain name,  or
-       a  domain  name  hierarchy, as described in section "TABLE
+       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
+       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. More details are given in section "RESULT
        FORMAT".
 
 <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
+       networked tables such as NIS, LDAP or  SQL,  patterns  are
        tried in the order as listed below:
 
        <i>user+extension@domain</i> <i>transport</i>:<i>nexthop</i>
@@ -75,134 +94,134 @@ TRANSPORT(5)                                         TRANSPORT(5)
               to <i>nexthop</i>.
 
        <i>domain</i> <i>transport</i>:<i>nexthop</i>
-              Mail for <i>domain</i> is delivered through  <i>transport</i>  to
+              Mail  for  <i>domain</i> is delivered through <i>transport</i> to
               <i>nexthop</i>.
 
        <i>.domain</i> <i>transport</i>:<i>nexthop</i>
-              Mail  for  any  subdomain  of  <i>domain</i>  is delivered
-              through <i>transport</i> to  <i>nexthop</i>.  This  applies  only
+              Mail for  any  subdomain  of  <i>domain</i>  is  delivered
+              through  <i>transport</i>  to  <i>nexthop</i>.  This applies only
               when the string <b>transport</b><i>_</i><b>maps</b> is not listed in the
               <b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdomains</b> configuration set-
-              ting.   Otherwise, a domain name matches itself and
+              ting.  Otherwise, a domain name matches itself  and
               its subdomains.
 
        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
+       Note 2:  the  null  recipient  address  is  looked  up  as
        <b>$empty</b><i>_</i><b>address</b><i>_</i><b>recipient</b>@<b>$myhostname</b> (default: mailer-dae-
        mon@hostname).
 
 <b>RESULT</b> <b>FORMAT</b>
-       The  transport field specifies the name of a mail delivery
+       The transport field specifies the name of a mail  delivery
        transport (the first name of a mail delivery service entry
        in the Postfix <b>master.cf</b> file).
 
-       The  interpretation  of  the  nexthop  field  is transport
+       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  []
+       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 is required when you specify an IP address instead of
        a hostname.
 
-       A null <i>transport</i> and null <i>nexthop</i>  result  means  "do  not
-       change":  use  the delivery transport and nexthop informa-
-       tion that would be used when the  entire  transport  table
+       A  null  <i>transport</i>  and  null <i>nexthop</i> result means "do not
+       change": use the delivery transport and  nexthop  informa-
+       tion  that  would  be used when the entire transport table
        did not exist.
 
-       A  non-null  <i>transport</i>  field  with  a  null <i>nexthop</i> field
+       A non-null <i>transport</i>  field  with  a  null  <i>nexthop</i>  field
        resets the nexthop information to the recipient domain.
 
-       A null <i>transport</i> field with non-null  <i>nexthop</i>  field  does
+       A  null  <i>transport</i>  field with non-null <i>nexthop</i> field does
        not modify the transport information.
 
 <b>EXAMPLES</b>
-       In  order to deliver internal mail directly, while using a
-       mail relay for all other mail, specify a  null  entry  for
-       internal  destinations  (do not change the delivery trans-
-       port or the nexthop information) and  specify  a  wildcard
+       In order to deliver internal mail directly, while using  a
+       mail  relay  for  all other mail, specify a null entry for
+       internal destinations (do not change the  delivery  trans-
+       port  or  the  nexthop information) and specify a wildcard
        for all other destinations.
 
             <b>my.domain</b>    <b>:</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>empty</b><i>_</i><b>address</b><i>_</i><b>recipient</b>
-              The address that is looked up instead of  the  null
+              The  address  that is looked up instead of the null
               sender address.
 
        <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>
@@ -215,7 +234,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 181063eb05967f7b3406f810d4951d3258ef750e..ec24b4add9dd8dad83647b4e1dad18856464998f 100644 (file)
@@ -33,9 +33,9 @@ VERIFY(8)                                               VERIFY(8)
               Update the status of the specified address.
 
        <b>VRFY</b><i>_</i><b>ADDR</b><i>_</i><b>QUERY</b> <i>address</i>
-              Look up  the  <i>status</i>  and  <i>text</i>  of  the  specified
-              address.  If the status is unknown, a probe is sent
-              and a default status is returned.
+              Look up the <i>status</i>, <i>last</i> <i>update</i> <i>time</i>  and  <i>text</i>  of
+              the specified address.  If the status is unknown, a
+              probe is sent and a default status is returned.
 
        The server reply status is one of:
 
index 91ede1d16d295fc8a570297672e5543e725997ed..47656a23153120cebd818ce38c4b10c5e60f4300 100644 (file)
@@ -12,7 +12,8 @@ COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
        man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
        man1/postqueue.1 man1/postsuper.1
 CONFIG = man5/access.5 man5/aliases.5 man5/canonical.5 man5/relocated.5 \
-       man5/transport.5 man5/virtual.5 man5/pcre_table.5 man5/regexp_table.5
+       man5/transport.5 man5/virtual.5 man5/pcre_table.5 man5/regexp_table.5 \
+       man5/cidr_table.5 man5/tcp_table.5
 TOOLS  = man1/smtp-sink.1 man1/smtp-source.1 man1/qmqp-sink.1 \
        man1/qmqp-source.1
 
@@ -149,6 +150,9 @@ man5/aliases.5: ../proto/aliases
 man5/canonical.5: ../proto/canonical
        ../mantools/srctoman - $? >$@
 
+man5/cidr_table.5: ../proto/cidr_table
+       ../mantools/srctoman - $? >$@
+
 man5/pcre_table.5: ../proto/pcre_table
        ../mantools/srctoman - $? >$@
 
@@ -170,6 +174,9 @@ man1/smtp-sink.1: ../src/smtpstone/smtp-sink.c
 man1/smtp-source.1: ../src/smtpstone/smtp-source.c
        ../mantools/srctoman $? >$@
 
+man5/tcp_table.5: ../proto/tcp_table
+       ../mantools/srctoman - $? >$@
+
 man1/qmqp-sink.1: ../src/smtpstone/qmqp-sink.c
        ../mantools/srctoman $? >$@
 
index fcdca96b4ca531ef1c7f1506feed90a1a218476d..5f5ae97a3440830d7af49f18bbe1597398c3311d 100644 (file)
@@ -106,6 +106,9 @@ order to match subdomains.
 .IP \fInet\fR
 Matches any host address in the specified network. A network
 address is a sequence of one or more octets separated by ".".
+
+NOTE: use the \fBcidr\fR lookup table type if you want to
+specify arbitrary network blocks.
 .SH ACTIONS
 .na
 .nf
@@ -194,8 +197,9 @@ The table format does not understand quoting conventions.
 .SH SEE ALSO
 .na
 .nf
-postmap(1) create mapping table
+postmap(1) create lookup table
 smtpd(8) smtp server
+cidr_table(5) format of CIDR tables
 pcre_table(5) format of PCRE tables
 regexp_table(5) format of POSIX regular expression tables
 .SH LICENSE
diff --git a/postfix/man/man5/cidr_table.5 b/postfix/man/man5/cidr_table.5
new file mode 100644 (file)
index 0000000..179eb66
--- /dev/null
@@ -0,0 +1,81 @@
+.TH CIDR_TABLE 5 
+.ad
+.fi
+.SH NAME
+cidr_table
+\-
+format of Postfix CIDR tables
+.SH SYNOPSIS
+.na
+.nf
+\fBpostmap -q "\fIstring\fB" cidr:/etc/postfix/\fIfilename\fR
+
+\fBpostmap -q - cidr:/etc/postfix/\fIfilename\fR <\fIinputfile\fR
+.SH DESCRIPTION
+.ad
+.fi
+The Postfix mail system uses optional access control tables.
+These tables are usually in \fBdbm\fR or \fBdb\fR format.
+Alternatively, access control tables can be specified in CIDR form.
+
+To find out what types of lookup tables your Postfix system
+supports use the \fBpostconf -m\fR command.
+
+To test lookup tables, use the \fBpostmap\fR command as
+described in the SYNOPSIS above.
+.SH TABLE FORMAT
+.na
+.nf
+.ad
+.fi
+The general form of a Postfix CIDR table is:
+.IP "\fInetwork_address\fB/\fInetwork_mask     result\fR"
+When a search string matches the specified network block,
+use the corresponding \fIresult\fR value.
+.IP "\fInetwork_address     result\fR"
+When a search string matches the specified network address,
+use the corresponding \fIresult\fR value.
+.IP "blank lines and comments"
+Empty lines and whitespace-only lines are ignored, as
+are lines whose first non-whitespace character is a `#'.
+.IP "multi-line text"
+A logical line starts with non-whitespace text. A line that
+starts with whitespace continues a logical line.
+.PP
+Patterns are applied in the order as specified in the table, until a
+pattern is found that matches the search string.
+.SH EXAMPLE SMTPD ACCESS MAP
+.na
+.nf
+/etc/postfix/main.cf:
+.ti +4
+smtpd_client_restrictions = ... cidr:/etc/postfix/client_cidr ...
+
+/etc/postfix/client_cidr:
+.in +4
+# Rule order matters. Put more specific whitelist entries
+# before more general blacklist entries.
+192.168.1.1             OK
+192.168.0.0/16          REJECT
+.in -4
+.SH SEE ALSO
+.na
+.nf
+regexp_table(5) format of regular expression tables
+pcre_table(5) format of PCRE tables
+tcp_table(5) TCP client/server table lookup protocol
+.SH AUTHOR(S)
+.na
+.nf
+The CIDR table lookup code was originally written by:
+Jozsef Kadlecsik
+kadlec@blackhole.kfki.hu
+KFKI Research Institute for Particle and Nuclear Physics
+POB. 49
+1525 Budapest, Hungary
+
+Adopted and adapted by:
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
index 7fcedcb888dff91b08e73c4c1621fcf7ef4641cd..98bd0f7c51ffcffdaa83693784d61b92ea06ee6e 100644 (file)
@@ -8,8 +8,6 @@ format of Postfix PCRE tables
 .SH SYNOPSIS
 .na
 .nf
-\fBpcre:/etc/postfix/\fIfilename\fR
-
 \fBpostmap -q "\fIstring\fB" pcre:/etc/postfix/\fIfilename\fR
 
 \fBpostmap -q - pcre:/etc/postfix/\fIfilename\fR <\fIinputfile\fR
@@ -29,8 +27,9 @@ described in the SYNOPSIS above.
 
 The general form of a PCRE table is:
 .IP "\fB/\fIpattern\fB/\fIflags result\fR"
-When \fIpattern\fR matches a search string, use the corresponding
-\fIresult\fR value.
+.IP "\fB!/\fIpattern\fB/\fIflags result\fR"
+When \fIpattern\fR matches (does not match) a search string, use
+the corresponding \fIresult\fR value.
 .IP "blank lines and comments"
 Empty lines and whitespace-only lines are ignored, as
 are lines whose first non-whitespace character is a `#'.
@@ -38,10 +37,12 @@ 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.
 .IP "\fBif /\fIpattern\fB/\fIflags\fR"
+.IP "\fBif !/\fIpattern\fB/\fIflags\fR"
 .IP "\fBendif\fR"
 Examine the lines between \fBif\fR..\fBendif\fR only if
-\fIpattern\fR matches. The \fBif\fR..\fBendif\fR can nest.
-Do not prepend whitespace to patterns inside \fBif\fR..\fBendif\fR.
+\fIpattern\fR matches (does not match). The \fBif\fR..\fBendif\fR
+can nest. Do not prepend whitespace to patterns inside
+\fBif\fR..\fBendif\fR.
 .PP
 Each pattern is a perl-like regular expression. The expression
 delimiter can be any character, except whitespace or characters
@@ -114,7 +115,9 @@ pattern is found that matches the search string.
 Substitution of substrings from the matched expression into the result
 string is possible using the conventional perl syntax ($1, $2, etc.).
 The macros in the result string may need to be written as ${n}
-or $(n) if they aren't followed by whitespace.
+or $(n) if they aren't followed by whitespace. Since negated patterns
+(those preceded by \fB!\fR) return a result when the expression does
+not match, substitutions are not available for negated patterns.
 .SH EXAMPLE SMTPD ACCESS MAP
 .na
 .nf
@@ -147,6 +150,8 @@ or $(n) if they aren't followed by whitespace.
 .na
 .nf
 regexp_table(5) format of POSIX regular expression tables
+cidr_table(5) format of CIDR tables
+tcp_table(5) TCP client/server table lookup protocol
 .SH AUTHOR(S)
 .na
 .nf
index 8b418efe2f57faef2b0d905943d95525b80d6cdd..0f5173d5173d5457b7b19dd971a5ac50375a38c0 100644 (file)
@@ -8,8 +8,6 @@ format of Postfix regular expression tables
 .SH SYNOPSIS
 .na
 .nf
-\fBregexp:/etc/postfix/\fIfilename\fR
-
 \fBpostmap -q "\fIstring\fB" regexp:/etc/postfix/\fIfilename\fR
 
 \fBpostmap -q - regexp:/etc/postfix/\fIfilename\fR <\fIinputfile\fR
@@ -71,7 +69,9 @@ pattern is found that matches the search string.
 Substitution of substrings from the matched expression into the result
 string is possible using $1, $2, etc.. The macros in the result string
 may need to be written as ${n} or $(n) if they aren't followed
-by whitespace.
+by whitespace. Since negated patterns (those preceded by \fB!\fR)
+return a result when the expression does not match, substitutions are
+not available for negated patterns.
 .SH EXAMPLE SMTPD ACCESS MAP
 .na
 .nf
@@ -104,6 +104,8 @@ endif
 .na
 .nf
 pcre_table(5) format of PCRE tables
+cidr_table(5) format of CIDR tables
+tcp_table(5) TCP client/server table lookup protocol
 .SH AUTHOR(S)
 .na
 .nf
diff --git a/postfix/man/man5/tcp_table.5 b/postfix/man/man5/tcp_table.5
new file mode 100644 (file)
index 0000000..69ab6b4
--- /dev/null
@@ -0,0 +1,96 @@
+.TH TCP_TABLE 5 
+.ad
+.fi
+.SH NAME
+tcp_table
+\-
+Postfix client/server table lookup protocol
+.SH SYNOPSIS
+.na
+.nf
+\fBpostmap -q "\fIstring\fB" tcp:\fIhost:port\fR
+
+\fBpostmap -q - regexp:\fIhost:port\fR <\fIinputfile\fR
+.SH DESCRIPTION
+.ad
+.fi
+The Postfix mail system uses optional tables for address
+rewriting or mail routing. These tables are usually in
+\fBdbm\fR or \fBdb\fR format. Alternatively, lookup tables
+can be specified as a TCP client/server pair.
+
+To find out what types of lookup tables your Postfix system
+supports use the \fBpostconf -m\fR command.
+
+To test lookup tables, use the \fBpostmap\fR command as
+described in the SYNOPSIS above.
+.SH PROTOCOL DESCRIPTION
+.na
+.nf
+.ad
+.fi
+The TCP map class implements a very simple protocol: the client
+sends a request, and the server sends one reply. Requests and
+replies are sent as one line of ASCII text, terminated by the
+ASCII newline character. Request and reply parameters (see below)
+are separated by whitespace.
+.SH ENCODING
+.na
+.nf
+.ad
+.fi
+In request and reply parameters, the character % and any non-printing
+and whitespace characters must be replaced by %XX, XX being the
+corresponding ASCII hexadecimal character value. The hexadecimal codes
+can be specified in any case (upper, lower, mixed).
+.SH REQUEST FORMAT
+.na
+.nf
+.ad
+.fi
+Requests are strings that serve as lookup key in the simulated
+table.
+.IP "\fBget\fR SPACE \fIkey\fR NEWLINE"
+Look up data under the specified key.
+.IP "\fBput\fR SPACE \fIkey\fR SPACE \fIvalue\fR NEWLINE"
+This request is currently not implemented.
+.SH REPLY FORMAT
+.na
+.nf
+.ad
+.fi
+Replies must be no longer than 4096 characters including the
+newline terminator, and must have the following form:
+.IP "\fB500\fR SPACE \fIoptional-text\fR NEWLINE"
+In case of a lookup request, the requested data does not exist.
+In case of an update request, the request was rejected.
+.IP "\fB400\fR SPACE \fIoptional-text\fR NEWLINE"
+This indicates an error condition. The text gives the nature of
+the problem. The client should retry the request later.
+.IP "\fB200\fR SPACE \fItext\fR NEWLINE"
+The request was successful. In the case of a lookup request,
+the text contains an encoded version of the requested data.
+Otherwise the text is optional.
+.SH SEE ALSO
+.na
+.nf
+regexp_table(5) format of regular expression tables
+pcre_table(5) format of PCRE tables
+cidr_table(5) format of CIDR tables
+.SH BUGS
+.ad
+.fi
+Only the lookup method is currently implemented.
+.SH LICENSE
+.na
+.nf
+.ad
+.fi
+The Secure Mailer license must be distributed with this software.
+.SH AUTHOR(S)
+.na
+.nf
+Wietse Venema
+IBM T.J. Watson Research
+P.O. Box 704
+Yorktown Heights, NY 10598, USA
index e4c69f3728ecc600af8517122dc02c418dc2db29..05eba4ca10b52fa632a651e224508ff1425a6610 100644 (file)
@@ -20,6 +20,21 @@ The optional \fBtransport\fR table specifies a mapping from email
 addresses to message delivery transports and/or relay hosts. The
 mapping is used by the \fBtrivial-rewrite\fR(8) daemon.
 
+This mapping overrides the default routing that is built into
+Postfix:
+.IP \fBmydestination\fR
+A list of domains that is by default delivered via
+\fB$local_transport\fR.
+.IP \fBvirtual_mailbox_domains\fR
+A list of domains that is by default delivered via
+\fB$virtual_transport\fR.
+.IP \fBrelay_domains\fR
+A list of domains that is by default delivered via
+\fB$relay_transport\fR.
+.IP "any other destination"
+Mail for any other destination is by default delivered via
+\fB$default_transport\fR.
+.PP
 Normally, the \fBtransport\fR table is specified as a text file
 that serves as input to the \fBpostmap\fR(1) command.
 The result, an indexed file in \fBdbm\fR or \fBdb\fR format, is used
index fdadfa4a80a36291a540917f849b0daca2a33856..0e21c52d290321ebd0bad9a649055d9c688a1ba7 100644 (file)
@@ -150,6 +150,11 @@ substitution is done before all other address rewriting.
 .IP \fBcanonical_maps\fR
 Address mapping lookup table for sender and recipient addresses
 in envelopes and headers.
+.IP \fBenable_original_recipient\fR
+Enable support for the X-Original-To message header, which is
+needed for multi-recipient mailboxes. When this is enabled, Postfix
+performs duplicate elimination on (original recipient, rewritten
+recipient) pairs, instead of looking at the rewritten recipient only.
 .IP \fBrecipient_canonical_maps\fR
 Address mapping lookup table for envelope and header recipient
 addresses.
index 1ca75585d41b88c767a9133950159df7d249ec75..10484ffac00c49248640eeb03d3b996a67b4733e 100644 (file)
@@ -27,10 +27,6 @@ The SMTP client looks up a list of mail exchanger addresses for
 the destination host, sorts the list by preference, and connects
 to each listed address until it finds a server that responds.
 
-When the domain or host is specified as a comma/whitespace
-separated list, the SMTP client repeats the above process
-for all destinations until it finds a server that responds.
-
 Once the SMTP client has received the server greeting banner, no
 error will cause it to proceed to the next address on the mail
 exchanger list. Instead, the message is either bounced, or its
@@ -134,6 +130,9 @@ Length limit for SMTP message content lines. Zero means no limit.
 Some SMTP servers misbehave on long lines.
 .IP \fBsmtp_helo_name\fR
 The hostname to be used in HELO and EHLO commands.
+.IP \fBsmtp_quote_rfc821_envelope\fR
+Whether or not to quote MAIL FROM and RCPT TO addresses as
+per the rules laid out in RFC 821.
 .IP \fBsmtp_skip_4xx_greeting\fR
 Skip servers that greet us with a 4xx status code.
 .IP \fBsmtp_skip_5xx_greeting\fR
index 8646cd8bb203a15dcdc237119789b7136e5586eb..8c63d52aac9842fc41781c4a403c5cad1ad22f93 100644 (file)
@@ -111,6 +111,24 @@ Disallow anonymous logins.
 Maps that specify the SASL login name that owns a MAIL FROM sender
 address. Used by the \fBreject_sender_login_mismatch\fR sender
 anti-spoofing restriction.
+.SH "Pass-through proxy"
+.ad
+.fi
+.ad
+Optionally, the Postfix SMTP server can be configured to
+forward all mail to a proxy server, for example a real-time
+content filter. This proxy server should support the same
+MAIL FROM and RCPT TO command syntax as Postfix, but does not
+need to support ESMTP command pipelining.
+.IP \fBsmtpd_proxy_filter\fR
+The \fIhost:port\fR of the SMTP proxy server. The \fIhost\fR
+or \fIhost:\fR portion is optional.
+.IP \fBsmtpd_proxy_timeout\fR
+Timeout for connecting to, sending to and receiving from
+the SMTP proxy server.
+.IP \fBsmtpd_proxy_ehlo\fR
+The hostname to use when sending an EHLO command to the
+SMTP proxy server.
 .SH Miscellaneous
 .ad
 .fi
@@ -259,6 +277,21 @@ are eligible for the \fBpermit_mx_backup\fR feature.
 Restrict what domains this mail system will relay
 mail to. The domains are routed to the delivery agent
 specified with the \fBrelay_transport\fR setting.
+.SH "Sender/recipient address verification"
+.ad
+.fi
+Address verification is implemented by sending probe email
+messages that are not actually delivered, and is enabled
+via the reject_unverified_{sender,recipient} access restriction.
+The status of verification probes is maintained by the address
+verification service.
+.IP \fBaddress_verify_poll_count\fR
+How many times to query the address verification service
+for completion of an address verification request.
+Specify 0 to implement a simple form of greylisting.
+.IP \fBaddress_verify_poll_delay\fR
+Time to wait after querying the address verification service
+for completion of an address verification request.
 .SH "UCE control responses"
 .ad
 .fi
@@ -305,10 +338,11 @@ Response code when a recipient address is known to be undeliverable.
 .SH SEE ALSO
 .na
 .nf
-trivial-rewrite(8) address resolver
 cleanup(8) message canonicalization
 master(8) process manager
 syslogd(8) system logging
+trivial-rewrite(8) address resolver
+verify(8) address verification service
 .SH LICENSE
 .na
 .nf
index 61a903edfc4ecd3463940238f09ae536de19e1fe..ece5ba89f50e5f467d0c761651e6d0f0921f81d9 100644 (file)
@@ -35,7 +35,8 @@ This server implements the following requests:
 .IP "\fBVRFY_ADDR_UPDATE\fI address status text\fR"
 Update the status of the specified address.
 .IP "\fBVRFY_ADDR_QUERY\fI address\fR"
-Look up the \fIstatus\fR and \fItext\fR of the specified address.
+Look up the \fIstatus\fR, \fIlast update time\fR and \fItext\fR
+of the specified address.
 If the status is unknown, a probe is sent and a default status is
 returned.
 .PP
index fadc1467865b5098b0bd8b9591e982e40f01b604..a5b3de8ce3fada695128f318aac6eb605b590931 100644 (file)
@@ -4,7 +4,7 @@ SHELL   = /bin/sh
 
 CONFIG = ../conf/access ../conf/aliases ../conf/canonical ../conf/relocated \
        ../conf/transport ../conf/virtual ../conf/pcre_table \
-       ../conf/regexp_table
+       ../conf/regexp_table ../conf/cidr_table ../conf/tcp_table
 
 AWK    = awk '{ print; if (NR == 1) print ".pl 9999" }'
 
@@ -30,6 +30,9 @@ clobber:
 ../conf/canonical: canonical
        srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
 
+../conf/cidr_table: cidr_table
+       srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+
 ../conf/pcre_table: pcre_table
        srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
 
@@ -39,6 +42,9 @@ clobber:
 ../conf/relocated: relocated
        srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
 
+../conf/tcp_table: tcp_table
+       srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
+
 ../conf/transport: transport
        srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@
 
index f1bbc99f16b881747f22c0bfef8b272ec6891a06..d5cddcc069f00c5a09f4f54386a6124c5d1daffe 100644 (file)
@@ -92,6 +92,9 @@
 # .IP \fInet\fR
 #      Matches any host address in the specified network. A network
 #      address is a sequence of one or more octets separated by ".".
+#
+#      NOTE: use the \fBcidr\fR lookup table type if you want to
+#      specify arbitrary network blocks.
 # ACTIONS
 # .ad
 # .fi
 # BUGS
 #      The table format does not understand quoting conventions.
 # SEE ALSO
-#      postmap(1) create mapping table
+#      postmap(1) create lookup table
 #      smtpd(8) smtp server
+#      cidr_table(5) format of CIDR tables
 #      pcre_table(5) format of PCRE tables
 #      regexp_table(5) format of POSIX regular expression tables
 # LICENSE
diff --git a/postfix/proto/cidr_table b/postfix/proto/cidr_table
new file mode 100644 (file)
index 0000000..13273a0
--- /dev/null
@@ -0,0 +1,68 @@
+#++
+# NAME
+#      cidr_table 5
+# SUMMARY
+#      format of Postfix CIDR tables
+# SYNOPSIS
+#      \fBpostmap -q "\fIstring\fB" cidr:/etc/postfix/\fIfilename\fR
+#
+#      \fBpostmap -q - cidr:/etc/postfix/\fIfilename\fR <\fIinputfile\fR
+# DESCRIPTION
+#      The Postfix mail system uses optional access control tables.
+#      These tables are usually in \fBdbm\fR or \fBdb\fR format. 
+#      Alternatively, access control tables can be specified in CIDR form.
+#
+#      To find out what types of lookup tables your Postfix system
+#      supports use the \fBpostconf -m\fR command.
+#
+#      To test lookup tables, use the \fBpostmap\fR command as
+#      described in the SYNOPSIS above.
+# TABLE FORMAT
+# .ad
+# .fi
+#      The general form of a Postfix CIDR table is:
+# .IP "\fInetwork_address\fB/\fInetwork_mask     result\fR"
+#      When a search string matches the specified network block,
+#      use the corresponding \fIresult\fR value.
+# .IP "\fInetwork_address     result\fR"
+#      When a search string matches the specified network address,
+#      use the corresponding \fIresult\fR value.
+# .IP "blank lines and comments"
+#      Empty lines and whitespace-only lines are ignored, as
+#      are lines whose first non-whitespace character is a `#'.
+# .IP "multi-line text"
+#      A logical line starts with non-whitespace text. A line that
+#      starts with whitespace continues a logical line.
+# .PP
+#      Patterns are applied in the order as specified in the table, until a
+#      pattern is found that matches the search string.
+# EXAMPLE SMTPD ACCESS MAP
+#      /etc/postfix/main.cf:
+# .ti +4
+#      smtpd_client_restrictions = ... cidr:/etc/postfix/client_cidr ...
+#
+#      /etc/postfix/client_cidr:
+# .in +4
+#      # Rule order matters. Put more specific whitelist entries
+#      # before more general blacklist entries.
+#       192.168.1.1             OK
+#       192.168.0.0/16          REJECT
+# .in -4
+# SEE ALSO
+#      regexp_table(5) format of regular expression tables
+#      pcre_table(5) format of PCRE tables
+#      tcp_table(5) TCP client/server table lookup protocol
+# AUTHOR(S)
+#      The CIDR table lookup code was originally written by:
+#      Jozsef Kadlecsik
+#      kadlec@blackhole.kfki.hu
+#      KFKI Research Institute for Particle and Nuclear Physics
+#      POB. 49
+#      1525 Budapest, Hungary
+#
+#      Adopted and adapted by:
+#      Wietse Venema
+#      IBM T.J. Watson Research
+#      P.O. Box 704
+#      Yorktown Heights, NY 10598, USA
+#--
index eab2ebbee5ce2db300389b008cc0e4ee19f78d07..08f595484c70b7d11c997bf73d47444409a3e402 100644 (file)
@@ -4,8 +4,6 @@
 # SUMMARY
 #      format of Postfix PCRE tables
 # SYNOPSIS
-#      \fBpcre:/etc/postfix/\fIfilename\fR
-#
 #      \fBpostmap -q "\fIstring\fB" pcre:/etc/postfix/\fIfilename\fR
 #
 #      \fBpostmap -q - pcre:/etc/postfix/\fIfilename\fR <\fIinputfile\fR
@@ -23,8 +21,9 @@
 #
 #      The general form of a PCRE table is:
 # .IP "\fB/\fIpattern\fB/\fIflags result\fR"
-#      When \fIpattern\fR matches a search string, use the corresponding
-#      \fIresult\fR value.
+# .IP "\fB!/\fIpattern\fB/\fIflags result\fR"
+#      When \fIpattern\fR matches (does not match) a search string, use
+#      the corresponding \fIresult\fR value.
 # .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.
 # .IP "\fBif /\fIpattern\fB/\fIflags\fR"
+# .IP "\fBif !/\fIpattern\fB/\fIflags\fR"
 # .IP "\fBendif\fR"
 #      Examine the lines between \fBif\fR..\fBendif\fR only if
-#      \fIpattern\fR matches. The \fBif\fR..\fBendif\fR can nest.
-#      Do not prepend whitespace to patterns inside \fBif\fR..\fBendif\fR.
+#      \fIpattern\fR matches (does not match). The \fBif\fR..\fBendif\fR
+#      can nest. Do not prepend whitespace to patterns inside
+#      \fBif\fR..\fBendif\fR.
 # .PP
 #      Each pattern is a perl-like regular expression. The expression
 #      delimiter can be any character, except whitespace or characters
 #      Substitution of substrings from the matched expression into the result
 #      string is possible using the conventional perl syntax ($1, $2, etc.).
 #      The macros in the result string may need to be written as ${n}
-#      or $(n) if they aren't followed by whitespace.
+#      or $(n) if they aren't followed by whitespace. Since negated patterns
+#      (those preceded by \fB!\fR) return a result when the expression does
+#      not match, substitutions are not available for negated patterns.
 # EXAMPLE SMTPD ACCESS MAP
 #      # Protect your outgoing majordomo exploders
 #      /^(?!owner-)(.*)-outgoing@(.*)/ 550 Use ${1}@${2} instead
 #      # Put your own body patterns here.
 # SEE ALSO
 #      regexp_table(5) format of POSIX regular expression tables
+#      cidr_table(5) format of CIDR tables
+#      tcp_table(5) TCP client/server table lookup protocol
 # AUTHOR(S)
 #      The PCRE table lookup code was originally written by:
 #      Andrew McNamara
index 6c7ab4553d016d8f044749d91b0a2e45117b2453..2e32819a7599be61d7a9bc9f6c0534cd296fc343 100644 (file)
@@ -4,8 +4,6 @@
 # SUMMARY
 #      format of Postfix regular expression tables
 # SYNOPSIS
-#      \fBregexp:/etc/postfix/\fIfilename\fR
-#
 #      \fBpostmap -q "\fIstring\fB" regexp:/etc/postfix/\fIfilename\fR
 #
 #      \fBpostmap -q - regexp:/etc/postfix/\fIfilename\fR <\fIinputfile\fR
@@ -65,7 +63,9 @@
 #      Substitution of substrings from the matched expression into the result
 #      string is possible using $1, $2, etc.. The macros in the result string
 #      may need to be written as ${n} or $(n) if they aren't followed
-#      by whitespace.
+#      by whitespace. Since negated patterns (those preceded by \fB!\fR)
+#      return a result when the expression does not match, substitutions are
+#      not available for negated patterns.
 # EXAMPLE SMTPD ACCESS MAP
 #      # Disallow sender-specified routing. This is a must if you relay mail
 #      # for other domains.
@@ -90,6 +90,8 @@
 #      # Put your own body patterns here.
 # SEE ALSO
 #      pcre_table(5) format of PCRE tables
+#      cidr_table(5) format of CIDR tables
+#      tcp_table(5) TCP client/server table lookup protocol
 # AUTHOR(S)
 #      The regexp table lookup code was originally written by:
 #      LaMont Jones
diff --git a/postfix/proto/tcp_table b/postfix/proto/tcp_table
new file mode 100644 (file)
index 0000000..e099ea2
--- /dev/null
@@ -0,0 +1,75 @@
+#++
+# NAME
+#      tcp_table 5
+# SUMMARY
+#      Postfix client/server table lookup protocol
+# SYNOPSIS
+#      \fBpostmap -q "\fIstring\fB" tcp:\fIhost:port\fR
+#
+#      \fBpostmap -q - regexp:\fIhost:port\fR <\fIinputfile\fR
+# DESCRIPTION
+#       The Postfix mail system uses optional tables for address
+#       rewriting or mail routing. These tables are usually in
+#       \fBdbm\fR or \fBdb\fR format. Alternatively, lookup tables
+#       can be specified as a TCP client/server pair.
+#
+#       To find out what types of lookup tables your Postfix system
+#       supports use the \fBpostconf -m\fR command.
+#
+#       To test lookup tables, use the \fBpostmap\fR command as
+#       described in the SYNOPSIS above.
+# PROTOCOL DESCRIPTION
+# .ad
+# .fi
+#      The TCP map class implements a very simple protocol: the client
+#      sends a request, and the server sends one reply. Requests and
+#      replies are sent as one line of ASCII text, terminated by the
+#      ASCII newline character. Request and reply parameters (see below)
+#      are separated by whitespace.
+# ENCODING
+# .ad
+# .fi
+#      In request and reply parameters, the character % and any non-printing
+#      and whitespace characters must be replaced by %XX, XX being the
+#      corresponding ASCII hexadecimal character value. The hexadecimal codes
+#      can be specified in any case (upper, lower, mixed).
+# REQUEST FORMAT
+# .ad
+# .fi
+#      Requests are strings that serve as lookup key in the simulated
+#      table.
+# .IP "\fBget\fR SPACE \fIkey\fR NEWLINE"
+#      Look up data under the specified key.
+# .IP "\fBput\fR SPACE \fIkey\fR SPACE \fIvalue\fR NEWLINE"
+#      This request is currently not implemented.
+# REPLY FORMAT
+# .ad
+# .fi
+#      Replies must be no longer than 4096 characters including the
+#      newline terminator, and must have the following form:
+# .IP "\fB500\fR SPACE \fIoptional-text\fR NEWLINE"
+#      In case of a lookup request, the requested data does not exist.
+#      In case of an update request, the request was rejected.
+# .IP "\fB400\fR SPACE \fIoptional-text\fR NEWLINE"
+#      This indicates an error condition. The text gives the nature of
+#      the problem. The client should retry the request later.
+# .IP "\fB200\fR SPACE \fItext\fR NEWLINE"
+#      The request was successful. In the case of a lookup request,
+#      the text contains an encoded version of the requested data.
+#      Otherwise the text is optional.
+# SEE ALSO
+#      regexp_table(5) format of regular expression tables
+#      pcre_table(5) format of PCRE tables
+#      cidr_table(5) format of CIDR tables
+# BUGS
+#      Only the lookup method is currently implemented.
+# LICENSE
+# .ad
+# .fi
+#      The Secure Mailer license must be distributed with this software.
+# AUTHOR(S)
+#      Wietse Venema
+#      IBM T.J. Watson Research
+#      P.O. Box 704
+#      Yorktown Heights, NY 10598, USA
+#--*/
index e9ca553a0c1658a1cb24385ec22db3a5aff25129..122fdfb5ddcffafd10df3e3d3e0459f4f2f333e6 100644 (file)
 #      addresses to message delivery transports and/or relay hosts. The
 #      mapping is used by the \fBtrivial-rewrite\fR(8) daemon.
 #
+#      This mapping overrides the default routing that is built into
+#      Postfix:
+# .IP \fBmydestination\fR
+#      A list of domains that is by default delivered via
+#      \fB$local_transport\fR.
+# .IP \fBvirtual_mailbox_domains\fR
+#      A list of domains that is by default delivered via
+#      \fB$virtual_transport\fR.
+# .IP \fBrelay_domains\fR
+#      A list of domains that is by default delivered via
+#      \fB$relay_transport\fR.
+# .IP "any other destination"
+#      Mail for any other destination is by default delivered via
+#      \fB$default_transport\fR.
+# .PP
 #      Normally, the \fBtransport\fR table is specified as a text file
 #      that serves as input to the \fBpostmap\fR(1) command.
 #      The result, an indexed file in \fBdbm\fR or \fBdb\fR format, is used
index aafc24afbd81e258c7da1f3ead79f6017a950050..232875a8f576760804bab9e158b26c0fdebe329c 100644 (file)
@@ -132,6 +132,8 @@ bounce_notify_util.o: ../../include/vstring.h
 bounce_notify_util.o: ../../include/vbuf.h
 bounce_notify_util.o: ../../include/vstream.h
 bounce_notify_util.o: ../../include/line_wrap.h
+bounce_notify_util.o: ../../include/stringops.h
+bounce_notify_util.o: ../../include/xtext.h
 bounce_notify_util.o: ../../include/mail_queue.h
 bounce_notify_util.o: ../../include/quote_822_local.h
 bounce_notify_util.o: ../../include/quote_flags.h
index c14f0482b19f0857507dd526fdb4fb4e6659a612..e04a71b4120136cad495957de40e92703a05360d 100644 (file)
 #include <vstring.h>
 #include <vstream.h>
 #include <line_wrap.h>
+#include <stringops.h>
+#include <xtext.h>
 
 /* Global library. */
 
@@ -210,10 +212,19 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service,
     }
     bounce_info->flush = flush;
     bounce_info->buf = vstring_alloc(100);
+    bounce_info->sender = vstring_alloc(100);
     bounce_info->arrival_time = 0;
     bounce_info->orig_offs = 0;
     bounce_info->log_handle = log_handle;
 
+    /*
+     * RFC 1894: diagnostic-type is an RFC 822 atom. We use X-$mail_name and
+     * must ensure it is valid.
+     */
+    bounce_info->mail_name = mystrdup(var_mail_name);
+    translit(bounce_info->mail_name, " \t\r\n()<>@,;:\\\".[]",
+            "-----------------");
+
     /*
      * Compute a supposedly unique boundary string. This assumes that a queue
      * ID and a hostname contain acceptable characters for a boundary string,
@@ -247,7 +258,16 @@ static BOUNCE_INFO *bounce_mail_alloc(const char *service,
            if (rec_type == REC_TYPE_TIME && bounce_info->arrival_time == 0) {
                if ((bounce_info->arrival_time = atol(STR(bounce_info->buf))) < 0)
                    bounce_info->arrival_time = 0;
+           } else if (rec_type == REC_TYPE_FROM) {
+               quote_822_local_flags(bounce_info->sender,
+                                     VSTRING_LEN(bounce_info->buf) ?
+                                     STR(bounce_info->buf) :
+                                     mail_addr_mail_daemon(), 0);
            } else if (rec_type == REC_TYPE_MESG) {
+               /* XXX Future: sender+recipient after message content. */
+               if (VSTRING_LEN(bounce_info->sender) == 0)
+                   msg_warn("%s: no sender before message content record",
+                               bounce_info->queue_id);
                bounce_info->orig_offs = vstream_ftell(bounce_info->orig_fp);
                break;
            }
@@ -322,6 +342,8 @@ void    bounce_mail_free(BOUNCE_INFO *bounce_info)
                 bounce_info->queue_id, bounce_info->queue_name,
                 bounce_info->queue_id);
     vstring_free(bounce_info->buf);
+    vstring_free(bounce_info->sender);
+    myfree(bounce_info->mail_name);
     myfree((char *) bounce_info->mime_boundary);
     myfree((char *) bounce_info);
 }
@@ -542,6 +564,11 @@ int     bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
 #if 0
     post_mail_fprintf(bounce, "Received-From-MTA: dns; %s", "whatever");
 #endif
+    post_mail_fprintf(bounce, "X-%s-Queue-ID: %s",
+                     bounce_info->mail_name, bounce_info->queue_id);
+    if (VSTRING_LEN(bounce_info->sender) > 0)
+       post_mail_fprintf(bounce, "X-%s-Sender: rfc822; %s",
+                         bounce_info->mail_name, STR(bounce_info->sender));
     if (bounce_info->arrival_time > 0)
        post_mail_fprintf(bounce, "Arrival-Date: %s",
                          mail_date(bounce_info->arrival_time));
@@ -552,25 +579,21 @@ int     bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
 
 int     bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
 {
-    char   *fixed_mail_name;
-
     post_mail_fputs(bounce, "");
     post_mail_fprintf(bounce, "Final-Recipient: rfc822; %s",
                      bounce_info->log_handle->recipient);
-    if (bounce_info->log_handle->orig_rcpt)
+    if (bounce_info->log_handle->orig_rcpt) {
+       xtext_quote(bounce_info->buf, bounce_info->log_handle->orig_rcpt, "+=");
        post_mail_fprintf(bounce, "Original-Recipient: rfc822; %s",
-                         bounce_info->log_handle->orig_rcpt);
+                         STR(bounce_info->buf));
+    }
     post_mail_fprintf(bounce, "Action: %s",
                      bounce_info->flush == BOUNCE_MSG_FAIL ?
                      "failed" : bounce_info->log_handle->dsn_action);
     post_mail_fprintf(bounce, "Status: %s",
                      bounce_info->log_handle->dsn_status);
-    /* RFC 1894: diagnostic-type is an RFC 822 atom. */
-    fixed_mail_name = mystrdup(var_mail_name);
-    translit(fixed_mail_name, " \t\r\n()<>@,;:\\\".[]", "-----------------");
     bounce_print_wrap(bounce, bounce_info, "Diagnostic-Code: X-%s; %s",
-                     fixed_mail_name, bounce_info->log_handle->text);
-    myfree(fixed_mail_name);
+                     bounce_info->mail_name, bounce_info->log_handle->text);
 #if 0
     post_mail_fprintf(bounce, "Last-Attempt-Date: %s",
                      bounce_info->log_handle->log_time);
index 3c919e99b9f62efb5db4d61b3f280ccab86dc975..c3c56af82eb196a0355039f38f6769661f471083 100644 (file)
@@ -69,10 +69,12 @@ typedef struct {
     const char *mime_boundary;         /* for MIME */
     int     flush;                     /* 0=defer, other=bounce */
     VSTRING *buf;                      /* scratch pad */
+    VSTRING *sender;                   /* envelope sender */
     VSTREAM *orig_fp;                  /* open queue file */
     long    orig_offs;                 /* start of content */
     time_t  arrival_time;              /* time of arrival */
     BOUNCE_LOG *log_handle;            /* open logfile */
+    char   *mail_name;                 /* $mail_name, cooked */
 } BOUNCE_INFO;
 
 extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, const char *, int);
index 0d8afa8b457de7d0009eee7487b4a7bd5457e075..b0dd7911eea65fd19c511f0604483f75b704eaed 100644 (file)
 /* .IP \fBcanonical_maps\fR
 /*     Address mapping lookup table for sender and recipient addresses
 /*     in envelopes and headers.
+/* .IP \fBenable_original_recipient\fR
+/*     Enable support for the X-Original-To message header, which is
+/*     needed for multi-recipient mailboxes. When this is enabled, Postfix
+/*     performs duplicate elimination on (original recipient, rewritten
+/*     recipient) pairs, instead of looking at the rewritten recipient only.
 /* .IP \fBrecipient_canonical_maps\fR
 /*     Address mapping lookup table for envelope and header recipient
 /*     addresses.
@@ -342,6 +347,7 @@ int     main(int argc, char **argv)
      */
     single_server_main(argc, argv, cleanup_service,
                       MAIL_SERVER_INT_TABLE, cleanup_int_table,
+                      MAIL_SERVER_BOOL_TABLE, cleanup_bool_table,
                       MAIL_SERVER_STR_TABLE, cleanup_str_table,
                       MAIL_SERVER_TIME_TABLE, cleanup_time_table,
                       MAIL_SERVER_PRE_INIT, cleanup_pre_jail,
index bb09e8fe12e1e3f4a2eac37cdc299d9a3bc3f851..3077dc99b9343ecf15baf9fe38500a86a3329a78 100644 (file)
@@ -127,6 +127,7 @@ extern void cleanup_all(void);
 extern void cleanup_pre_jail(char *, char **);
 extern void cleanup_post_jail(char *, char **);
 extern CONFIG_INT_TABLE cleanup_int_table[];
+extern CONFIG_BOOL_TABLE cleanup_bool_table[];
 extern CONFIG_STR_TABLE cleanup_str_table[];
 extern CONFIG_TIME_TABLE cleanup_time_table[];
 
index dcd1dfbf09fb3ac470f3d4b2636de2d3b262bc15..30585e7d11bc1149c818ae7eb5c89519a625e435 100644 (file)
@@ -8,6 +8,8 @@
 /*
 /*     CONFIG_INT_TABLE cleanup_int_table[];
 /*
+/*     CONFIG_BOOL_TABLE cleanup_bool_table[];
+/*
 /*     CONFIG_STR_TABLE cleanup_str_table[];
 /*
 /*     CONFIG_TIME_TABLE cleanup_time_table[];
@@ -102,6 +104,7 @@ char   *var_mimehdr_checks;         /* mime header checks */
 char   *var_nesthdr_checks;            /* nested header checks */
 char   *var_body_checks;               /* any body checks */
 int     var_dup_filter_limit;          /* recipient dup filter */
+bool    var_enable_orcpt;              /* Include orcpt in dup filter? */
 char   *var_empty_addr;                        /* destination of bounced bounces */
 int     var_delay_warn_time;           /* delay that triggers warning */
 char   *var_prop_extension;            /* propagate unmatched extension */
@@ -125,6 +128,11 @@ CONFIG_INT_TABLE cleanup_int_table[] = {
     0,
 };
 
+CONFIG_BOOL_TABLE cleanup_bool_table[] = {
+    VAR_ENABLE_ORCPT, DEF_ENABLE_ORCPT, &var_enable_orcpt,
+    0,
+};
+
 CONFIG_TIME_TABLE cleanup_time_table[] = {
     VAR_DELAY_WARN_TIME, DEF_DELAY_WARN_TIME, &var_delay_warn_time, 0, 0,
     0,
index 97129487edc0599d4a130b732fdfb2764d75649d..b70747673609d6d73e6c7afa5dc9133bb17b5eb6 100644 (file)
@@ -68,6 +68,12 @@ void    cleanup_out_recipient(CLEANUP_STATE *state, const char *orcpt,
     ARGV   *argv;
     char  **cpp;
 
+    /*
+     * XXX Not elegant, but eliminates complexity in the record reading loop.
+     */
+    if (!var_enable_orcpt)
+       orcpt = "";
+
     /*
      * Distinguish between different original recipient addresses that map
      * onto the same mailbox. The recipient will use our original recipient
index 612a03e2ddd895b59f1bc425cf2142ecd2438122..062735f6bf78ce649bc685c38101634366942913 100644 (file)
@@ -77,7 +77,7 @@ TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \
        off_cvt quote_822_local rec2stream recdump resolve_clnt \
        resolve_local rewrite_clnt stream2rec string_list tok822_parse \
        quote_821_local mail_conf_time mime_state strip_addr \
-       virtual8_maps verify_clnt
+       virtual8_maps verify_clnt xtext
 
 LIBS   = ../../lib/libutil.a
 LIB_DIR        = ../../lib
@@ -240,9 +240,14 @@ verify_clnt: $(LIB) $(LIBS)
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
        mv junk $@.o
 
+xtext: $(LIB)
+       mv $@.o junk
+       $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+       mv junk $@.o
+
 tests: tok822_test mime_test mime_nest mime_8bit mime_dom mime_trunc \
        mime_cvt mime_cvt2 mime_cvt3 strip_addr_test tok822_limit_test \
-       virtual8_test
+       virtual8_test xtext_test
 
 tok822_test: tok822_parse tok822_parse.in tok822_parse.ref
        ./tok822_parse <tok822_parse.in >tok822_parse.tmp 2>&1
@@ -306,6 +311,12 @@ virtual8_test: virtual8_maps virtual8_map virtual8.in virtual8.ref \
        diff virtual8.ref virtual8.tmp
        rm -f virtual8.tmp virtual8_map.db
 
+xtext_test: xtext
+       ./xtext <xtext.c | od -cb >xtext.tmp
+       od -cb <xtext.c >xtext.ref
+       cmp xtext.ref xtext.tmp
+       rm -f xtext.ref xtext.tmp
+
 # Requires: Postfix running, root privileges
 
 rewrite_clnt_test: rewrite_clnt rewrite_clnt.in rewrite_clnt.ref
@@ -1344,7 +1355,7 @@ virtual8_maps.o: strip_addr.h
 virtual8_maps.o: virtual8_maps.h
 xtext.o: xtext.c
 xtext.o: ../../include/sys_defs.h
-xtext.o: ../../include/vstream.h
-xtext.o: ../../include/vbuf.h
+xtext.o: ../../include/msg.h
 xtext.o: ../../include/vstring.h
+xtext.o: ../../include/vbuf.h
 xtext.o: xtext.h
index b4fc4249e46528840bd86c0688dbea0a7ee431dc..bfb7f6723301b22146343ab13d21e54cc6b6e0cf 100644 (file)
@@ -38,6 +38,7 @@
 #define CLEANUP_STAT_CONT      (1<<3)  /* Message content rejected */
 #define CLEANUP_STAT_HOPS      (1<<4)  /* Too many hops */
 #define CLEANUP_STAT_RCPT      (1<<6)  /* No recipients found */
+#define CLEANUP_STAT_PROXY     (1<<7)  /* Proxy reject */
 
  /*
   * These are set when we can't bounce even if we were asked to.
index c95207fb3cb3c85ea64863ef2f413413bc2d5c78..7a2bf0597ba5f7bff6cc0bcb07c15b7d944487c9 100644 (file)
@@ -176,11 +176,14 @@ int     header_token(HEADER_TOKEN *token, int token_len,
                if (ch == '"')
                    break;
                if (ch == '\n') {               /* unfold */
-                   len = LEN(token_buffer);
-                   while (len > 0 && IS_SPACE_TAB_CR_LF(STR(token_buffer)[len - 1]))
-                       len--;
-                   if (len < LEN(token_buffer))
-                       vstring_truncate(token_buffer, len);
+                   if (tok_count < token_len) {
+                       len = LEN(token_buffer);
+                       while (len > 0
+                         && IS_SPACE_TAB_CR_LF(STR(token_buffer)[len - 1]))
+                           len--;
+                       if (len < LEN(token_buffer))
+                           vstring_truncate(token_buffer, len);
+                   }
                    continue;
                }
                if (ch == '\\') {
index e42df74838513d8e456ae10830ef0f8f1ca687fe..03a3539f096dffd9b13bdb978b9ba0a2f300a7ba 100644 (file)
@@ -115,9 +115,7 @@ void    vlog_adhoc(const char *id, const char *orig_rcpt,
     int     delay = time((time_t *) 0) - entry;
 
     vstring_vsprintf(why, fmt, ap);
-    if (orig_rcpt == 0)
-       orig_rcpt = "";
-    if (strcasecmp(recipient, orig_rcpt) != 0)
+    if (orig_rcpt && *orig_rcpt && strcasecmp(recipient, orig_rcpt) != 0)
        msg_info("%s: to=<%s>, orig_to=<%s>, relay=%s, delay=%d, status=%s (%s)",
          id, recipient, orig_rcpt, relay, delay, status, vstring_str(why));
     else
index da4f0ddab0384b138d7d609f8953adec2a03e0d4..e00e1de0af66589be9e64d183b88c04edc852cc2 100644 (file)
@@ -112,9 +112,9 @@ static int convert_mail_conf_int(const char *name, int *intval)
 static void check_mail_conf_int(const char *name, int intval, int min, int max)
 {
     if (min && intval < min)
-       msg_fatal("invalid %s: %d (min %d)", name, intval, min);
+       msg_fatal("invalid %s parameter value %d < %d", name, intval, min);
     if (max && intval > max)
-       msg_fatal("invalid %s: %d (max %d)", name, intval, max);
+       msg_fatal("invalid %s parameter value %d > %d", name, intval, max);
 }
 
 /* get_mail_conf_int - evaluate integer-valued configuration variable */
index fba5ead46351189d6a81f27d5a99ce074200b276..1c2c170ab80b99a1f47d20c9aaa78013b9638797 100644 (file)
@@ -87,10 +87,10 @@ static void check_mail_conf_str(const char *name, const char *strval,
     int     len = strlen(strval);
 
     if (min && len < min)
-       msg_fatal("bad string length (%d < %d): %s = %s",
+       msg_fatal("bad string length %d < %d: %s = %s",
                  len, min, name, strval);
     if (max && len > max)
-       msg_fatal("bad string length (%d > %d): %s = %s",
+       msg_fatal("bad string length %d > %d: %s = %s",
                  len, max, name, strval);
 }
 
index dc51da9eacbc3f84e92aa8ced0bc46cf8ff49a75..496625764b0ce03726965948dd7edf5fb48a2f81 100644 (file)
@@ -165,8 +165,15 @@ int     mail_copy(const char *sender,
     if (flags & MAIL_COPY_ORIG_RCPT) {
        if (orig_rcpt == 0)
            msg_panic("%s: null orig_rcpt", myname);
-       quote_822_local(buf, orig_rcpt);
-       vstream_fprintf(dst, "X-Original-To: %s%s", vstring_str(buf), eol);
+
+       /*
+        * An empty original recipient record almost certainly means that
+        * original recipient processing was disabled.
+        */
+       if (*orig_rcpt) {
+           quote_822_local(buf, orig_rcpt);
+           vstream_fprintf(dst, "X-Original-To: %s%s", vstring_str(buf), eol);
+       }
     }
     if (flags & MAIL_COPY_DELIVERED) {
        if (delivered == 0)
index f1675e2d30dbfb9faea82000fff88123d5223461..203f71b47ff09339b79ad2d127db250daaa42d16 100644 (file)
@@ -486,6 +486,16 @@ extern char *var_fwd_exp_filter;
 #define DEF_DELIVER_HDR                "command, file, forward"
 extern char *var_deliver_hdr;
 
+ /*
+  * Cleanup: enable support for X-Original-To message headers, which are
+  * needed for multi-recipient mailboxes. When this is turned on, perform
+  * duplicate elimination on (original rcpt, rewritten rcpt) pairs, and
+  * generating non-empty original recipient records in the queue file.
+  */
+#define VAR_ENABLE_ORCPT       "enable_original_recipient"
+#define DEF_ENABLE_ORCPT       1
+extern bool var_enable_orcpt;
+
 #define VAR_EXP_OWN_ALIAS      "expand_owner_alias"
 #define DEF_EXP_OWN_ALIAS      0
 extern bool var_exp_own_alias;
@@ -763,6 +773,10 @@ extern int var_smtp_rset_tmout;
 #define DEF_SMTP_QUIT_TMOUT    "300s"
 extern int var_smtp_quit_tmout;
 
+#define VAR_SMTP_QUOTE_821_ENV "smtp_quote_rfc821_envelope"
+#define DEF_SMTP_QUOTE_821_ENV 1
+extern int var_smtp_quote_821_env;
+
 #define VAR_SMTP_SKIP_4XX      "smtp_skip_4xx_greeting"
 #define DEF_SMTP_SKIP_4XX      1
 extern bool var_smtp_skip_4xx_greeting;
@@ -1691,6 +1705,14 @@ extern bool var_verify_neg_cache;
 #define DEF_VERIFY_SENDER              "postmaster"
 extern char *var_verify_sender;
 
+#define VAR_VERIFY_POLL_COUNT          "address_verify_poll_count"
+#define DEF_VERIFY_POLL_COUNT          3
+extern int var_verify_poll_count;
+
+#define VAR_VERIFY_POLL_DELAY          "address_verify_poll_delay"
+#define DEF_VERIFY_POLL_DELAY          "3s"
+extern int var_verify_poll_delay;
+
 #define VAR_VRFY_LOCAL_XPORT           "address_verify_local_transport"
 #define DEF_VRFY_LOCAL_XPORT           "$" VAR_LOCAL_TRANSPORT
 extern char *var_vrfy_local_xport;
@@ -1804,6 +1826,21 @@ extern char *var_xport_null_key;
 #define DEF_OLDLOG_COMPAT              1
 extern bool var_oldlog_compat;
 
+ /*
+  * SMTPD content proxy.
+  */
+#define VAR_SMTPD_PROXY_FILT           "smtpd_proxy_filter"
+#define DEF_SMTPD_PROXY_FILT           ""
+extern char *var_smtpd_proxy_filt;
+
+#define VAR_SMTPD_PROXY_EHLO           "smtpd_proxy_ehlo"
+#define DEF_SMTPD_PROXY_EHLO           "$" VAR_MYHOSTNAME
+extern char *var_smtpd_proxy_ehlo;
+
+#define VAR_SMTPD_PROXY_TMOUT          "smtpd_proxy_timeout"
+#define DEF_SMTPD_PROXY_TMOUT          "100s"
+extern int var_smtpd_proxy_tmout;
+
 /* LICENSE
 /* .ad
 /* .fi
index 7cd711ca6f9461e76112bfc7a5e5df1dfa2bb675..3f96086e511c2fd0e18c5a86815e058b652d5485 100644 (file)
   * 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      "20030621"
+#define MAIL_RELEASE_DATE      "20030702"
 
 #define VAR_MAIL_VERSION       "mail_version"
-#define DEF_MAIL_VERSION       "2.0.12-" MAIL_RELEASE_DATE
+#define DEF_MAIL_VERSION       "2.0.13-" MAIL_RELEASE_DATE
 extern char *var_mail_version;
 
  /*
index 5892018d2e967c46d1d636f50e49b660ae51c3d9..83df201006c50339545c0075740221cffa235e46 100644 (file)
@@ -66,8 +66,8 @@
 /* .IP RESOLVE_CLASS_LOCAL
 /*     The address domain matches $mydestination or $inet_interfaces.
 /* .IP RESOLVE_CLASS_ALIAS
-/*     The address domain matches $virtual_alias_domains (simulated
-/*     virtual domains, where each address is redirected to a real
+/*     The address domain matches $virtual_alias_domains (virtual
+/*     alias domains, where each address is redirected to a real
 /*     local or remote address).
 /* .IP RESOLVE_CLASS_VIRTUAL
 /*     The address domain matches $virtual_mailbox_domains (true
index ebcac033eeaa229ca1bc8dc3daf65199b30fb5b0..40f47903352635c079d005cd4ecf0c16544bdcb4 100644 (file)
@@ -1,13 +1,13 @@
-#ifndef _VRFY_STAT_H_INCLUDED_
-#define _VRFY_STAT_H_INCLUDED_
+#ifndef _VRFY_CLNT_H_INCLUDED_
+#define _VRFY_CLNT_H_INCLUDED_
 
 /*++
 /* NAME
-/*     mail_proto 3h
+/*     verify_clnt 3h
 /* SUMMARY
-/*     mail internal IPC support
+/*     address verification client interface
 /* SYNOPSIS
-/*     #include <mail_proto.h>
+/*     #include <verify_clnt.h>
 /* DESCRIPTION
 /* .nf
 
index 32a51e499b05082d16de7dcd572fc372ef46465f..efbc9671bc0bde4f2f174619d0ab6f61ab65f4ba 100644 (file)
@@ -2,22 +2,29 @@
 /* NAME
 /*     xtext 3
 /* SUMMARY
-/*     translate characters according to RFC 1894
+/*     quote/unquote text, HTTP style.
 /* SYNOPSIS
 /*     #include <xtext.h>
 /*
-/*     VSTRING *xtext(result, original)
-/*     VSTRING *result;
-/*     const char *original;
+/*     VSTRING *xtext_quote(quoted, unquoted, special)
+/*     VSTRING *quoted;
+/*     const char *unquoted;
+/*     const char *special;
+/*
+/*     VSTRING *xtext_unquote(unquoted, quoted)
+/*     VSTRING *unquoted;
+/*     const char *quoted;
 /* DESCRIPTION
-/*     xtext() takes a null-terminated string, and produces a translation
-/*     according to RFC 1894 (DSN).
-/* BUGS
-/*     Cannot replace null characters.
+/*     xtext_quote() takes a null-terminated string and replaces characters
+/*     <33(10) and >126(10), as well as characters specified with "special"
+/*     by +XX, XX being the two-digit uppercase hexadecimal equivalent.
 /*
-/*     Does not insert CR LF SPACE to limit output line length.
-/* SEE ALSO
-/*     RFC 1894, Delivery Status Notifications
+/*     xtext_unquote() performs the opposite transformation. This function
+/*     understands lowercase, uppercase, and mixed case %XX sequences. The
+/*     result value is the unquoted argument in case of success, a null pointer
+/*     otherwise.
+/* BUGS
+/*     This module cannot process null characters in data.
 /* LICENSE
 /* .ad
 /* .fi
 
 /* System library. */
 
-#include "sys_defs.h"
-#include <vstream.h>
+#include <sys_defs.h>
+#include <string.h>
+#include <ctype.h>
 
 /* Utility library. */
 
-#include <vstring.h>
+#include "msg.h"
+#include "vstring.h"
+#include "xtext.h"
 
-/* Global library. */
+/* Application-specific. */
 
-#include <xtext.h>
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
 
-/* xtext - translate text according to RFC 1894 */
+/* xtext_quote - unquoted data to quoted */
 
-VSTRING *xtext(VSTRING *result, const char *original)
+VSTRING *xtext_quote(VSTRING *quoted, const char *unquoted, const char *special)
 {
     const char *cp;
     int     ch;
 
-    /*
-     * Preliminary implementation. ASCII specific!!
-     */
-    VSTRING_RESET(result);
-    for (cp = original; (ch = *(unsigned char *) cp) != 0; cp++) {
-       if (ch == '+' || ch == '\\' || ch == '(' || ch < 33 || ch > 126)
-           vstring_sprintf_append(result, "+%02X", ch);
-       else
-           VSTRING_ADDCH(result, ch);
+    VSTRING_RESET(quoted);
+    for (cp = unquoted; (ch = *(unsigned const char *) cp) != 0; cp++) {
+       if (ch != '+' && ch > 32 && ch < 127 && strchr(special, ch) == 0) {
+           VSTRING_ADDCH(quoted, ch);
+       } else {
+           vstring_sprintf_append(quoted, "+%02X", ch);
+       }
     }
-    VSTRING_TERMINATE(result);
+    VSTRING_TERMINATE(quoted);
+    return (quoted);
+}
+
+/* xtext_unquote - quoted data to unquoted */
+
+VSTRING *xtext_unquote(VSTRING *unquoted, const char *quoted)
+{
+    const char *cp;
+    int     ch;
 
-    return (result);
+    VSTRING_RESET(unquoted);
+    for (cp = quoted; (ch = *cp) != 0; cp++) {
+       if (ch == '+') {
+           if (ISDIGIT(cp[1]))
+               ch = (cp[1] - '0') << 4;
+           else if (cp[1] >= 'a' && cp[1] <= 'f')
+               ch = (cp[1] - 'a' + 10) << 4;
+           else if (cp[1] >= 'A' && cp[1] <= 'F')
+               ch = (cp[1] - 'A' + 10) << 4;
+           else
+               return (0);
+           if (ISDIGIT(cp[2]))
+               ch |= (cp[2] - '0');
+           else if (cp[2] >= 'a' && cp[2] <= 'f')
+               ch |= (cp[2] - 'a' + 10);
+           else if (cp[2] >= 'A' && cp[2] <= 'F')
+               ch |= (cp[2] - 'A' + 10);
+           else
+               return (0);
+           cp += 2;
+       }
+       VSTRING_ADDCH(unquoted, ch);
+    }
+    VSTRING_TERMINATE(unquoted);
+    return (unquoted);
 }
 
 #ifdef TEST
 
-#define STR(x) vstring_str(x)
-
+ /*
+  * Proof-of-concept test program: convert to quoted and back.
+  */
 #include <vstream.h>
 
-int     main(int unused_argc, char **unused_argv)
+#define BUFLEN 1024
+
+static int read_buf(VSTREAM *fp, VSTRING *buf)
 {
-    VSTRING *ibuf = vstring_alloc(100);
-    VSTRING *obuf = vstring_alloc(100);
+    int     len;
+
+    VSTRING_RESET(buf);
+    len = vstream_fread(fp, STR(buf), vstring_avail(buf));
+    VSTRING_AT_OFFSET(buf, len);               /* XXX */
+    VSTRING_TERMINATE(buf);
+    return (len);
+}
 
-    while (vstring_fgets(ibuf, VSTREAM_IN)) {
-       vstream_fputs(STR(xtext(obuf, STR(ibuf))));
-       vstream_fflush(VSTREAM_OUT);
+main(int unused_argc, char **unused_argv)
+{
+    VSTRING *unquoted = vstring_alloc(BUFLEN);
+    VSTRING *quoted = vstring_alloc(100);
+    int     len;
+
+    while ((len = read_buf(VSTREAM_IN, unquoted)) > 0) {
+       xtext_quote(quoted, STR(unquoted), "+=");
+       if (xtext_unquote(unquoted, STR(quoted)) == 0)
+           msg_fatal("bad input: %.100s", STR(quoted));
+       if (LEN(unquoted) != len)
+           msg_fatal("len %d != unquoted len %d", len, LEN(unquoted));
+       if (vstream_fwrite(VSTREAM_OUT, STR(unquoted), LEN(unquoted)) != LEN(unquoted))
+           msg_fatal("write error: %m");
     }
-    vstring_free(ibuf);
-    vstring_free(obuf);
+    vstream_fflush(VSTREAM_OUT);
+    vstring_free(unquoted);
+    vstring_free(quoted);
     return (0);
 }
 
index 3c02057e7bb21abd1e17d9b42492575c3331052a..8b924c6bcea68bb58002ad298800ca287d1020f4 100644 (file)
@@ -1,8 +1,11 @@
+#ifndef _XTEXT_H_INCLUDED_
+#define _XTEXT_H_INCLUDED_
+
 /*++
 /* NAME
 /*     xtext 3h
 /* SUMMARY
-/*     translate characters according to RFC 1894
+/*     quote/unquote text, xtext style.
 /* SYNOPSIS
 /*     #include <xtext.h>
 /* DESCRIPTION
 
  /*
   * Utility library.
 */
+ */
 #include <vstring.h>
 
  /*
   * External interface.
   */
-extern VSTRING *xtext(VSTRING *, const char *);
+extern VSTRING *xtext_quote(VSTRING *, const char *, const char *);
+extern VSTRING *xtext_unquote(VSTRING *, const char *);
 
 /* LICENSE
 /* .ad
@@ -28,3 +32,5 @@ extern VSTRING *xtext(VSTRING *, const char *);
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
 /*--*/
+
+#endif
index 5ac19442d89c16638c1404f507c3a4fac6c89adf..74b5ab6395d75f7626eb4f24b9fd03ff32db26cb 100644 (file)
@@ -389,7 +389,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
            if (message->rcpt_offset == 0) {
                message->rcpt_unread--;
                qmgr_rcpt_list_add(&message->rcpt_list, curr_offset,
-                                  orig_rcpt ? orig_rcpt : "unknown", start);
+                                  orig_rcpt ? orig_rcpt : "", start);
                if (orig_rcpt) {
                    myfree(orig_rcpt);
                    orig_rcpt = 0;
index 3e19547b57bc38cbe74fe6c76a8c323cc857b92a..d45f376ac640618846e94e89247c2728a4246545 100644 (file)
@@ -98,7 +98,7 @@ static void postcat(VSTREAM *fp, VSTRING *buffer)
      * See if this is a plausible file.
      */
     if ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF) {
-       if (!strchr(REC_TYPE_POST_ENVELOPE, ch)) {
+       if (!strchr(REC_TYPE_ENVELOPE, ch)) {
            msg_warn("%s: input is not a valid queue file", VSTREAM_PATH(fp));
            return;
        }
index b556179b7ea6c3bfa814218fb4480036d4b229bb..6ed6e62a011c2a179e9fd97955d3f41f9668e399 100644 (file)
@@ -357,7 +357,7 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
 #define FUDGE(x)       ((x) * (var_qmgr_fudge / 100.0))
            if (message->rcpt_offset == 0) {
                qmgr_rcpt_list_add(&message->rcpt_list, curr_offset,
-                                  orig_rcpt ? orig_rcpt : "unknown", start);
+                                  orig_rcpt ? orig_rcpt : "", start);
                if (orig_rcpt) {
                    myfree(orig_rcpt);
                    orig_rcpt = 0;
index 59d6ad3cf91709ed8f2aa3e5aee65bae07a7685d..4c561a1afa107591317334ed0019e03afb59aa59 100644 (file)
@@ -104,7 +104,7 @@ static void showq_reasons(VSTREAM *, BOUNCE_LOG *, HTABLE *);
 /* showq_report - report status of sender and recipients */
 
 static void showq_report(VSTREAM *client, char *queue, char *id,
-                                VSTREAM *qfile, long size)
+                                VSTREAM *qfile, long size, time_t mtime)
 {
     VSTRING *buf = vstring_alloc(100);
     VSTRING *printable_quoted_addr = vstring_alloc(100);
@@ -152,7 +152,8 @@ static void showq_report(VSTREAM *client, char *queue, char *id,
            printable(STR(printable_quoted_addr), '?');
            vstream_fprintf(client, DATA_FORMAT, id, status,
                          msg_size > 0 ? msg_size : size, arrival_time > 0 ?
-                           asctime(localtime(&arrival_time)) : "??",
+                           asctime(localtime(&arrival_time)) : 
+                           asctime(localtime(&mtime)),
                            STR(printable_quoted_addr));
            break;
        case REC_TYPE_RCPT:
@@ -302,7 +303,8 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv)
                    vstream_fprintf(client, "\n");
                if ((qfile = mail_queue_open(qp->name, id, O_RDONLY, 0)) != 0) {
                    queue_size += st.st_size;
-                   showq_report(client, qp->name, id, qfile, (long) st.st_size);
+                   showq_report(client, qp->name, id, qfile, (long) st.st_size,
+                       st.st_mtime);
                    if (vstream_fclose(qfile))
                        msg_warn("close file %s %s: %m", qp->name, id);
                } else if (strcmp(qp->name, MAIL_QUEUE_MAILDROP) == 0) {
index f6c0a4c24320e83a8f8ea8ec363591ef84437b7e..531878753fc61db6ce7273c0691ae14eb55090f4 100644 (file)
 /*     the destination host, sorts the list by preference, and connects
 /*     to each listed address until it finds a server that responds.
 /*
-/*     When the domain or host is specified as a comma/whitespace
-/*     separated list, the SMTP client repeats the above process
-/*     for all destinations until it finds a server that responds.
-/*
 /*     Once the SMTP client has received the server greeting banner, no
 /*     error will cause it to proceed to the next address on the mail
 /*     exchanger list. Instead, the message is either bounced, or its
 /*     Some SMTP servers misbehave on long lines.
 /* .IP \fBsmtp_helo_name\fR
 /*     The hostname to be used in HELO and EHLO commands.
+/* .IP \fBsmtp_quote_rfc821_envelope\fR
+/*     Whether or not to quote MAIL FROM and RCPT TO addresses as
+/*     per the rules laid out in RFC 821.
 /* .IP \fBsmtp_skip_4xx_greeting\fR
 /*     Skip servers that greet us with a 4xx status code.
 /* .IP \fBsmtp_skip_5xx_greeting\fR
@@ -298,6 +297,7 @@ int     var_smtp_pix_delay;
 int     var_smtp_line_limit;
 char   *var_smtp_helo_name;
 char   *var_smtp_host_lookup;
+int     var_smtp_quote_821_env;
 
  /*
   * Global variables. smtp_errno is set by the address lookup routines and by
@@ -509,6 +509,7 @@ int     main(int argc, char **argv)
        VAR_SMTP_NEVER_EHLO, DEF_SMTP_NEVER_EHLO, &var_smtp_never_ehlo,
        VAR_SMTP_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable,
        VAR_SMTP_RAND_ADDR, DEF_SMTP_RAND_ADDR, &var_smtp_rand_addr,
+       VAR_SMTP_QUOTE_821_ENV, DEF_SMTP_QUOTE_821_ENV, &var_smtp_quote_821_env,
        0,
     };
 
index b7cc68c0598c0c3e75f52be3583065309f98beee..6cbdb5d3ff9b6ef50c5f6ac1475c2ed6eb859cb0 100644 (file)
@@ -379,7 +379,7 @@ int     smtp_xfer(SMTP_STATE *state)
      * Macros for readability.
      */
 #define REWRITE_ADDRESS(dst, mid, src) do { \
-       if (*(src)) { \
+       if (*(src) && var_smtp_quote_821_env) { \
            quote_821_local(mid, src); \
            smtp_unalias_addr(dst, vstring_str(mid)); \
        } else { \
@@ -388,7 +388,7 @@ int     smtp_xfer(SMTP_STATE *state)
     } while (0)
 
 #define QUOTE_ADDRESS(dst, src) do { \
-       if (*(src)) { \
+       if (*(src) && var_smtp_quote_821_env) { \
            quote_821_local(dst, src); \
        } else { \
            vstring_strcpy(dst, src); \
@@ -640,6 +640,7 @@ int     smtp_xfer(SMTP_STATE *state)
                        if (resp->code == 552)
                            resp->code = 452;
 #endif
+                       rcpt = request->rcpt_list.info + recv_rcpt;
                        if (resp->code / 100 == 2) {
                            ++nrcpt;
                            /* If trace-only, mark the recipient done. */
@@ -654,7 +655,6 @@ int     smtp_xfer(SMTP_STATE *state)
                                rcpt->offset = 0;       /* in case deferred */
                            }
                        } else {
-                           rcpt = request->rcpt_list.info + recv_rcpt;
                            smtp_rcpt_fail(state, resp->code, rcpt,
                                        "host %s said: %s (in reply to %s)",
                                           session->namaddr,
index fbb0223970b72fc6a6cf0e06ef9e19c392a013bb..2f5c64e7d53bc5d4b4a17f1e583b8125e5e49aa2 100644 (file)
@@ -1,10 +1,10 @@
 SHELL  = /bin/sh
 SRCS   = smtpd.c smtpd_token.c smtpd_check.c smtpd_chat.c smtpd_state.c \
-       smtpd_peer.c smtpd_sasl_proto.c smtpd_sasl_glue.c
+       smtpd_peer.c smtpd_sasl_proto.c smtpd_sasl_glue.c smtpd_proxy.c
 OBJS   = smtpd.o smtpd_token.o smtpd_check.o smtpd_chat.o smtpd_state.o \
-       smtpd_peer.o smtpd_sasl_proto.o smtpd_sasl_glue.o
+       smtpd_peer.o smtpd_sasl_proto.o smtpd_sasl_glue.o smtpd_proxy.o
 HDRS   = smtpd_token.h smtpd_check.h smtpd_chat.h smtpd_sasl_proto.h \
-       smtpd_sasl_glue.h
+       smtpd_sasl_glue.h smtpd_proxy.h
 TESTSRC        = smtpd_token_test.c
 WARN   = -W -Wformat -Wimplicit -Wmissing-prototypes \
        -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
@@ -154,6 +154,7 @@ smtpd.o: smtpd_check.h
 smtpd.o: smtpd_chat.h
 smtpd.o: smtpd_sasl_proto.h
 smtpd.o: smtpd_sasl_glue.h
+smtpd.o: smtpd_proxy.h
 smtpd_chat.o: smtpd_chat.c
 smtpd_chat.o: ../../include/sys_defs.h
 smtpd_chat.o: ../../include/msg.h
@@ -241,6 +242,25 @@ smtpd_peer.o: smtpd.h
 smtpd_peer.o: ../../include/vstream.h
 smtpd_peer.o: ../../include/argv.h
 smtpd_peer.o: ../../include/mail_stream.h
+smtpd_proxy.o: smtpd_proxy.c
+smtpd_proxy.o: ../../include/sys_defs.h
+smtpd_proxy.o: ../../include/msg.h
+smtpd_proxy.o: ../../include/vstream.h
+smtpd_proxy.o: ../../include/vbuf.h
+smtpd_proxy.o: ../../include/vstring.h
+smtpd_proxy.o: ../../include/stringops.h
+smtpd_proxy.o: ../../include/connect.h
+smtpd_proxy.o: ../../include/iostuff.h
+smtpd_proxy.o: ../../include/mail_error.h
+smtpd_proxy.o: ../../include/name_mask.h
+smtpd_proxy.o: ../../include/smtp_stream.h
+smtpd_proxy.o: ../../include/cleanup_user.h
+smtpd_proxy.o: ../../include/mail_params.h
+smtpd_proxy.o: ../../include/rec_type.h
+smtpd_proxy.o: smtpd.h
+smtpd_proxy.o: ../../include/argv.h
+smtpd_proxy.o: ../../include/mail_stream.h
+smtpd_proxy.o: smtpd_proxy.h
 smtpd_sasl_glue.o: smtpd_sasl_glue.c
 smtpd_sasl_glue.o: ../../include/sys_defs.h
 smtpd_sasl_glue.o: ../../include/msg.h
index 054817accd5e687fa59e341ac2035188199e8196..b3dca183aef8f406fecbd3a690864543061ff946 100644 (file)
 /*     Maps that specify the SASL login name that owns a MAIL FROM sender
 /*     address. Used by the \fBreject_sender_login_mismatch\fR sender
 /*     anti-spoofing restriction.
+/* .SH "Pass-through proxy"
+/* .ad
+/* .fi
+/* .ad
+/*     Optionally, the Postfix SMTP server can be configured to
+/*     forward all mail to a proxy server, for example a real-time
+/*     content filter. This proxy server should support the same
+/*     MAIL FROM and RCPT TO command syntax as Postfix, but does not
+/*     need to support ESMTP command pipelining.
+/* .IP \fBsmtpd_proxy_filter\fR
+/*     The \fIhost:port\fR of the SMTP proxy server. The \fIhost\fR
+/*     or \fIhost:\fR portion is optional.
+/* .IP \fBsmtpd_proxy_timeout\fR
+/*     Timeout for connecting to, sending to and receiving from
+/*     the SMTP proxy server.
+/* .IP \fBsmtpd_proxy_ehlo\fR
+/*     The hostname to use when sending an EHLO command to the
+/*     SMTP proxy server.
 /* .SH Miscellaneous
 /* .ad
 /* .fi
 /*     Restrict what domains this mail system will relay
 /*     mail to. The domains are routed to the delivery agent
 /*     specified with the \fBrelay_transport\fR setting.
+/* .SH "Sender/recipient address verification"
+/* .ad
+/* .fi
+/*     Address verification is implemented by sending probe email
+/*     messages that are not actually delivered, and is enabled
+/*     via the reject_unverified_{sender,recipient} access restriction.
+/*     The status of verification probes is maintained by the address
+/*     verification service.
+/* .IP \fBaddress_verify_poll_count\fR
+/*     How many times to query the address verification service
+/*     for completion of an address verification request.
+/*     Specify 0 to implement a simple form of greylisting.
+/* .IP \fBaddress_verify_poll_delay\fR
+/*     Time to wait after querying the address verification service
+/*     for completion of an address verification request.
 /* .SH "UCE control responses"
 /* .ad
 /* .fi
 /* .IP \fBunverified_recipient_reject_code\fR
 /*     Response code when a recipient address is known to be undeliverable.
 /* SEE ALSO
-/*     trivial-rewrite(8) address resolver
 /*     cleanup(8) message canonicalization
 /*     master(8) process manager
 /*     syslogd(8) system logging
+/*     trivial-rewrite(8) address resolver
+/*     verify(8) address verification service
 /* LICENSE
 /* .ad
 /* .fi
 
 /* Application-specific */
 
-#include "smtpd_token.h"
-#include "smtpd.h"
-#include "smtpd_check.h"
-#include "smtpd_chat.h"
-#include "smtpd_sasl_proto.h"
-#include "smtpd_sasl_glue.h"
+#include <smtpd_token.h>
+#include <smtpd.h>
+#include <smtpd_check.h>
+#include <smtpd_chat.h>
+#include <smtpd_sasl_proto.h>
+#include <smtpd_sasl_glue.h>
+#include <smtpd_proxy.h>
 
  /*
   * Tunable parameters. Make sure that there is some bound on the length of
@@ -446,6 +481,12 @@ int     var_virt_mailbox_code;
 int     var_relay_rcpt_code;
 char   *var_verp_clients;
 int     var_show_unk_rcpt_table;
+int     var_verify_poll_count;
+int     var_verify_poll_delay;
+
+char   *var_smtpd_proxy_filt;
+int     var_smtpd_proxy_tmout;
+char   *var_smtpd_proxy_ehlo;
 
  /*
   * Silly little macros.
@@ -762,7 +803,9 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        smtpd_chat_reply(state, "503 Error: send HELO/EHLO first");
        return (-1);
     }
-    if (state->cleanup != 0) {
+#define IN_MAIL_TRANSACTION(state) ((state)->cleanup || (state)->proxy)
+
+    if (IN_MAIL_TRANSACTION(state)) {
        state->error_mask |= MAIL_ERROR_PROTOCOL;
        smtpd_chat_reply(state, "503 Error: nested MAIL command");
        return (-1);
@@ -840,50 +883,58 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        smtpd_chat_reply(state, "%s", err);
        return (-1);
     }
-    if ((err = smtpd_check_size(state, state->msg_size)) != 0) {
-       smtpd_chat_reply(state, "%s", err);
-       return (-1);
-    }
+    if (SMTPD_STAND_ALONE(state) == 0 && *var_smtpd_proxy_filt) {
+       if (smtpd_proxy_open(state, var_smtpd_proxy_filt, var_smtpd_proxy_tmout,
+                          var_smtpd_proxy_ehlo, STR(state->buffer)) != 0) {
+           smtpd_chat_reply(state, "%s", STR(state->proxy_buffer));
+           return (-1);
+       }
+    } else {
+       if ((err = smtpd_check_size(state, state->msg_size)) != 0) {
+           smtpd_chat_reply(state, "%s", err);
+           return (-1);
+       }
 
-    /*
-     * Open queue file or IPC stream.
-     */
-    mail_open_stream(state);
+       /*
+        * Open queue file or IPC stream.
+        */
+       mail_open_stream(state);
 #ifdef USE_SASL_AUTH
-    if (var_smtpd_sasl_enable)
-       smtpd_sasl_mail_log(state);
-    else
+       if (var_smtpd_sasl_enable)
+           smtpd_sasl_mail_log(state);
+       else
 #endif
-       msg_info("%s: client=%s[%s]", state->queue_id, state->name, state->addr);
-
-    /*
-     * Record the time of arrival and the sender envelope address.
-     */
-    if (SMTPD_STAND_ALONE(state) == 0) {
-       rec_fprintf(state->cleanup, REC_TYPE_TIME, "%ld",
-                   (long) time((time_t *) 0));
-       if (*var_filter_xport)
-           rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
-    }
-    rec_fputs(state->cleanup, REC_TYPE_FROM, argv[2].strval);
-    if (encoding != 0)
-       rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
-                   MAIL_ATTR_ENCODING, encoding);
-    if (SMTPD_STAND_ALONE(state) == 0) {
-       rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
-                   MAIL_ATTR_CLIENT_NAME, state->name);
-       rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
-                   MAIL_ATTR_CLIENT_ADDR, state->addr);
-       rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
-                   MAIL_ATTR_ORIGIN, state->namaddr);
-       if (state->helo_name != 0)
+           msg_info("%s: client=%s[%s]", state->queue_id, state->name, state->addr);
+
+       /*
+        * Record the time of arrival and the sender envelope address.
+        */
+       if (SMTPD_STAND_ALONE(state) == 0) {
+           rec_fprintf(state->cleanup, REC_TYPE_TIME, "%ld",
+                       (long) time((time_t *) 0));
+           if (*var_filter_xport)
+               rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
+       }
+       rec_fputs(state->cleanup, REC_TYPE_FROM, argv[2].strval);
+       if (encoding != 0)
+           rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+                       MAIL_ATTR_ENCODING, encoding);
+       if (SMTPD_STAND_ALONE(state) == 0) {
            rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
-                       MAIL_ATTR_HELO_NAME, state->helo_name);
-       rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
-                   MAIL_ATTR_PROTO_NAME, state->protocol);
+                       MAIL_ATTR_CLIENT_NAME, state->name);
+           rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+                       MAIL_ATTR_CLIENT_ADDR, state->addr);
+           rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+                       MAIL_ATTR_ORIGIN, state->namaddr);
+           if (state->helo_name != 0)
+               rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+                           MAIL_ATTR_HELO_NAME, state->helo_name);
+           rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
+                       MAIL_ATTR_PROTO_NAME, state->protocol);
+       }
+       if (verp_delims)
+           rec_fputs(state->cleanup, REC_TYPE_VERP, verp_delims);
     }
-    if (verp_delims)
-       rec_fputs(state->cleanup, REC_TYPE_VERP, verp_delims);
     state->sender = mystrdup(argv[2].strval);
     smtpd_chat_reply(state, "250 Ok");
     return (0);
@@ -918,6 +969,8 @@ static void mail_reset(SMTPD_STATE *state)
        smtpd_sasl_mail_reset(state);
 #endif
     state->discard = 0;
+    if (state->proxy)
+       smtpd_proxy_close(state);
 }
 
 /* rcpt_cmd - process RCPT TO command */
@@ -937,7 +990,7 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
      * command with a 501 response. So much for the principle of "be liberal
      * in what you accept, be strict in what you send".
      */
-    if (state->cleanup == 0) {
+    if (!IN_MAIL_TRANSACTION(state)) {
        state->error_mask |= MAIL_ERROR_PROTOCOL;
        smtpd_chat_reply(state, "503 Error: need MAIL command");
        return (-1);
@@ -977,6 +1030,11 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
            return (-1);
        }
     }
+    if (state->proxy && smtpd_proxy_cmd(state, SMTPD_PROX_STAT_OK,
+                                       "%s", STR(state->buffer)) != 0) {
+       smtpd_chat_reply(state, "%s", STR(state->proxy_buffer));
+       return (-1);
+    }
 
     /*
      * Store the recipient. Remember the first one.
@@ -984,7 +1042,8 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
     state->rcpt_count++;
     if (state->recipient == 0)
        state->recipient = mystrdup(argv[2].strval);
-    rec_fputs(state->cleanup, REC_TYPE_RCPT, argv[2].strval);
+    if (state->cleanup)
+       rec_fputs(state->cleanup, REC_TYPE_RCPT, argv[2].strval);
     smtpd_chat_reply(state, "250 Ok");
     return (0);
 }
@@ -1012,6 +1071,10 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
     int     first = 1;
     VSTRING *why = 0;
     int     saved_err;
+    int     (*out_record) (VSTREAM *, int, const char *, int);
+    int     (*out_fprintf) (VSTREAM *, int, const char *,...);
+    VSTREAM *out_stream;
+    int     out_error;
 
     /*
      * Sanity checks. With ESMTP command pipelining the client can send DATA
@@ -1019,7 +1082,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
      * error.
      */
     if (state->rcpt_count == 0) {
-       if (state->cleanup == 0) {
+       if (!IN_MAIL_TRANSACTION(state)) {
            state->error_mask |= MAIL_ERROR_PROTOCOL;
            smtpd_chat_reply(state, "503 Error: need RCPT command");
        } else {
@@ -1036,35 +1099,61 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
        smtpd_chat_reply(state, "%s", err);
        return (-1);
     }
+    if (state->proxy && smtpd_proxy_cmd(state, SMTPD_PROX_STAT_MORE,
+                                       "%s", STR(state->buffer)) != 0) {
+       smtpd_chat_reply(state, "%s", STR(state->proxy_buffer));
+       return (-1);
+    }
+
+    /*
+     * One level of indirection to choose between normal or proxied
+     * operation. We want to avoid massive code duplication within tons of
+     * if-else clauses.
+     */
+    if (state->proxy) {
+       out_stream = state->proxy;
+       out_record = smtpd_proxy_rec_put;
+       out_fprintf = smtpd_proxy_rec_fprintf;
+       out_error = CLEANUP_STAT_PROXY;
+    } else {
+       out_stream = state->cleanup;
+       out_record = rec_put;
+       out_fprintf = rec_fprintf;
+       out_error = CLEANUP_STAT_WRITE;
+    }
 
     /*
      * Terminate the message envelope segment. Start the message content
      * segment, and prepend our own Received: header. If there is only one
      * recipient, list the recipient address.
      */
-    rec_fputs(state->cleanup, REC_TYPE_MESG, "");
-    rec_fprintf(state->cleanup, REC_TYPE_NORM,
+    if (state->cleanup)
+       rec_fputs(state->cleanup, REC_TYPE_MESG, "");
+    out_fprintf(out_stream, REC_TYPE_NORM,
                "Received: from %s (%s [%s])",
                state->helo_name ? state->helo_name : state->name,
                state->name, state->addr);
     if (state->rcpt_count == 1 && state->recipient) {
-       rec_fprintf(state->cleanup, REC_TYPE_NORM,
-                   "\tby %s (%s) with %s id %s",
+       out_fprintf(out_stream, REC_TYPE_NORM,
+                   state->cleanup ? "\tby %s (%s) with %s id %s" :
+                   "\tby %s (%s) with %s",
                    var_myhostname, var_mail_name,
                    state->protocol, state->queue_id);
        quote_822_local(state->buffer, state->recipient);
-       rec_fprintf(state->cleanup, REC_TYPE_NORM,
+       out_fprintf(out_stream, REC_TYPE_NORM,
              "\tfor <%s>; %s", STR(state->buffer), mail_date(state->time));
     } else {
-       rec_fprintf(state->cleanup, REC_TYPE_NORM,
-                   "\tby %s (%s) with %s",
-                   var_myhostname, var_mail_name, state->protocol);
-       rec_fprintf(state->cleanup, REC_TYPE_NORM,
-                   "\tid %s; %s", state->queue_id, mail_date(state->time));
+       out_fprintf(out_stream, REC_TYPE_NORM,
+                   state->cleanup ? "\tby %s (%s) with %s id %s;" :
+                   "\tby %s (%s) with %s;",
+                   var_myhostname, var_mail_name,
+                   state->protocol, state->queue_id);
+       out_fprintf(out_stream, REC_TYPE_NORM,
+                   "\t%s", mail_date(state->time));
     }
 #ifdef RECEIVED_ENVELOPE_FROM
     quote_822_local(state->buffer, state->sender);
-    rec_fprintf(state->cleanup, REC_TYPE_NORM,
+    out_fprintf(out_stream, REC_TYPE_NORM,
                "\t(envelope-from %s)", STR(state->buffer));
 #endif
     smtpd_chat_reply(state, "354 End data with <CR><LF>.<CR><LF>");
@@ -1081,9 +1170,6 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
      * XXX Deal with UNIX-style From_ lines at the start of message content
      * because sendmail permits it.
      */
-    if (vstream_fflush(state->cleanup))
-       state->err = CLEANUP_STAT_WRITE;
-
     for (prev_rec_type = 0; /* void */ ; prev_rec_type = curr_rec_type) {
        if (smtp_get(state->buffer, state->client, var_line_limit) == '\n')
            curr_rec_type = REC_TYPE_NORM;
@@ -1093,40 +1179,46 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
        len = VSTRING_LEN(state->buffer);
        if (first) {
            if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) {
-               rec_fprintf(state->cleanup, curr_rec_type,
+               out_fprintf(out_stream, curr_rec_type,
                            "X-Mailbox-Line: %s", start);
                continue;
            }
            first = 0;
            if (len > 0 && IS_SPACE_TAB(start[0]))
-               rec_put(state->cleanup, REC_TYPE_NORM, "", 0);
+               out_record(out_stream, REC_TYPE_NORM, "", 0);
        }
-       if (prev_rec_type != REC_TYPE_CONT
-           && *start == '.' && (++start, --len) == 0)
+       if (prev_rec_type != REC_TYPE_CONT && *start == '.'
+           && (state->proxy == 0 ? (++start, --len) == 0 : len == 1))
            break;
        if (state->err == CLEANUP_STAT_OK
-           && rec_put(state->cleanup, curr_rec_type, start, len) < 0)
-           state->err = CLEANUP_STAT_WRITE;
+           && out_record(out_stream, curr_rec_type, start, len) < 0)
+           state->err = out_error;
     }
 
     /*
      * Send the end-of-segment markers.
      */
-    if (state->err == CLEANUP_STAT_OK)
-       if (rec_fputs(state->cleanup, REC_TYPE_XTRA, "") < 0
-           || rec_fputs(state->cleanup, REC_TYPE_END, "") < 0
-           || vstream_fflush(state->cleanup))
-           state->err = CLEANUP_STAT_WRITE;
-
-    /*
-     * Finish the queue file or finish the cleanup conversation.
-     */
-    if (state->err == 0)
-       state->err = mail_stream_finish(state->dest, why = vstring_alloc(10));
-    else
-       mail_stream_cleanup(state->dest);
-    state->dest = 0;
-    state->cleanup = 0;
+    if (state->proxy) {
+       if (state->err == CLEANUP_STAT_OK)
+           (void) smtpd_proxy_cmd(state, SMTPD_PROX_STAT_ANY, ".");
+       smtpd_proxy_close(state);
+    } else {
+       if (state->err == CLEANUP_STAT_OK)
+           if (rec_fputs(state->cleanup, REC_TYPE_XTRA, "") < 0
+               || rec_fputs(state->cleanup, REC_TYPE_END, "") < 0
+               || vstream_fflush(state->cleanup))
+               state->err = CLEANUP_STAT_WRITE;
+
+       /*
+        * Finish the queue file or finish the cleanup conversation.
+        */
+       if (state->err == 0)
+           state->err = mail_stream_finish(state->dest, why = vstring_alloc(10));
+       else
+           mail_stream_cleanup(state->dest);
+       state->dest = 0;
+       state->cleanup = 0;
+    }
 
     /*
      * Handle any errors. One message may suffer from multiple errors, so
@@ -1139,7 +1231,10 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
        state->error_count = 0;
        state->error_mask = 0;
        state->junk_cmds = 0;
-       smtpd_chat_reply(state, "250 Ok: queued as %s", state->queue_id);
+       if (state->queue_id)
+           smtpd_chat_reply(state, "250 Ok: queued as %s", state->queue_id);
+       else
+           smtpd_chat_reply(state, "%s", STR(state->proxy_buffer));
     } else if ((state->err & CLEANUP_STAT_BAD) != 0) {
        state->error_mask |= MAIL_ERROR_SOFTWARE;
        smtpd_chat_reply(state, "451 Error: internal error %d", state->err);
@@ -1156,6 +1251,9 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
     } else if ((state->err & CLEANUP_STAT_WRITE) != 0) {
        state->error_mask |= MAIL_ERROR_RESOURCE;
        smtpd_chat_reply(state, "451 Error: queue file write error");
+    } else if ((state->err & CLEANUP_STAT_PROXY) != 0) {
+       state->error_mask |= MAIL_ERROR_SOFTWARE;
+       smtpd_chat_reply(state, "451 Error: queue file write error");
     } else {
        state->error_mask |= MAIL_ERROR_SOFTWARE;
        smtpd_chat_reply(state, "451 Error: internal error %d", state->err);
@@ -1310,7 +1408,7 @@ static int etrn_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        smtpd_chat_reply(state, "503 Error: send HELO/EHLO first");
        return (-1);
     }
-    if (state->cleanup != 0) {
+    if (IN_MAIL_TRANSACTION(state)) {
        state->error_mask |= MAIL_ERROR_PROTOCOL;
        smtpd_chat_reply(state, "503 Error: MAIL transaction in progress");
        return (-1);
@@ -1409,7 +1507,7 @@ typedef struct SMTPD_CMD {
 } SMTPD_CMD;
 
 #define SMTPD_CMD_FLAG_LIMIT    (1<<0) /* limit usage */
-#define SMTPD_CMD_FLAG_HEADER  (1<<1)  /* RFC 2822 mail header */
+#define SMTPD_CMD_FLAG_FORBIDDEN       (1<<1)  /* RFC 2822 mail header */
 
 static SMTPD_CMD smtpd_cmd_table[] = {
     "HELO", helo_cmd, SMTPD_CMD_FLAG_LIMIT,
@@ -1427,11 +1525,13 @@ static SMTPD_CMD smtpd_cmd_table[] = {
     "VRFY", vrfy_cmd, SMTPD_CMD_FLAG_LIMIT,
     "ETRN", etrn_cmd, SMTPD_CMD_FLAG_LIMIT,
     "QUIT", quit_cmd, 0,
-    "Received:", 0, SMTPD_CMD_FLAG_HEADER,
-    "Reply-To:", 0, SMTPD_CMD_FLAG_HEADER,
-    "Message-ID:", 0, SMTPD_CMD_FLAG_HEADER,
-    "Subject:", 0, SMTPD_CMD_FLAG_HEADER,
-    "From:", 0, SMTPD_CMD_FLAG_HEADER,
+    "Received:", 0, SMTPD_CMD_FLAG_FORBIDDEN,
+    "Reply-To:", 0, SMTPD_CMD_FLAG_FORBIDDEN,
+    "Message-ID:", 0, SMTPD_CMD_FLAG_FORBIDDEN,
+    "Subject:", 0, SMTPD_CMD_FLAG_FORBIDDEN,
+    "From:", 0, SMTPD_CMD_FLAG_FORBIDDEN,
+    "CONNECT", 0, SMTPD_CMD_FLAG_FORBIDDEN,
+    "User-Agent:", 0, SMTPD_CMD_FLAG_FORBIDDEN,
     0,
 };
 
@@ -1521,8 +1621,8 @@ static void smtpd_proto(SMTPD_STATE *state)
                state->error_count++;
                continue;
            }
-           if (cmdp->flags & SMTPD_CMD_FLAG_HEADER) {
-               msg_warn("%s sent %s header instead of SMTP command: %.100s",
+           if (cmdp->flags & SMTPD_CMD_FLAG_FORBIDDEN) {
+               msg_warn("%s sent %s instead of SMTP command: %.100s",
                    state->namaddr, cmdp->name, vstring_str(state->buffer));
                smtpd_chat_reply(state, "221 Error: I can break rules, too. Goodbye.");
                break;
@@ -1685,11 +1785,14 @@ int     main(int argc, char **argv)
        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,
+       VAR_VERIFY_POLL_COUNT, DEF_VERIFY_POLL_COUNT, &var_verify_poll_count, 1, 0,
        0,
     };
     static CONFIG_TIME_TABLE time_table[] = {
        VAR_SMTPD_TMOUT, DEF_SMTPD_TMOUT, &var_smtpd_tmout, 1, 0,
        VAR_SMTPD_ERR_SLEEP, DEF_SMTPD_ERR_SLEEP, &var_smtpd_err_sleep, 0, 0,
+       VAR_SMTPD_PROXY_TMOUT, DEF_SMTPD_PROXY_TMOUT, &var_smtpd_proxy_tmout, 1, 0,
+       VAR_VERIFY_POLL_DELAY, DEF_VERIFY_POLL_DELAY, &var_verify_poll_delay, 1, 0,
        0,
     };
     static CONFIG_BOOL_TABLE bool_table[] = {
@@ -1732,6 +1835,8 @@ int     main(int argc, char **argv)
        VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0,
        VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender, 0, 0,
        VAR_VERP_CLIENTS, DEF_VERP_CLIENTS, &var_verp_clients, 0, 0,
+       VAR_SMTPD_PROXY_FILT, DEF_SMTPD_PROXY_FILT, &var_smtpd_proxy_filt, 0, 0,
+       VAR_SMTPD_PROXY_EHLO, DEF_SMTPD_PROXY_EHLO, &var_smtpd_proxy_ehlo, 0, 0,
        0,
     };
     static CONFIG_RAW_TABLE raw_table[] = {
index a369b7e8603abae1d5cbeb6925777f733d03c77f..bc825be1e00fbb3cb36e278eb2bb689d433daad3 100644 (file)
@@ -95,6 +95,8 @@ typedef struct SMTPD_STATE {
     int     defer_if_permit_sender;    /* force permit into warning */
     int     discard;                   /* discard message */
     VSTRING *expand_buf;               /* scratch space for $name expansion */
+    VSTREAM *proxy;                    /* proxy handle */
+    VSTRING *proxy_buffer;             /* proxy query/reply buffer */
 } SMTPD_STATE;
 
 extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *);
index 1bb029133e7ef30b68e634a787fa2986caa7aa77..54ce51789b8fb1fed883c707824c916e566c78f0 100644 (file)
@@ -1153,8 +1153,9 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient,
 
     if (once == 0) {
        once = 1;
-       msg_warn("the \"%s\" restriction is going away; use \"%s\" instead",
-                CHECK_RELAY_DOMAINS, REJECT_UNAUTH_DEST);
+       msg_warn("support for restriction \"%s\" will be removed from %s; "
+                "use \"%s\" instead",
+                CHECK_RELAY_DOMAINS, var_mail_name, REJECT_UNAUTH_DEST);
     }
 #endif
 
@@ -1650,17 +1651,17 @@ static int reject_unverified_address(SMTPD_STATE *state, const char *addr,
     /*
      * Verify the address. Don't waste too much of their or our time.
      */
-    for (count = 0; /* see below */ ; count++) {
+    for (count = 0; /* see below */ ; /* see below */ ) {
        verify_status = verify_clnt_query(addr, &rcpt_status, why);
        if (verify_status != VRFY_STAT_OK || rcpt_status != DEL_RCPT_STAT_TODO)
            break;
-       if (count >= 2)
+       if (++count >= var_verify_poll_count)
            break;
-       sleep(3);
+       sleep(var_verify_poll_delay);
     }
     if (verify_status != VRFY_STAT_OK) {
        msg_warn("%s service failure", var_verify_service);
-       DEFER_IF_REJECT2(state, MAIL_ERROR_POLICY,
+       DEFER_IF_PERMIT2(state, MAIL_ERROR_POLICY,
                      "450 <%s>: %s rejected: address verification problem",
                         reply_name, reply_class);
        rqst_status = SMTPD_CHECK_DUNNO;
@@ -2589,8 +2590,9 @@ static int reject_maps_rbl(SMTPD_STATE *state)
 
     if (warned == 0) {
        warned++;
-       msg_warn("restriction %s is going away. Please use %s <domain> instead",
-                REJECT_MAPS_RBL, REJECT_RBL_CLIENT);
+       msg_warn("support for restriction \"%s\" will be removed from %s; "
+                "use \"%s <domain-name>\" instead",
+                REJECT_MAPS_RBL, var_mail_name, REJECT_RBL_CLIENT);
     }
     while ((rbl_domain = mystrtok(&bp, " \t\r\n,")) != 0) {
        result = reject_rbl_addr(state, rbl_domain, state->addr,
@@ -2683,7 +2685,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
     int     saved_recursion = state->recursion++;
 
     if (msg_verbose)
-       msg_info("%s: START", myname);
+       msg_info(">>> START %s RESTRICTIONS <<<", reply_class);
 
     for (cpp = restrictions->argv; (name = *cpp) != 0; cpp++) {
 
@@ -2980,7 +2982,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
            break;
     }
     if (msg_verbose && name == 0)
-       msg_info("%s: END", myname);
+       msg_info(">>> END %s RESTRICTIONS <<<", reply_class);
 
     state->recursion = saved_recursion;
 
@@ -3296,6 +3298,9 @@ static int check_rcpt_maps(SMTPD_STATE *state, const char *recipient)
        return (0);
     state->rcptmap_checked = 1;
 
+    if (msg_verbose)
+       msg_info(">>> CHECKING RECIPIENT MAPS <<<");
+
     /*
      * Resolve the address.
      */
@@ -3653,6 +3658,8 @@ int     var_relay_rcpt_code;
 int     var_virt_mailbox_code;
 int     var_virt_alias_code;
 int     var_show_unk_rcpt_table;
+int     var_verify_poll_count;
+int     var_verify_poll_delay;
 
 static INT_TABLE int_table[] = {
     "msg_verbose", 0, &msg_verbose,
@@ -3676,6 +3683,8 @@ static INT_TABLE int_table[] = {
     VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code,
     VAR_VIRT_MAILBOX_CODE, DEF_VIRT_MAILBOX_CODE, &var_virt_mailbox_code,
     VAR_SHOW_UNK_RCPT_TABLE, DEF_SHOW_UNK_RCPT_TABLE, &var_show_unk_rcpt_table,
+    VAR_VERIFY_POLL_COUNT, DEF_VERIFY_POLL_COUNT, &var_verify_poll_count,
+    VAR_VERIFY_POLL_DELAY, DEF_VERIFY_POLL_DELAY, &var_verify_poll_delay,
     0,
 };
 
@@ -3803,6 +3812,14 @@ int     permit_sasl_auth(SMTPD_STATE *state, int ifyes, int ifnot)
 
 #endif
 
+/* verify_clnt_query - stub */
+
+int     verify_clnt_query(const char *addr, int *addr_status, VSTRING *why)
+{
+    *addr_status = DEL_RCPT_STAT_OK;
+    return (VRFY_STAT_OK);
+}
+
 /* canon_addr_internal - stub */
 
 VSTRING *canon_addr_internal(VSTRING *result, const char *addr)
@@ -3816,7 +3833,7 @@ VSTRING *canon_addr_internal(VSTRING *result, const char *addr)
 
 /* resolve_clnt_query - stub */
 
-void    resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply)
+void    resolve_clnt(const char *class, const char *addr, RESOLVE_REPLY *reply)
 {
     const char *domain;
 
diff --git a/postfix/src/smtpd/smtpd_proxy.c b/postfix/src/smtpd/smtpd_proxy.c
new file mode 100644 (file)
index 0000000..ffe998b
--- /dev/null
@@ -0,0 +1,437 @@
+/*++
+/* NAME
+/*     smtpd_proto 3
+/* SUMMARY
+/*     SMTP server pass-through proxy client
+/* SYNOPSIS
+/*     #include <smtpd.h>
+/*     #include <smtpd_proxy.h>
+/*
+/*     typedef struct {
+/* .in +4
+/*             /* other fields... */
+/*             VSTREAM *proxy;         /* connection to SMTP proxy */
+/*             VSTRING *proxy_reply;   /* last SMTP proxy response */
+/*             /* other fields... */
+/* .in -4
+/*     } SMTPD_STATE;
+/*
+/*     int     smtpd_proxy_open(state, service, timeout, ehlo_name, mail_from)
+/*     SMTPD_STATE *state;
+/*     const char *service;
+/*     int     timeout;
+/*     const char *ehlo_name;
+/*     const char *mail_from;
+/*
+/*     int     smtpd_proxy_cmd(state, expect, format, ...)
+/*     SMTPD_STATE *state;
+/*     int     expect;
+/*     cont char *format;
+/*
+/*     void    smtpd_proxy_open(state)
+/*     SMTPD_STATE *state;
+/* RECORD-LEVEL ROUTINES
+/*     int     smtpd_proxy_rec_put(stream, rec_type, data, len)
+/*     VSTREAM *stream;
+/*     int     rec_type;
+/*     const char *data;
+/*     int     len;
+/*
+/*     int     smtpd_proxy_rec_fprintf(stream, rec_type, format, ...)
+/*     VSTREAM *stream;
+/*     int     rec_type;
+/*     cont char *format;
+/* DESCRIPTION
+/*     The functions in this module implement a pass-through proxy
+/*     client.
+/*
+/*     In order to minimize the intrusiveness of pass-through proxying, 1) the
+/*     proxy server must support the same MAIL FROM/RCPT syntax that Postfix
+/*     supports, 2) the record-level routines for message content proxying
+/*     have the same interface as the routines that are used for non-proxied
+/*     mail.
+/*
+/*     smtpd_proxy_open() should be called after receiving the MAIL FROM
+/*     command. It connects to the proxy service, sends EHLO, sends the
+/*     MAIL FROM command, and receives the reply. A non-zero result means
+/*     trouble: either the proxy is unavailable, or it did not send the
+/*     expected reply.
+/*     All results are reported via the state->proxy_reply field in a form
+/*     that can be sent to the SMTP client. In case of error, the
+/*     state->error_mask and state->err fields are updated.
+/*     A state->proxy_reply field is created automatically; this field
+/*     persists beyond the end of a proxy session.
+/*
+/*     smtpd_proxy_cmd() formats and sends the specified command to the
+/*     proxy server, and receives the proxy server reply. A non-zero result
+/*     means trouble: either the proxy is unavailable, or it did not send the
+/*      expected reply.
+/*     All results are reported via the state->proxy_reply field in a form
+/*     that can be sent to the SMTP client. In case of error, the
+/*     state->error_mask and state->err fields are updated.
+/*
+/*     smtpd_proxy_close() disconnects from a proxy server and resets
+/*     the state->proxy field. The last proxy server reply or error
+/*     description remains available via state->proxy-reply.
+/*
+/*     smtpd_proxy_rec_put() is a rec_put() clone that passes arbitrary
+/*     message content records to the proxy server. The data is expected
+/*     to be in SMTP dot-escaped form. All errors are reported as a
+/*     REC_TYPE_ERROR result value.
+/*
+/*     smtpd_proxy_rec_fprintf() is a rec_fprintf() clone that formats
+/*     message content and sends it to the proxy server. Leading dots are
+/*     not escaped. All errors are reported as a REC_TYPE_ERROR result
+/*     value.
+/*
+/* Arguments:
+/* .IP server
+/*     The SMTP proxy server host:port. The host or host: part is optional.
+/* .IP timeout
+/*     Time limit for connecting to the proxy server and for
+/*     sending and receiving proxy server commands and replies.
+/* .IP ehlo_name
+/*     The EHLO Hostname that will be sent to the proxy server.
+/* .IP mail_from
+/*     The MAIL FROM command.
+/* .IP state
+/*     SMTP server state.
+/* .IP expect
+/*     Expected proxy server reply status code range. A warning is logged
+/*     when an unexpected reply is received. Specify one of the following:
+/* .RS
+/* .IP SMTPD_PROX_STAT_ANY
+/*     The caller has no expectation. Do not warn for unexpected replies.
+/* .IP SMTPD_PROX_STAT_OK
+/*     The caller expects a reply in the 200 range.
+/* .IP SMTPD_PROX_STAT_MORE
+/*     The caller expects a reply in the 300 range.
+/* .IP SMTPD_PROX_STAT_DEFER
+/* .IP SMTPD_PROX_STAT_FAIL
+/*     The caller perversely expects a reply in the 400 and 500 range,
+/*     respectively.
+/* .RE
+/* .IP format
+/*     A format string.
+/* .IP stream
+/*     Connection to proxy server.
+/* .IP data
+/*     Pointer to the content of one message content record.
+/* .IP len
+/*     The length of a message content record.
+/* SEE ALSO
+/*     smtpd(8) Postfix smtp server
+/* DIAGNOSTICS
+/*     Fatal errors: memory allocation problem.
+/*
+/*     Warnings: unexpected response from proxy server, unable
+/*     to connect to proxy server, proxy server read/write error.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <ctype.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstream.h>
+#include <vstring.h>
+#include <stringops.h>
+#include <connect.h>
+
+/* Global library. */
+
+#include <mail_error.h>
+#include <smtp_stream.h>
+#include <cleanup_user.h>
+#include <mail_params.h>
+#include <rec_type.h>
+
+/* Application-specific. */
+
+#include <smtpd.h>
+#include <smtpd_proxy.h>
+
+ /*
+  * SLMs.
+  */
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+/* smtpd_proxy_open - open proxy connection after MAIL FROM */
+
+int     smtpd_proxy_open(SMTPD_STATE *state, const char *service,
+                                int timeout, const char *ehlo_name,
+                                const char *mail_from)
+{
+    int     fd;
+
+    /*
+     * This buffer persists beyond the end of a proxy session so we can
+     * inspect the last command's reply.
+     */
+    if (state->proxy_buffer == 0)
+       state->proxy_buffer = vstring_alloc(10);
+
+    /*
+     * Connect to proxy.
+     */
+    if ((fd = inet_connect(service, BLOCKING, timeout)) < 0) {
+       state->error_mask |= MAIL_ERROR_SOFTWARE;
+       state->err |= CLEANUP_STAT_PROXY;
+       msg_warn("connect to proxy service %s: %m", service);
+       vstring_sprintf(state->proxy_buffer,
+                       "451 Error: queue file write error");
+       return (-1);
+    }
+    state->proxy = vstream_fdopen(fd, O_RDWR);
+    vstream_control(state->proxy, VSTREAM_CTL_PATH, service, VSTREAM_CTL_END);
+    smtp_timeout_setup(state->proxy, timeout);
+
+    /*
+     * Get server greeting banner.
+     * 
+     * XXX If this fails then we should not send the initial reply when the
+     * client expects the MAIL FROM reply.
+     */
+    if (smtpd_proxy_cmd(state, SMTPD_PROX_STAT_OK, (char *) 0) != 0) {
+       vstring_sprintf(state->proxy_buffer,
+                       "451 Error: queue file write error");
+       smtpd_proxy_close(state);
+       return (-1);
+    }
+
+    /*
+     * Send our own EHLO command.
+     * 
+     * XXX If this fails then we should not send the EHLO reply when the client
+     * expects the MAIL FROM reply.
+     */
+    if (smtpd_proxy_cmd(state, SMTPD_PROX_STAT_OK, "EHLO %s", ehlo_name) != 0) {
+       vstring_sprintf(state->proxy_buffer,
+                       "451 Error: queue file write error");
+       smtpd_proxy_close(state);
+       return (-1);
+    }
+
+    /*
+     * Pass-through the client's MAIL FROM command.
+     */
+    if (smtpd_proxy_cmd(state, SMTPD_PROX_STAT_OK, "%s", mail_from) != 0) {
+       smtpd_proxy_close(state);
+       return (-1);
+    }
+    return (0);
+}
+
+/* smtpd_proxy_comms_error - report proxy communication error */
+
+static int smtpd_proxy_comms_error(VSTREAM *stream, int err)
+{
+    switch (err) {
+       case SMTP_ERR_EOF:
+       msg_warn("lost connection with proxy %s", VSTREAM_PATH(stream));
+       return (err);
+    case SMTP_ERR_TIME:
+       msg_warn("timeout talking to proxy %s", VSTREAM_PATH(stream));
+       return (err);
+    default:
+       msg_panic("smtpd_proxy_comms_error: unknown proxy %s stream error %d",
+                 VSTREAM_PATH(stream), err);
+    }
+}
+
+/* smtpd_proxy_cmd_error - report unexpected proxy reply */
+
+static void smtpd_proxy_cmd_error(SMTPD_STATE *state, const char *fmt,
+                                         va_list ap)
+{
+    VSTRING *buf;
+
+    /*
+     * The command can be omitted at the start of an SMTP session. A null
+     * format string is not documented as part of the official interface
+     * because it is used only internally to this module.
+     */
+    buf = vstring_alloc(100);
+    vstring_vsprintf(buf, fmt && *fmt ? fmt : "connection request", ap);
+    msg_warn("proxy %s rejected \"%s\": \"%s\"", VSTREAM_PATH(state->proxy),
+            STR(buf), STR(state->proxy_buffer));
+    vstring_free(buf);
+}
+
+/* smtpd_proxy_cmd - send command to proxy, receive reply */
+
+int     smtpd_proxy_cmd(SMTPD_STATE *state, int expect, const char *fmt,...)
+{
+    va_list ap;
+    char   *cp;
+    int     last_char;
+    int     err = 0;
+
+    /*
+     * Errors first. Be prepared for delayed errors from the DATA phase.
+     */
+    if (vstream_ftimeout(state->proxy)
+       || vstream_ferror(state->proxy)
+       || vstream_feof(state->proxy)
+       || ((err = vstream_setjmp(state->proxy) != 0)
+           && smtpd_proxy_comms_error(state->proxy, err))) {
+       state->error_mask |= MAIL_ERROR_SOFTWARE;
+       state->err |= CLEANUP_STAT_PROXY;
+       vstring_sprintf(state->proxy_buffer,
+                       "451 Error: queue file write error");
+       return (-1);
+    }
+
+    /*
+     * The command can be omitted at the start of an SMTP session. A null
+     * format string is not documented as part of the official interface
+     * because it is used only internally to this module.
+     */
+    if (fmt && *fmt) {
+
+       /*
+        * Format the command.
+        */
+       va_start(ap, fmt);
+       vstring_vsprintf(state->proxy_buffer, fmt, ap);
+       va_end(ap);
+
+       /*
+        * Optionally log the command first, so that we can see in the log
+        * what the program is trying to do.
+        */
+       if (msg_verbose)
+           msg_info("> %s: %s", VSTREAM_PATH(state->proxy),
+                    STR(state->proxy_buffer));
+
+       /*
+        * Send the command to the proxy server. Since we're going to read a
+        * reply immediately, there is no need to flush buffers.
+        */
+       smtp_fputs(STR(state->proxy_buffer), LEN(state->proxy_buffer),
+                  state->proxy);
+    }
+
+    /*
+     * Censor out non-printable characters in server responses and keep the
+     * last line of multi-line responses.
+     */
+    for (;;) {
+       last_char = smtp_get(state->proxy_buffer, state->proxy, var_line_limit);
+       printable(STR(state->proxy_buffer), '?');
+       if (last_char != '\n')
+           msg_warn("%s: response longer than %d: %.30s...",
+                    VSTREAM_PATH(state->proxy), var_line_limit,
+                    STR(state->proxy_buffer));
+       if (msg_verbose)
+           msg_info("< %s: %s", VSTREAM_PATH(state->proxy),
+                    STR(state->proxy_buffer));
+
+       /*
+        * Parse the response into code and text. Ignore unrecognized
+        * garbage. This means that any character except space (or end of
+        * line) will have the same effect as the '-' line continuation
+        * character.
+        */
+       for (cp = STR(state->proxy_buffer); *cp && ISDIGIT(*cp); cp++)
+            /* void */ ;
+       if (cp - STR(state->proxy_buffer) == 3) {
+           if (*cp == '-')
+               continue;
+           if (*cp == ' ' || *cp == 0)
+               break;
+       }
+       msg_warn("received garbage from proxy %s: %.100s",
+                VSTREAM_PATH(state->proxy), STR(state->proxy_buffer));
+    }
+
+    /*
+     * Log a warning in case the proxy does not send the expected response.
+     * Silently accept any response when the client expressed no expectation.
+     */
+    if (expect != SMTPD_PROX_STAT_ANY
+       && expect != (STR(state->proxy_buffer)[0] - '0')) {
+       va_start(ap, fmt);
+       smtpd_proxy_cmd_error(state, fmt, ap);
+       va_end(ap);
+       return (-1);
+    } else {
+       return (0);
+    }
+}
+
+/* smtpd_proxy_rec_put - send message content, rec_put() clone */
+
+int     smtpd_proxy_rec_put(VSTREAM *stream, int rec_type,
+                                   const char *data, int len)
+{
+    int     err;
+
+    /*
+     * Errors first.
+     */
+    if (vstream_ftimeout(stream) || vstream_ferror(stream)
+       || vstream_feof(stream))
+       return (REC_TYPE_ERROR);
+    if ((err = vstream_setjmp(stream)) != 0)
+       return (smtpd_proxy_comms_error(stream, err), REC_TYPE_ERROR);
+
+    /*
+     * Send one content record. Errors and results must be as with rec_put().
+     */
+    if (rec_type == REC_TYPE_NORM)
+       smtp_fputs(data, len, stream);
+    else
+       smtp_fwrite(data, len, stream);
+    return (rec_type);
+}
+
+/* smtpd_proxy_rec_fprintf - send message content, rec_fprintf() clone */
+
+int     smtpd_proxy_rec_fprintf(VSTREAM *stream, int rec_type,
+                                       const char *fmt,...)
+{
+    va_list ap;
+    int     err;
+
+    /*
+     * Errors first.
+     */
+    if (vstream_ftimeout(stream) || vstream_ferror(stream)
+       || vstream_feof(stream))
+       return (REC_TYPE_ERROR);
+    if ((err = vstream_setjmp(stream)) != 0)
+       return (smtpd_proxy_comms_error(stream, err), REC_TYPE_ERROR);
+
+    /*
+     * Send one content record. Errors and results must be as with
+     * rec_fprintf().
+     */
+    va_start(ap, fmt);
+    if (rec_type != REC_TYPE_NORM)
+       msg_panic("smtpd_proxy_rec_fprintf: need REC_TYPE_NORM");
+    smtp_vprintf(stream, fmt, ap);
+    va_end(ap);
+    return (rec_type);
+}
+
+/* smtpd_proxy_close - close proxy connection */
+
+void    smtpd_proxy_close(SMTPD_STATE *state)
+{
+    (void) vstream_fclose(state->proxy);
+    state->proxy = 0;
+}
diff --git a/postfix/src/smtpd/smtpd_proxy.h b/postfix/src/smtpd/smtpd_proxy.h
new file mode 100644 (file)
index 0000000..9d0fe53
--- /dev/null
@@ -0,0 +1,42 @@
+/*++
+/* NAME
+/*     smtpd_proxy 3h
+/* SUMMARY
+/*     SMTP server pass-through proxy client
+/* SYNOPSIS
+/*     #include <smtpd.h>
+/*     #include <smtpd_proxy.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <vstream.h>
+#include <vstring.h>
+
+ /*
+  * Application-specific.
+  */
+#define SMTPD_PROX_STAT_ANY    0
+#define SMTPD_PROX_STAT_OK     2
+#define SMTPD_PROX_STAT_MORE   3
+#define SMTPD_PROX_STAT_DEFER  4
+#define SMTPD_PROX_STAT_FAIL   5
+
+extern int smtpd_proxy_open(SMTPD_STATE *, const char *, int, const char *, const char *);
+extern int smtpd_proxy_cmd(SMTPD_STATE *, int, const char *,...);
+extern int smtpd_proxy_rec_put(VSTREAM *, int, const char *, int);
+extern int smtpd_proxy_rec_fprintf(VSTREAM *, int, const char *,...);
+extern void smtpd_proxy_close(SMTPD_STATE *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
index 6475ae49b05f220bcbd470511cd37ed5f1f8de76..f0b148d5515d62aee60711d8abbcfe1252ef7f6a 100644 (file)
@@ -99,6 +99,8 @@ void    smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream)
     state->defer_if_permit.reason = 0;
     state->discard = 0;
     state->expand_buf = 0;
+    state->proxy = 0;
+    state->proxy_buffer = 0;
 
 #ifdef USE_SASL_AUTH
     if (SMTPD_STAND_ALONE(state))
@@ -137,6 +139,8 @@ void    smtpd_state_reset(SMTPD_STATE *state)
        vstring_free(state->defer_if_reject.reason);
     if (state->expand_buf)
        vstring_free(state->expand_buf);
+    if (state->proxy_buffer)
+       vstring_free(state->proxy_buffer);
 
 #ifdef USE_SASL_AUTH
     if (var_smtpd_sasl_enable)
index 19c863f43f8b01e2730edc698c531ca96f1d0c34..74b5387831560b476e980b21a7bac123e999b25d 100644 (file)
@@ -3,7 +3,7 @@ SRCS    = alldig.c argv.c argv_split.c attr_print0.c attr_print64.c \
        attr_scan0.c attr_scan64.c base64_code.c basename.c binhash.c \
        chroot_uid.c clean_env.c close_on_exec.c concatenate.c ctable.c \
        dict.c dict_alloc.c dict_db.c dict_dbm.c dict_debug.c dict_env.c \
-       dict_ht.c dict_ldap.c dict_mysql.c dict_ni.c dict_nis.c \
+       dict_cidr.c dict_ht.c dict_ldap.c dict_mysql.c dict_ni.c dict_nis.c \
        dict_nisplus.c dict_open.c dict_pcre.c dict_pgsql.c dict_regexp.c \
        dict_static.c dict_tcp.c dict_unix.c dir_forest.c doze.c \
        duplex_pipe.c environ.c events.c exec_command.c fifo_listen.c \
@@ -31,7 +31,7 @@ OBJS  = alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \
        attr_scan0.o attr_scan64.o base64_code.o basename.o binhash.o \
        chroot_uid.o clean_env.o close_on_exec.o concatenate.o ctable.o \
        dict.o dict_alloc.o dict_db.o dict_dbm.o dict_debug.o dict_env.o \
-       dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
+       dict_cidr.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
        dict_nisplus.o dict_open.o dict_pcre.o dict_pgsql.o dict_regexp.o \
        dict_static.o dict_tcp.o dict_unix.o dir_forest.o doze.o \
        duplex_pipe.o environ.o events.o exec_command.o fifo_listen.o \
@@ -57,7 +57,7 @@ OBJS  = alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \
        write_buf.o write_wait.o $(STRCASE)
 HDRS   = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \
        connect.h ctable.h dict.h dict_db.h dict_dbm.h dict_env.h \
-       dict_ht.h dict_ldap.h dict_mysql.h dict_ni.h dict_nis.h \
+       dict_cidr.h dict_ht.h dict_ldap.h dict_mysql.h dict_ni.h dict_nis.h \
        dict_nisplus.h dict_pcre.h dict_pgsql.h dict_regexp.h \
        dict_static.h dict_tcp.h dict_unix.h dir_forest.h events.h \
        exec_command.h find_inet.h fsspace.h fullname.h get_domainname.h \
@@ -337,7 +337,8 @@ stream_test: stream_test.c $(LIB)
 
 tests: valid_hostname_test mac_expand_test dict_test unescape_test \
        hex_quote_test ctable_test inet_addr_list_test base64_code_test \
-       attr_scan64_test attr_scan0_test dict_pcre_test host_port_test
+       attr_scan64_test attr_scan0_test dict_pcre_test host_port_test \
+       dict_cidr_test
 
 valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
        ./valid_hostname <valid_hostname.in 2>valid_hostname.tmp
@@ -403,6 +404,11 @@ dict_regexp_test: dict_open dict_regexp.in dict_regexp.map dict_regexp.ref
        diff dict_regexp.ref dict_regexp.tmp
        rm -f dict_regexp.tmp
 
+dict_cidr_test: dict_open dict_cidr.in dict_cidr.map dict_cidr.ref
+       ./dict_open cidr:dict_cidr.map read <dict_cidr.in >dict_cidr.tmp 2>&1
+       diff dict_cidr.ref dict_cidr.tmp
+       rm -f dict_cidr.tmp
+
 host_port_test: host_port host_port.in host_port.ref
        ./host_port <host_port.in >host_port.tmp 2>&1
        diff host_port.ref host_port.tmp
@@ -529,6 +535,19 @@ dict_alloc.o: dict.h
 dict_alloc.o: vstream.h
 dict_alloc.o: vbuf.h
 dict_alloc.o: argv.h
+dict_cidr.o: dict_cidr.c
+dict_cidr.o: sys_defs.h
+dict_cidr.o: mymalloc.h
+dict_cidr.o: msg.h
+dict_cidr.o: vstream.h
+dict_cidr.o: vbuf.h
+dict_cidr.o: vstring.h
+dict_cidr.o: stringops.h
+dict_cidr.o: readlline.h
+dict_cidr.o: dict.h
+dict_cidr.o: argv.h
+dict_cidr.o: dict_cidr.h
+dict_cidr.o: split_at.h
 dict_db.o: dict_db.c
 dict_db.o: sys_defs.h
 dict_db.o: msg.h
@@ -619,6 +638,7 @@ dict_open.o: dict_pgsql.h
 dict_open.o: dict_pcre.h
 dict_open.o: dict_regexp.h
 dict_open.o: dict_static.h
+dict_open.o: dict_cidr.h
 dict_open.o: stringops.h
 dict_open.o: vstring.h
 dict_open.o: split_at.h
diff --git a/postfix/src/util/dict_cidr.c b/postfix/src/util/dict_cidr.c
new file mode 100644 (file)
index 0000000..6c06803
--- /dev/null
@@ -0,0 +1,242 @@
+/*++
+/* NAME
+/*     dict_cidr 3
+/* SUMMARY
+/*     Dictionary interface for CIDR data
+/* SYNOPSIS
+/*     #include <dict_cidr.h>
+/*
+/*     DICT    *dict_cidr_open(name, dummy, dict_flags)
+/*     const char *name;
+/*     int     dummy;
+/*     int     dict_flags;
+/* DESCRIPTION
+/*     dict_cidr_open() opens the named file and stores
+/*     the key/value pairs where the key must be either a
+/*     "naked" IP address or a netblock in CIDR notation.
+/* SEE ALSO
+/*     dict(3) generic dictionary manager
+/* AUTHOR(S)
+/*     Jozsef Kadlecsik
+/*     kadlec@blackhole.kfki.hu
+/*     KFKI Research Institute for Particle and Nuclear Physics
+/*     POB. 49
+/*     1525 Budapest, Hungary
+/*
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+/* Utility library. */
+
+#include <mymalloc.h>
+#include <msg.h>
+#include <vstream.h>
+#include <vstring.h>
+#include <stringops.h>
+#include <readlline.h>
+#include <dict.h>
+#include <dict_cidr.h>
+#include <split_at.h>
+
+/* Application-specific. */
+
+ /*
+  * Each rule in a CIDR table is parsed and stored in a linked list.
+  * Obviously all this is IPV4 specific and needs to be redone for IPV6.
+  */
+typedef struct DICT_CIDR_ENTRY {
+    unsigned long net_bits;            /* network portion of address */
+    unsigned long mask_bits;           /* network mask */
+    char   *value;                     /* lookup result */
+    struct DICT_CIDR_ENTRY *next;      /* next entry */
+} DICT_CIDR_ENTRY;
+
+typedef struct {
+    DICT    dict;                      /* generic members */
+    DICT_CIDR_ENTRY *head;             /* first entry */
+} DICT_CIDR;
+
+#define BITS_PER_ADDR   32
+
+/* dict_cidr_lookup - CIDR table lookup */
+
+static const char *dict_cidr_lookup(DICT *dict, const char *key)
+{
+    DICT_CIDR *dict_cidr = (DICT_CIDR *) dict;
+    DICT_CIDR_ENTRY *entry;
+    unsigned long addr;
+
+    if (msg_verbose)
+       msg_info("dict_cidr_lookup: %s: %s", dict_cidr->dict.name, key);
+
+    if ((addr = inet_addr(key)) == INADDR_NONE)
+       return (0);
+
+    for (entry = dict_cidr->head; entry; entry = entry->next)
+       if ((addr & entry->mask_bits) == entry->net_bits)
+           return (entry->value);
+
+    return (0);
+}
+
+/* dict_cidr_close - close the CIDR table */
+
+static void dict_cidr_close(DICT *dict)
+{
+    DICT_CIDR *dict_cidr = (DICT_CIDR *) dict;
+    DICT_CIDR_ENTRY *entry;
+    DICT_CIDR_ENTRY *next;
+
+    for (entry = dict_cidr->head; entry; entry = next) {
+       next = entry->next;
+       myfree(entry->value);
+       myfree((char *) entry);
+    }
+    dict_free(dict);
+}
+
+/* dict_cidr_parse_rule - parse CIDR table rule into network, mask and value */
+
+static DICT_CIDR_ENTRY *dict_cidr_parse_rule(const char *mapname, int lineno,
+                                                    char *p)
+{
+    DICT_CIDR_ENTRY *rule;
+    char   *key;
+    char   *value;
+    char   *mask;
+    int     mask_shift;
+    unsigned long net_bits;
+    unsigned long mask_bits;
+    struct in_addr net_addr;
+
+    /*
+     * Split into key and value. We already eliminated leading whitespace,
+     * comments, empty lines or lines with whitespace only. This means a null
+     * key can't happen but we will handle this anyway.
+     */
+    key = p;
+    while (*p && !ISSPACE(*p))                 /* Skip over key */
+       p++;
+    if (*p)                                    /* Terminate key */
+       *p++ = 0;
+    while (*p && ISSPACE(*p))                  /* Skip whitespace */
+       p++;
+    value = p;
+    trimblanks(value, 0)[0] = 0;               /* Trim trailing blanks */
+    if (*key == 0) {
+       msg_warn("cidr map %s, line %d: no address pattern: skipping this rule",
+                mapname, lineno);
+       return (0);
+    }
+    if (*value == 0) {
+       msg_warn("cidr map %s, line %d: no lookup result: skipping this rule",
+                mapname, lineno);
+       return (0);
+    }
+
+    /*
+     * Parse the key into network and mask, and destroy the key. Treat a bare
+     * network address as /32.
+     */
+    if ((mask = split_at(key, '/')) != 0) {
+       if ((mask_shift = atoi(mask)) <= 0 || mask_shift > BITS_PER_ADDR
+           || (net_bits = inet_addr(key)) == INADDR_NONE) {
+           msg_warn("cidr map %s, line %d: bad net/mask pattern: \"%s/%s\": "
+                    "skipping this rule", mapname, lineno, key, mask);
+           return (0);
+       }
+       mask_bits = htonl((0xffffffff) << (BITS_PER_ADDR - mask_shift));
+       if (net_bits & ~mask_bits) {
+           net_addr.s_addr = (net_bits & mask_bits);
+           msg_warn("cidr map %s, line %d: net/mask pattern \"%s/%s\" with "
+                    "non-null host portion: skipping this rule",
+                    mapname, lineno, key, mask);
+           msg_warn("specify \"%s/%d\" if this is really what you want",
+                    inet_ntoa(net_addr), mask_shift);
+           return (0);
+       }
+    } else {
+       if ((net_bits = inet_addr(key)) == INADDR_NONE) {
+           msg_warn("cidr map %s, line %d: bad address pattern: \"%s\": "
+                    "skipping this rule", mapname, lineno, key);
+           return (0);
+       }
+       mask_shift = 32;
+       mask_bits = htonl(0xffffffff);
+    }
+
+    rule = (DICT_CIDR_ENTRY *) mymalloc(sizeof(DICT_CIDR_ENTRY));
+    rule->net_bits = net_bits;
+    rule->mask_bits = mask_bits;
+    rule->value = mystrdup(value);
+    rule->next = 0;
+
+    if (msg_verbose)
+       msg_info("dict_cidr_open: %s: %lu/%d %s",
+                mapname, rule->net_bits, mask_shift, rule->value);
+
+    return (rule);
+}
+
+/* dict_cidr_open - parse CIDR table */
+
+DICT   *dict_cidr_open(const char *mapname, int unused_flags, int dict_flags)
+{
+    DICT_CIDR *dict_cidr;
+    VSTREAM *map_fp;
+    VSTRING *line_buffer = vstring_alloc(100);
+    DICT_CIDR_ENTRY *rule;
+    DICT_CIDR_ENTRY *last_rule = 0;
+    int     lineno = 0;
+
+    /*
+     * XXX Eliminate unnecessary queries by setting a flag that says "this
+     * map matches network addresses only".
+     */
+    dict_cidr = (DICT_CIDR *) dict_alloc(DICT_TYPE_CIDR, mapname,
+                                        sizeof(*dict_cidr));
+    dict_cidr->dict.lookup = dict_cidr_lookup;
+    dict_cidr->dict.close = dict_cidr_close;
+    dict_cidr->dict.flags = dict_flags | DICT_FLAG_PATTERN;
+    dict_cidr->head = 0;
+
+    if ((map_fp = vstream_fopen(mapname, O_RDONLY, 0)) == 0)
+       msg_fatal("open %s: %m", mapname);
+
+    while (readlline(line_buffer, map_fp, &lineno)) {
+       rule = dict_cidr_parse_rule(mapname, lineno, vstring_str(line_buffer));
+       if (rule == 0)
+           continue;
+       if (last_rule == 0)
+           dict_cidr->head = rule;
+       else
+           last_rule->next = rule;
+       last_rule = rule;
+    }
+
+    /*
+     * Clean up.
+     */
+    if (vstream_fclose(map_fp))
+       msg_fatal("cidr map %s: read error: %m", mapname);
+    vstring_free(line_buffer);
+
+    return (DICT_DEBUG (&dict_cidr->dict));
+}
diff --git a/postfix/src/util/dict_cidr.h b/postfix/src/util/dict_cidr.h
new file mode 100644 (file)
index 0000000..308a765
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _DICT_CIDR_H_INCLUDED_
+#define _DICT_CIDR_H_INCLUDED_
+
+/*++
+/* NAME
+/*     dict_cidr 3h
+/* SUMMARY
+/*     Dictionary manager interface to handle cidr data.
+/* SYNOPSIS
+/*     #include <dict_cidr.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <dict.h>
+
+ /*
+  * External interface.
+  */
+extern DICT *dict_cidr_open(const char *, int, int);
+
+#define DICT_TYPE_CIDR         "cidr"
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*
+/*     Jozsef Kadlecsik
+/*     kadlec@blackhole.kfki.hu
+/*     KFKI Research Institute for Particle and Nuclear Physics
+/*     POB. 49
+/*     1525 Budapest 114, Hungary
+/*--*/
+
+#endif
diff --git a/postfix/src/util/dict_cidr.in b/postfix/src/util/dict_cidr.in
new file mode 100644 (file)
index 0000000..bfcb080
--- /dev/null
@@ -0,0 +1,7 @@
+get 172.16.0.0
+get 172.16.0.1
+get 172.16.7.255
+get 172.16.8.1
+get 172.16.17.1
+get 172.17.1.1
+get 172.17.1.2
diff --git a/postfix/src/util/dict_cidr.map b/postfix/src/util/dict_cidr.map
new file mode 100644 (file)
index 0000000..a655ac4
--- /dev/null
@@ -0,0 +1,9 @@
+172.16.0.0/21          554 match bad netblock 172.16.0.0/21
+172.16.8.0/21          554 match bad netblock 172.16.8.0/21
+172.16.0.0/16          554 match bad netblock 172.16.0.0/16
+172.17.1.1             554 match bad naked address
+172.16.1.3/21          whatever
+172.16.1.3/33          whatever
+172.999.0.0/21         whatever
+172.16.1.999           whatever
+172.16.1.4
diff --git a/postfix/src/util/dict_cidr.ref b/postfix/src/util/dict_cidr.ref
new file mode 100644 (file)
index 0000000..a1fe357
--- /dev/null
@@ -0,0 +1,13 @@
+./dict_open: warning: cidr map dict_cidr.map, line 5: net/mask pattern "172.16.1.3/21" with non-null host portion: skipping this rule
+./dict_open: warning: specify "172.16.0.0/21" if this is really what you want
+./dict_open: warning: cidr map dict_cidr.map, line 6: bad net/mask pattern: "172.16.1.3/33": skipping this rule
+./dict_open: warning: cidr map dict_cidr.map, line 7: bad net/mask pattern: "172.999.0.0/21": skipping this rule
+./dict_open: warning: cidr map dict_cidr.map, line 8: bad address pattern: "172.16.1.999": skipping this rule
+./dict_open: warning: cidr map dict_cidr.map, line 9: no lookup result: skipping this rule
+172.16.0.0=554 match bad netblock 172.16.0.0/21
+172.16.0.1=554 match bad netblock 172.16.0.0/21
+172.16.7.255=554 match bad netblock 172.16.0.0/21
+172.16.8.1=554 match bad netblock 172.16.8.0/21
+172.16.17.1=554 match bad netblock 172.16.0.0/16
+172.17.1.1=554 match bad naked address
+172.17.1.2: not found
index 8b21278d45af90a69df0d75bb8cb68a5a7d49c35..c4867ba65f1be17e21a2d1b9416052e81e80e96d 100644 (file)
 /*     If you must bind to the server, do it with this distinguished name ...
 /* .IP \fIldapsource_\fRbind_pw
 /*     \&... and this password.
-/* .IP \fIldapsource_\fRcache
+/* .IP \fIldapsource_\fRcache (no longer supported)
 /*     Whether or not to turn on client-side caching.
-/* .IP \fIldapsource_\fRcache_expiry
+/* .IP \fIldapsource_\fRcache_expiry (no longer supported)
 /*     If you do cache results, expire them after this many seconds.
-/* .IP \fIldapsource_\fRcache_size
+/* .IP \fIldapsource_\fRcache_size (no longer supported)
 /*     The cache size in bytes. Does nothing if the cache is off, of course.
+/* .IP \fIldapsource_\fRrecursion_limit
+/*     Maximum recursion depth when expanding DN or URL references.
+/*     Queries which exceed the recursion limit fail with
+/*     dict_errno = DICT_ERR_RETRY.
+/* .IP \fIldapsource_\fRexpansion_limit
+/*     Limit (if any) on the total number of lookup result values. Lookups which
+/*     exceed the limit fail with dict_errno=DICT_ERR_RETRY. Note that
+/*     each value of a multivalued result attribute counts as one result.
+/* .IP \fIldapsource_\fRsize_limit
+/*     Limit on the number of entries returned by individual LDAP queries.
+/*     Queries which exceed the limit fail with dict_errno=DICT_ERR_RETRY.
+/*     This is an *entry* count, for any single query performed during the
+/*     possibly recursive lookup.
+/* .IP \fIldapsource_\fRchase_referrals
+/*     Controls whether LDAP referrals are obeyed.
 /* .IP \fIldapsource_\fRdereference
 /*     How to handle LDAP aliases. See ldap.h or ldap_open(3) man page.
 /* .IP \fIldapsource_\fRdebuglevel
@@ -152,10 +167,10 @@ typedef struct {
     char   *bind_dn;
     char   *bind_pw;
     int     timeout;
-    int     cache;
-    long    cache_expiry;
-    long    cache_size;
     int     dereference;
+    long    recursion_limit;
+    long    expansion_limit;
+    long    size_limit;
     int     chase_referrals;
     int     debuglevel;
     int     version;
@@ -231,11 +246,6 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
     char   *myname = "dict_ldap_connect";
     int     rc = 0;
 
-#ifdef LDAP_API_FEATURE_X_MEMCACHE
-    LDAPMemCache *dircache;
-
-#endif
-
 #ifdef LDAP_OPT_NETWORK_TIMEOUT
     struct timeval mytimeval;
 
@@ -313,6 +323,16 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
     }
 #endif
 
+    /*
+     * Limit the number of entries returned by each query.
+     */
+    if (dict_ldap->size_limit) {
+       if (ldap_set_option(dict_ldap->ld, LDAP_OPT_SIZELIMIT,
+                           &dict_ldap->size_limit) != LDAP_OPT_SUCCESS)
+           msg_warn("%s: %s: Unable to set query result size limit to %ld.",
+                    myname, dict_ldap->ldapsource, dict_ldap->size_limit);
+    }
+
     /*
      * Configure alias dereferencing for this connection. Thanks to Mike
      * Mattice for this, and to Hery Rakotoarisoa for the v3 update.
@@ -370,52 +390,6 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
            msg_info("%s: Successful bind to server %s as %s ",
                     myname, dict_ldap->server_host, dict_ldap->bind_dn);
     }
-
-    /*
-     * Set up client-side caching if it's configured.
-     */
-    if (dict_ldap->cache) {
-       if (msg_verbose)
-           msg_info
-               ("%s: Enabling %ld-byte cache for %s with %ld-second expiry",
-                myname, dict_ldap->cache_size, dict_ldap->ldapsource,
-                dict_ldap->cache_expiry);
-
-#ifdef LDAP_API_FEATURE_X_MEMCACHE
-       rc = ldap_memcache_init(dict_ldap->cache_expiry, dict_ldap->cache_size,
-                               NULL, NULL, &dircache);
-       if (rc != LDAP_SUCCESS) {
-           msg_warn
-               ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
-                myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
-       } else {
-           rc = ldap_memcache_set(dict_ldap->ld, dircache);
-           if (rc != LDAP_SUCCESS) {
-               msg_warn
-                   ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
-                    myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
-           } else {
-               if (msg_verbose)
-                   msg_info("%s: Caching enabled for %s",
-                            myname, dict_ldap->ldapsource);
-           }
-       }
-#else
-
-       rc = ldap_enable_cache(dict_ldap->ld, dict_ldap->cache_expiry,
-                              dict_ldap->cache_size);
-       if (rc != LDAP_SUCCESS) {
-           msg_warn
-               ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
-                myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
-       } else {
-           if (msg_verbose)
-               msg_info("%s: Caching enabled for %s",
-                        myname, dict_ldap->ldapsource);
-       }
-
-#endif
-    }
     if (msg_verbose)
        msg_info("%s: Cached connection handle for LDAP source %s",
                 myname, dict_ldap->ldapsource);
@@ -426,7 +400,8 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
 /*
  * expand a filter (lookup or result)
  */
-static void dict_ldap_expand_filter(char *filter, char *value, VSTRING *out)
+static void dict_ldap_expand_filter(char *ldapsource, char *filter,
+                                           char *value, VSTRING *out)
 {
     char   *myname = "dict_ldap_expand_filter";
     char   *sub,
@@ -461,9 +436,8 @@ static void dict_ldap_expand_filter(char *filter, char *value, VSTRING *out)
                    vstring_strcat(out, u);
                break;
            default:
-               msg_warn
-                   ("%s: Invalid filter substitution format '%%%c'!",
-                    myname, *(sub + 1));
+               msg_warn("%s: %s: Invalid filter substitution format '%%%c'!",
+                        myname, ldapsource, *(sub + 1));
                /* fall through */
            case 's':
                vstring_strcat(out, u);
@@ -486,6 +460,9 @@ static void dict_ldap_expand_filter(char *filter, char *value, VSTRING *out)
 static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
                                         VSTRING *result)
 {
+    static int recursion = 0;
+    static int expansion;
+    long    entries = 0;
     long    i = 0;
     int     rc = 0;
     LDAPMessage *resloop = 0;
@@ -500,13 +477,27 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
     tv.tv_sec = dict_ldap->timeout;
     tv.tv_usec = 0;
 
+    if (++recursion == 1)
+       expansion = 0;
+
     if (msg_verbose)
-       msg_info("%s: Search found %d match(es)", myname,
+       msg_info("%s[%d]: Search found %d match(es)", myname, recursion,
                 ldap_count_entries(dict_ldap->ld, res));
 
     for (entry = ldap_first_entry(dict_ldap->ld, res); entry != NULL;
         entry = ldap_next_entry(dict_ldap->ld, entry)) {
        ber = NULL;
+
+       /*
+        * LDAP should not, but may produce more than the requested maximum
+        * number of entries.
+        */
+       if (dict_errno == 0 && ++entries > dict_ldap->size_limit
+           && dict_ldap->size_limit) {
+           msg_warn("%s[%d]: %s: Query size limit (%ld) exceeded", myname,
+                  recursion, dict_ldap->ldapsource, dict_ldap->size_limit);
+           dict_errno = DICT_ERR_RETRY;
+       }
        for (attr = ldap_first_attribute(dict_ldap->ld, entry, &ber);
             attr != NULL;
             ldap_memfree(attr), attr = ldap_next_attribute(dict_ldap->ld,
@@ -514,17 +505,38 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
            vals = ldap_get_values(dict_ldap->ld, entry, attr);
            if (vals == NULL) {
                if (msg_verbose)
-                   msg_info("%s: Entry doesn't have any values for %s",
-                            myname, attr);
+                   msg_info("%s[%d]: Entry doesn't have any values for %s",
+                            myname, recursion, attr);
+               continue;
+           }
+
+           /*
+            * If we previously encountered an error, we still continue
+            * through the loop, to avoid memory leaks, but we don't waste
+            * time accumulating any further results.
+            * 
+            * XXX: There may be a more efficient way to exit the loop with no
+            * leaks, but it will likely be more fragile and not worth the
+            * extra code.
+            */
+           if (dict_errno != 0 || vals[0] == 0) {
+               ldap_value_free(vals);
                continue;
            }
+
+           /*
+            * The "result_attributes" list enumerates all the requested
+            * attributes, first the ordinary result attribtutes and then the
+            * special result attributes that hold DN or LDAP URL values.
+            * 
+            * The number of ordinary attributes is "num_attributes".
+            * 
+            * We compute the attribute type (ordinary or special) from its
+            * index on the "result_attributes" list.
+            */
            for (i = 0; dict_ldap->result_attributes->argv[i]; i++) {
-               if (strcasecmp(dict_ldap->result_attributes->argv[i],
-                              attr) == 0) {
-                   if (msg_verbose)
-                       msg_info("%s: search returned %ld value(s) for requested result attribute %s", myname, i, attr);
+               if (strcasecmp(dict_ldap->result_attributes->argv[i], attr) == 0)
                    break;
-               }
            }
 
            /*
@@ -532,21 +544,39 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
             * recursing (for dn or url attributes).
             */
            if (i < dict_ldap->num_attributes) {
+               /* Ordinary result attribute */
                for (i = 0; vals[i] != NULL; i++) {
+                   if (++expansion > dict_ldap->expansion_limit &&
+                       dict_ldap->expansion_limit) {
+                       msg_warn("%s[%d]: %s: Expansion limit exceeded at"
+                              " result attribute %s=%s", myname, recursion,
+                                dict_ldap->ldapsource, attr, vals[i]);
+                       dict_errno = DICT_ERR_RETRY;
+                       break;
+                   }
                    if (VSTRING_LEN(result) > 0)
                        vstring_strcat(result, ",");
                    if (dict_ldap->result_filter == NULL)
                        vstring_strcat(result, vals[i]);
                    else
-                       dict_ldap_expand_filter(dict_ldap->result_filter,
+                       dict_ldap_expand_filter(dict_ldap->ldapsource,
+                                               dict_ldap->result_filter,
                                                vals[i], result);
                }
-           } else if (dict_ldap->result_attributes->argv[i]) {
+               if (dict_errno != 0)
+                   continue;
+               if (msg_verbose)
+                   msg_info("%s[%d]: search returned %ld value(s) for"
+                            " requested result attribute %s",
+                            myname, recursion, i, attr);
+           } else if (recursion < dict_ldap->recursion_limit
+                      && dict_ldap->result_attributes->argv[i]) {
+               /* Special result attribute */
                for (i = 0; vals[i] != NULL; i++) {
                    if (ldap_is_ldap_url(vals[i])) {
                        if (msg_verbose)
-                           msg_info("%s: looking up URL %s", myname,
-                                    vals[i]);
+                           msg_info("%s[%d]: looking up URL %s", myname,
+                                    recursion, vals[i]);
                        rc = ldap_url_parse(vals[i], &url);
                        if (rc == 0) {
                            rc = ldap_search_st(dict_ldap->ld, url->lud_dn,
@@ -557,7 +587,8 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
                        }
                    } else {
                        if (msg_verbose)
-                           msg_info("%s: looking up DN %s", myname, vals[i]);
+                           msg_info("%s[%d]: looking up DN %s",
+                                    myname, recursion, vals[i]);
                        rc = ldap_search_st(dict_ldap->ld, vals[i],
                                            LDAP_SCOPE_BASE, "objectclass=*",
                                         dict_ldap->result_attributes->argv,
@@ -573,27 +604,44 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res,
                         * Go ahead and treat this as though the DN existed
                         * and just didn't have any result attributes.
                         */
-                       msg_warn("%s: DN %s not found, skipping ", myname,
-                                vals[i]);
+                       msg_warn("%s[%d]: DN %s not found, skipping ", myname,
+                                recursion, vals[i]);
                        break;
                    default:
-                       msg_warn("%s: search error %d: %s ", myname, rc,
-                                ldap_err2string(rc));
+                       msg_warn("%s[%d]: search error %d: %s ", myname,
+                                recursion, rc, ldap_err2string(rc));
                        dict_errno = DICT_ERR_RETRY;
                        break;
                    }
 
                    if (resloop != 0)
                        ldap_msgfree(resloop);
+
+                   if (dict_errno != 0)
+                       break;
                }
+               if (dict_errno != 0)
+                   continue;
+               if (msg_verbose)
+                   msg_info("%s[%d]: search returned %ld value(s) for"
+                            " special result attribute %s",
+                            myname, recursion, i, attr);
+           } else if (recursion >= dict_ldap->recursion_limit
+                      && dict_ldap->result_attributes->argv[i]) {
+               msg_warn("%s[%d]: %s: Recursion limit exceeded"
+                        " for special attribute %s=%s",
+                  myname, recursion, dict_ldap->ldapsource, attr, vals[0]);
+               dict_errno = DICT_ERR_RETRY;
            }
            ldap_value_free(vals);
        }
        if (ber)
            ber_free(ber, 0);
     }
+
     if (msg_verbose)
-       msg_info("%s: Leaving %s", myname, myname);
+       msg_info("%s[%d]: Leaving %s", myname, recursion, myname);
+    --recursion;
 }
 
 /* dict_ldap_lookup - find database entry */
@@ -720,11 +768,11 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
        /*
         * No, log the fact and continue.
         */
-       msg_warn("%s: Fixed query_filter %s is probably useless", myname,
-                dict_ldap->query_filter);
+       msg_warn("%s: %s: Fixed query_filter %s is probably useless",
+                myname, dict_ldap->ldapsource, dict_ldap->query_filter);
        vstring_strcpy(filter_buf, dict_ldap->query_filter);
     } else {
-       dict_ldap_expand_filter(dict_ldap->query_filter,
+       dict_ldap_expand_filter(dict_ldap->ldapsource, dict_ldap->query_filter,
                                vstring_str(escaped_name), filter_buf);
     }
 
@@ -858,6 +906,7 @@ DICT   *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
     char   *domainlist;
     char   *scope;
     char   *attr;
+    int     tmp;
 
     if (msg_verbose)
        msg_info("%s: Using LDAP source %s", myname, ldapsource);
@@ -1040,31 +1089,58 @@ DICT   *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
      * get configured value of "ldapsource_cache"; default to false
      */
     vstring_sprintf(config_param, "%s_cache", ldapsource);
-    dict_ldap->cache = get_mail_conf_bool(vstring_str(config_param), 0);
-    if (msg_verbose)
-       msg_info("%s: %s is %d", myname, vstring_str(config_param),
-                dict_ldap->cache);
+    tmp = get_mail_conf_bool(vstring_str(config_param), 0);
+    if (tmp)
+       msg_warn("%s: ignoring %s", myname, vstring_str(config_param));
 
     /*
      * get configured value of "ldapsource_cache_expiry"; default to 30
      * seconds
      */
     vstring_sprintf(config_param, "%s_cache_expiry", ldapsource);
-    dict_ldap->cache_expiry = get_mail_conf_int(vstring_str(config_param),
-                                               30, 0, 0);
-    if (msg_verbose)
-       msg_info("%s: %s is %ld", myname, vstring_str(config_param),
-                dict_ldap->cache_expiry);
+    tmp = get_mail_conf_int(vstring_str(config_param), -1, 0, 0);
+    if (tmp >= 0)
+       msg_warn("%s: ignoring %s", myname, vstring_str(config_param));
 
     /*
      * get configured value of "ldapsource_cache_size"; default to 32k
      */
     vstring_sprintf(config_param, "%s_cache_size", ldapsource);
-    dict_ldap->cache_size = get_mail_conf_int(vstring_str(config_param),
-                                             32768, 0, 0);
+    tmp = get_mail_conf_int(vstring_str(config_param), -1, 0, 0);
+    if (tmp >= 0)
+       msg_warn("%s: ignoring %s", myname, vstring_str(config_param));
+
+    /*
+     * get configured value of "ldapsource_recursion_limit"; default to 1000
+     */
+    vstring_sprintf(config_param, "%s_recursion_limit", ldapsource);
+    dict_ldap->recursion_limit = get_mail_conf_int(vstring_str(config_param),
+                                                  1000, 1, 0);
+    if (msg_verbose)
+       msg_info("%s: %s is %ld", myname, vstring_str(config_param),
+                dict_ldap->recursion_limit);
+
+    /*
+     * get configured value of "ldapsource_expansion_limit"; default to 1000
+     */
+    vstring_sprintf(config_param, "%s_expansion_limit", ldapsource);
+    dict_ldap->expansion_limit = get_mail_conf_int(vstring_str(config_param),
+                                                  0, 0, 0);
+    if (msg_verbose)
+       msg_info("%s: %s is %ld", myname, vstring_str(config_param),
+                dict_ldap->expansion_limit);
+
+    /*
+     * get configured value of "ldapsource_size_limit"; default to
+     * expansion_limit
+     */
+    vstring_sprintf(config_param, "%s_size_limit", ldapsource);
+    dict_ldap->size_limit = get_mail_conf_int(vstring_str(config_param),
+                                             dict_ldap->expansion_limit,
+                                             0, 0);
     if (msg_verbose)
        msg_info("%s: %s is %ld", myname, vstring_str(config_param),
-                dict_ldap->cache_size);
+                dict_ldap->size_limit);
 
     /*
      * Alias dereferencing suggested by Mike Mattice.
index 0e01366f2d19a88e306186b68abe39b1ac5302cc..32fa0ae498d56a5e4f3f0662db2db9dbf92286e7 100644 (file)
 #include <dict_pcre.h>
 #include <dict_regexp.h>
 #include <dict_static.h>
+#include <dict_cidr.h>
 #include <stringops.h>
 #include <split_at.h>
 #include <htable.h>
@@ -193,9 +194,7 @@ typedef struct {
 static DICT_OPEN_INFO dict_open_info[] = {
     DICT_TYPE_ENVIRON, dict_env_open,
     DICT_TYPE_UNIX, dict_unix_open,
-#if 0
     DICT_TYPE_TCP, dict_tcp_open,
-#endif
 #ifdef HAS_DBM
     DICT_TYPE_DBM, dict_dbm_open,
 #endif
@@ -228,6 +227,7 @@ static DICT_OPEN_INFO dict_open_info[] = {
     DICT_TYPE_REGEXP, dict_regexp_open,
 #endif
     DICT_TYPE_STATIC, dict_static_open,
+    DICT_TYPE_CIDR, dict_cidr_open,
     0,
 };
 
index 38c77b902987df95e9b1691b9c3247c809203cd7..4745281e0f45fb30ebc332b18d7692dd75eb5610 100644 (file)
@@ -73,6 +73,7 @@
 typedef struct {
     char   *regexp;                    /* regular expression */
     int     options;                   /* options */
+    int     match;                     /* positive or negative match */
 } DICT_PCRE_REGEXP;
 
 typedef struct {
@@ -95,12 +96,14 @@ typedef struct {
     pcre   *pattern;                   /* compiled pattern */
     pcre_extra *hints;                 /* hints to speed pattern execution */
     char   *replacement;               /* replacement string */
+    int     match;                     /* positive or negative match */
 } DICT_PCRE_MATCH_RULE;
 
 typedef struct {
     DICT_PCRE_RULE rule;               /* generic members */
     pcre   *pattern;                   /* compiled pattern */
     pcre_extra *hints;                 /* hints to speed pattern execution */
+    int     match;                     /* positive or negative match */
 } DICT_PCRE_IF_RULE;
 
  /*
@@ -132,6 +135,7 @@ typedef struct {
     const char *mapname;               /* name of regexp map */
     int     lineno;                    /* where in file */
     int     flags;                     /* dict_flags */
+    size_t  max_sub;                   /* Largest $n seen */
 } DICT_PCRE_PRESCAN_CONTEXT;
 
  /*
@@ -251,13 +255,23 @@ static const char *dict_pcre_lookup(DICT *dict, const char *lookup_string)
                                     lookup_string, lookup_len,
                                     NULL_STARTOFFSET, NULL_EXEC_OPTIONS,
                                     ctxt.offsets, PCRE_MAX_CAPTURE * 3);
-           if (ctxt.matches == PCRE_ERROR_NOMATCH)
-               continue;
-           if (ctxt.matches <= 0) {
+
+           if (ctxt.matches > 0) {
+               if (!match_rule->match)
+                   continue;                   /* Negative rule matched */
+           } else if (ctxt.matches == PCRE_ERROR_NOMATCH) {
+               if (match_rule->match)
+                   continue;                   /* Positive rule did not
+                                                * match */
+           } else {
                dict_pcre_exec_error(dict->name, rule->lineno, ctxt.matches);
-               continue;
+               continue;                       /* pcre_exec failed */
            }
 
+           /* Negative rules can't have any substitutions */
+           if (!match_rule->match)
+               return match_rule->replacement;
+
            /*
             * We've got a match. Perform substitution on replacement string.
             */
@@ -289,11 +303,17 @@ static const char *dict_pcre_lookup(DICT *dict, const char *lookup_string)
                                     lookup_string, lookup_len,
                                     NULL_STARTOFFSET, NULL_EXEC_OPTIONS,
                                     ctxt.offsets, PCRE_MAX_CAPTURE * 3);
-           if (ctxt.matches == PCRE_ERROR_NOMATCH)
-               continue;
-           if (ctxt.matches <= 0) {
+
+           if (ctxt.matches > 0) {
+               if (!if_rule->match)
+                   continue;                   /* Negative rule matched */
+           } else if (ctxt.matches == PCRE_ERROR_NOMATCH) {
+               if (if_rule->match)
+                   continue;                   /* Positive rule did not
+                                                * match */
+           } else {
                dict_pcre_exec_error(dict->name, rule->lineno, ctxt.matches);
-               continue;
+               continue;                       /* pcre_exec failed */
            }
            nesting++;
            continue;
@@ -359,6 +379,25 @@ static int dict_pcre_get_pattern(const char *mapname, int lineno, char **bufp,
     char   *p = *bufp;
     char    re_delimiter;
 
+    /*
+     * Process negation operators.
+     */
+    pattern->match = 1;
+    while (*p == '!') {
+       pattern->match = !pattern->match;
+       p++;
+    }
+
+    /*
+     * Grr...aceful handling of whitespace after '!'.
+     */
+    while (*p && ISSPACE(*p))
+       p++;
+    if (*p == 0) {
+       msg_warn("pcre map %s, line %d: no regexp: skipping this rule",
+                mapname, lineno);
+       return (0);
+    }
     re_delimiter = *p++;
     pattern->regexp = p;
 
@@ -433,11 +472,10 @@ static int dict_pcre_prescan(int type, VSTRING *buf, char *context)
     if (type == MAC_PARSE_VARNAME) {
        if (ctxt->flags & DICT_FLAG_NO_REGSUB) {
            msg_warn("pcre map %s, line %d: "
-                     "regular expression substitution is not allowed",
-                     ctxt->mapname, ctxt->lineno);
+                    "regular expression substitution is not allowed",
+                    ctxt->mapname, ctxt->lineno);
            return (MAC_PARSE_ERROR);
        }
-
        if (!alldig(vstring_str(buf))) {
            msg_warn("pcre map %s, line %d: non-numeric replacement index \"%s\"",
                     ctxt->mapname, ctxt->lineno, vstring_str(buf));
@@ -449,6 +487,8 @@ static int dict_pcre_prescan(int type, VSTRING *buf, char *context)
                     ctxt->mapname, ctxt->lineno, vstring_str(buf));
            return (MAC_PARSE_ERROR);
        }
+       if (n > ctxt->max_sub)
+           ctxt->max_sub = n;
     }
     return (MAC_PARSE_OK);
 }
@@ -536,6 +576,7 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
        prescan_context.mapname = mapname;
        prescan_context.lineno = lineno;
        prescan_context.flags = dict_flags;
+       prescan_context.max_sub = 0;
 
        if (mac_parse(p, dict_pcre_prescan, (char *) &prescan_context)
            & MAC_PARSE_ERROR) {
@@ -544,6 +585,15 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
            return (0);
        }
 
+       /*
+        * Substring replacement not possible with negative regexps.
+        */
+       if (prescan_context.max_sub > 0 && regexp.match == 0) {
+           msg_warn("pcre map %s, line %d: $number found in negative match "
+                  "replacement text: skipping this rule", mapname, lineno);
+           return (0);
+       }
+
        /*
         * Compile the pattern.
         */
@@ -556,6 +606,7 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
        match_rule = (DICT_PCRE_MATCH_RULE *)
            dict_pcre_rule_alloc(DICT_PCRE_OP_MATCH, nesting, lineno,
                                 sizeof(DICT_PCRE_MATCH_RULE));
+       match_rule->match = regexp.match;
        match_rule->replacement = mystrdup(p);
        match_rule->pattern = engine.pattern;
        match_rule->hints = engine.hints;
@@ -583,6 +634,8 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
        /*
         * Warn about out-of-place text.
         */
+       while (*p && ISSPACE(*p))
+           ++p;
        if (*p)
            msg_warn("pcre map %s, line %d: ignoring extra text after IF",
                     mapname, lineno);
@@ -599,6 +652,7 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
        if_rule = (DICT_PCRE_IF_RULE *)
            dict_pcre_rule_alloc(DICT_PCRE_OP_IF, nesting, lineno,
                                 sizeof(DICT_PCRE_IF_RULE));
+       if_rule->match = regexp.match;
        if_rule->pattern = engine.pattern;
        if_rule->hints = engine.hints;
        return ((DICT_PCRE_RULE *) if_rule);
@@ -624,6 +678,8 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
        /*
         * Warn about out-of-place text.
         */
+       while (*p && ISSPACE(*p))
+           ++p;
        if (*p)
            msg_warn("pcre map %s, line %d: ignoring extra text after ENDIF",
                     mapname, lineno);
index 1dcba54a1b527191c4bca7876d4c937f33e45882..324342e8313860b8bb1621599981e5da59a59287 100644 (file)
@@ -8,3 +8,7 @@ get c
 get d
 get 1234
 get 123
+get bar/find
+get bar/whynot
+get bar/elbereth
+get say/elbereth
index 690899c3fec5d21363867afe46eb17f5e65115a7..948b5c35367133f7bd855a7e1ca9462b513d5b2b 100644 (file)
@@ -10,3 +10,12 @@ endif
 /(1)(2)(3)(5)/ ($1)($2)($3)($4)($5)
 /(1)(2)(3)(4)/ ($1)($2)($3)($4)
 /(1)(2)(3)/    ($1)($2)($3)
+# trailing whitespace below
+if /bar/       
+if !/xyzzy/
+/(elbereth)/   ($1)
+!/(bogus)/     ($1)
+!/find/                Don't have a liquor license
+endif
+endif   
+# trailing whitespace above
index daae8bcec5cc6213fe624dbd8787646af683fbbc..4b5910790b7492e18abcb8ae80aa419776a87036 100644 (file)
@@ -2,6 +2,7 @@
 ./dict_open: warning: pcre map dict_pcre.map, line 5: ignoring extra text after ENDIF
 ./dict_open: warning: pcre map dict_pcre.map, line 8: unknown regexp option "!": skipping this rule
 ./dict_open: warning: dict_pcre.map, line 9: no replacement text: using empty string
+./dict_open: warning: pcre map dict_pcre.map, line 17: $number found in negative match replacement text: skipping this rule
 true: not found
 true1=1
 true2: not found
@@ -12,3 +13,7 @@ c=
 d: not found
 1234=(1)(2)(3)(4)
 123=(1)(2)(3)
+bar/find: not found
+bar/whynot=Don't have a liquor license
+bar/elbereth=(elbereth)
+say/elbereth: not found
index 5735ca8a831fc656b181050617abe511d7868aaa..73ea34f28e3ca7b23d9464e30d93783541ad0998 100644 (file)
@@ -584,9 +584,9 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *mapname, int lineno,
            first_pat.options |= REG_NOSUB;
        } else if (dict_flags & DICT_FLAG_NO_REGSUB) {
            msg_warn("regexp map %s, line %d: "
-                     "regular expression substitution is not allowed: "
-                     "skipping this rule", mapname, lineno);
-           return(0);
+                    "regular expression substitution is not allowed: "
+                    "skipping this rule", mapname, lineno);
+           return (0);
        }
        if ((first_exp = dict_regexp_compile_pat(mapname, lineno,
                                                 &first_pat)) == 0)
@@ -636,6 +636,8 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *mapname, int lineno,
            p++;
        if (!dict_regexp_get_pat(mapname, lineno, &p, &pattern))
            return (0);
+       while (*p && ISSPACE(*p))
+           ++p;
        if (*p)
            msg_warn("regexp map %s, line %d: ignoring extra text after IF",
                     mapname, lineno);
@@ -661,6 +663,8 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *mapname, int lineno,
                     mapname, lineno);
            return (0);
        }
+       while (*p && ISSPACE(*p))
+           ++p;
        if (*p)
            msg_warn("regexp map %s, line %d: ignoring extra text after ENDIF",
                     mapname, lineno);
index 4e4b473b195dcd336e05a6e8c588ffe3f484c198..d5f3b2ed07acdda680adcdb953777f8256d9da33 100644 (file)
@@ -11,3 +11,7 @@ get aa
 get 1235
 get 1234
 get 123
+get bar/find
+get bar/whynot
+get bar/elbereth
+get say/elbereth
index 690899c3fec5d21363867afe46eb17f5e65115a7..948b5c35367133f7bd855a7e1ca9462b513d5b2b 100644 (file)
@@ -10,3 +10,12 @@ endif
 /(1)(2)(3)(5)/ ($1)($2)($3)($4)($5)
 /(1)(2)(3)(4)/ ($1)($2)($3)($4)
 /(1)(2)(3)/    ($1)($2)($3)
+# trailing whitespace below
+if /bar/       
+if !/xyzzy/
+/(elbereth)/   ($1)
+!/(bogus)/     ($1)
+!/find/                Don't have a liquor license
+endif
+endif   
+# trailing whitespace above
index 2ca40eb9335d44bcce863cfd7091eb7cfc710f2f..8cf7d82341bd8bfa9129903792a3b63647226f91 100644 (file)
@@ -2,6 +2,7 @@
 ./dict_open: warning: regexp map dict_regexp.map, line 5: ignoring extra text after ENDIF
 ./dict_open: warning: regexp map dict_regexp.map, line 9: using empty replacement string
 ./dict_open: warning: regexp map dict_regexp.map, line 10: out of range replacement index "5": skipping this rule
+./dict_open: warning: regexp map dict_regexp.map, line 17: $number found in negative match replacement text: skipping this rule
 true: not found
 true1=1
 true2: not found
@@ -15,3 +16,7 @@ aa=a!b
 1235=(1)(2)(3)
 1234=(1)(2)(3)(4)
 123=(1)(2)(3)
+bar/find: not found
+bar/whynot=Don't have a liquor license
+bar/elbereth=(elbereth)
+say/elbereth: not found
index 6686055802e5dc4dadfa95eb08cf2c1f5903671d..b7345feb824a915e5123e355ac87e93053d5f5c7 100644 (file)
@@ -27,8 +27,8 @@
 /* ENCODING
 /* .ad
 /* .fi
-/*     In request and reply parameters, the character % and any non-printable
-/*     characters (including whitespace) are replaced by %XX, XX being the
+/*     In request and reply parameters, the character % and any non-printing
+/*     and whitespace characters must be replaced by %XX, XX being the
 /*     corresponding ASCII hexadecimal character value. The hexadecimal codes
 /*     can be specified in any case (upper, lower, mixed).
 /* REQUEST FORMAT
@@ -43,7 +43,8 @@
 /* REPLY FORMAT
 /* .ad
 /* .fi
-/*      Replies can have the following form:
+/*      Replies must be no longer than 4096 characters including the
+/*     newline terminator, and must have the following form:
 /* .IP "500 SPACE optional-text NEWLINE"
 /*     In case of a lookup request, the requested data does not exist.
 /*     In case of an update request, the request was rejected.
 
 /* Utility library. */
 
-#include "msg.h"
-#include "mymalloc.h"
-#include "vstring.h"
-#include "vstream.h"
-#include "vstring_vstream.h"
-#include "connect.h"
-#include "hex_quote.h"
-#include "dict.h"
-#include "stringops.h"
-#include "dict_tcp.h"
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstring.h>
+#include <vstream.h>
+#include <vstring_vstream.h>
+#include <connect.h>
+#include <hex_quote.h>
+#include <dict.h>
+#include <stringops.h>
+#include <dict_tcp.h>
 
 /* Application-specific. */
 
@@ -103,8 +104,9 @@ typedef struct {
     VSTREAM *fp;                       /* I/O stream */
 } DICT_TCP;
 
-#define DICT_TCP_MAXTRY        10
-#define DICT_TCP_TMOUT 100
+#define DICT_TCP_MAXTRY        10              /* attempts before giving up */
+#define DICT_TCP_TMOUT 100             /* connect/read/write timeout */
+#define DICT_TCP_MAXLEN        4096            /* server reply size limit */
 
 #define STR(x)         vstring_str(x)
 
@@ -115,10 +117,10 @@ static int dict_tcp_connect(DICT_TCP *dict_tcp)
     int     fd;
 
     /*
-     * Connect to the server. Enforce a time limit on read/write operations
-     * so that we do not get stuck.
+     * Connect to the server. Enforce a time limit on all operations so that
+     * we do not get stuck.
      */
-    if ((fd = inet_connect(dict_tcp->dict.name, BLOCKING, 0)) < 0) {
+    if ((fd = inet_connect(dict_tcp->dict.name, NON_BLOCKING, DICT_TCP_TMOUT)) < 0) {
        msg_warn("connect to TCP map %s: %m", dict_tcp->dict.name);
        return (-1);
     }
@@ -153,6 +155,7 @@ static const char *dict_tcp_lookup(DICT *dict, const char *key)
     char   *myname = "dict_tcp_lookup";
     int     tries;
     char   *start;
+    int     last_ch;
 
 #define RETURN(errval, result) { dict_errno = errval; return (result); }
 
@@ -173,14 +176,22 @@ static const char *dict_tcp_lookup(DICT *dict, const char *key)
             */
            hex_quote(dict_tcp->hex_buf, key);
            vstream_fprintf(dict_tcp->fp, "get %s\n", STR(dict_tcp->hex_buf));
-           if (vstring_get_nonl(dict_tcp->hex_buf, dict_tcp->fp) > 0)
+           if (msg_verbose)
+               msg_info("%s: send \"get %s\"", myname, STR(dict_tcp->hex_buf));
+           last_ch = vstring_get_nonl_bound(dict_tcp->hex_buf, dict_tcp->fp,
+                                            DICT_TCP_MAXLEN);
+           if (last_ch == '\n')
                break;
 
            /*
             * Disconnect from the server if it can't talk to us.
             */
-           msg_warn("read TCP map reply from %s: unexpected EOF (%m)",
-                    dict_tcp->dict.name);
+           if (last_ch < 0)
+               msg_warn("read TCP map reply from %s: unexpected EOF (%m)",
+                        dict_tcp->dict.name);
+           else
+               msg_warn("read TCP map reply from %s: text longer than %d",
+                        dict_tcp->dict.name, DICT_TCP_MAXLEN);
            dict_tcp_disconnect(dict_tcp);
        }
 
@@ -195,6 +206,8 @@ static const char *dict_tcp_lookup(DICT *dict, const char *key)
         */
        sleep(1);
     }
+    if (msg_verbose)
+       msg_info("%s: recv: \"%s\"", myname, STR(dict_tcp->hex_buf));
 
     /*
      * Check the general reply syntax. If the reply is malformed, disconnect
@@ -205,7 +218,7 @@ static const char *dict_tcp_lookup(DICT *dict, const char *key)
        || !ISDIGIT(start[2]) || !ISSPACE(start[3])
        || !hex_unquote(dict_tcp->raw_buf, start + 4)) {
        msg_warn("read TCP map reply from %s: malformed reply %.100s",
-                dict_tcp->dict.name, printable(STR(dict_tcp->hex_buf), '_'));
+              dict_tcp->dict.name, printable(STR(dict_tcp->hex_buf), '_'));
        dict_tcp_disconnect(dict_tcp);
        RETURN(DICT_ERR_RETRY, 0);
     }
@@ -217,7 +230,7 @@ static const char *dict_tcp_lookup(DICT *dict, const char *key)
     switch (start[0]) {
     default:
        msg_warn("read TCP map reply from %s: bad status code %.100s",
-                dict_tcp->dict.name, printable(STR(dict_tcp->hex_buf), '_'));
+              dict_tcp->dict.name, printable(STR(dict_tcp->hex_buf), '_'));
        dict_tcp_disconnect(dict_tcp);
        RETURN(DICT_ERR_RETRY, 0);
     case '4':
@@ -268,5 +281,5 @@ DICT   *dict_tcp_open(const char *map, int unused_flags, int dict_flags)
     dict_tcp->dict.lookup = dict_tcp_lookup;
     dict_tcp->dict.close = dict_tcp_close;
     dict_tcp->dict.flags = dict_flags | DICT_FLAG_FIXED;
-    return (DICT_DEBUG(&dict_tcp->dict));
+    return (DICT_DEBUG (&dict_tcp->dict));
 }
index f82a92001bc939be3a484a228b3ed7caff4dfa46..662fdddc8aebd2007a94fd9a5731c0b6dae8cf1b 100644 (file)
@@ -15,7 +15,8 @@
 /*     const char *hex;
 /* DESCRIPTION
 /*     hex_quote() takes a null-terminated string and replaces non-printable
-/*     characters and % by %XX, XX being the two-digit hexadecimal equivalent.
+/*     and whitespace characters and the % by %XX, XX being the two-digit
+/*     hexadecimal equivalent.
 /*     The hexadecimal codes are produced as upper-case characters. The result
 /*     value is the hex argument.
 /*
@@ -61,7 +62,7 @@ VSTRING *hex_quote(VSTRING *hex, const char *raw)
 
     VSTRING_RESET(hex);
     for (cp = raw; (ch = *(unsigned const char *) cp) != 0; cp++) {
-       if (ch != '%' && ISPRINT(ch)) {
+       if (ch != '%' && !ISSPACE(ch) && ISPRINT(ch)) {
            VSTRING_ADDCH(hex, ch);
        } else {
            vstring_sprintf_append(hex, "%%%02X", ch);
index d1586f7be6a423c446110c4bc650b6dc4e7aa0cd..5d9e6a5d249d85f0159e4348072b319c93d6f50f 100644 (file)
@@ -69,7 +69,7 @@
 #endif
 
 #ifndef INADDR_NONE
-#define INADDR_NONE 0xffffff
+#define INADDR_NONE 0xffffffff
 #endif
 
 /* Utility library. */
index 657f9a32a12d54a1b08f87d12b03828ece10190c..c047a5bac546c96981301b82677b4adb188d04df 100644 (file)
@@ -244,12 +244,16 @@ VSTREAM *safe_open(const char *path, int flags, int mode,
        /*
         * Open an existing file or create a new one, carefully. When opening
         * an existing file, we are prepared to deal with "no file" errors
-        * only. Any other error means we better give up trying.
+        * only. When creating a file, we are prepared for "file exists"
+        * errors only. Any other error means we better give up trying.
         */
     case O_CREAT:
-       if ((fp = safe_open_exist(path, flags, st, why)) == 0)
-           if (errno == ENOENT)
-               fp = safe_open_create(path, flags, mode, st, user, group, why);
+       fp = safe_open_exist(path, flags, st, why);
+       if (fp == 0 && errno == ENOENT) {
+           fp = safe_open_create(path, flags, mode, st, user, group, why);
+           if (fp == 0 && errno == EEXIST)
+               fp = safe_open_exist(path, flags, st, why);
+       }
        return (fp);
 
        /*
index b0a5f2e350b220eaaa247dd53409acf35a321f82..23dd4b4d73f2eae815983e3394b7c400cb3317e6 100644 (file)
@@ -234,7 +234,7 @@ int     valid_hostliteral(const char *addr, int gripe)
            msg_warn("%s: unexpected text after ']': %.100s", myname, addr);
        return (0);
     }
-    if (last - addr >= sizeof(buf)) {
+    if (last >= addr + sizeof(buf)) {
        if (gripe)
            msg_warn("%s: too much text: %.100s", myname, addr);
        return (0);
index 443b07ecc291481e87c4c6d8de9011c24ab5396f..a68b726d38ce9c800fa3d8dd9d6a90b5e952dfd4 100644 (file)
@@ -29,7 +29,8 @@
 /* .IP "\fBVRFY_ADDR_UPDATE\fI address status text\fR"
 /*     Update the status of the specified address.
 /* .IP "\fBVRFY_ADDR_QUERY\fI address\fR"
-/*     Look up the \fIstatus\fR and \fItext\fR of the specified address.
+/*     Look up the \fIstatus\fR, \fIlast update time\fR and \fItext\fR 
+/*     of the specified address.
 /*     If the status is unknown, a probe is sent and a default status is
 /*     returned.
 /* .PP