2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-09-01 14:45:32 +00:00

postfix-1.1.11-20020910

This commit is contained in:
Wietse Venema
2002-09-10 00:00:00 -05:00
committed by Viktor Dukhovni
parent 7a8151a014
commit e01fc53a21
10 changed files with 214 additions and 79 deletions

View File

@@ -6926,6 +6926,25 @@ Apologies for any names omitted.
Bugfix: the LDAP client dumped core in verbose mode. Bugfix: the LDAP client dumped core in verbose mode.
Reported by Will Day and others. File: util/dict_ldap.c. 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: Open problems:
Low: smtpd should log queue ID with reject/warn/hold/discard Low: smtpd should log queue ID with reject/warn/hold/discard

View File

@@ -138,7 +138,7 @@ virtual_mailbox_lock
Use the "postconf -m" command to find out what locking methods Use the "postconf -m" command to find out what locking methods
Postfix supports on your system. Postfix supports on your system.
virtual_mailbox_size virtual_mailbox_limit
An upper limit on the size of a mailbox file or maildir file. An upper limit on the size of a mailbox file or maildir file.

View File

@@ -12,6 +12,12 @@ snapshot release). Patches change the patchlevel and the release
date. Snapshots change only the release date, unless they include date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release. 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 Incompatible changes with Postfix snapshot 1.1.11-20020906
========================================================== ==========================================================

View File

@@ -20,7 +20,7 @@
* Patches change the patchlevel and the release date. Snapshots change the * Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release. * 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 VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "1.1.11-" MAIL_RELEASE_DATE #define DEF_MAIL_VERSION "1.1.11-" MAIL_RELEASE_DATE

View File

@@ -149,14 +149,6 @@ void smtp_chat_cmd(SMTP_STATE *state, char *fmt,...)
* Send the command to the SMTP server. * Send the command to the SMTP server.
*/ */
smtp_fputs(STR(state->buffer), LEN(state->buffer), session->stream); 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 */ /* smtp_chat_resp - read and process SMTP server response */

View File

@@ -391,9 +391,9 @@ SMTP_SESSION *smtp_connect(char *destination, VSTRING *why)
char *host; char *host;
unsigned port; unsigned port;
char *def_service = "smtp"; /* XXX configurable? */ char *def_service = "smtp"; /* XXX configurable? */
char *save; ARGV *sites;
char *dest; char *dest;
char *cp; char **cpp;
int found_myself = 0; 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 * to the optional fall-back relays. Each can be a list of destinations
* by itself, with domain, host, [], numerical address, and port. * 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. * 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); VAR_RELAYHOST, var_relayhost);
smtp_errno = SMTP_RETRY; smtp_errno = SMTP_RETRY;
} }
if (*var_fallback_relay) { if (cpp > sites->argv && sites->argc > 1) {
msg_warn("%s configuration problem: %s", msg_warn("%s problem: %s",
VAR_FALLBACK_RELAY, var_fallback_relay); VAR_FALLBACK_RELAY, var_fallback_relay);
smtp_errno = SMTP_RETRY; smtp_errno = SMTP_RETRY;
} }
@@ -458,6 +460,6 @@ SMTP_SESSION *smtp_connect(char *destination, VSTRING *why)
/* /*
* Cleanup. * Cleanup.
*/ */
myfree(save); argv_free(sites);
return (session); return (session);
} }

View File

@@ -139,6 +139,7 @@ void smtpd_chat_query(SMTPD_STATE *state)
void smtpd_chat_reply(SMTPD_STATE *state, char *format,...) void smtpd_chat_reply(SMTPD_STATE *state, char *format,...)
{ {
va_list ap; va_list ap;
int delay = 0;
va_start(ap, format); va_start(ap, format);
vstring_vsprintf(state->buffer, format, ap); vstring_vsprintf(state->buffer, format, ap);
@@ -157,9 +158,10 @@ void smtpd_chat_reply(SMTPD_STATE *state, char *format,...)
* errors within a session. * errors within a session.
*/ */
if (state->error_count > var_smtpd_soft_erlim) 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') 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); 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 * timeouts with pipelined SMTP sessions that have lots of server-side
* delays (tarpit delays or DNS lookups for UCE restrictions). * 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); 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 */ /* print_line - line_wrap callback */

View File

@@ -308,7 +308,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
&dict_ldap->version) != LDAP_OPT_SUCCESS) &dict_ldap->version) != LDAP_OPT_SUCCESS)
msg_warn("%s: Unable to get LDAP protocol version", myname); msg_warn("%s: Unable to get LDAP protocol version", myname);
else else
msg_warn("%s: Actual Protocol version used was %d.", msg_warn("%s: Actual Protocol version used is %d.",
myname, dict_ldap->version); myname, dict_ldap->version);
} }
#endif #endif

View File

@@ -16,6 +16,7 @@
/* against the table. /* against the table.
/* SEE ALSO /* SEE ALSO
/* dict(3) generic dictionary manager /* dict(3) generic dictionary manager
/* regexp_table(5) format of Postfix regular expression tables
/* AUTHOR(S) /* AUTHOR(S)
/* LaMont Jones /* LaMont Jones
/* lamont@hp.com /* lamont@hp.com
@@ -43,6 +44,9 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <regex.h> #include <regex.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
/* Utility library. */ /* Utility library. */
@@ -57,6 +61,13 @@
#include "dict_regexp.h" #include "dict_regexp.h"
#include "mac_parse.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. * Regular expression before compiling.
*/ */
@@ -75,6 +86,8 @@ typedef struct dict_regexp_list {
char *replacement; /* replacement text */ char *replacement; /* replacement text */
size_t max_nsub; /* largest replacement $number */ size_t max_nsub; /* largest replacement $number */
int lineno; /* source file line 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; } DICT_REGEXP_RULE;
/* /*
@@ -168,6 +181,7 @@ static const char *dict_regexp_lookup(DICT *dict, const char *name)
DICT_REGEXP_EXPAND_CONTEXT ctxt; DICT_REGEXP_EXPAND_CONTEXT ctxt;
static VSTRING *buf; static VSTRING *buf;
int error; int error;
int nesting = 0;
dict_errno = 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 substring substitution to the bare minimum.
*/ */
for (rule = dict_regexp->head; rule; rule = rule->next) { 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, error = regexec(rule->primary_exp, name, rule->max_nsub + 1,
rule->max_nsub ? dict_regexp->pmatch : rule->max_nsub ? dict_regexp->pmatch :
(regmatch_t *) 0, 0); (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 * Match found.
* contains no $number strings (as learned during the pre-scan). */
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) if (rule->max_nsub == 0)
return (rule->replacement); return (rule->replacement);
@@ -364,10 +392,32 @@ static int dict_regexp_prescan(int type, VSTRING *buf, char *context)
return (MAC_PARSE_OK); 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 */ /* dict_regexp_parseline - parse one rule */
static DICT_REGEXP_RULE *dict_regexp_parseline(const char *map, int lineno, static DICT_REGEXP_RULE *dict_regexp_parseline(const char *map, int lineno,
char *line) char *line, int nesting)
{ {
DICT_REGEXP_RULE *rule; DICT_REGEXP_RULE *rule;
char *p; 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 primary_pat;
DICT_REGEXP_PATTERN negated_pat; DICT_REGEXP_PATTERN negated_pat;
DICT_REGEXP_PRESCAN_CONTEXT ctxt; DICT_REGEXP_PRESCAN_CONTEXT ctxt;
int op = REGEXP_OP_MATCH;
p = line; 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) if (!ISALNUM(*p)) {
return (0); op = REGEXP_OP_MATCH;
if (*p == '!' && p[1] && !ISSPACE(p[1])) { if (!dict_regexp_patterns(map, lineno, &p, &primary_pat, &negated_pat))
p++;
if (dict_regexp_get_pattern(map, lineno, &p, &negated_pat) == 0)
return (0); 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)) { else if (strncasecmp(p, "IF", 2) == 0 && !ISALNUM(p[2])) {
msg_warn("regexp map %s, line %d: invalid expression: " op = REGEXP_OP_IF;
"skipping this rule", map, lineno); p += 2;
return (0); 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) { * The ENDIF operator takes no patterns and no replacement text.
msg_warn("regexp map %s, line %d: using empty replacement string", */
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); 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); return (0);
} }
/* /*
* Compile the primary and the optional negated pattern. Speed up * Do some compile-time optimizations to speed up pattern matches.
* 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) if (primary_pat.regexp) {
primary_pat.options |= REG_NOSUB; ctxt.map = map;
if ((primary_exp = dict_regexp_compile(map, lineno, &primary_pat)) == 0) ctxt.lineno = lineno;
return (0); ctxt.max_nsub = 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); * Find the highest-numbered $number substitution string. We can
regfree(primary_exp); * speed up processing 1) by passing hints to the regexp compiler,
myfree((char *) primary_exp); * setting the REG_NOSUB flag when the replacement text contains no
return (0); * $number string; 2) by passing hints to the regexp execution code,
} * limiting the amount of text that is made available for
if (negated_pat.regexp != 0) { * substitution.
negated_pat.options |= REG_NOSUB; */
if ((negated_exp = dict_regexp_compile(map, lineno, &negated_pat)) == 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.
*/
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); regfree(primary_exp);
myfree((char *) primary_exp); myfree((char *) primary_exp);
return (0); return (0);
} }
} else if (negated_pat.regexp != 0) {
negated_exp = 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. * 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->replacement = mystrdup(p);
rule->max_nsub = ctxt.max_nsub; rule->max_nsub = ctxt.max_nsub;
rule->lineno = lineno; rule->lineno = lineno;
rule->op = op;
rule->nesting = nesting;
rule->next = 0; rule->next = 0;
return (rule); 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; DICT_REGEXP_RULE *last_rule = 0;
int lineno = 0; int lineno = 0;
size_t max_nsub = 0; size_t max_nsub = 0;
int nesting = 0;
char *p; char *p;
line_buffer = vstring_alloc(100); 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)) { while (readlline(line_buffer, map_fp, &lineno)) {
p = vstring_str(line_buffer); p = vstring_str(line_buffer);
trimblanks(p, 0)[0] = 0; 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) {
if (rule->max_nsub > max_nsub) if (rule->max_nsub > max_nsub)
max_nsub = rule->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) if (last_rule == 0)
dict_regexp->head = rule; dict_regexp->head = rule;
else 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 * Allocate space for only as many matched substrings as used in the
* replacement text. * replacement text.

View File

@@ -44,7 +44,7 @@
/* dict_static_lookup - access static value*/ /* 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; dict_errno = 0;