]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.3-20051014
authorWietse Venema <wietse@porcupine.org>
Fri, 14 Oct 2005 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:31:32 +0000 (06:31 +0000)
16 files changed:
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/html/sendmail.1.html
postfix/man/man1/sendmail.1
postfix/src/anvil/anvil.c
postfix/src/global/mail_version.h
postfix/src/postdrop/postdrop.c
postfix/src/postqueue/Makefile.in
postfix/src/postqueue/postqueue.c
postfix/src/sendmail/sendmail.c
postfix/src/smtpd/smtpd.c
postfix/src/util/Makefile.in
postfix/src/util/sane_basename.c [new file with mode: 0644]
postfix/src/util/sane_basename.in [new file with mode: 0644]
postfix/src/util/sane_basename.ref [new file with mode: 0644]
postfix/src/util/stringops.h

index 418176d83535a93d1af0e9bf3bfff7a8329d97b6..523ecbd42ee55b93d1d66c08b2c4f5925425d435 100644 (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?
 
index a6fd5a21762474c439a546977331e1b8ea5f3c8d..d6b254f5128f939e08d5e43009e824d4f0c760c7 100644 (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
 ====================================
index 734f9a921abd6fb12cad77e7342313a8779ccf07..faa2317e4c71d9b3522e7b5c6d2a546020ad3d1c 100644 (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
index 9282483511324a78931de534a7f0905427e5699d..92f7e3a5cf38c36005191477aa8fe43c8a05edd3 100644 (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.
index 972144470563576bb7fcfa85b96bb222a101ac29..fb0aa89e6844dc62a5b8d6ee6580e966a7d87491 100644 (file)
 
 /* 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.
-  */
-typedef struct {
-    int     value;                     /* peak value */
-    char   *ident;                     /* lookup key */
-    time_t  when;                      /* time of peak value */
-} ANVIL_MAX;
-
-static ANVIL_MAX max_conn_count;       /* peak connection count */
-static ANVIL_MAX max_conn_rate;                /* peak connection rate */
-static ANVIL_MAX max_mail_rate;                /* peak message rate */
-static ANVIL_MAX max_rcpt_rate;                /* peak recipient rate */
-static ANVIL_MAX max_ntls_rate;                /* peak new TLS session rate */
-
-static int max_cache_size;             /* peak cache size */
-static time_t max_cache_time;          /* time of peak size */
-
-/* Update/report peak usage. */
-
-#define ANVIL_MAX_UPDATE(_max, _value, _ident) \
-    do { \
-       _max.value = _value; \
-       if (_max.ident == 0) { \
-           _max.ident = mystrdup(_ident); \
-       } else if (!STREQ(_max.ident, _ident)) { \
-           myfree(_max.ident); \
-           _max.ident = mystrdup(_ident); \
-       } \
-       _max.when = event_time(); \
-    } while (0)
-
-#define ANVIL_MAX_RATE_REPORT(_max, _name) \
-    do { \
-       if (_max.value > 0) { \
-           msg_info("statistics: max " _name " rate %d/%ds for (%s) at %.15s", \
-               _max.value, var_anvil_time_unit, \
-               _max.ident, ctime(&_max.when) + 4); \
-           _max.value = 0; \
-       } \
-    } while (0);
-
-#define ANVIL_MAX_COUNT_REPORT(_max, _name) \
-    do { \
-       if (_max.value > 0) { \
-           msg_info("statistics: max " _name " count %d for (%s) at %.15s", \
-               _max.value, _max.ident, ctime(&_max.when) + 4); \
-           _max.value = 0; \
-       } \
-    } while (0);
-
  /*
   * Remote connection state, one instance for each (service, client) pair.
   */
@@ -350,8 +301,9 @@ typedef struct {
 } 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.
+  * 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 */
@@ -386,7 +338,7 @@ typedef struct {
        myfree((char *) (remote)); \
     } while(0)
 
-/* Reset event rate counters and start of data collection interval. */
+/* Reset or update rate information for existing (service, client) state. */
 
 #define ANVIL_REMOTE_RSET_RATE(remote, _start) \
     do { \
@@ -397,8 +349,6 @@ typedef struct {
        (remote)->start = _start; \
     } while(0)
 
-/* Add connection to (service, client) state. */
-
 #define ANVIL_REMOTE_INCR_RATE(remote, _what) \
     do { \
        time_t _now = event_time(); \
@@ -408,6 +358,8 @@ typedef struct {
             (remote)->_what += 1; \
     } while(0)
 
+/* Update existing (service, client) state. */
+
 #define ANVIL_REMOTE_NEXT_CONN(remote) \
     do { \
        ANVIL_REMOTE_INCR_RATE((remote), rate); \
@@ -440,7 +392,7 @@ typedef struct {
        (local)->anvil_remote = 0; \
     } while(0)
 
-/* Add connection to local server. */
+/* Add remote connection to local server. */
 
 #define ANVIL_LOCAL_ADD_ONE(local, remote) \
     do { \
@@ -450,12 +402,12 @@ typedef struct {
        (local)->anvil_remote = (remote); \
     } while(0)
 
-/* Test if this remote site is listed for this local client. */
+/* Test if this remote connection is listed for this local server. */
 
 #define ANVIL_LOCAL_REMOTE_LINKED(local, remote) \
     ((local)->anvil_remote == (remote))
 
-/* Drop connection from local server. */
+/* Drop specific remote connection from local server. */
 
 #define ANVIL_LOCAL_DROP_ONE(local, remote) \
     do { \
@@ -464,7 +416,7 @@ typedef struct {
            (local)->anvil_remote = 0; \
     } while(0)
 
-/* Drop all connections from local server. */
+/* Drop all remote connections from local server. */
 
 #define ANVIL_LOCAL_DROP_ALL(stream, local) \
     do { \
@@ -481,6 +433,60 @@ typedef struct {
     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 */
+    char   *ident;                     /* lookup key */
+    time_t  when;                      /* time of peak value */
+} ANVIL_MAX;
+
+static ANVIL_MAX max_conn_count;       /* peak connection count */
+static ANVIL_MAX max_conn_rate;                /* peak connection rate */
+static ANVIL_MAX max_mail_rate;                /* peak message rate */
+static ANVIL_MAX max_rcpt_rate;                /* peak recipient rate */
+static ANVIL_MAX max_ntls_rate;                /* peak new TLS session rate */
+
+static int max_cache_size;             /* peak cache size */
+static time_t max_cache_time;          /* time of peak size */
+
+/* Update/report peak usage. */
+
+#define ANVIL_MAX_UPDATE(_max, _value, _ident) \
+    do { \
+       _max.value = _value; \
+       if (_max.ident == 0) { \
+           _max.ident = mystrdup(_ident); \
+       } else if (!STREQ(_max.ident, _ident)) { \
+           myfree(_max.ident); \
+           _max.ident = mystrdup(_ident); \
+       } \
+       _max.when = event_time(); \
+    } while (0)
+
+#define ANVIL_MAX_RATE_REPORT(_max, _name) \
+    do { \
+       if (_max.value > 0) { \
+           msg_info("statistics: max " _name " rate %d/%ds for (%s) at %.15s", \
+               _max.value, var_anvil_time_unit, \
+               _max.ident, ctime(&_max.when) + 4); \
+           _max.value = 0; \
+       } \
+    } while (0);
+
+#define ANVIL_MAX_COUNT_REPORT(_max, _name) \
+    do { \
+       if (_max.value > 0) { \
+           msg_info("statistics: max " _name " count %d for (%s) at %.15s", \
+               _max.value, _max.ident, ctime(&_max.when) + 4); \
+           _max.value = 0; \
+       } \
+    } while (0);
+
  /*
   * 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)
index 343b7fa40481417ee6924fce1bd9b1408cd5bc15..780c2441acd9523a81889cbe9f2084b76d79ea10 100644 (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
index d8592b9cd6d7e64aa765bbb3f4125bf118246241..222756224b55cea16b0f7d3723cc5d12831cf883 100644 (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]));
 
     /*
index be70e25f7b43c1806f497222854c436a4eacd922..49bc5f5f5b782c9b5518cbaeef530f5f96a78fc8 100644 (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
index 76925d55e72d45f7daddb94cf0f27a502228daf7..70f34cfb5090ab962cb8156f01bafd3daa2a42cf 100644 (file)
 #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>
index 955137de60c071de38d4762e4943b09431728b61..2f21822243f677851185a5d93651ba6dc1ef5a40 100644 (file)
 /*     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:
index 92becfb5719c670cfaa7203cb749a6e914504ed6..8728e6752730fc6c338267e92d163a16d73f05dd 100644 (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);
index 21beffee7437b6a58fa4c6a788e24f415ecedb93..df1168c68c07e274e710c3da9172582c8321857b 100644 (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
diff --git a/postfix/src/util/sane_basename.c b/postfix/src/util/sane_basename.c
new file mode 100644 (file)
index 0000000..3dea9e1
--- /dev/null
@@ -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
diff --git a/postfix/src/util/sane_basename.in b/postfix/src/util/sane_basename.in
new file mode 100644 (file)
index 0000000..75d613d
--- /dev/null
@@ -0,0 +1,18 @@
+///
+/
+fo2///
+fo2/
+fo2
+///fo2
+/fo2
+///fo2///bar///
+fo2///bar///
+fo2///bar/
+fo2/bar
+
+/usr/lib
+/usr/
+usr
+/
+.
+..
diff --git a/postfix/src/util/sane_basename.ref b/postfix/src/util/sane_basename.ref
new file mode 100644 (file)
index 0000000..8edcfcd
--- /dev/null
@@ -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=".."
index 47cfeb63114f50a3289415ac7f57e7a3fe093dac..02ea3079a3f485105b94ab8807a4a925f4b282de 100644 (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 *);