2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 21:55:20 +00:00

postfix-2.3-20051014

This commit is contained in:
Wietse Venema
2005-10-14 00:00:00 -05:00
committed by Viktor Dukhovni
parent 9dba3caad0
commit 3bb375dbd2
16 changed files with 529 additions and 229 deletions

View File

@@ -11177,7 +11177,7 @@ Apologies for any names omitted.
due to expensive crypto operations. Files: global/anvil_clnt.c,
anvil/anvil.c, smtpd/smtpd.c.
Cleanup: eliminated massive code duplicatiom in the anvil
Cleanup: eliminated massive code duplication in the anvil
server that resulted from adding similar features one at a
time. File: anvil/anvil.c.
@@ -11191,6 +11191,37 @@ Apologies for any names omitted.
many MAIL FROM or RCPT TO commands) when we aren't closing
the connection. File: smtpd/smtpd.c.
20051012
Polishing: content of comments and sequence of code blocks
in the anvil server, TLS request rate error message in the
smtp server, and documentation, but no changes in code.
Files: anvil/anvil.c, smtpd/smtpd.c.
20051013
Horror: some systems have basename() and dirname() and some
don't; some implementations modify their input and some
don't; and some implementations use a private buffer that
is overwritten upon the next call. Postfix will use its own
safer versions called sane_basename() and sane_dirname().
These never modify the input, and allow the caller to control
how memory is allocated for the result. File:
util/sane_basename.c.
Feature: "sendmail -C path-to-main.cf" and "sendmail -C
config_directory" now do what one would expect. File:
sendmail/sendmail.c.
Bugfix: don't do smtpd_end_of_data_restrictions after the
transaction failed due to, e.g., a write error. File:
smtpd/smtpd.c.
Cleanup: the SMTP server now enforces the message_size_limit
even when the client did not send SIZE information with the
MAIL FROM command. This protects before-queue content
filters against over-size messages. File: smtpd/smtpd.c.
Open problems:
Try to recognize that Resent- headers appear in blocks,
@@ -11199,11 +11230,6 @@ Open problems:
Hard limits on cache sizes (anvil, specifically).
Look for systems with XPG basename() declared in <libgen.h>,
and prepare for phasing out the Postfix-supplied one.
Beware, however, that XPG basename() takes (char *), and
not (const char *) because it may change its argument.
Laptop friendliness: make the qmgr remember when the next
deferred queue scan needs to be done, and have the pickup
server stat() the maildrop directory before searching it.
@@ -11213,11 +11239,6 @@ Open problems:
Or do we punt the issue and issue X-Postfix for all errors
except SMTP?
Implement smtp_greet() routine to distinguish between reject
before versus after sending HELO/EHLO; this is needed to
eliminate the hack that uses one character lookahead to
find out if the server wants to talk to us.
Low: replace_sender/replace_recipient actions in access
maps?

View File

@@ -26,10 +26,11 @@ files. With deeply nested aliases or .forward files, this can greatly
reduce the number of queue files and cleanup process instances. To
get the earlier behavior, specify "frozen_delivered_to = no".
The frozen_delivered_to feature also fixes a long-standing problem
with multiple deliveries to recipients that are listed in multiple
nested aliases, but does so only when only the top-level alias has
an owner- alias, and none of the subordinate aliases.
The frozen_delivered_to feature can help to alleviate a long-standing
problem with multiple deliveries to recipients that are listed
multiple times in a hierarchy of nested aliases. For this to work,
only the top-level alias should have an owner- alias, and none of
the subordinate aliases.
Major changes with snapshot 20051011
====================================

View File

@@ -107,10 +107,16 @@ SENDMAIL(1) SENDMAIL(1)
This feature is available in Postfix version 2.1
and later.
<b>-C</b> <i>config</i><b>_</b><i>file</i> (ignored)
The path name of the <b>sendmail.cf</b> file. Postfix con-
figuration files are kept in the <b>/etc/postfix</b>
directory.
<b>-C</b> <i>config</i><b>_</b><i>file</i>
<b>-C</b> <i>config</i><b>_</b><i>dir</i>
The path name of the Postfix <b>main.cf</b> file, or of
its parent directory. This information is ignored
with Postfix versions before 2.3.
With older Postfix versions, specify a directory
pathname with the MAIL_CONFIG environment variable
to override the location of configuration files.
<b>-F</b> <i>full</i><b>_</b><i>name</i>
Set the sender full name. This is used only with

View File

@@ -91,9 +91,15 @@ report after verifying each recipient address. This is useful
for testing address rewriting and routing configurations.
.sp
This feature is available in Postfix version 2.1 and later.
.IP "\fB-C \fIconfig_file\fR (ignored)"
The path name of the \fBsendmail.cf\fR file. Postfix configuration
files are kept in the \fB/etc/postfix\fR directory.
.IP "\fB-C \fIconfig_file\fR"
.IP "\fB-C \fIconfig_dir\fR"
The path name of the Postfix \fBmain.cf\fR file, or of its
parent directory. This information is ignored with Postfix
versions before 2.3.
With older Postfix versions, specify a directory pathname
with the MAIL_CONFIG environment variable to override the
location of configuration files.
.IP "\fB-F \fIfull_name\fR
Set the sender full name. This is used only with messages that
have no \fBFrom:\fR message header.

View File

@@ -276,17 +276,168 @@
/* Application-specific. */
/*
* Configuration parameters.
*/
int var_anvil_time_unit;
int var_anvil_stat_time;
/*
* State.
* Global dynamic state.
*/
static HTABLE *anvil_remote_map; /* indexed by service+ remote client */
/*
* Absent a real-time query interface, these are logged at process exit time
* and at regular intervals.
* Remote connection state, one instance for each (service, client) pair.
*/
typedef struct {
char *ident; /* lookup key */
int count; /* connection count */
int rate; /* connection rate */
int mail; /* message rate */
int rcpt; /* recipient rate */
int ntls; /* new TLS session rate */
time_t start; /* time of first rate sample */
} ANVIL_REMOTE;
/*
* Local server state, one instance per anvil client connection. This allows
* us to clean up remote connection state when a local server goes away
* without cleaning up.
*/
typedef struct {
ANVIL_REMOTE *anvil_remote; /* XXX should be list */
} ANVIL_LOCAL;
/*
* The following operations are implemented as macros with recognizable
* names so that we don't lose sight of what the code is trying to do.
*
* Related operations are defined side by side so that the code implementing
* them isn't pages apart.
*/
/* Create new (service, client) state. */
#define ANVIL_REMOTE_FIRST_CONN(remote, id) \
do { \
(remote)->ident = mystrdup(id); \
(remote)->count = 1; \
(remote)->rate = 1; \
(remote)->mail = 0; \
(remote)->rcpt = 0; \
(remote)->ntls = 0; \
(remote)->start = event_time(); \
} while(0)
/* Destroy unused (service, client) state. */
#define ANVIL_REMOTE_FREE(remote) \
do { \
myfree((remote)->ident); \
myfree((char *) (remote)); \
} while(0)
/* Reset or update rate information for existing (service, client) state. */
#define ANVIL_REMOTE_RSET_RATE(remote, _start) \
do { \
(remote)->rate = 0; \
(remote)->mail = 0; \
(remote)->rcpt = 0; \
(remote)->ntls = 0; \
(remote)->start = _start; \
} while(0)
#define ANVIL_REMOTE_INCR_RATE(remote, _what) \
do { \
time_t _now = event_time(); \
if ((remote)->start + var_anvil_time_unit < _now) \
ANVIL_REMOTE_RSET_RATE((remote), _now); \
if ((remote)->_what < INT_MAX) \
(remote)->_what += 1; \
} while(0)
/* Update existing (service, client) state. */
#define ANVIL_REMOTE_NEXT_CONN(remote) \
do { \
ANVIL_REMOTE_INCR_RATE((remote), rate); \
if ((remote)->count == 0) \
event_cancel_timer(anvil_remote_expire, (char *) remote); \
(remote)->count++; \
} while(0)
#define ANVIL_REMOTE_INCR_MAIL(remote) ANVIL_REMOTE_INCR_RATE((remote), mail)
#define ANVIL_REMOTE_INCR_RCPT(remote) ANVIL_REMOTE_INCR_RATE((remote), rcpt)
#define ANVIL_REMOTE_INCR_NTLS(remote) ANVIL_REMOTE_INCR_RATE((remote), ntls)
/* Drop connection from (service, client) state. */
#define ANVIL_REMOTE_DROP_ONE(remote) \
do { \
if ((remote) && (remote)->count > 0) { \
if (--(remote)->count == 0) \
event_request_timer(anvil_remote_expire, (char *) remote, \
var_anvil_time_unit); \
} \
} while(0)
/* Create local server state. */
#define ANVIL_LOCAL_INIT(local) \
do { \
(local)->anvil_remote = 0; \
} while(0)
/* Add remote connection to local server. */
#define ANVIL_LOCAL_ADD_ONE(local, remote) \
do { \
/* XXX allow multiple remote clients per local server. */ \
if ((local)->anvil_remote) \
ANVIL_REMOTE_DROP_ONE((local)->anvil_remote); \
(local)->anvil_remote = (remote); \
} while(0)
/* Test if this remote connection is listed for this local server. */
#define ANVIL_LOCAL_REMOTE_LINKED(local, remote) \
((local)->anvil_remote == (remote))
/* Drop specific remote connection from local server. */
#define ANVIL_LOCAL_DROP_ONE(local, remote) \
do { \
/* XXX allow multiple remote clients per local server. */ \
if ((local)->anvil_remote == (remote)) \
(local)->anvil_remote = 0; \
} while(0)
/* Drop all remote connections from local server. */
#define ANVIL_LOCAL_DROP_ALL(stream, local) \
do { \
/* XXX allow multiple remote clients per local server. */ \
if ((local)->anvil_remote) \
anvil_remote_disconnect((stream), (local)->anvil_remote->ident); \
} while (0)
/*
* Lookup table to map request names to action routines.
*/
typedef struct {
const char *name;
void (*action) (VSTREAM *, const char *);
} ANVIL_REQ_TABLE;
/*
* Run-time statistics for maximal connection counts and event rates. These
* store the peak resource usage, remote connection, and time. Absent a
* query interface, this information is logged at process exit time and at
* configurable intervals.
*/
typedef struct {
int value; /* peak value */
@@ -336,151 +487,6 @@ static time_t max_cache_time; /* time of peak size */
} \
} while (0);
/*
* Remote connection state, one instance for each (service, client) pair.
*/
typedef struct {
char *ident; /* lookup key */
int count; /* connection count */
int rate; /* connection rate */
int mail; /* message rate */
int rcpt; /* recipient rate */
int ntls; /* new TLS session rate */
time_t start; /* time of first rate sample */
} ANVIL_REMOTE;
/*
* Local server state, one per server instance. This allows us to clean up
* connection state when a local server goes away without cleaning up.
*/
typedef struct {
ANVIL_REMOTE *anvil_remote; /* XXX should be list */
} ANVIL_LOCAL;
/*
* The following operations are implemented as macros with recognizable
* names so that we don't lose sight of what the code is trying to do.
*
* Related operations are defined side by side so that the code implementing
* them isn't pages apart.
*/
/* Create new (service, client) state. */
#define ANVIL_REMOTE_FIRST_CONN(remote, id) \
do { \
(remote)->ident = mystrdup(id); \
(remote)->count = 1; \
(remote)->rate = 1; \
(remote)->mail = 0; \
(remote)->rcpt = 0; \
(remote)->ntls = 0; \
(remote)->start = event_time(); \
} while(0)
/* Destroy unused (service, client) state. */
#define ANVIL_REMOTE_FREE(remote) \
do { \
myfree((remote)->ident); \
myfree((char *) (remote)); \
} while(0)
/* Reset event rate counters and start of data collection interval. */
#define ANVIL_REMOTE_RSET_RATE(remote, _start) \
do { \
(remote)->rate = 0; \
(remote)->mail = 0; \
(remote)->rcpt = 0; \
(remote)->ntls = 0; \
(remote)->start = _start; \
} while(0)
/* Add connection to (service, client) state. */
#define ANVIL_REMOTE_INCR_RATE(remote, _what) \
do { \
time_t _now = event_time(); \
if ((remote)->start + var_anvil_time_unit < _now) \
ANVIL_REMOTE_RSET_RATE((remote), _now); \
if ((remote)->_what < INT_MAX) \
(remote)->_what += 1; \
} while(0)
#define ANVIL_REMOTE_NEXT_CONN(remote) \
do { \
ANVIL_REMOTE_INCR_RATE((remote), rate); \
if ((remote)->count == 0) \
event_cancel_timer(anvil_remote_expire, (char *) remote); \
(remote)->count++; \
} while(0)
#define ANVIL_REMOTE_INCR_MAIL(remote) ANVIL_REMOTE_INCR_RATE((remote), mail)
#define ANVIL_REMOTE_INCR_RCPT(remote) ANVIL_REMOTE_INCR_RATE((remote), rcpt)
#define ANVIL_REMOTE_INCR_NTLS(remote) ANVIL_REMOTE_INCR_RATE((remote), ntls)
/* Drop connection from (service, client) state. */
#define ANVIL_REMOTE_DROP_ONE(remote) \
do { \
if ((remote) && (remote)->count > 0) { \
if (--(remote)->count == 0) \
event_request_timer(anvil_remote_expire, (char *) remote, \
var_anvil_time_unit); \
} \
} while(0)
/* Create local server state. */
#define ANVIL_LOCAL_INIT(local) \
do { \
(local)->anvil_remote = 0; \
} while(0)
/* Add connection to local server. */
#define ANVIL_LOCAL_ADD_ONE(local, remote) \
do { \
/* XXX allow multiple remote clients per local server. */ \
if ((local)->anvil_remote) \
ANVIL_REMOTE_DROP_ONE((local)->anvil_remote); \
(local)->anvil_remote = (remote); \
} while(0)
/* Test if this remote site is listed for this local client. */
#define ANVIL_LOCAL_REMOTE_LINKED(local, remote) \
((local)->anvil_remote == (remote))
/* Drop connection from local server. */
#define ANVIL_LOCAL_DROP_ONE(local, remote) \
do { \
/* XXX allow multiple remote clients per local server. */ \
if ((local)->anvil_remote == (remote)) \
(local)->anvil_remote = 0; \
} while(0)
/* Drop all connections from local server. */
#define ANVIL_LOCAL_DROP_ALL(stream, local) \
do { \
/* XXX allow multiple remote clients per local server. */ \
if ((local)->anvil_remote) \
anvil_remote_disconnect((stream), (local)->anvil_remote->ident); \
} while (0)
/*
* Lookup table to map request names to action routines.
*/
typedef struct {
const char *name;
void (*action) (VSTREAM *, const char *);
} ANVIL_REQ_TABLE;
/*
* Silly little macros.
*/
@@ -587,8 +593,8 @@ static ANVIL_REMOTE *anvil_remote_conn_update(VSTREAM *client_stream, const char
}
/*
* Record this connection under the local client information, so that we
* can clean up all its connection state when the local client goes away.
* Record this connection under the local server information, so that we
* can clean up all its connection state when the local server goes away.
*/
if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) == 0) {
anvil_local = (ANVIL_LOCAL *) mymalloc(sizeof(*anvil_local));
@@ -617,7 +623,7 @@ static void anvil_remote_connect(VSTREAM *client_stream, const char *ident)
anvil_remote = anvil_remote_conn_update(client_stream, ident);
/*
* Respond to the local client.
* Respond to the local server.
*/
attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
@@ -648,7 +654,7 @@ static void anvil_remote_mail(VSTREAM *client_stream, const char *ident)
anvil_remote = anvil_remote_conn_update(client_stream, ident);
/*
* Update message delivery request rate and respond to local client.
* Update message delivery request rate and respond to local server.
*/
ANVIL_REMOTE_INCR_MAIL(anvil_remote);
attr_print_plain(client_stream, ATTR_FLAG_NONE,
@@ -677,7 +683,7 @@ static void anvil_remote_rcpt(VSTREAM *client_stream, const char *ident)
anvil_remote = anvil_remote_conn_update(client_stream, ident);
/*
* Update recipient address rate and respond to local client.
* Update recipient address rate and respond to local server.
*/
ANVIL_REMOTE_INCR_RCPT(anvil_remote);
attr_print_plain(client_stream, ATTR_FLAG_NONE,
@@ -706,7 +712,7 @@ static void anvil_remote_newtls(VSTREAM *client_stream, const char *ident)
anvil_remote = anvil_remote_conn_update(client_stream, ident);
/*
* Update newtls rate and respond to local client.
* Update newtls rate and respond to local server.
*/
ANVIL_REMOTE_INCR_NTLS(anvil_remote);
attr_print_plain(client_stream, ATTR_FLAG_NONE,
@@ -747,7 +753,7 @@ static void anvil_remote_newtls_stat(VSTREAM *client_stream, const char *ident)
}
/*
* Respond to local client.
* Respond to local server.
*/
attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
@@ -769,8 +775,8 @@ static void anvil_remote_disconnect(VSTREAM *client_stream, const char *ident)
(unsigned long) client_stream, ident);
/*
* Update local and remote info if this remote site is listed for this
* local client.
* Update local and remote info if this remote connection is listed for
* this local server.
*/
if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) != 0
&& (anvil_remote =
@@ -784,7 +790,7 @@ static void anvil_remote_disconnect(VSTREAM *client_stream, const char *ident)
myname, (unsigned long) anvil_local);
/*
* Respond to the local client.
* Respond to the local server.
*/
attr_print_plain(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, ANVIL_ATTR_STATUS, ANVIL_STAT_OK,
@@ -805,8 +811,8 @@ static void anvil_service_done(VSTREAM *client_stream, char *unused_service,
(unsigned long) client_stream);
/*
* Look up the local client, and get rid of open remote connection state
* that we still have for this local client. Do not destroy remote client
* Look up the local server, and get rid of any remote connection state
* that we still have for this local server. Do not destroy remote client
* status information before it expires.
*/
if ((anvil_local = (ANVIL_LOCAL *) vstream_context(client_stream)) != 0) {
@@ -820,6 +826,31 @@ static void anvil_service_done(VSTREAM *client_stream, char *unused_service,
vstream_fileno(client_stream));
}
/* anvil_status_dump - log and reset extreme usage */
static void anvil_status_dump(char *unused_name, char **unused_argv)
{
ANVIL_MAX_RATE_REPORT(max_conn_rate, "connection");
ANVIL_MAX_COUNT_REPORT(max_conn_count, "connection");
ANVIL_MAX_RATE_REPORT(max_mail_rate, "message");
ANVIL_MAX_RATE_REPORT(max_rcpt_rate, "recipient");
ANVIL_MAX_RATE_REPORT(max_ntls_rate, "newtls");
if (max_cache_size > 0) {
msg_info("statistics: max cache size %d at %.15s",
max_cache_size, ctime(&max_cache_time) + 4);
max_cache_size = 0;
}
}
/* anvil_status_update - log and reset extreme usage periodically */
static void anvil_status_update(int unused_event, char *context)
{
anvil_status_dump((char *) 0, (char **) 0);
event_request_timer(anvil_status_update, context, var_anvil_stat_time);
}
/* anvil_service - perform service for client */
static void anvil_service(VSTREAM *client_stream, char *unused_service, char **argv)
@@ -889,8 +920,6 @@ static void anvil_service(VSTREAM *client_stream, char *unused_service, char **a
/* post_jail_init - post-jail initialization */
static void anvil_status_update(int, char *);
static void post_jail_init(char *unused_name, char **unused_argv)
{
@@ -910,31 +939,6 @@ static void post_jail_init(char *unused_name, char **unused_argv)
var_use_limit = 0;
}
/* anvil_status_dump - log and reset extreme usage */
static void anvil_status_dump(char *unused_name, char **unused_argv)
{
ANVIL_MAX_RATE_REPORT(max_conn_rate, "connection");
ANVIL_MAX_COUNT_REPORT(max_conn_count, "connection");
ANVIL_MAX_RATE_REPORT(max_mail_rate, "message");
ANVIL_MAX_RATE_REPORT(max_rcpt_rate, "recipient");
ANVIL_MAX_RATE_REPORT(max_ntls_rate, "newtls");
if (max_cache_size > 0) {
msg_info("statistics: max cache size %d at %.15s",
max_cache_size, ctime(&max_cache_time) + 4);
max_cache_size = 0;
}
}
/* anvil_status_update - log and reset extreme usage periodically */
static void anvil_status_update(int unused_event, char *context)
{
anvil_status_dump((char *) 0, (char **) 0);
event_request_timer(anvil_status_update, context, var_anvil_stat_time);
}
/* main - pass control to the multi-threaded skeleton */
int main(int argc, char **argv)

View File

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

View File

@@ -249,7 +249,7 @@ int main(int argc, char **argv)
*/
argv[0] = "postdrop";
msg_vstream_init(argv[0], VSTREAM_ERR);
msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
msg_syslog_init(mail_task("postdrop"), LOG_PID, LOG_FACILITY);
set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));
/*

View File

@@ -59,7 +59,6 @@ postqueue.o: ../../include/argv.h
postqueue.o: ../../include/attr.h
postqueue.o: ../../include/clean_env.h
postqueue.o: ../../include/connect.h
postqueue.o: ../../include/debug_process.h
postqueue.o: ../../include/flush_clnt.h
postqueue.o: ../../include/iostuff.h
postqueue.o: ../../include/mail_conf.h

View File

@@ -184,7 +184,6 @@
#include <mail_params.h>
#include <mail_conf.h>
#include <mail_task.h>
#include <debug_process.h>
#include <mail_run.h>
#include <mail_flush.h>
#include <flush_clnt.h>

View File

@@ -85,9 +85,15 @@
/* for testing address rewriting and routing configurations.
/* .sp
/* This feature is available in Postfix version 2.1 and later.
/* .IP "\fB-C \fIconfig_file\fR (ignored)"
/* The path name of the \fBsendmail.cf\fR file. Postfix configuration
/* files are kept in the \fB/etc/postfix\fR directory.
/* .IP "\fB-C \fIconfig_file\fR"
/* .IP "\fB-C \fIconfig_dir\fR"
/* The path name of the Postfix \fBmain.cf\fR file, or of its
/* parent directory. This information is ignored with Postfix
/* versions before 2.3.
/*
/* With older Postfix versions, specify a directory pathname
/* with the MAIL_CONFIG environment variable to override the
/* location of configuration files.
/* .IP "\fB-F \fIfull_name\fR
/* Set the sender full name. This is used only with messages that
/* have no \fBFrom:\fR message header.
@@ -901,6 +907,7 @@ int main(int argc, char **argv)
char *rewrite_context = MAIL_ATTR_RWR_LOCAL;
int dsn_notify = 0;
const char *dsn_envid = 0;
int saved_optind;
/*
* Be consistent with file permissions.
@@ -959,8 +966,24 @@ int main(int argc, char **argv)
}
/*
* Further initialization...
* Further initialization. Load main.cf first, so that command-line
* options can override main.cf settings. Pre-scan the argument list so
* that we load the right main.cf file.
*/
#define GETOPT_LIST "A:B:C:F:GIL:N:O:R:UV:X:b:ce:f:h:imno:p:r:q:tvx"
saved_optind = optind;
while ((c = GETOPT(argc, argv, GETOPT_LIST)) > 0) {
VSTRING *buf = vstring_alloc(1);
if (c == 'C'
&& setenv(CONF_ENV_PATH,
strcmp(sane_basename(buf, optarg), MAIN_CONF_FILE) == 0 ?
sane_dirname(buf, optarg) : optarg, 1) < 0)
msg_fatal_status(EX_UNAVAILABLE, "out of memory");
vstring_free(buf);
}
optind = saved_optind;
mail_conf_read();
get_mail_conf_str_table(str_table);
@@ -1024,7 +1047,7 @@ int main(int argc, char **argv)
optind++;
continue;
}
if ((c = GETOPT(argc, argv, "A:B:C:F:GIL:N:O:R:UV:X:b:ce:f:h:imno:p:r:q:tvx")) <= 0)
if ((c = GETOPT(argc, argv, GETOPT_LIST)) <= 0)
break;
switch (c) {
default:

View File

@@ -2253,13 +2253,18 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
if (prev_rec_type != REC_TYPE_CONT && *start == '.'
&& (state->proxy == 0 ? (++start, --len) == 0 : len == 1))
break;
state->act_size += len + 2;
if (state->err == CLEANUP_STAT_OK
&& out_record(out_stream, curr_rec_type, start, len) < 0)
state->err = out_error;
if (state->err == CLEANUP_STAT_OK) {
state->act_size += len + 2;
if (var_message_limit > 0 && state->act_size > var_message_limit)
state->err = CLEANUP_STAT_SIZE;
else if (out_record(out_stream, curr_rec_type, start, len) < 0)
state->err = out_error;
}
}
state->where = SMTPD_AFTER_DOT;
if (SMTPD_STAND_ALONE(state) == 0 && (err = smtpd_check_eod(state)) != 0) {
if (state->err == CLEANUP_STAT_OK
&& SMTPD_STAND_ALONE(state) == 0
&& (err = smtpd_check_eod(state)) != 0) {
smtpd_chat_reply(state, "%s", err);
if (state->proxy) {
smtpd_proxy_close(state);
@@ -2285,8 +2290,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
if (state->err == CLEANUP_STAT_OK &&
*STR(state->proxy_buffer) != '2')
state->err = CLEANUP_STAT_CONT;
} else {
state->error_mask |= MAIL_ERROR_SOFTWARE;
} else if (state->err != CLEANUP_STAT_SIZE) {
state->err |= CLEANUP_STAT_PROXY;
detail = cleanup_stat_detail(CLEANUP_STAT_PROXY);
vstring_sprintf(state->proxy_buffer,
@@ -3077,7 +3081,7 @@ static void smtpd_start_tls(SMTPD_STATE *state)
smtpd_chat_reply(state,
"421 4.7.0 %s Error: too many new TLS sessions from %s",
var_myhostname, state->namaddr);
msg_warn("Too many new TLS sessions: %d from %s for service %s",
msg_warn("New TLS session rate limit exceeded: %d from %s for service %s",
rate, state->namaddr, state->service);
/* XXX Use regular return to signal end of session. */
vstream_longjmp(state->client, SMTP_ERR_QUIET);

View File

@@ -29,7 +29,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
unix_recv_fd.c unix_send_fd.c unix_trigger.c unsafe.c uppercase.c \
username.c valid_hostname.c vbuf.c vbuf_print.c vstream.c \
vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \
write_buf.c write_wait.c
write_buf.c write_wait.c sane_basename.c
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@@ -60,7 +60,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
unix_recv_fd.o unix_send_fd.o unix_trigger.o unsafe.o uppercase.o \
username.o valid_hostname.o vbuf.o vbuf_print.o vstream.o \
vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \
write_buf.o write_wait.o
write_buf.o write_wait.o sane_basename.o
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
@@ -96,7 +96,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
inet_addr_list attr_print64 attr_scan64 base64_code attr_print0 \
attr_scan0 host_port attr_scan_plain attr_print_plain htable \
unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \
myaddrinfo myaddrinfo4 inet_proto
myaddrinfo myaddrinfo4 inet_proto sane_basename
LIB_DIR = ../../lib
INC_DIR = ../../include
@@ -387,6 +387,11 @@ inet_proto: $(LIB)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
sane_basename: $(LIB)
mv $@.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
stream_test: stream_test.c $(LIB)
$(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS)
@@ -433,6 +438,11 @@ inet_addr_list_test: inet_addr_list
diff inet_addr_list.ref inet_addr_list.tmp
rm -f inet_addr_list.tmp
sane_basename_test: sane_basename
./sane_basename <sane_basename.in >sane_basename.tmp 2>&1
diff sane_basename.ref sane_basename.tmp
rm -f sane_basename.tmp
base64_code_test: base64_code
./base64_code
@@ -1299,6 +1309,14 @@ sane_accept.o: msg.h
sane_accept.o: sane_accept.c
sane_accept.o: sane_accept.h
sane_accept.o: sys_defs.h
sane_basename.o: msg.h
sane_basename.o: mymalloc.c
sane_basename.o: mymalloc.h
sane_basename.o: sane_basename.c
sane_basename.o: stringops.h
sane_basename.o: sys_defs.h
sane_basename.o: vbuf.h
sane_basename.o: vstring.h
sane_connect.o: msg.h
sane_connect.o: sane_connect.c
sane_connect.o: sane_connect.h

View File

@@ -0,0 +1,180 @@
/*++
/* NAME
/* sane_basename 3
/* SUMMARY
/* split pathname into last component and parent directory
/* SYNOPSIS
/* #include <stringops.h>
/*
/* char *sane_basename(buf, path)
/* VSTRING *buf;
/* const char *path;
/*
/* char *sane_dirname(buf, path)
/* VSTRING *buf;
/* const char *path;
/* DESCRIPTION
/* These functions split a pathname into its last component
/* and its parent directory, excluding any trailing "/"
/* characters from the input. The result is a pointer to "/"
/* when the input is all "/" characters, or a pointer to "."
/* when the input is a null pointer or zero-length string.
/*
/* sane_basename() and sane_dirname() differ as follows
/* from standard basename() and dirname() implementations:
/* .IP \(bu
/* They can use caller-provided storage or private storage.
/* .IP \(bu
/* They never modify their input.
/* .PP
/* sane_basename() returns a pointer to string with the last
/* pathname component.
/*
/* sane_dirname() returns a pointer to string with the parent
/* directory. The result is a pointer to "." when the input
/* contains no '/' character.
/*
/* Arguments:
/* .IP buf
/* Result storage. If a null pointer is specified, each function
/* uses its own private memory that is overwritten upon each call.
/* .IP path
/* The input pathname.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this
/* software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
/* Utility library. */
#include <vstring.h>
#include <stringops.h>
#define STR(x) vstring_str(x)
/* sane_basename - skip directory prefix */
char *sane_basename(VSTRING *bp, const char *path)
{
static VSTRING *buf;
const char *first;
const char *last;
/*
* Your buffer or mine?
*/
if (bp == 0) {
bp = buf;
if (bp == 0)
bp = buf = vstring_alloc(10);
}
/*
* Special case: return "." for null or zero-length input.
*/
if (path == 0 || *path == 0)
return (STR(vstring_strcpy(bp, ".")));
/*
* Remove trailing '/' characters from input. Return "/" if input is all
* '/' characters.
*/
last = path + strlen(path) - 1;
while (*last == '/') {
if (last == path)
return (STR(vstring_strcpy(bp, "/")));
last--;
}
/*
* The pathname does not end in '/'. Skip to last '/' character if any.
*/
first = last - 1;
while (first >= path && *first != '/')
first--;
return (STR(vstring_strncpy(bp, first + 1, last - first)));
}
/* sane_dirname - keep directory prefix */
char *sane_dirname(VSTRING *bp, const char *path)
{
static VSTRING *buf;
const char *last;
/*
* Your buffer or mine?
*/
if (bp == 0) {
bp = buf;
if (bp == 0)
bp = buf = vstring_alloc(10);
}
/*
* Special case: return "." for null or zero-length input.
*/
if (path == 0 || *path == 0)
return (STR(vstring_strcpy(bp, ".")));
/*
* Remove trailing '/' characters from input. Return "/" if input is all
* '/' characters.
*/
last = path + strlen(path) - 1;
while (*last == '/') {
if (last == path)
return (STR(vstring_strcpy(bp, "/")));
last--;
}
/*
* This pathname does not end in '/'. Skip to last '/' character if any.
*/
while (last >= path && *last != '/')
last--;
if (last < path) /* no '/' */
return (STR(vstring_strcpy(bp, ".")));
/*
* Strip trailing '/' characters from dirname (not strictly needed).
*/
while (last > path && *last == '/')
last--;
return (STR(vstring_strncpy(bp, path, last - path + 1)));
}
#ifdef TEST
#include <vstring_vstream.h>
int main(int argc, char **argv)
{
VSTRING *buf = vstring_alloc(10);
char *dir;
char *base;
while (vstring_get_nonl(buf, VSTREAM_IN) > 0) {
dir = sane_dirname((VSTRING *) 0, STR(buf));
base = sane_basename((VSTRING *) 0, STR(buf));
vstream_printf("input=\"%s\" dir=\"%s\" base=\"%s\"\n",
STR(buf), dir, base);
}
vstream_fflush(VSTREAM_OUT);
vstring_free(buf);
return (0);
}
#endif

View File

@@ -0,0 +1,18 @@
///
/
fo2///
fo2/
fo2
///fo2
/fo2
///fo2///bar///
fo2///bar///
fo2///bar/
fo2/bar
/usr/lib
/usr/
usr
/
.
..

View File

@@ -0,0 +1,18 @@
input="///" dir="/" base="/"
input="/" dir="/" base="/"
input="fo2///" dir="." base="fo2"
input="fo2/" dir="." base="fo2"
input="fo2" dir="." base="fo2"
input="///fo2" dir="/" base="fo2"
input="/fo2" dir="/" base="fo2"
input="///fo2///bar///" dir="///fo2" base="bar"
input="fo2///bar///" dir="fo2" base="bar"
input="fo2///bar/" dir="fo2" base="bar"
input="fo2/bar" dir="fo2" base="bar"
input="" dir="." base="."
input="/usr/lib" dir="/usr" base="lib"
input="/usr/" dir="/" base="usr"
input="usr" dir="." base="usr"
input="/" dir="/" base="/"
input="." dir="." base="."
input=".." dir="." base=".."

View File

@@ -29,8 +29,11 @@ extern char *concatenate(const char *,...);
extern char *mystrtok(char **, const char *);
extern char *translit(char *, const char *, const char *);
#ifndef HAVE_BASENAME
#define basename postfix_basename
extern char *basename(const char *);
#endif
extern char *sane_basename(VSTRING *, const char *);
extern char *sane_dirname(VSTRING *, const char *);
extern VSTRING *unescape(VSTRING *, const char *);
extern int alldig(const char *);
extern int allprint(const char *);