2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-09-03 23:55:18 +00:00

postfix-2.3-20051226

This commit is contained in:
Wietse Venema
2005-12-26 00:00:00 -05:00
committed by Viktor Dukhovni
parent 51da02abb8
commit bb0be7749b
23 changed files with 334 additions and 219 deletions

View File

@@ -11660,6 +11660,23 @@ Apologies for any names omitted.
Bugfix: 20051219 "postconf -A" produced "postconf -a" output. Bugfix: 20051219 "postconf -A" produced "postconf -a" output.
Andreas Winkelmann. Andreas Winkelmann.
20051225
Bugfix: the regexp map cleverly avoided scanning constant
lookup results for non-existent $number expressions, but
failed to subject those results to the necessary $$ -> $
replacement. Files: util/dict_regexp.c.
Performance: the pcre map did not optimize constant lookup
results; they were always scanned for non-existent $number
expressions. File: util/dict_pcre.c.
This round of edits eliminates architectural differences
between the pcre and regexp table implementations. The
remaining difference is that regexp tables still support
the obsolete "/pattern1/!/pattern2/ action" syntax, for
backwards compatibility with Postfix 2.0 and earlier.
Open problems: Open problems:
"postsuper -r" no longer resets the message arrival time, "postsuper -r" no longer resets the message arrival time,
@@ -11670,11 +11687,6 @@ Open problems:
Is it safe to cache a connection after it has been used for Is it safe to cache a connection after it has been used for
more than some number of address verification probes? more than some number of address verification probes?
Access map actions such as FILTER and REDIRECT don't work
in smtpd_end_of_data_restrictions (or anything else that
generates additional queue file records after the message
content is stored).
Try to recognize that Resent- headers appear in blocks, Try to recognize that Resent- headers appear in blocks,
newest block first. But don't break on incorrect header newest block first. But don't break on incorrect header
block organization. block organization.

View File

@@ -10,7 +10,9 @@ delivery notifications.
Specifically, DSN support gives an email sender the ability to specify: Specifically, DSN support gives an email sender the ability to specify:
* What notifications are sent: success, failure, delay, or none. * What notifications are sent: success, failure, delay, or none. Normally,
Postfix informs the sender only mail when delivery is delayed or when
delivery fails.
* What content is returned in case of failure: only the message headers, or * What content is returned in case of failure: only the message headers, or
the full message. the full message.
@@ -37,9 +39,11 @@ Unfortunately, disallowing "success" notification requests requires disallowing
other DSN requests as well. The RFCs do not offer the option to negotiate other DSN requests as well. The RFCs do not offer the option to negotiate
feature subsets. feature subsets.
This is not as bad as it sounds. Remote senders with DSN support will still be This is not as bad as it sounds. When you turn off DSN for remote inbound mail,
informed that their mail reached your Postfix gateway successfully; they just remote senders with DSN support will still be informed that their mail reached
will not get successful delivery notices from your internal systems. your Postfix gateway successfully; they just will not get successful delivery
notices from your internal systems. Remote senders lose very little: they can
no longer specify how Postfix should report delayed or failed delivery.
Use the smtpd_discard_ehlo_keyword_address_maps feature if you wish to allow Use the smtpd_discard_ehlo_keyword_address_maps feature if you wish to allow
DSN requests from trusted clients but not from random strangers (see below for DSN requests from trusted clients but not from random strangers (see below for

View File

@@ -221,33 +221,27 @@
# transport(5) table to direct mail to the discard(8) # transport(5) table to direct mail to the discard(8)
# service. # service.
# #
# Note: this action does not work in Postfix 2.2
# smtpd_end_of_data_restrictions.
#
# This feature is available in Postfix 2.0 and later. # This feature is available in Postfix 2.0 and later.
# #
# DUNNO Pretend that the lookup key was not found. This # DUNNO Pretend that the lookup key was not found. This
# prevents Postfix from trying substrings of the # prevents Postfix from trying substrings of the
# lookup key (such as a subdomain name, or a network # lookup key (such as a subdomain name, or a network
# address subnetwork). # address subnetwork).
# #
# This feature is available in Postfix 2.0 and later. # This feature is available in Postfix 2.0 and later.
# #
# FILTER transport:destination # FILTER transport:destination
# After the message is queued, send the entire mes- # After the message is queued, send the entire mes-
# sage through the specified external content filter. # sage through the specified external content filter.
# The transport:destination syntax is described in # The transport:destination syntax is described in
# the transport(5) manual page. More information # the transport(5) manual page. More information
# about external content filters is in the Postfix # about external content filters is in the Postfix
# FILTER_README file. # FILTER_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 # tent_filter setting, and currently affects all
# recipients of the message. # recipients of the message.
# #
# Note: this action does not work in Postfix 2.2
# smtpd_end_of_data_restrictions.
#
# This feature is available in Postfix 2.0 and later. # This feature is available in Postfix 2.0 and later.
# #
# HOLD optional text... # HOLD optional text...
@@ -268,37 +262,31 @@
# Note: this action currently affects all recipients # Note: this action currently affects all recipients
# of the message. # of the message.
# #
# Note: this action does not work in Postfix 2.2
# smtpd_end_of_data_restrictions.
#
# This feature is available in Postfix 2.0 and later. # This feature is available in Postfix 2.0 and later.
# #
# PREPEND headername: headervalue # PREPEND headername: headervalue
# Prepend the specified message header to the mes- # Prepend the specified message header to the mes-
# sage. When this action is used multiple times, the # sage. When this action is used multiple times, the
# first prepended header appears before the second # first prepended header appears before the second
# etc. prepended header. # etc. prepended header.
# #
# Note: this action does not support multi-line mes- # Note: this action does not support multi-line mes-
# sage headers. # sage headers.
# #
# Note: this action must be used before the message # Note: this action must be used before the message
# content is received; it cannot be used in # content is received; it cannot be used in
# smtpd_end_of_data_restrictions. # smtpd_end_of_data_restrictions.
# #
# This feature is available in Postfix 2.1 and later. # This feature is available in Postfix 2.1 and later.
# #
# REDIRECT user@domain # 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 # the specified address instead of the intended
# recipient(s). # 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. # currently affects all recipients of the message.
# #
# Note: this action does not work in Postfix 2.2
# smtpd_end_of_data_restrictions.
#
# This feature is available in Postfix 2.1 and later. # This feature is available in Postfix 2.1 and later.
# #
# WARN optional text... # WARN optional text...

View File

@@ -30,7 +30,8 @@ specify: </p>
<ul> <ul>
<li> <p> What notifications are sent: success, failure, delay, or <li> <p> What notifications are sent: success, failure, delay, or
none. </p> none. Normally, Postfix informs the sender only mail when delivery
is delayed or when delivery fails. </p>
<li> <p> What content is returned in case of failure: only the <li> <p> What content is returned in case of failure: only the
message headers, or the full message. </p> message headers, or the full message. </p>
@@ -68,10 +69,12 @@ internal infrastructure than desirable. Unfortunately, disallowing
requests as well. The RFCs do not offer the option to negotiate requests as well. The RFCs do not offer the option to negotiate
feature subsets. </p> feature subsets. </p>
<p> This is not as bad as it sounds. Remote senders with DSN support <p> This is not as bad as it sounds. When you turn off DSN for
will still be informed that their mail reached your Postfix gateway remote inbound mail, remote senders with DSN support will still be
successfully; they just will not get successful delivery notices informed that their mail reached your Postfix gateway successfully;
from your internal systems. </p> they just will not get successful delivery notices from your internal
systems. Remote senders lose very little: they can no longer specify
how Postfix should report delayed or failed delivery. </p>
<p> Use the <a href="postconf.5.html#smtpd_discard_ehlo_keyword_address_maps">smtpd_discard_ehlo_keyword_address_maps</a> feature if you <p> Use the <a href="postconf.5.html#smtpd_discard_ehlo_keyword_address_maps">smtpd_discard_ehlo_keyword_address_maps</a> feature if you
wish to allow DSN requests from trusted clients but not from random wish to allow DSN requests from trusted clients but not from random

View File

@@ -227,33 +227,27 @@ ACCESS(5) ACCESS(5)
<a href="transport.5.html">transport(5)</a> table to direct mail to the <a href="discard.8.html">discard(8)</a> <a href="transport.5.html">transport(5)</a> table to direct mail to the <a href="discard.8.html">discard(8)</a>
service. service.
Note: this action does not work in Postfix 2.2
<b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a></b>.
This feature is available in Postfix 2.0 and later. This feature is available in Postfix 2.0 and later.
<b>DUNNO</b> Pretend that the lookup key was not found. This <b>DUNNO</b> Pretend that the lookup key was not found. This
prevents Postfix from trying substrings of the prevents Postfix from trying substrings of the
lookup key (such as a subdomain name, or a network lookup key (such as a subdomain name, or a network
address subnetwork). address subnetwork).
This feature is available in Postfix 2.0 and later. This feature is available in Postfix 2.0 and later.
<b>FILTER</b> <i>transport:destination</i> <b>FILTER</b> <i>transport:destination</i>
After the message is queued, send the entire mes- After the message is queued, send the entire mes-
sage through the specified external content filter. sage through the specified external content filter.
The <i>transport:destination</i> syntax is described in The <i>transport:destination</i> syntax is described in
the <a href="transport.5.html"><b>transport</b>(5)</a> manual page. More information the <a href="transport.5.html"><b>transport</b>(5)</a> manual page. More information
about external content filters is in the Postfix about external content filters is in the Postfix
<a href="FILTER_README.html">FILTER_README</a> file. <a href="FILTER_README.html">FILTER_README</a> file.
Note: this action overrides the <b>main.cf <a href="postconf.5.html#content_filter">con</a>-</b> Note: this action overrides the <b>main.cf <a href="postconf.5.html#content_filter">con</a>-</b>
<b><a href="postconf.5.html#content_filter">tent_filter</a></b> setting, and currently affects all <b><a href="postconf.5.html#content_filter">tent_filter</a></b> setting, and currently affects all
recipients of the message. recipients of the message.
Note: this action does not work in Postfix 2.2
<b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a></b>.
This feature is available in Postfix 2.0 and later. This feature is available in Postfix 2.0 and later.
<b>HOLD</b> <i>optional text...</i> <b>HOLD</b> <i>optional text...</i>
@@ -274,37 +268,31 @@ ACCESS(5) ACCESS(5)
Note: this action currently affects all recipients Note: this action currently affects all recipients
of the message. of the message.
Note: this action does not work in Postfix 2.2
<b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a></b>.
This feature is available in Postfix 2.0 and later. This feature is available in Postfix 2.0 and later.
<b>PREPEND</b> <i>headername: headervalue</i> <b>PREPEND</b> <i>headername: headervalue</i>
Prepend the specified message header to the mes- Prepend the specified message header to the mes-
sage. When this action is used multiple times, the sage. When this action is used multiple times, the
first prepended header appears before the second first prepended header appears before the second
etc. prepended header. etc. prepended header.
Note: this action does not support multi-line mes- Note: this action does not support multi-line mes-
sage headers. sage headers.
Note: this action must be used before the message Note: this action must be used before the message
content is received; it cannot be used in content is received; it cannot be used in
<b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a></b>. <b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a></b>.
This feature is available in Postfix 2.1 and later. This feature is available in Postfix 2.1 and later.
<b>REDIRECT</b> <i>user@domain</i> <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 the specified address instead of the intended
recipient(s). 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. currently affects all recipients of the message.
Note: this action does not work in Postfix 2.2
<b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a></b>.
This feature is available in Postfix 2.1 and later. This feature is available in Postfix 2.1 and later.
<b>WARN</b> <i>optional text...</i> <b>WARN</b> <i>optional text...</i>

View File

@@ -50,112 +50,120 @@ PCRE_TABLE(5) PCRE_TABLE(5)
Note: do not prepend whitespace to patterns inside Note: do not prepend whitespace to patterns inside
<b>if</b>..<b>endif</b>. <b>if</b>..<b>endif</b>.
This feature is available in Postfix 2.1 and later.
<b>if !/</b><i>pattern</i><b>/</b><i>flags</i> <b>if !/</b><i>pattern</i><b>/</b><i>flags</i>
<b>endif</b> Match the input string against the patterns between <b>endif</b> Match the input string against the patterns between
<b>if</b> and <b>endif</b>, if and only if the input string does <b>if</b> and <b>endif</b>, if and only if the input string does
<b>not</b> match <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest. <b>not</b> match <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
Note: do not prepend whitespace to patterns inside
<b>if</b>..<b>endif</b>.
This feature is available in Postfix 2.1 and later.
blank lines and comments blank lines and comments
Empty lines and whitespace-only lines are ignored, Empty lines and whitespace-only lines are ignored,
as are lines whose first non-whitespace character as are lines whose first non-whitespace character
is a `#'. is a `#'.
multi-line text multi-line text
A logical line starts with non-whitespace text. A A logical line starts with non-whitespace text. A
line that starts with whitespace continues a logi- line that starts with whitespace continues a logi-
cal line. cal line.
Each pattern is a perl-like regular expression. The Each pattern is a perl-like regular expression. The
expression delimiter can be any character, except white- expression delimiter can be any character, except white-
space or characters that have special meaning (tradition- space or characters that have special meaning (tradition-
ally the forward slash is used). The regular expression ally the forward slash is used). The regular expression
can contain whitespace. can contain whitespace.
By default, matching is case-insensitive, and newlines are By default, matching is case-insensitive, and newlines are
not treated as special characters. The behavior is con- not treated as special characters. The behavior is con-
trolled by flags, which are toggled by appending one or trolled by flags, which are toggled by appending one or
more of the following characters after the pattern: more of the following characters after the pattern:
<b>i</b> (default: on) <b>i</b> (default: on)
Toggles the case sensitivity flag. By default, Toggles the case sensitivity flag. By default,
matching is case insensitive. matching is case insensitive.
<b>m</b> (default: off) <b>m</b> (default: off)
Toggles the PCRE_MULTILINE flag. When this flag is Toggles the PCRE_MULTILINE flag. When this flag is
on, the <b>^</b> and <b>$</b> metacharacters match immediately on, the <b>^</b> and <b>$</b> metacharacters match immediately
after and immediately before a newline character, after and immediately before a newline character,
respectively, in addition to matching at the start respectively, in addition to matching at the start
and end of the subject string. and end of the subject string.
<b>s</b> (default: on) <b>s</b> (default: on)
Toggles the PCRE_DOTALL flag. When this flag is on, Toggles the PCRE_DOTALL flag. When this flag is on,
the <b>.</b> metacharacter matches the newline character. the <b>.</b> metacharacter matches the newline character.
With Postfix versions prior to 2.0, The flag is off With Postfix versions prior to 2.0, The flag is off
by default, which is inconvenient for multi-line by default, which is inconvenient for multi-line
message header matching. message header matching.
<b>x</b> (default: off) <b>x</b> (default: off)
Toggles the pcre extended flag. When this flag is Toggles the pcre extended flag. When this flag is
on, whitespace in the pattern (other than in a on, whitespace in the pattern (other than in a
character class) and characters between a <b>#</b> outside character class) and characters between a <b>#</b> outside
a character class and the next newline character a character class and the next newline character
are ignored. An escaping backslash can be used to are ignored. An escaping backslash can be used to
include a whitespace or <b>#</b> character as part of the include a whitespace or <b>#</b> character as part of the
pattern. pattern.
<b>A</b> (default: off) <b>A</b> (default: off)
Toggles the PCRE_ANCHORED flag. When this flag is Toggles the PCRE_ANCHORED flag. When this flag is
on, the pattern is forced to be "anchored", that on, the pattern is forced to be "anchored", that
is, it is constrained to match only at the start of is, it is constrained to match only at the start of
the string which is being searched (the "subject the string which is being searched (the "subject
string"). This effect can also be achieved by string"). This effect can also be achieved by
appropriate constructs in the pattern itself. appropriate constructs in the pattern itself.
<b>E</b> (default: off) <b>E</b> (default: off)
Toggles the PCRE_DOLLAR_ENDONLY flag. When this Toggles the PCRE_DOLLAR_ENDONLY flag. When this
flag is on, a <b>$</b> metacharacter in the pattern flag is on, a <b>$</b> metacharacter in the pattern
matches only at the end of the subject string. matches only at the end of the subject string.
Without this flag, a dollar also matches immedi- Without this flag, a dollar also matches immedi-
ately before the final character if it is a newline ately before the final character if it is a newline
character (but not before any other newline charac- 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. is set.
<b>U</b> (default: off) <b>U</b> (default: off)
Toggles the ungreedy matching flag. When this flag Toggles the ungreedy matching flag. When this flag
is on, the pattern matching engine inverts the is on, the pattern matching engine inverts the
"greediness" of the quantifiers so that they are "greediness" of the quantifiers so that they are
not greedy by default, but become greedy if fol- not greedy by default, but become greedy if fol-
lowed by "?". This flag can also set by a (?U) lowed by "?". This flag can also set by a (?U)
modifier within the pattern. modifier within the pattern.
<b>X</b> (default: off) <b>X</b> (default: off)
Toggles the PCRE_EXTRA flag. When this flag is on, 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, letter that has no special meaning causes an error,
thus reserving these combinations for future expan- thus reserving these combinations for future expan-
sion. sion.
<b>SEARCH ORDER</b> <b>SEARCH ORDER</b>
Patterns are applied in the order as specified in the ta- Patterns are applied in the order as specified in the ta-
ble, until a pattern is found that matches the input ble, until a pattern is found that matches the input
string. string.
Each pattern is applied to the entire input string. Each pattern is applied to the entire input string.
Depending on the application, that string is an entire Depending on the application, that string is an entire
client hostname, an entire client IP address, or an entire client hostname, an entire client IP address, or an entire
mail address. Thus, no parent domain or parent network mail address. Thus, no parent domain or parent network
search is done, and <i>user@domain</i> mail addresses are not 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, 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>. nor is <i>user+foo</i> broken up into <i>user</i> and <i>foo</i>.
<b>TEXT SUBSTITUTION</b> <b>TEXT SUBSTITUTION</b>
Substitution of substrings from the matched expression Substitution of substrings from the matched expression
into the result string is possible using the conventional into the result string is possible using the conventional
perl syntax ($1, $2, etc.). The macros in the result perl syntax ($1, $2, etc.); specify $$ to produce a $
string may need to be written as ${n} or $(n) if they character as output. The macros in the result string may
aren't followed by whitespace. need to be written as ${n} or $(n) if they aren't followed
by whitespace.
Note: since negated patterns (those preceded by <b>!</b>) return Note: since negated patterns (those preceded by <b>!</b>) return
a result when the expression does not match, substitutions a result when the expression does not match, substitutions

View File

@@ -50,11 +50,19 @@ REGEXP_TABLE(5) REGEXP_TABLE(5)
Note: do not prepend whitespace to patterns inside Note: do not prepend whitespace to patterns inside
<b>if</b>..<b>endif</b>. <b>if</b>..<b>endif</b>.
This feature is available in Postfix 2.1 and later.
<b>if !/</b><i>pattern</i><b>/</b><i>flags</i> <b>if !/</b><i>pattern</i><b>/</b><i>flags</i>
<b>endif</b> Match the input string against the patterns between <b>endif</b> Match the input string against the patterns between
<b>if</b> and <b>endif</b>, if and only if that same input string <b>if</b> and <b>endif</b>, if and only if that same input string
does <b>not</b> match <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest. does <b>not</b> match <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
matches <i>pattern</i>. The <b>if</b>..<b>endif</b> can nest.
Note: do not prepend whitespace to patterns inside
<b>if</b>..<b>endif</b>.
This feature is available in Postfix 2.1 and later.
blank lines and comments blank lines and comments
Empty lines and whitespace-only lines are ignored, Empty lines and whitespace-only lines are ignored,
@@ -113,11 +121,12 @@ REGEXP_TABLE(5) REGEXP_TABLE(5)
<b>TEXT SUBSTITUTION</b> <b>TEXT SUBSTITUTION</b>
Substitution of substrings from the matched expression Substitution of substrings from the matched expression
into the result string is possible using $1, $2, etc.. The into the result string is possible using $1, $2, etc.;
macros in the result string may need to be written as ${n} specify $$ to produce a $ character as output. The macros
or $(n) if they aren't followed by whitespace. in the result string may need to be written as ${n} or
$(n) if they aren't followed by whitespace.
Note: since negated patterns (those preceded by <b>!</b>) return Note: since negated patterns (those preceded by <b>!</b>) return
a result when the expression does not match, substitutions a result when the expression does not match, substitutions
are not available for negated patterns. are not available for negated patterns.

View File

@@ -212,9 +212,6 @@ Note: this action currently affects all recipients of the message.
To discard only one recipient without discarding the entire message, To discard only one recipient without discarding the entire message,
use the transport(5) table to direct mail to the discard(8) service. use the transport(5) table to direct mail to the discard(8) service.
.sp .sp
Note: this action does not work in Postfix 2.2
\fBsmtpd_end_of_data_restrictions\fR.
.sp
This feature is available in Postfix 2.0 and later. This feature is available in Postfix 2.0 and later.
.IP \fBDUNNO\fR .IP \fBDUNNO\fR
Pretend that the lookup key was not found. This Pretend that the lookup key was not found. This
@@ -232,9 +229,6 @@ about external content filters is in the Postfix FILTER_README file.
Note: this action overrides the \fBmain.cf content_filter\fR setting, Note: this action overrides the \fBmain.cf content_filter\fR setting,
and currently affects all recipients of the message. and currently affects all recipients of the message.
.sp .sp
Note: this action does not work in Postfix 2.2
\fBsmtpd_end_of_data_restrictions\fR.
.sp
This feature is available in Postfix 2.0 and later. This feature is available in Postfix 2.0 and later.
.IP "\fBHOLD \fIoptional text...\fR" .IP "\fBHOLD \fIoptional text...\fR"
Place the message on the \fBhold\fR queue, where it will sit Place the message on the \fBhold\fR queue, where it will sit
@@ -252,9 +246,6 @@ or \fB$bounce_queue_lifetime\fR, or longer.
.sp .sp
Note: this action currently affects all recipients of the message. Note: this action currently affects all recipients of the message.
.sp .sp
Note: this action does not work in Postfix 2.2
\fBsmtpd_end_of_data_restrictions\fR.
.sp
This feature is available in Postfix 2.0 and later. This feature is available in Postfix 2.0 and later.
.IP "\fBPREPEND \fIheadername: headervalue\fR" .IP "\fBPREPEND \fIheadername: headervalue\fR"
Prepend the specified message header to the message. Prepend the specified message header to the message.
@@ -274,9 +265,6 @@ address instead of the intended recipient(s).
Note: this action overrides the FILTER action, and currently affects Note: this action overrides the FILTER action, and currently affects
all recipients of the message. all recipients of the message.
.sp .sp
Note: this action does not work in Postfix 2.2
\fBsmtpd_end_of_data_restrictions\fR.
.sp
This feature is available in Postfix 2.1 and later. This feature is available in Postfix 2.1 and later.
.IP "\fBWARN \fIoptional text...\fR .IP "\fBWARN \fIoptional text...\fR
Log a warning with the optional text, together with client information Log a warning with the optional text, together with client information

View File

@@ -48,11 +48,18 @@ and \fBendif\fR, if and only if the input string also matches
.sp .sp
Note: do not prepend whitespace to patterns inside Note: do not prepend whitespace to patterns inside
\fBif\fR..\fBendif\fR. \fBif\fR..\fBendif\fR.
.sp
This feature is available in Postfix 2.1 and later.
.IP "\fBif !/\fIpattern\fB/\fIflags\fR" .IP "\fBif !/\fIpattern\fB/\fIflags\fR"
.IP "\fBendif\fR" .IP "\fBendif\fR"
Match the input string against the patterns between \fBif\fR Match the input string against the patterns between \fBif\fR
and \fBendif\fR, if and only if the input string does \fBnot\fR and \fBendif\fR, if and only if the input string does \fBnot\fR
match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest. match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
.sp
Note: do not prepend whitespace to patterns inside
\fBif\fR..\fBendif\fR.
.sp
This feature is available in Postfix 2.1 and later.
.IP "blank lines and comments" .IP "blank lines and comments"
Empty lines and whitespace-only lines are ignored, as Empty lines and whitespace-only lines are ignored, as
are lines whose first non-whitespace character is a `#'. are lines whose first non-whitespace character is a `#'.
@@ -137,7 +144,8 @@ broken up into \fIuser\fR and \fIfoo\fR.
.ad .ad
.fi .fi
Substitution of substrings from the matched expression into the result Substitution of substrings from the matched expression into the result
string is possible using the conventional perl syntax ($1, $2, etc.). string is possible using the conventional perl syntax ($1, $2, etc.);
specify $$ to produce a $ character as output.
The macros in the result string may need to be written as ${n} 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.

View File

@@ -48,11 +48,19 @@ matches \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
.sp .sp
Note: do not prepend whitespace to patterns inside Note: do not prepend whitespace to patterns inside
\fBif\fR..\fBendif\fR. \fBif\fR..\fBendif\fR.
.sp
This feature is available in Postfix 2.1 and later.
.IP "\fBif !/\fIpattern\fB/\fIflags\fR" .IP "\fBif !/\fIpattern\fB/\fIflags\fR"
.IP "\fBendif\fR" .IP "\fBendif\fR"
Match the input string against the patterns between \fBif\fR Match the input string against the patterns between \fBif\fR
and \fBendif\fR, if and only if that same input string does and \fBendif\fR, if and only if that same input string does
\fBnot\fR match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest. \fBnot\fR match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
matches \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
.sp
Note: do not prepend whitespace to patterns inside
\fBif\fR..\fBendif\fR.
.sp
This feature is available in Postfix 2.1 and later.
.IP "blank lines and comments" .IP "blank lines and comments"
Empty lines and whitespace-only lines are ignored, as Empty lines and whitespace-only lines are ignored, as
are lines whose first non-whitespace character is a `#'. are lines whose first non-whitespace character is a `#'.
@@ -105,7 +113,9 @@ broken up into \fIuser\fR and \fIfoo\fR.
.ad .ad
.fi .fi
Substitution of substrings from the matched expression into the result Substitution of substrings from the matched expression into the result
string is possible using $1, $2, etc.. The macros in the result string string is possible using $1, $2, etc.;
specify $$ to produce a $ character as output.
The macros in the result string
may need to be written as ${n} or $(n) if they aren't followed may need to be written as ${n} or $(n) if they aren't followed
by whitespace. by whitespace.

View File

@@ -30,7 +30,8 @@ specify: </p>
<ul> <ul>
<li> <p> What notifications are sent: success, failure, delay, or <li> <p> What notifications are sent: success, failure, delay, or
none. </p> none. Normally, Postfix informs the sender only mail when delivery
is delayed or when delivery fails. </p>
<li> <p> What content is returned in case of failure: only the <li> <p> What content is returned in case of failure: only the
message headers, or the full message. </p> message headers, or the full message. </p>
@@ -68,10 +69,12 @@ internal infrastructure than desirable. Unfortunately, disallowing
requests as well. The RFCs do not offer the option to negotiate requests as well. The RFCs do not offer the option to negotiate
feature subsets. </p> feature subsets. </p>
<p> This is not as bad as it sounds. Remote senders with DSN support <p> This is not as bad as it sounds. When you turn off DSN for
will still be informed that their mail reached your Postfix gateway remote inbound mail, remote senders with DSN support will still be
successfully; they just will not get successful delivery notices informed that their mail reached your Postfix gateway successfully;
from your internal systems. </p> they just will not get successful delivery notices from your internal
systems. Remote senders lose very little: they can no longer specify
how Postfix should report delayed or failed delivery. </p>
<p> Use the smtpd_discard_ehlo_keyword_address_maps feature if you <p> Use the smtpd_discard_ehlo_keyword_address_maps feature if you
wish to allow DSN requests from trusted clients but not from random wish to allow DSN requests from trusted clients but not from random

View File

@@ -219,9 +219,6 @@
# To discard only one recipient without discarding the entire message, # To discard only one recipient without discarding the entire message,
# use the transport(5) table to direct mail to the discard(8) service. # use the transport(5) table to direct mail to the discard(8) service.
# .sp # .sp
# Note: this action does not work in Postfix 2.2
# \fBsmtpd_end_of_data_restrictions\fR.
# .sp
# This feature is available in Postfix 2.0 and later. # This feature is available in Postfix 2.0 and later.
# .IP \fBDUNNO\fR # .IP \fBDUNNO\fR
# Pretend that the lookup key was not found. This # Pretend that the lookup key was not found. This
@@ -239,9 +236,6 @@
# Note: this action overrides the \fBmain.cf content_filter\fR setting, # Note: this action overrides the \fBmain.cf content_filter\fR setting,
# and currently affects all recipients of the message. # and currently affects all recipients of the message.
# .sp # .sp
# Note: this action does not work in Postfix 2.2
# \fBsmtpd_end_of_data_restrictions\fR.
# .sp
# This feature is available in Postfix 2.0 and later. # This feature is available in Postfix 2.0 and later.
# .IP "\fBHOLD \fIoptional text...\fR" # .IP "\fBHOLD \fIoptional text...\fR"
# Place the message on the \fBhold\fR queue, where it will sit # Place the message on the \fBhold\fR queue, where it will sit
@@ -259,9 +253,6 @@
# .sp # .sp
# Note: this action currently affects all recipients of the message. # Note: this action currently affects all recipients of the message.
# .sp # .sp
# Note: this action does not work in Postfix 2.2
# \fBsmtpd_end_of_data_restrictions\fR.
# .sp
# This feature is available in Postfix 2.0 and later. # This feature is available in Postfix 2.0 and later.
# .IP "\fBPREPEND \fIheadername: headervalue\fR" # .IP "\fBPREPEND \fIheadername: headervalue\fR"
# Prepend the specified message header to the message. # Prepend the specified message header to the message.
@@ -281,9 +272,6 @@
# Note: this action overrides the FILTER action, and currently affects # Note: this action overrides the FILTER action, and currently affects
# all recipients of the message. # all recipients of the message.
# .sp # .sp
# Note: this action does not work in Postfix 2.2
# \fBsmtpd_end_of_data_restrictions\fR.
# .sp
# This feature is available in Postfix 2.1 and later. # This feature is available in Postfix 2.1 and later.
# .IP "\fBWARN \fIoptional text...\fR # .IP "\fBWARN \fIoptional text...\fR
# Log a warning with the optional text, together with client information # Log a warning with the optional text, together with client information

View File

@@ -40,11 +40,18 @@
# .sp # .sp
# Note: do not prepend whitespace to patterns inside # Note: do not prepend whitespace to patterns inside
# \fBif\fR..\fBendif\fR. # \fBif\fR..\fBendif\fR.
# .sp
# This feature is available in Postfix 2.1 and later.
# .IP "\fBif !/\fIpattern\fB/\fIflags\fR" # .IP "\fBif !/\fIpattern\fB/\fIflags\fR"
# .IP "\fBendif\fR" # .IP "\fBendif\fR"
# Match the input string against the patterns between \fBif\fR # Match the input string against the patterns between \fBif\fR
# and \fBendif\fR, if and only if the input string does \fBnot\fR # and \fBendif\fR, if and only if the input string does \fBnot\fR
# match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest. # match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
# .sp
# Note: do not prepend whitespace to patterns inside
# \fBif\fR..\fBendif\fR.
# .sp
# This feature is available in Postfix 2.1 and later.
# .IP "blank lines and comments" # .IP "blank lines and comments"
# Empty lines and whitespace-only lines are ignored, as # Empty lines and whitespace-only lines are ignored, as
# are lines whose first non-whitespace character is a `#'. # are lines whose first non-whitespace character is a `#'.
@@ -125,7 +132,8 @@
# .ad # .ad
# .fi # .fi
# Substitution of substrings from the matched expression into the result # Substitution of substrings from the matched expression into the result
# string is possible using the conventional perl syntax ($1, $2, etc.). # string is possible using the conventional perl syntax ($1, $2, etc.);
# specify $$ to produce a $ character as output.
# The macros in the result string may need to be written as ${n} # 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.
# #

View File

@@ -40,11 +40,19 @@
# .sp # .sp
# Note: do not prepend whitespace to patterns inside # Note: do not prepend whitespace to patterns inside
# \fBif\fR..\fBendif\fR. # \fBif\fR..\fBendif\fR.
# .sp
# This feature is available in Postfix 2.1 and later.
# .IP "\fBif !/\fIpattern\fB/\fIflags\fR" # .IP "\fBif !/\fIpattern\fB/\fIflags\fR"
# .IP "\fBendif\fR" # .IP "\fBendif\fR"
# Match the input string against the patterns between \fBif\fR # Match the input string against the patterns between \fBif\fR
# and \fBendif\fR, if and only if that same input string does # and \fBendif\fR, if and only if that same input string does
# \fBnot\fR match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest. # \fBnot\fR match \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
# matches \fIpattern\fR. The \fBif\fR..\fBendif\fR can nest.
# .sp
# Note: do not prepend whitespace to patterns inside
# \fBif\fR..\fBendif\fR.
# .sp
# This feature is available in Postfix 2.1 and later.
# .IP "blank lines and comments" # .IP "blank lines and comments"
# Empty lines and whitespace-only lines are ignored, as # Empty lines and whitespace-only lines are ignored, as
# are lines whose first non-whitespace character is a `#'. # are lines whose first non-whitespace character is a `#'.
@@ -93,7 +101,9 @@
# .ad # .ad
# .fi # .fi
# Substitution of substrings from the matched expression into the result # Substitution of substrings from the matched expression into the result
# string is possible using $1, $2, etc.. The macros in the result string # string is possible using $1, $2, etc.;
# specify $$ to produce a $ character as output.
# The macros in the result string
# may need to be written as ${n} or $(n) if they aren't followed # may need to be written as ${n} or $(n) if they aren't followed
# by whitespace. # by whitespace.
# #

View File

@@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no * Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only. * patchlevel; they change the release date only.
*/ */
#define MAIL_RELEASE_DATE "20051223" #define MAIL_RELEASE_DATE "20051226"
#define MAIL_VERSION_NUMBER "2.3" #define MAIL_VERSION_NUMBER "2.3"
#ifdef SNAPSHOT #ifdef SNAPSHOT

View File

@@ -40,7 +40,7 @@ typedef struct DICT {
time_t mtime; /* mod time at open */ time_t mtime; /* mod time at open */
} DICT; } DICT;
extern DICT *dict_alloc(const char *, const char *, int); extern DICT *dict_alloc(const char *, const char *, ssize_t);
extern void dict_free(DICT *); extern void dict_free(DICT *);
extern DICT *dict_debug(DICT *); extern DICT *dict_debug(DICT *);

View File

@@ -9,7 +9,7 @@
/* DICT *dict_alloc(dict_type, dict_name, size) /* DICT *dict_alloc(dict_type, dict_name, size)
/* const char *dict_type; /* const char *dict_type;
/* const char *dict_name; /* const char *dict_name;
/* int size; /* ssize_t size;
/* /*
/* void dict_free(dict) /* void dict_free(dict)
/* DICT *ptr; /* DICT *ptr;
@@ -105,7 +105,7 @@ static void dict_default_close(DICT *dict)
/* dict_alloc - allocate dictionary object, initialize super-class */ /* dict_alloc - allocate dictionary object, initialize super-class */
DICT *dict_alloc(const char *dict_type, const char *dict_name, int size) DICT *dict_alloc(const char *dict_type, const char *dict_name, ssize_t size)
{ {
DICT *dict = (DICT *) mymalloc(size); DICT *dict = (DICT *) mymalloc(size);

View File

@@ -101,6 +101,7 @@ typedef struct {
pcre_extra *hints; /* hints to speed pattern execution */ pcre_extra *hints; /* hints to speed pattern execution */
char *replacement; /* replacement string */ char *replacement; /* replacement string */
int match; /* positive or negative match */ int match; /* positive or negative match */
size_t max_sub; /* largest $number in replacement */
} DICT_PCRE_MATCH_RULE; } DICT_PCRE_MATCH_RULE;
typedef struct { typedef struct {
@@ -116,6 +117,7 @@ typedef struct {
typedef struct { typedef struct {
DICT dict; /* generic members */ DICT dict; /* generic members */
DICT_PCRE_RULE *head; DICT_PCRE_RULE *head;
VSTRING *expansion_buf; /* lookup result */
} DICT_PCRE; } DICT_PCRE;
static int dict_pcre_init = 0; /* flag need to init pcre library */ static int dict_pcre_init = 0; /* flag need to init pcre library */
@@ -124,9 +126,8 @@ static int dict_pcre_init = 0; /* flag need to init pcre library */
* Context for $number expansion callback. * Context for $number expansion callback.
*/ */
typedef struct { typedef struct {
const char *mapname; /* source dict name */ DICT_PCRE *dict_pcre; /* the dictionary handle */
int lineno; /* source file line number */ DICT_PCRE_MATCH_RULE *match_rule; /* the rule we matched */
VSTRING *expansion_buf; /* target string buffer */
const char *lookup_string; /* string against which we match */ const char *lookup_string; /* string against which we match */
int offsets[PCRE_MAX_CAPTURE * 3]; /* Cut substrings */ int offsets[PCRE_MAX_CAPTURE * 3]; /* Cut substrings */
int matches; /* Count of cuts */ int matches; /* Count of cuts */
@@ -138,8 +139,8 @@ typedef struct {
typedef struct { typedef struct {
const char *mapname; /* name of regexp map */ const char *mapname; /* name of regexp map */
int lineno; /* where in file */ int lineno; /* where in file */
int flags; /* dict_flags */
size_t max_sub; /* Largest $n seen */ size_t max_sub; /* Largest $n seen */
char *literal; /* constant result, $$ -> $ */
} DICT_PCRE_PRESCAN_CONTEXT; } DICT_PCRE_PRESCAN_CONTEXT;
/* /*
@@ -162,6 +163,8 @@ typedef struct {
static int dict_pcre_expand(int type, VSTRING *buf, char *ptr) static int dict_pcre_expand(int type, VSTRING *buf, char *ptr)
{ {
DICT_PCRE_EXPAND_CONTEXT *ctxt = (DICT_PCRE_EXPAND_CONTEXT *) ptr; DICT_PCRE_EXPAND_CONTEXT *ctxt = (DICT_PCRE_EXPAND_CONTEXT *) ptr;
DICT_PCRE_MATCH_RULE *match_rule = ctxt->match_rule;
DICT_PCRE *dict_pcre = ctxt->dict_pcre;
const char *pp; const char *pp;
int n; int n;
int ret; int ret;
@@ -176,16 +179,16 @@ static int dict_pcre_expand(int type, VSTRING *buf, char *ptr)
if (ret < 0) { if (ret < 0) {
if (ret == PCRE_ERROR_NOSUBSTRING) if (ret == PCRE_ERROR_NOSUBSTRING)
msg_fatal("regexp %s, line %d: replace index out of range", msg_fatal("regexp %s, line %d: replace index out of range",
ctxt->mapname, ctxt->lineno); dict_pcre->dict.name, match_rule->rule.lineno);
else else
msg_fatal("regexp %s, line %d: pcre_get_substring error: %d", msg_fatal("regexp %s, line %d: pcre_get_substring error: %d",
ctxt->mapname, ctxt->lineno, ret); dict_pcre->dict.name, match_rule->rule.lineno, ret);
} }
if (*pp == 0) { if (*pp == 0) {
myfree((char *) pp); myfree((char *) pp);
return (MAC_PARSE_UNDEF); return (MAC_PARSE_UNDEF);
} }
vstring_strcat(ctxt->expansion_buf, pp); vstring_strcat(dict_pcre->expansion_buf, pp);
myfree((char *) pp); myfree((char *) pp);
return (MAC_PARSE_OK); return (MAC_PARSE_OK);
} }
@@ -194,7 +197,7 @@ static int dict_pcre_expand(int type, VSTRING *buf, char *ptr)
* Straight text - duplicate with no substitution. * Straight text - duplicate with no substitution.
*/ */
else { else {
vstring_strcat(ctxt->expansion_buf, vstring_str(buf)); vstring_strcat(dict_pcre->expansion_buf, vstring_str(buf));
return (MAC_PARSE_OK); return (MAC_PARSE_OK);
} }
} }
@@ -252,7 +255,6 @@ static const char *dict_pcre_lookup(DICT *dict, const char *lookup_string)
DICT_PCRE_MATCH_RULE *match_rule; DICT_PCRE_MATCH_RULE *match_rule;
int lookup_len = strlen(lookup_string); int lookup_len = strlen(lookup_string);
DICT_PCRE_EXPAND_CONTEXT ctxt; DICT_PCRE_EXPAND_CONTEXT ctxt;
static VSTRING *expansion_buf;
int nesting = 0; int nesting = 0;
dict_errno = 0; dict_errno = 0;
@@ -292,28 +294,31 @@ static const char *dict_pcre_lookup(DICT *dict, const char *lookup_string)
continue; /* pcre_exec failed */ continue; /* pcre_exec failed */
} }
/* Negative rules can't have any substitutions */ /*
if (!match_rule->match) * Skip $number substitutions when the replacement text contains
* no $number strings, as learned during the compile time
* pre-scan. The pre-scan already replaced $$ by $.
*/
if (match_rule->max_sub == 0)
return match_rule->replacement; return match_rule->replacement;
/* /*
* We've got a match. Perform substitution on replacement string. * We've got a match. Perform substitution on replacement string.
*/ */
if (expansion_buf == 0) if (dict_pcre->expansion_buf == 0)
expansion_buf = vstring_alloc(10); dict_pcre->expansion_buf = vstring_alloc(10);
VSTRING_RESET(expansion_buf); VSTRING_RESET(dict_pcre->expansion_buf);
ctxt.expansion_buf = expansion_buf; ctxt.dict_pcre = dict_pcre;
ctxt.match_rule = match_rule;
ctxt.lookup_string = lookup_string; ctxt.lookup_string = lookup_string;
ctxt.mapname = dict->name;
ctxt.lineno = rule->lineno;
if (mac_parse(match_rule->replacement, dict_pcre_expand, if (mac_parse(match_rule->replacement, dict_pcre_expand,
(char *) &ctxt) & MAC_PARSE_ERROR) (char *) &ctxt) & MAC_PARSE_ERROR)
msg_fatal("pcre map %s, line %d: bad replacement syntax", msg_fatal("pcre map %s, line %d: bad replacement syntax",
dict->name, rule->lineno); dict->name, rule->lineno);
VSTRING_TERMINATE(expansion_buf); VSTRING_TERMINATE(dict_pcre->expansion_buf);
return (vstring_str(expansion_buf)); return (vstring_str(dict_pcre->expansion_buf));
/* /*
* Conditional. XXX We provide space for matched substring info * Conditional. XXX We provide space for matched substring info
@@ -392,6 +397,8 @@ static void dict_pcre_close(DICT *dict)
} }
myfree((char *) rule); myfree((char *) rule);
} }
if (dict_pcre->expansion_buf)
vstring_free(dict_pcre->expansion_buf);
dict_free(dict); dict_free(dict);
} }
@@ -493,12 +500,15 @@ static int dict_pcre_prescan(int type, VSTRING *buf, char *context)
DICT_PCRE_PRESCAN_CONTEXT *ctxt = (DICT_PCRE_PRESCAN_CONTEXT *) context; DICT_PCRE_PRESCAN_CONTEXT *ctxt = (DICT_PCRE_PRESCAN_CONTEXT *) context;
size_t n; size_t n;
/*
* Keep a copy of literal text (with $$ already replaced by $) if and
* only if the replacement text contains no $number expression. This way
* we can avoid having to scan the replacement text at lookup time.
*/
if (type == MAC_PARSE_VARNAME) { if (type == MAC_PARSE_VARNAME) {
if (ctxt->flags & DICT_FLAG_NO_REGSUB) { if (ctxt->literal) {
msg_warn("pcre map %s, line %d: " myfree(ctxt->literal);
"regular expression substitution is not allowed", ctxt->literal = 0;
ctxt->mapname, ctxt->lineno);
return (MAC_PARSE_ERROR);
} }
if (!alldig(vstring_str(buf))) { if (!alldig(vstring_str(buf))) {
msg_warn("pcre map %s, line %d: non-numeric replacement index \"%s\"", msg_warn("pcre map %s, line %d: non-numeric replacement index \"%s\"",
@@ -513,6 +523,11 @@ static int dict_pcre_prescan(int type, VSTRING *buf, char *context)
} }
if (n > ctxt->max_sub) if (n > ctxt->max_sub)
ctxt->max_sub = n; ctxt->max_sub = n;
} else if (type == MAC_PARSE_LITERAL && ctxt->max_sub == 0) {
if (ctxt->literal)
msg_panic("pcre map %s, line %d: multiple literals but no $number",
ctxt->mapname, ctxt->lineno);
ctxt->literal = mystrdup(vstring_str(buf));
} }
return (MAC_PARSE_OK); return (MAC_PARSE_OK);
} }
@@ -599,14 +614,23 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
*/ */
prescan_context.mapname = mapname; prescan_context.mapname = mapname;
prescan_context.lineno = lineno; prescan_context.lineno = lineno;
prescan_context.flags = dict_flags;
prescan_context.max_sub = 0; prescan_context.max_sub = 0;
prescan_context.literal = 0;
/*
* The optimizer will eliminate code duplication and/or dead code.
*/
#define CREATE_MATCHOP_ERROR_RETURN(rval) do { \
if (prescan_context.literal) \
myfree(prescan_context.literal); \
return (rval); \
} while (0)
if (mac_parse(p, dict_pcre_prescan, (char *) &prescan_context) if (mac_parse(p, dict_pcre_prescan, (char *) &prescan_context)
& MAC_PARSE_ERROR) { & MAC_PARSE_ERROR) {
msg_warn("pcre map %s, line %d: bad replacement syntax: " msg_warn("pcre map %s, line %d: bad replacement syntax: "
"skipping this rule", mapname, lineno); "skipping this rule", mapname, lineno);
return (0); CREATE_MATCHOP_ERROR_RETURN(0);
} }
/* /*
@@ -615,14 +639,20 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
if (prescan_context.max_sub > 0 && regexp.match == 0) { if (prescan_context.max_sub > 0 && regexp.match == 0) {
msg_warn("pcre map %s, line %d: $number found in negative match " msg_warn("pcre map %s, line %d: $number found in negative match "
"replacement text: skipping this rule", mapname, lineno); "replacement text: skipping this rule", mapname, lineno);
return (0); CREATE_MATCHOP_ERROR_RETURN(0);
}
if (prescan_context.max_sub > 0 && (dict_flags & DICT_FLAG_NO_REGSUB)) {
msg_warn("pcre map %s, line %d: "
"regular expression substitution is not allowed: "
"skipping this rule", mapname, lineno);
CREATE_MATCHOP_ERROR_RETURN(0);
} }
/* /*
* Compile the pattern. * Compile the pattern.
*/ */
if (dict_pcre_compile(mapname, lineno, &regexp, &engine) == 0) if (dict_pcre_compile(mapname, lineno, &regexp, &engine) == 0)
return (0); CREATE_MATCHOP_ERROR_RETURN(0);
/* /*
* Save the result. * Save the result.
@@ -631,7 +661,11 @@ static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
dict_pcre_rule_alloc(DICT_PCRE_OP_MATCH, nesting, lineno, dict_pcre_rule_alloc(DICT_PCRE_OP_MATCH, nesting, lineno,
sizeof(DICT_PCRE_MATCH_RULE)); sizeof(DICT_PCRE_MATCH_RULE));
match_rule->match = regexp.match; match_rule->match = regexp.match;
match_rule->replacement = mystrdup(p); match_rule->max_sub = prescan_context.max_sub;
if (prescan_context.literal)
match_rule->replacement = prescan_context.literal;
else
match_rule->replacement = mystrdup(p);
match_rule->pattern = engine.pattern; match_rule->pattern = engine.pattern;
match_rule->hints = engine.hints; match_rule->hints = engine.hints;
return ((DICT_PCRE_RULE *) match_rule); return ((DICT_PCRE_RULE *) match_rule);
@@ -747,6 +781,7 @@ DICT *dict_pcre_open(const char *mapname, int unused_flags, int dict_flags)
dict_pcre->dict.close = dict_pcre_close; dict_pcre->dict.close = dict_pcre_close;
dict_pcre->dict.flags = dict_flags | DICT_FLAG_PATTERN; dict_pcre->dict.flags = dict_flags | DICT_FLAG_PATTERN;
dict_pcre->head = 0; dict_pcre->head = 0;
dict_pcre->expansion_buf = 0;
if (dict_pcre_init == 0) { if (dict_pcre_init == 0) {
pcre_malloc = (void *(*) (size_t)) mymalloc; pcre_malloc = (void *(*) (size_t)) mymalloc;

View File

@@ -110,6 +110,7 @@ typedef struct {
DICT dict; /* generic members */ DICT dict; /* generic members */
regmatch_t *pmatch; /* matched substring info */ regmatch_t *pmatch; /* matched substring info */
DICT_REGEXP_RULE *head; /* first rule */ DICT_REGEXP_RULE *head; /* first rule */
VSTRING *expansion_buf; /* lookup result */
} DICT_REGEXP; } DICT_REGEXP;
/* /*
@@ -122,10 +123,9 @@ typedef struct {
* Context for $number expansion callback. * Context for $number expansion callback.
*/ */
typedef struct { typedef struct {
DICT_REGEXP *dict_regexp; /* the dictionary entry */ DICT_REGEXP *dict_regexp; /* the dictionary handle */
DICT_REGEXP_MATCH_RULE *match_rule; /* the rule we matched */ DICT_REGEXP_MATCH_RULE *match_rule; /* the rule we matched */
const char *lookup_string; /* matched text */ const char *lookup_string; /* matched text */
VSTRING *expansion_buf; /* buffer for $number expansion */
} DICT_REGEXP_EXPAND_CONTEXT; } DICT_REGEXP_EXPAND_CONTEXT;
/* /*
@@ -135,6 +135,7 @@ typedef struct {
const char *mapname; /* name of regexp map */ const char *mapname; /* name of regexp map */
int lineno; /* where in file */ int lineno; /* where in file */
size_t max_sub; /* largest $number seen */ size_t max_sub; /* largest $number seen */
char *literal; /* constant result, $$ -> $ */
} DICT_REGEXP_PRESCAN_CONTEXT; } DICT_REGEXP_PRESCAN_CONTEXT;
/* /*
@@ -168,7 +169,7 @@ static int dict_regexp_expand(int type, VSTRING *buf, char *ptr)
pmatch = dict_regexp->pmatch + n; pmatch = dict_regexp->pmatch + n;
if (pmatch->rm_so < 0 || pmatch->rm_so == pmatch->rm_eo) if (pmatch->rm_so < 0 || pmatch->rm_so == pmatch->rm_eo)
return (MAC_PARSE_UNDEF); /* empty or not matched */ return (MAC_PARSE_UNDEF); /* empty or not matched */
vstring_strncat(ctxt->expansion_buf, vstring_strncat(dict_regexp->expansion_buf,
ctxt->lookup_string + pmatch->rm_so, ctxt->lookup_string + pmatch->rm_so,
pmatch->rm_eo - pmatch->rm_so); pmatch->rm_eo - pmatch->rm_so);
return (MAC_PARSE_OK); return (MAC_PARSE_OK);
@@ -178,7 +179,7 @@ static int dict_regexp_expand(int type, VSTRING *buf, char *ptr)
* Straight text - duplicate with no substitution. * Straight text - duplicate with no substitution.
*/ */
else { else {
vstring_strcat(ctxt->expansion_buf, vstring_str(buf)); vstring_strcat(dict_regexp->expansion_buf, vstring_str(buf));
return (MAC_PARSE_OK); return (MAC_PARSE_OK);
} }
} }
@@ -212,7 +213,6 @@ static const char *dict_regexp_lookup(DICT *dict, const char *lookup_string)
DICT_REGEXP_IF_RULE *if_rule; DICT_REGEXP_IF_RULE *if_rule;
DICT_REGEXP_MATCH_RULE *match_rule; DICT_REGEXP_MATCH_RULE *match_rule;
DICT_REGEXP_EXPAND_CONTEXT expand_context; DICT_REGEXP_EXPAND_CONTEXT expand_context;
static VSTRING *expansion_buf;
int error; int error;
int nesting = 0; int nesting = 0;
@@ -256,7 +256,8 @@ static const char *dict_regexp_lookup(DICT *dict, const char *lookup_string)
/* /*
* Skip $number substitutions when the replacement text contains * Skip $number substitutions when the replacement text contains
* no $number strings (as learned during the pre-scan). * no $number strings, as learned during the compile time
* pre-scan. The pre-scan already replaced $$ by $.
*/ */
if (match_rule->max_sub == 0) if (match_rule->max_sub == 0)
return (match_rule->replacement); return (match_rule->replacement);
@@ -267,10 +268,9 @@ static const char *dict_regexp_lookup(DICT *dict, const char *lookup_string)
* expansion errors at this point mean something impossible has * expansion errors at this point mean something impossible has
* happened. * happened.
*/ */
if (!expansion_buf) if (!dict_regexp->expansion_buf)
expansion_buf = vstring_alloc(10); dict_regexp->expansion_buf = vstring_alloc(10);
VSTRING_RESET(expansion_buf); VSTRING_RESET(dict_regexp->expansion_buf);
expand_context.expansion_buf = expansion_buf;
expand_context.lookup_string = lookup_string; expand_context.lookup_string = lookup_string;
expand_context.match_rule = match_rule; expand_context.match_rule = match_rule;
expand_context.dict_regexp = dict_regexp; expand_context.dict_regexp = dict_regexp;
@@ -279,8 +279,8 @@ static const char *dict_regexp_lookup(DICT *dict, const char *lookup_string)
(char *) &expand_context) & MAC_PARSE_ERROR) (char *) &expand_context) & MAC_PARSE_ERROR)
msg_panic("regexp map %s, line %d: bad replacement syntax", msg_panic("regexp map %s, line %d: bad replacement syntax",
dict->name, rule->lineno); dict->name, rule->lineno);
VSTRING_TERMINATE(expansion_buf); VSTRING_TERMINATE(dict_regexp->expansion_buf);
return (vstring_str(expansion_buf)); return (vstring_str(dict_regexp->expansion_buf));
/* /*
* Conditional. * Conditional.
@@ -349,6 +349,8 @@ static void dict_regexp_close(DICT *dict)
} }
if (dict_regexp->pmatch) if (dict_regexp->pmatch)
myfree((char *) dict_regexp->pmatch); myfree((char *) dict_regexp->pmatch);
if (dict_regexp->expansion_buf)
vstring_free(dict_regexp->expansion_buf);
dict_free(dict); dict_free(dict);
} }
@@ -467,15 +469,34 @@ static int dict_regexp_prescan(int type, VSTRING *buf, char *context)
DICT_REGEXP_PRESCAN_CONTEXT *ctxt = (DICT_REGEXP_PRESCAN_CONTEXT *) context; DICT_REGEXP_PRESCAN_CONTEXT *ctxt = (DICT_REGEXP_PRESCAN_CONTEXT *) context;
size_t n; size_t n;
/*
* Keep a copy of literal text (with $$ already replaced by $) if and
* only if the replacement text contains no $number expression. This way
* we can avoid having to scan the replacement text at lookup time.
*/
if (type == MAC_PARSE_VARNAME) { if (type == MAC_PARSE_VARNAME) {
if (ctxt->literal) {
myfree(ctxt->literal);
ctxt->literal = 0;
}
if (!alldig(vstring_str(buf))) { if (!alldig(vstring_str(buf))) {
msg_warn("regexp map %s, line %d: non-numeric replacement index \"%s\"", msg_warn("regexp map %s, line %d: non-numeric replacement index \"%s\"",
ctxt->mapname, ctxt->lineno, vstring_str(buf)); ctxt->mapname, ctxt->lineno, vstring_str(buf));
return (MAC_PARSE_ERROR); return (MAC_PARSE_ERROR);
} }
n = atoi(vstring_str(buf)); n = atoi(vstring_str(buf));
if (n < 1) {
msg_warn("regexp map %s, line %d: out-of-range replacement index \"%s\"",
ctxt->mapname, ctxt->lineno, vstring_str(buf));
return (MAC_PARSE_ERROR);
}
if (n > ctxt->max_sub) if (n > ctxt->max_sub)
ctxt->max_sub = n; ctxt->max_sub = n;
} else if (type == MAC_PARSE_LITERAL && ctxt->max_sub == 0) {
if (ctxt->literal)
msg_panic("regexp map %s, line %d: multiple literals but no $number",
ctxt->mapname, ctxt->lineno);
ctxt->literal = mystrdup(vstring_str(buf));
} }
return (MAC_PARSE_OK); return (MAC_PARSE_OK);
} }
@@ -532,7 +553,7 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *mapname, int lineno,
DICT_REGEXP_PATTERN first_pat; DICT_REGEXP_PATTERN first_pat;
DICT_REGEXP_PATTERN second_pat; DICT_REGEXP_PATTERN second_pat;
DICT_REGEXP_PRESCAN_CONTEXT prescan_context; DICT_REGEXP_PRESCAN_CONTEXT prescan_context;
regex_t *first_exp; regex_t *first_exp = 0;
regex_t *second_exp; regex_t *second_exp;
DICT_REGEXP_MATCH_RULE *match_rule; DICT_REGEXP_MATCH_RULE *match_rule;
@@ -563,12 +584,26 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *mapname, int lineno,
prescan_context.mapname = mapname; prescan_context.mapname = mapname;
prescan_context.lineno = lineno; prescan_context.lineno = lineno;
prescan_context.max_sub = 0; prescan_context.max_sub = 0;
prescan_context.literal = 0;
/*
* The optimizer will eliminate code duplication and/or dead code.
*/
#define CREATE_MATCHOP_ERROR_RETURN(rval) do { \
if (first_exp) { \
regfree(first_exp); \
myfree((char *) first_exp); \
} \
if (prescan_context.literal) \
myfree(prescan_context.literal); \
return (rval); \
} while (0)
if (mac_parse(p, dict_regexp_prescan, (char *) &prescan_context) if (mac_parse(p, dict_regexp_prescan, (char *) &prescan_context)
& MAC_PARSE_ERROR) { & MAC_PARSE_ERROR) {
msg_warn("regexp map %s, line %d: bad replacement syntax: " msg_warn("regexp map %s, line %d: bad replacement syntax: "
"skipping this rule", mapname, lineno); "skipping this rule", mapname, lineno);
return (0); CREATE_MATCHOP_ERROR_RETURN(0);
} }
/* /*
@@ -577,36 +612,33 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *mapname, int lineno,
* result string, or when the highest numbered substring is less than * result string, or when the highest numbered substring is less than
* the total number of () subpatterns. * the total number of () subpatterns.
*/ */
#define FREE_EXPR_AND_RETURN(expr, rval) \ if (prescan_context.max_sub == 0)
{ regfree(expr); myfree((char *) (expr)); return (rval); }
if (prescan_context.max_sub == 0 || first_pat.match == 0) {
first_pat.options |= REG_NOSUB; first_pat.options |= REG_NOSUB;
} else if (dict_flags & DICT_FLAG_NO_REGSUB) { if (prescan_context.max_sub > 0 && first_pat.match == 0) {
msg_warn("regexp map %s, line %d: $number found in negative match "
"replacement text: skipping this rule", mapname, lineno);
CREATE_MATCHOP_ERROR_RETURN(0);
}
if (prescan_context.max_sub > 0 && (dict_flags & DICT_FLAG_NO_REGSUB)) {
msg_warn("regexp map %s, line %d: " msg_warn("regexp map %s, line %d: "
"regular expression substitution is not allowed: " "regular expression substitution is not allowed: "
"skipping this rule", mapname, lineno); "skipping this rule", mapname, lineno);
return (0); CREATE_MATCHOP_ERROR_RETURN(0);
} }
if ((first_exp = dict_regexp_compile_pat(mapname, lineno, if ((first_exp = dict_regexp_compile_pat(mapname, lineno,
&first_pat)) == 0) &first_pat)) == 0)
return (0); CREATE_MATCHOP_ERROR_RETURN(0);
if (prescan_context.max_sub > 0 && first_pat.match == 0) {
msg_warn("regexp map %s, line %d: $number found in negative match replacement text: "
"skipping this rule", mapname, lineno);
FREE_EXPR_AND_RETURN(first_exp, 0);
}
if (prescan_context.max_sub > first_exp->re_nsub) { if (prescan_context.max_sub > first_exp->re_nsub) {
msg_warn("regexp map %s, line %d: out of range replacement index \"%d\": " msg_warn("regexp map %s, line %d: out of range replacement index \"%d\": "
"skipping this rule", mapname, lineno, "skipping this rule", mapname, lineno,
(int) prescan_context.max_sub); (int) prescan_context.max_sub);
FREE_EXPR_AND_RETURN(first_exp, 0); CREATE_MATCHOP_ERROR_RETURN(0);
} }
if (second_pat.regexp != 0) { if (second_pat.regexp != 0) {
second_pat.options |= REG_NOSUB; second_pat.options |= REG_NOSUB;
if ((second_exp = dict_regexp_compile_pat(mapname, lineno, if ((second_exp = dict_regexp_compile_pat(mapname, lineno,
&second_pat)) == 0) &second_pat)) == 0)
FREE_EXPR_AND_RETURN(first_exp, 0); CREATE_MATCHOP_ERROR_RETURN(0);
} else { } else {
second_exp = 0; second_exp = 0;
} }
@@ -615,11 +647,13 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *mapname, int lineno,
sizeof(DICT_REGEXP_MATCH_RULE)); sizeof(DICT_REGEXP_MATCH_RULE));
match_rule->first_exp = first_exp; match_rule->first_exp = first_exp;
match_rule->first_match = first_pat.match; match_rule->first_match = first_pat.match;
match_rule->max_sub = match_rule->max_sub = prescan_context.max_sub;
(prescan_context.max_sub > 0 ? prescan_context.max_sub + 1 : 0);
match_rule->second_exp = second_exp; match_rule->second_exp = second_exp;
match_rule->second_match = second_pat.match; match_rule->second_match = second_pat.match;
match_rule->replacement = mystrdup(p); if (prescan_context.literal)
match_rule->replacement = prescan_context.literal;
else
match_rule->replacement = mystrdup(p);
return ((DICT_REGEXP_RULE *) match_rule); return ((DICT_REGEXP_RULE *) match_rule);
} }
@@ -706,6 +740,7 @@ DICT *dict_regexp_open(const char *mapname, int unused_flags, int dict_flags)
dict_regexp->dict.flags = dict_flags | DICT_FLAG_PATTERN; dict_regexp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
dict_regexp->head = 0; dict_regexp->head = 0;
dict_regexp->pmatch = 0; dict_regexp->pmatch = 0;
dict_regexp->expansion_buf = 0;
/* /*
* Parse the regexp table. * Parse the regexp table.

View File

@@ -4,20 +4,37 @@
./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 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 ./dict_open: warning: regexp map dict_regexp.map, line 17: $number found in negative match replacement text: skipping this rule
./dict_open: warning: regexp map dict_regexp.map, line 22: no regexp: skipping this rule ./dict_open: warning: regexp map dict_regexp.map, line 22: no regexp: skipping this rule
> get true
true: not found true: not found
> get true1
true1=1 true1=1
> get true2
true2: not found true2: not found
> get truefalse2
truefalse2=2 truefalse2=2
> get 3
3: not found 3: not found
> get true3
true3=3 true3=3
> get c
c= c=
> get d
d: not found d: not found
> get ab
ab: not found ab: not found
> get aa
aa=a!b aa=a!b
> get 1235
1235=(1)(2)(3) 1235=(1)(2)(3)
> get 1234
1234=(1)(2)(3)(4) 1234=(1)(2)(3)(4)
> get 123
123=(1)(2)(3) 123=(1)(2)(3)
> get bar/find
bar/find: not found bar/find: not found
> get bar/whynot
bar/whynot=Don't have a liquor license bar/whynot=Don't have a liquor license
> get bar/elbereth
bar/elbereth=(elbereth) bar/elbereth=(elbereth)
> get say/elbereth
say/elbereth: not found say/elbereth: not found

View File

@@ -550,6 +550,7 @@ int sockaddr_to_hostaddr(const struct sockaddr * sa, SOCKADDR_SIZE salen,
if (hostaddr != 0) { if (hostaddr != 0) {
if (inet_ntop(AF_INET, (void *) &(SOCK_ADDR_IN_ADDR(sa)), if (inet_ntop(AF_INET, (void *) &(SOCK_ADDR_IN_ADDR(sa)),
hostaddr->buf, sizeof(hostaddr->buf)) == 0) hostaddr->buf, sizeof(hostaddr->buf)) == 0)
errno = ENOSPC;
return (EAI_SYSTEM); return (EAI_SYSTEM);
} }
if (portnum != 0) { if (portnum != 0) {

View File

@@ -300,7 +300,7 @@ XSASL_CLIENT *xsasl_cyrus_client_create(XSASL_CLIENT_IMPL *unused_impl,
int sasl_status; int sasl_status;
/* /*
* The optimizer will eliminate duplication and/or dead code. * The optimizer will eliminate code duplication and/or dead code.
*/ */
#define XSASL_CYRUS_CLIENT_CREATE_ERROR_RETURN(x) \ #define XSASL_CYRUS_CLIENT_CREATE_ERROR_RETURN(x) \
do { \ do { \

View File

@@ -262,7 +262,7 @@ static XSASL_SERVER *xsasl_cyrus_server_create(XSASL_SERVER_IMPL *unused_impl,
myname, service, realm ? realm : "(null)"); myname, service, realm ? realm : "(null)");
/* /*
* The optimizer will eliminate duplication and/or dead code. * The optimizer will eliminate code duplication and/or dead code.
*/ */
#define XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(x) \ #define XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(x) \
do { \ do { \