2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-28 12:48:01 +00:00

postfix-2.0.13-20030702

This commit is contained in:
Wietse Venema 2003-07-02 00:00:00 -05:00 committed by Viktor Dukhovni
parent b1771bb6f5
commit 5884ef624c
101 changed files with 3223 additions and 829 deletions

2
postfix/.indent.pro vendored
View File

@ -26,6 +26,8 @@
-TDELIVER_ATTR
-TDELIVER_REQUEST
-TDICT
-TDICT_CIDR
-TDICT_CIDR_ENTRY
-TDICT_DB
-TDICT_DBM
-TDICT_DEBUG

View 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.

View 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 (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.
cache_expiry (30 seconds)
If the client-side cache is enabled, cached results will expire
after this many seconds.
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.
cache_size (32768 bytes)
If the client-side cache is enabled, this is its size in bytes.
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

View File

@ -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.

View 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.

View 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
===================================================

View File

@ -108,72 +108,75 @@
# 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...
@ -181,39 +184,40 @@
# 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)

77
postfix/conf/cidr_table Normal file
View File

@ -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)

View 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
@ -25,8 +23,10 @@
# 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,
@ -40,98 +40,104 @@
#
# 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
@ -160,6 +166,8 @@
#
# 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:

View 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

View 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)$'` ; \

View 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
@ -77,7 +75,10 @@
# 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
@ -106,6 +107,8 @@
#
# 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:

View File

@ -68,19 +68,40 @@
#
#ldap_bind_pw =
# The ldap_cache parameter specifies whether or not to turn on client-side
# caching.
#ldap_cache (IGNORED with a warning)
#ldap_cache_expiry (IGNORED with a warning)
#ldap_cache_size (IGNORED with a warning)
#
#ldap_cache = no
# The above parameters are NO LONGER SUPPORTED by Postfix.
# Cache support has been dropped from OpenLDAP as of release 2.1.13.
# The ldap_cache_expiry parameter specifies how many seconds to cache results
# for (if ldap_cache=yes)
#
#ldap_cache_expiry = 30
# 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_cache_size parameter specifies the cache size, in bytes.
# 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_cache_size = 32768
#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.

View 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.
#

View 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
#

View File

@ -8,22 +8,6 @@
# ADDRESS VERIFICATION (see also: verify(8) and SENDER_VERIFICATION_README)
#
# The address_verify_map configuration parameter specifies an optional
# table for persistent recipient status storage. The file is opened
# before the process enters a chroot jail and before it drops root
# privileges.
#
# By default, the information is kept in volatile memory, and is lost
# after postfix reload or postfix stop.
#
# Specify a pathname in a file system that will not fill up. If the
# database becomes corrupted, the world comes to an end. To recover
# you have to delete the file and do "postfix reload".
#
#address_verify_map = hash:/etc/postfix/verify
#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.
@ -38,6 +22,40 @@ address_verify_map =
#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 address status storage. The file is opened
# before the process enters a chroot jail and before it drops root
# privileges.
#
# By default, the information is kept in volatile memory, and is lost
# after postfix reload or postfix stop.
#
# Specify a pathname in a file system that will not fill up. If the
# database becomes corrupted, the world comes to an end. To recover
# you have to delete the file and do "postfix reload".
#
#address_verify_map = hash:/etc/postfix/verify
#address_verify_map = btree:/etc/postfix/verify
address_verify_map =
# The address_verify_positive_expire_time configuration parameter
# specifies the amount of time after which a known to be good address
# expires.

85
postfix/conf/tcp_table Normal file
View File

@ -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)

View File

@ -16,21 +16,40 @@
# 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
@ -41,28 +60,28 @@
# 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
@ -74,134 +93,134 @@
# 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
@ -214,7 +233,7 @@
# 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)

View 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>

View 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>

View 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>

View 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:

View 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:

View 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>

View 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.

View 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

View 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>

View 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:

View 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 $? >$@

View 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

View File

@ -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

View 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

View 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

View File

@ -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

View 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

View 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.

View 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

View 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

View 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

View 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/^/# /' >$@

View 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
@ -172,8 +175,9 @@
# 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

68
postfix/proto/cidr_table Normal file
View File

@ -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
#--

View 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 `#'.
@ -32,10 +31,12 @@
# 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
@ -108,7 +109,9 @@
# 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
@ -133,6 +136,8 @@
# # 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

View 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

75
postfix/proto/tcp_table Normal file
View File

@ -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
#--*/

View File

@ -14,6 +14,21 @@
# 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

View 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

View File

@ -155,6 +155,8 @@
#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);

View 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);

View File

@ -136,6 +136,11 @@
/* .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,

View 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[];

View 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,

View 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

View 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

View 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.

View 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 == '\\') {

View 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

View 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 */

View 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);
}

View 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)

View 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

View File

@ -20,10 +20,10 @@
* 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;
/*

View 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

View 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

View 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;
/* DESCRIPTION
/* xtext() takes a null-terminated string, and produces a translation
/* according to RFC 1894 (DSN).
/* BUGS
/* Cannot replace null characters.
/* VSTRING *xtext_quote(quoted, unquoted, special)
/* VSTRING *quoted;
/* const char *unquoted;
/* const char *special;
/*
/* Does not insert CR LF SPACE to limit output line length.
/* SEE ALSO
/* RFC 1894, Delivery Status Notifications
/* VSTRING *xtext_unquote(unquoted, quoted)
/* VSTRING *unquoted;
/* const char *quoted;
/* DESCRIPTION
/* 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.
/*
/* 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
@ -31,56 +38,112 @@
/* 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);
}
return (result);
/* xtext_unquote - quoted data to unquoted */
VSTRING *xtext_unquote(VSTRING *unquoted, const char *quoted)
{
const char *cp;
int ch;
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)
{
VSTRING *ibuf = vstring_alloc(100);
VSTRING *obuf = vstring_alloc(100);
#define BUFLEN 1024
while (vstring_fgets(ibuf, VSTREAM_IN)) {
vstream_fputs(STR(xtext(obuf, STR(ibuf))));
vstream_fflush(VSTREAM_OUT);
static int read_buf(VSTREAM *fp, VSTRING *buf)
{
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);
}
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);
}

View 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
@ -10,13 +13,14 @@
/*
* 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

View 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;

View 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;
}

View 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;

View 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) {

View File

@ -21,10 +21,6 @@
/* 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
@ -118,6 +114,9 @@
/* 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,
};

View 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,

View 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

View File

@ -97,6 +97,24 @@
/* 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
@ -245,6 +263,21 @@
/* 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
@ -289,10 +322,11 @@
/* .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
@ -368,12 +402,13 @@
/* 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);
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)
/*
* 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_HELO_NAME, state->helo_name);
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_PROTO_NAME, state->protocol);
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)
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;
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;
/*
* 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[] = {

View 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 *);

View 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;

View File

@ -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;
}

View File

@ -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
/*--*/

View 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)

View 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

View File

@ -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));
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -57,12 +57,27 @@
/* 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->cache_size);
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->size_limit);
/*
* Alias dereferencing suggested by Mike Mattice.

View File

@ -178,6 +178,7 @@
#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,
};

View 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);

View 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

View 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

View 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

View 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);

View 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

View 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

View 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

View 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.
@ -83,16 +84,16 @@
/* 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));
}

View 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);

View File

@ -69,7 +69,7 @@
#endif
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffff
#define INADDR_NONE 0xffffffff
#endif
/* Utility library. */

View 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);
/*

View 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);

Some files were not shown because too many files have changed in this diff Show More