mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 21:55:20 +00:00
postfix-1.1.11-20020910
This commit is contained in:
committed by
Viktor Dukhovni
parent
7a8151a014
commit
e01fc53a21
@@ -6926,6 +6926,25 @@ Apologies for any names omitted.
|
||||
Bugfix: the LDAP client dumped core in verbose mode.
|
||||
Reported by Will Day and others. File: util/dict_ldap.c.
|
||||
|
||||
20020906
|
||||
|
||||
Cleanup: dict_regexp module speedups by avoiding unnecessary
|
||||
work while matching strings. File: util/dict_regexp.c.
|
||||
|
||||
20020907
|
||||
|
||||
Feature: IF..ENDIF support based on code by Bert Driehuis.
|
||||
File: util/dict_regexp.c.
|
||||
|
||||
|
||||
200209010
|
||||
|
||||
Bugfix: the SMTP client produced unnecessary warnings about
|
||||
trouble with the fallback_relay hosts. File: smtp/smtp_connect.c.
|
||||
|
||||
Robustness: don't wait with detecting broken SMTP connections
|
||||
until reading input. Leandro Santi. File: smtpd/smtpd_chat.c.
|
||||
|
||||
Open problems:
|
||||
|
||||
Low: smtpd should log queue ID with reject/warn/hold/discard
|
||||
|
@@ -138,7 +138,7 @@ virtual_mailbox_lock
|
||||
Use the "postconf -m" command to find out what locking methods
|
||||
Postfix supports on your system.
|
||||
|
||||
virtual_mailbox_size
|
||||
virtual_mailbox_limit
|
||||
|
||||
An upper limit on the size of a mailbox file or maildir file.
|
||||
|
||||
|
@@ -12,6 +12,12 @@ 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 1.1.11-20020910
|
||||
==========================================================
|
||||
|
||||
The relayhost setting now behaves as documented, i.e. you can no
|
||||
longer specify multiple destinations.
|
||||
|
||||
Incompatible changes with Postfix snapshot 1.1.11-20020906
|
||||
==========================================================
|
||||
|
||||
|
@@ -20,7 +20,7 @@
|
||||
* Patches change the patchlevel and the release date. Snapshots change the
|
||||
* release date only, unless they include the same bugfix as a patch release.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20020906"
|
||||
#define MAIL_RELEASE_DATE "20020910"
|
||||
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "1.1.11-" MAIL_RELEASE_DATE
|
||||
|
@@ -149,14 +149,6 @@ void smtp_chat_cmd(SMTP_STATE *state, char *fmt,...)
|
||||
* Send the command to the SMTP server.
|
||||
*/
|
||||
smtp_fputs(STR(state->buffer), LEN(state->buffer), session->stream);
|
||||
|
||||
/*
|
||||
* Flush unsent output if no I/O happened for a while. This avoids
|
||||
* timeouts with pipelined SMTP sessions that have lots of delays
|
||||
* (typically, DNS lookups for sender/recipient unaliasing).
|
||||
*/
|
||||
if (time((time_t *) 0) - vstream_ftime(session->stream) > 10)
|
||||
vstream_fflush(session->stream);
|
||||
}
|
||||
|
||||
/* smtp_chat_resp - read and process SMTP server response */
|
||||
|
@@ -391,9 +391,9 @@ SMTP_SESSION *smtp_connect(char *destination, VSTRING *why)
|
||||
char *host;
|
||||
unsigned port;
|
||||
char *def_service = "smtp"; /* XXX configurable? */
|
||||
char *save;
|
||||
ARGV *sites;
|
||||
char *dest;
|
||||
char *cp;
|
||||
char **cpp;
|
||||
int found_myself = 0;
|
||||
|
||||
/*
|
||||
@@ -401,9 +401,11 @@ SMTP_SESSION *smtp_connect(char *destination, VSTRING *why)
|
||||
* to the optional fall-back relays. Each can be a list of destinations
|
||||
* by itself, with domain, host, [], numerical address, and port.
|
||||
*/
|
||||
cp = save = concatenate(destination, " ", var_fallback_relay, (char *) 0);
|
||||
sites = argv_alloc(1);
|
||||
argv_add(sites, destination, (char *) 0);
|
||||
argv_split_append(sites, var_fallback_relay, ", \t\r\n");
|
||||
|
||||
while ((dest = mystrtok(&cp, ", \t\r\n")) != 0) {
|
||||
for (cpp = sites->argv; (dest = *cpp) != 0; cpp++) {
|
||||
|
||||
/*
|
||||
* Parse the destination. Default is to use the SMTP port.
|
||||
@@ -448,8 +450,8 @@ SMTP_SESSION *smtp_connect(char *destination, VSTRING *why)
|
||||
VAR_RELAYHOST, var_relayhost);
|
||||
smtp_errno = SMTP_RETRY;
|
||||
}
|
||||
if (*var_fallback_relay) {
|
||||
msg_warn("%s configuration problem: %s",
|
||||
if (cpp > sites->argv && sites->argc > 1) {
|
||||
msg_warn("%s problem: %s",
|
||||
VAR_FALLBACK_RELAY, var_fallback_relay);
|
||||
smtp_errno = SMTP_RETRY;
|
||||
}
|
||||
@@ -458,6 +460,6 @@ SMTP_SESSION *smtp_connect(char *destination, VSTRING *why)
|
||||
/*
|
||||
* Cleanup.
|
||||
*/
|
||||
myfree(save);
|
||||
argv_free(sites);
|
||||
return (session);
|
||||
}
|
||||
|
@@ -139,6 +139,7 @@ void smtpd_chat_query(SMTPD_STATE *state)
|
||||
void smtpd_chat_reply(SMTPD_STATE *state, char *format,...)
|
||||
{
|
||||
va_list ap;
|
||||
int delay = 0;
|
||||
|
||||
va_start(ap, format);
|
||||
vstring_vsprintf(state->buffer, format, ap);
|
||||
@@ -157,9 +158,10 @@ void smtpd_chat_reply(SMTPD_STATE *state, char *format,...)
|
||||
* errors within a session.
|
||||
*/
|
||||
if (state->error_count > var_smtpd_soft_erlim)
|
||||
sleep(state->error_count);
|
||||
sleep(delay = (state->error_count > var_smtpd_err_sleep ?
|
||||
state->error_count : var_smtpd_err_sleep));
|
||||
else if (STR(state->buffer)[0] == '4' || STR(state->buffer)[0] == '5')
|
||||
sleep(var_smtpd_err_sleep);
|
||||
sleep(delay = var_smtpd_err_sleep);
|
||||
|
||||
smtp_fputs(STR(state->buffer), LEN(state->buffer), state->client);
|
||||
|
||||
@@ -168,8 +170,14 @@ void smtpd_chat_reply(SMTPD_STATE *state, char *format,...)
|
||||
* timeouts with pipelined SMTP sessions that have lots of server-side
|
||||
* delays (tarpit delays or DNS lookups for UCE restrictions).
|
||||
*/
|
||||
if (time((time_t *) 0) - vstream_ftime(state->client) > 10)
|
||||
if (delay || time((time_t *) 0) - vstream_ftime(state->client) > 10)
|
||||
vstream_fflush(state->client);
|
||||
|
||||
/*
|
||||
* Abort immediately if the connection is broken.
|
||||
*/
|
||||
if (vstream_ferror(state->client))
|
||||
vstream_longjmp(state->client, SMTP_ERR_EOF);
|
||||
}
|
||||
|
||||
/* print_line - line_wrap callback */
|
||||
|
@@ -308,7 +308,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
|
||||
&dict_ldap->version) != LDAP_OPT_SUCCESS)
|
||||
msg_warn("%s: Unable to get LDAP protocol version", myname);
|
||||
else
|
||||
msg_warn("%s: Actual Protocol version used was %d.",
|
||||
msg_warn("%s: Actual Protocol version used is %d.",
|
||||
myname, dict_ldap->version);
|
||||
}
|
||||
#endif
|
||||
|
@@ -16,6 +16,7 @@
|
||||
/* against the table.
|
||||
/* SEE ALSO
|
||||
/* dict(3) generic dictionary manager
|
||||
/* regexp_table(5) format of Postfix regular expression tables
|
||||
/* AUTHOR(S)
|
||||
/* LaMont Jones
|
||||
/* lamont@hp.com
|
||||
@@ -43,6 +44,9 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <regex.h>
|
||||
#ifdef STRCASECMP_IN_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
@@ -57,6 +61,13 @@
|
||||
#include "dict_regexp.h"
|
||||
#include "mac_parse.h"
|
||||
|
||||
/*
|
||||
* Support for IF/ENDIF based on code by Bert Driehuis.
|
||||
*/
|
||||
#define REGEXP_OP_MATCH 1 /* Match this regexp */
|
||||
#define REGEXP_OP_IF 2 /* Increase if/endif nesting on match */
|
||||
#define REGEXP_OP_ENDIF 3 /* Decrease if/endif nesting */
|
||||
|
||||
/*
|
||||
* Regular expression before compiling.
|
||||
*/
|
||||
@@ -75,6 +86,8 @@ typedef struct dict_regexp_list {
|
||||
char *replacement; /* replacement text */
|
||||
size_t max_nsub; /* largest replacement $number */
|
||||
int lineno; /* source file line number */
|
||||
int nesting; /* Level of search nesting */
|
||||
int op; /* REGEXP_OP_MATCH, OP_IF, OP_ENDIF */
|
||||
} DICT_REGEXP_RULE;
|
||||
|
||||
/*
|
||||
@@ -168,6 +181,7 @@ static const char *dict_regexp_lookup(DICT *dict, const char *name)
|
||||
DICT_REGEXP_EXPAND_CONTEXT ctxt;
|
||||
static VSTRING *buf;
|
||||
int error;
|
||||
int nesting = 0;
|
||||
|
||||
dict_errno = 0;
|
||||
|
||||
@@ -179,6 +193,12 @@ static const char *dict_regexp_lookup(DICT *dict, const char *name)
|
||||
* for substring substitution to the bare minimum.
|
||||
*/
|
||||
for (rule = dict_regexp->head; rule; rule = rule->next) {
|
||||
if (nesting < rule->nesting) /* inside false IF/ENDIF */
|
||||
continue;
|
||||
if (rule->op == REGEXP_OP_ENDIF) {
|
||||
nesting--;
|
||||
continue;
|
||||
}
|
||||
error = regexec(rule->primary_exp, name, rule->max_nsub + 1,
|
||||
rule->max_nsub ? dict_regexp->pmatch :
|
||||
(regmatch_t *) 0, 0);
|
||||
@@ -213,8 +233,16 @@ static const char *dict_regexp_lookup(DICT *dict, const char *name)
|
||||
}
|
||||
|
||||
/*
|
||||
* Match found. Skip $number substitutions when the replacement text
|
||||
* contains no $number strings (as learned during the pre-scan).
|
||||
* Match found.
|
||||
*/
|
||||
if (rule->op == REGEXP_OP_IF) {
|
||||
nesting++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip $number substitutions when the replacement text contains no
|
||||
* $number strings (as learned during the pre-scan).
|
||||
*/
|
||||
if (rule->max_nsub == 0)
|
||||
return (rule->replacement);
|
||||
@@ -364,10 +392,32 @@ static int dict_regexp_prescan(int type, VSTRING *buf, char *context)
|
||||
return (MAC_PARSE_OK);
|
||||
}
|
||||
|
||||
/* dict_regexp_patterns - get the primary and negated patterns and flags */
|
||||
|
||||
static int dict_regexp_patterns(const char *map, int lineno, char **p,
|
||||
DICT_REGEXP_PATTERN *primary_pat,
|
||||
DICT_REGEXP_PATTERN *negated_pat)
|
||||
{
|
||||
|
||||
/*
|
||||
* Get the primary and optional negated patterns and their flags.
|
||||
*/
|
||||
if (dict_regexp_get_pattern(map, lineno, p, primary_pat) == 0)
|
||||
return (0);
|
||||
if (*(*p) == '!' && (*p)[1] && !ISSPACE((*p)[1])) {
|
||||
(*p)++;
|
||||
if (dict_regexp_get_pattern(map, lineno, p, negated_pat) == 0)
|
||||
return (0);
|
||||
} else {
|
||||
negated_pat->regexp = 0;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* dict_regexp_parseline - parse one rule */
|
||||
|
||||
static DICT_REGEXP_RULE *dict_regexp_parseline(const char *map, int lineno,
|
||||
char *line)
|
||||
char *line, int nesting)
|
||||
{
|
||||
DICT_REGEXP_RULE *rule;
|
||||
char *p;
|
||||
@@ -376,79 +426,126 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *map, int lineno,
|
||||
DICT_REGEXP_PATTERN primary_pat;
|
||||
DICT_REGEXP_PATTERN negated_pat;
|
||||
DICT_REGEXP_PRESCAN_CONTEXT ctxt;
|
||||
int op = REGEXP_OP_MATCH;
|
||||
|
||||
p = line;
|
||||
|
||||
/*
|
||||
* Get the primary and optional negated patterns and their flags.
|
||||
* The MATCH operator takes both patterns and replacement text.
|
||||
*/
|
||||
if (dict_regexp_get_pattern(map, lineno, &p, &primary_pat) == 0)
|
||||
return (0);
|
||||
if (*p == '!' && p[1] && !ISSPACE(p[1])) {
|
||||
p++;
|
||||
if (dict_regexp_get_pattern(map, lineno, &p, &negated_pat) == 0)
|
||||
if (!ISALNUM(*p)) {
|
||||
op = REGEXP_OP_MATCH;
|
||||
if (!dict_regexp_patterns(map, lineno, &p, &primary_pat, &negated_pat))
|
||||
return (0);
|
||||
} else {
|
||||
negated_pat.regexp = 0;
|
||||
|
||||
/*
|
||||
* Get the replacement text.
|
||||
*/
|
||||
if (!ISSPACE(*p)) {
|
||||
msg_warn("regexp map %s, line %d: invalid expression: "
|
||||
"skipping this rule", map, lineno);
|
||||
return (0);
|
||||
}
|
||||
while (*p && ISSPACE(*p))
|
||||
++p;
|
||||
if (!*p) {
|
||||
msg_warn("regexp map %s, line %d: using empty replacement string",
|
||||
map, lineno);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the replacement text.
|
||||
* The IF operator takes patterns but no replacement text.
|
||||
*/
|
||||
if (!ISSPACE(*p)) {
|
||||
msg_warn("regexp map %s, line %d: invalid expression: "
|
||||
"skipping this rule", map, lineno);
|
||||
return (0);
|
||||
else if (strncasecmp(p, "IF", 2) == 0 && !ISALNUM(p[2])) {
|
||||
op = REGEXP_OP_IF;
|
||||
p += 2;
|
||||
while (*p && ISSPACE(*p))
|
||||
p++;
|
||||
if (!dict_regexp_patterns(map, lineno, &p, &primary_pat, &negated_pat))
|
||||
return (0);
|
||||
if (*p)
|
||||
msg_warn("%s, line %d: ignoring extra text after IF", map, lineno);
|
||||
}
|
||||
while (*p && ISSPACE(*p))
|
||||
++p;
|
||||
if (!*p) {
|
||||
msg_warn("regexp map %s, line %d: using empty replacement string",
|
||||
|
||||
/*
|
||||
* The ENDIF operator takes no patterns and no replacement text.
|
||||
*/
|
||||
else if (strncasecmp(p, "ENDIF", 5) == 0 && !ISALNUM(p[5])) {
|
||||
op = REGEXP_OP_ENDIF;
|
||||
p += 5;
|
||||
if (*p)
|
||||
msg_warn("%s, line %d: ignoring extra text after ENDIF",
|
||||
map, lineno);
|
||||
if (nesting == 0) {
|
||||
msg_warn("%s, line %d: ignoring ENDIF without matching IF",
|
||||
map, lineno);
|
||||
return (0);
|
||||
}
|
||||
primary_pat.regexp = negated_pat.regexp = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unrecognized request.
|
||||
*/
|
||||
else {
|
||||
msg_warn("regexp map %s, line %d: ignoring unrecognized request",
|
||||
map, lineno);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the highest-numbered $number substitution string. We can speed up
|
||||
* processing 1) by passing hints to the regexp compiler, setting the
|
||||
* REG_NOSUB flag when the replacement text contains no $number string;
|
||||
* 2) by passing hints to the regexp execution code, limiting the amount
|
||||
* of text that is made available for substitution.
|
||||
*/
|
||||
ctxt.map = map;
|
||||
ctxt.lineno = lineno;
|
||||
ctxt.max_nsub = 0;
|
||||
if (mac_parse(p, dict_regexp_prescan, (char *) &ctxt) & MAC_PARSE_ERROR) {
|
||||
msg_warn("regexp map %s, line %d: bad replacement syntax: "
|
||||
"skipping this rule", map, lineno);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile the primary and the optional negated pattern. Speed up
|
||||
* execution when no matched text needs to be substituted into the result
|
||||
* string, or when the highest numbered substring is less than the total
|
||||
* number of () subpatterns.
|
||||
* Do some compile-time optimizations to speed up pattern matches.
|
||||
*/
|
||||
if (ctxt.max_nsub == 0)
|
||||
primary_pat.options |= REG_NOSUB;
|
||||
if ((primary_exp = dict_regexp_compile(map, lineno, &primary_pat)) == 0)
|
||||
return (0);
|
||||
if (ctxt.max_nsub > primary_exp->re_nsub) {
|
||||
msg_warn("regexp map %s, line %d: out of range replacement index \"%d\": "
|
||||
"skipping this rule", map, lineno, ctxt.max_nsub);
|
||||
regfree(primary_exp);
|
||||
myfree((char *) primary_exp);
|
||||
return (0);
|
||||
}
|
||||
if (negated_pat.regexp != 0) {
|
||||
negated_pat.options |= REG_NOSUB;
|
||||
if ((negated_exp = dict_regexp_compile(map, lineno, &negated_pat)) == 0) {
|
||||
if (primary_pat.regexp) {
|
||||
ctxt.map = map;
|
||||
ctxt.lineno = lineno;
|
||||
ctxt.max_nsub = 0;
|
||||
|
||||
/*
|
||||
* Find the highest-numbered $number substitution string. We can
|
||||
* speed up processing 1) by passing hints to the regexp compiler,
|
||||
* setting the REG_NOSUB flag when the replacement text contains no
|
||||
* $number string; 2) by passing hints to the regexp execution code,
|
||||
* limiting the amount of text that is made available for
|
||||
* substitution.
|
||||
*/
|
||||
if (mac_parse(p, dict_regexp_prescan, (char *) &ctxt) & MAC_PARSE_ERROR) {
|
||||
msg_warn("regexp map %s, line %d: bad replacement syntax: "
|
||||
"skipping this rule", map, lineno);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile the primary and the optional negated pattern. Speed up
|
||||
* execution when no matched text needs to be substituted into the
|
||||
* result string, or when the highest numbered substring is less than
|
||||
* the total number of () subpatterns.
|
||||
*/
|
||||
if (ctxt.max_nsub == 0)
|
||||
primary_pat.options |= REG_NOSUB;
|
||||
if ((primary_exp = dict_regexp_compile(map, lineno, &primary_pat)) == 0)
|
||||
return (0);
|
||||
if (ctxt.max_nsub > primary_exp->re_nsub) {
|
||||
msg_warn("regexp map %s, line %d: out of range replacement index \"%d\": "
|
||||
"skipping this rule", map, lineno, ctxt.max_nsub);
|
||||
regfree(primary_exp);
|
||||
myfree((char *) primary_exp);
|
||||
return (0);
|
||||
}
|
||||
} else
|
||||
negated_exp = 0;
|
||||
if (negated_pat.regexp != 0) {
|
||||
negated_pat.options |= REG_NOSUB;
|
||||
if ((negated_exp = dict_regexp_compile(map, lineno, &negated_pat)) == 0) {
|
||||
regfree(primary_exp);
|
||||
myfree((char *) primary_exp);
|
||||
return (0);
|
||||
}
|
||||
} else
|
||||
negated_exp = 0;
|
||||
} else {
|
||||
primary_exp = negated_exp = 0;
|
||||
ctxt.max_nsub = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Package up the result.
|
||||
@@ -459,6 +556,8 @@ static DICT_REGEXP_RULE *dict_regexp_parseline(const char *map, int lineno,
|
||||
rule->replacement = mystrdup(p);
|
||||
rule->max_nsub = ctxt.max_nsub;
|
||||
rule->lineno = lineno;
|
||||
rule->op = op;
|
||||
rule->nesting = nesting;
|
||||
rule->next = 0;
|
||||
return (rule);
|
||||
}
|
||||
@@ -474,6 +573,7 @@ DICT *dict_regexp_open(const char *map, int unused_flags, int dict_flags)
|
||||
DICT_REGEXP_RULE *last_rule = 0;
|
||||
int lineno = 0;
|
||||
size_t max_nsub = 0;
|
||||
int nesting = 0;
|
||||
char *p;
|
||||
|
||||
line_buffer = vstring_alloc(100);
|
||||
@@ -495,11 +595,16 @@ DICT *dict_regexp_open(const char *map, int unused_flags, int dict_flags)
|
||||
while (readlline(line_buffer, map_fp, &lineno)) {
|
||||
p = vstring_str(line_buffer);
|
||||
trimblanks(p, 0)[0] = 0;
|
||||
rule = dict_regexp_parseline(map, lineno, p);
|
||||
if (*p == 0)
|
||||
continue;
|
||||
rule = dict_regexp_parseline(map, lineno, p, nesting);
|
||||
if (rule) {
|
||||
if (rule->max_nsub > max_nsub)
|
||||
max_nsub = rule->max_nsub;
|
||||
|
||||
if (rule->op == REGEXP_OP_IF)
|
||||
nesting++;
|
||||
if (rule->op == REGEXP_OP_ENDIF)
|
||||
nesting--;
|
||||
if (last_rule == 0)
|
||||
dict_regexp->head = rule;
|
||||
else
|
||||
@@ -508,6 +613,9 @@ DICT *dict_regexp_open(const char *map, int unused_flags, int dict_flags)
|
||||
}
|
||||
}
|
||||
|
||||
if (nesting)
|
||||
msg_warn("%s, line %d: more IFs than ENDIFs", map, lineno);
|
||||
|
||||
/*
|
||||
* Allocate space for only as many matched substrings as used in the
|
||||
* replacement text.
|
||||
|
@@ -44,7 +44,7 @@
|
||||
|
||||
/* dict_static_lookup - access static value*/
|
||||
|
||||
static const char *dict_static_lookup(DICT *dict, const char *name)
|
||||
static const char *dict_static_lookup(DICT *dict, const char *unused_name)
|
||||
{
|
||||
dict_errno = 0;
|
||||
|
||||
|
Reference in New Issue
Block a user