]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.0.16-20031220
authorWietse Venema <wietse@porcupine.org>
Sat, 20 Dec 2003 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:29:21 +0000 (06:29 +0000)
17 files changed:
postfix/html/smtp.8.html
postfix/man/man8/smtp.8
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/peer_name.c [new file with mode: 0644]
postfix/src/global/peer_name.h [new file with mode: 0644]
postfix/src/global/recipient_list.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp.h
postfix/src/smtp/smtp_connect.c
postfix/src/smtp/smtp_misc.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_state.c
postfix/src/smtp/smtp_trouble.c
postfix/src/smtpd/smtpd_xclient.c [new file with mode: 0644]
postfix/src/util/intv.c [new file with mode: 0644]
postfix/src/util/intv.h [new file with mode: 0644]

index 47a6f67a2ca28cb88aff6ec2e867438ad26833d8..ddee21531f10769fa80136bafb86de7ee70e6935 100644 (file)
@@ -235,11 +235,38 @@ SMTP(8)                                                   SMTP(8)
               destination.   The  default limit is taken from the
               <b>default_destination_concurrency_limit</b> parameter.
 
+              NB: This limit is enforced by the queue manager.
+
        <b>smtp_destination_recipient_limit</b>
               Limit the number of recipients per  message  deliv-
               ery.    The   default   limit  is  taken  from  the
               <b>default_destination_recipient_limit</b> parameter.
 
+       <b>smtp_mx_address_limit</b>
+              An upper bound on the number of MX (mail exchanger)
+              IP  addresses that the SMTP client will try to con-
+              nect to, before giving up or sending the mail to  a
+              fall-back relay host.
+
+              Specify zero to disable the limit.
+
+       <b>smtp_mx_session_limit</b>
+              An  upper bound on the number of SMTP sessions that
+              the SMTP client will engage in before giving up  or
+              sending the mail to a fall-back relay host.
+
+              Specify zero to disable the limit.
+
+       <b>smtp_backup_on_soft_error</b>
+              The  types  of  recoverable  error that qualify for
+              sending a recipient to a backup mail server or to a
+              fall-back relay host.  Specify zero or more of <b>ses-</b>
+              <b>sion</b> (SMTP  handshake  failure,  connection  loss),
+              <b>message</b>  (failure  of  MAIL  FROM, DATA or "."), or
+              <b>recipient</b> (failure of RCPT TO).
+
+              Recipients that do not qualify are deferred.
+
 <b>Timeout controls</b>
        The default time unit is seconds; an  explicit  time  unit
        can  be  specified by appending a one-letter suffix to the
index f805b7b1b7ae4a8eaf0d92206bba68476bf23012..73af6be685c1c50baf989c58a0b5f8ec73690d59 100644 (file)
@@ -197,10 +197,32 @@ Disallow anonymous logins.
 Limit the number of parallel deliveries to the same destination.
 The default limit is taken from the
 \fBdefault_destination_concurrency_limit\fR parameter.
+.sp
+NB: This limit is enforced by the queue manager.
 .IP \fBsmtp_destination_recipient_limit\fR
 Limit the number of recipients per message delivery.
 The default limit is taken from the
 \fBdefault_destination_recipient_limit\fR parameter.
+.IP \fBsmtp_mx_address_limit\fR
+An upper bound on the number of MX (mail exchanger) IP addresses
+that the SMTP client will try to connect to, before giving up or
+sending the mail to a fall-back relay host.
+.sp
+Specify zero to disable the limit.
+.IP \fBsmtp_mx_session_limit\fR
+An upper bound on the number of SMTP sessions that the SMTP client
+will engage in before giving up or sending the mail to a fall-back
+relay host.
+.sp
+Specify zero to disable the limit.
+.IP \fBsmtp_backup_on_soft_error\fR
+The types of recoverable error that qualify for sending a
+recipient to a backup mail server or to a fall-back relay host.
+Specify zero or more of \fBsession\fR (SMTP handshake failure,
+connection loss), \fBmessage\fR (failure of MAIL FROM, DATA or
+"."), or \fBrecipient\fR (failure of RCPT TO).
+.sp
+Recipients that do not qualify are deferred.
 .SH "Timeout controls"
 .ad
 .fi
index dc503c7cd486b99811a36f052faa08aa32b3453d..7dafb2fdd14f780211b6cb1c15e92868bb4595ca 100644 (file)
@@ -189,6 +189,14 @@ extern int var_smtp_dns_lookup;
                                " " SMTP_BACKUP_MESSAGE \
                                " " SMTP_BACKUP_RECIPIENT
 
+#define VAR_SMTP_MXADDR_LIMIT  "smtp_mx_address_limit"
+#define DEF_SMTP_MXADDR_LIMIT  0
+extern int var_smtp_mxaddr_limit;
+
+#define VAR_SMTP_MXSESS_LIMIT  "smtp_mx_session_limit"
+#define DEF_SMTP_MXSESS_LIMIT  2
+extern int var_smtp_mxsess_limit;
+
  /*
   * Location of the mail queue directory tree.
   */
index 386f333bcd4fd60f6aca264ac2eb8beff2b3ff4d..3b06fb7ca88d9f8eb4806a514bf52b400cb83aff 100644 (file)
@@ -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      "20031219"
+#define MAIL_RELEASE_DATE      "20031220"
 
 #define VAR_MAIL_VERSION       "mail_version"
 #define DEF_MAIL_VERSION       "2.0.16-" MAIL_RELEASE_DATE
diff --git a/postfix/src/global/peer_name.c b/postfix/src/global/peer_name.c
new file mode 100644 (file)
index 0000000..5e3affa
--- /dev/null
@@ -0,0 +1,113 @@
+/*++
+/* NAME
+/*     peer_name 3
+/* SUMMARY
+/*     produce printable peer name and address
+/* SYNOPSIS
+/*     #include <peer_name.h>
+/*
+/*     typedef struct {
+/* .in +4
+/*             int     type;
+/*             char    name;
+/*             char    addr;
+/* .in -4
+/*     } PEER_NAME;
+/*
+/*     PEER_NAME *peer_name(sock)
+/*     int     sock;
+/* DESCRIPTION
+/*     The \fIpeer_name\fR() routine attempts to produce a printable
+/*     version of the peer name and address of the specified socket.
+/*     The result is in static memory that will be overwritten.
+/*     Make a copy if the result is to be used for an appreciable
+/*     amount of time.
+/*
+/*     Where information is unavailable, the name and/or address
+/*     are set to "unknown".
+/*     The \fItype\fR result field specifies how the name and address
+/*     should be interpreted:
+/* .IP PEER_TYPE_INET
+/*     The socket specifies a TCP/IP endpoint.
+/*     The result is a hostname (from the DNS, a local hosts file or
+/*     other); the address a dotted quad.
+/* .IP PEER_TYPE_LOCAL
+/*     The socket argument specifies a local transport.
+/*     The result name is "localhost"; the result address is "127.0.0.1".
+/* .IP PEER_TYPE_UNKNOWN
+/*     The socket argument does not specify a socket.
+/*     The result name is "localhost"; the result address is "127.0.0.1".
+/* 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>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <valid_hostname.h>
+#include <peer_name.h>
+
+/* peer_name - produce printable peer name and address */
+
+PEER_NAME *peer_name(int sock)
+{
+    static PEER_NAME peer;
+    struct sockaddr_in sin;
+    SOCKADDR_SIZE len = sizeof(sin);
+    struct hostent *hp;
+
+    if (getpeername(sock, (struct sockaddr *) & sin, &len) == 0) {
+       switch (sin.sin_family) {
+       case AF_INET:
+           peer.type = PEER_TYPE_INET;
+           hp = gethostbyaddr((char *) &(sin.sin_addr),
+                              sizeof(sin.sin_addr), AF_INET);
+           peer.name = (hp && valid_hostname(hp->h_name, DO_GRIPE) ?
+                        hp->h_name : "unknown");
+           peer.addr = inet_ntoa(sin.sin_addr);
+           return (&peer);
+       case AF_UNSPEC:
+       case AF_UNIX:
+           peer.type = PEER_TYPE_LOCAL;
+           peer.name = "localhost";
+           peer.addr = "127.0.0.1";
+           return (&peer);
+       }
+    }
+    peer.type = PEER_TYPE_UNKNOWN;
+    peer.name = "localhost";
+    peer.addr = "127.0.0.1";
+    return (&peer);
+
+}
+
+#ifdef TEST
+
+#include <unistd.h>
+
+int     main(int unused_argc, char **unused_argv)
+{
+    PEER_NAME *peer;
+
+    peer = peer_name(STDIN_FILENO);
+    msg_info("name %s addr %s", peer->name, peer->addr);
+}
+
+#endif
diff --git a/postfix/src/global/peer_name.h b/postfix/src/global/peer_name.h
new file mode 100644 (file)
index 0000000..f1c9637
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _PEER_NAME_H_INCLUDED_
+#define _PEER_NAME_H_INCLUDED_
+
+/*++
+/* NAME
+/*     peer_name 3h
+/* SUMMARY
+/*     produce printable peer name and address
+/* SYNOPSIS
+/*     #include <peer_name.h>
+/* DESCRIPTION
+
+ /*
+  * External interface.
+  */
+typedef struct {
+    int     type;                      /* IPC type, see below */
+    char   *name;                      /* peer official name */
+    char   *addr;                      /* peer address */
+} PEER_NAME;
+
+#define PEER_TYPE_UNKNOWN      0
+#define PEER_TYPE_INET         1
+#define PEER_TYPE_LOCAL                2
+
+extern PEER_NAME *peer_name(int);
+
+/* 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
+/*--*/
+
+#endif
index 84e1e1061613ac266db004c2fecf848fdb397537..099e118875a67da4a223cfbc1b0d0a82e8cadcdb 100644 (file)
@@ -141,6 +141,7 @@ void    recipient_list_truncate(RECIPIENT_LIST *list, int new_len)
 
 void    recipient_list_free(RECIPIENT_LIST *list)
 {
-    recipient_list_truncate(list, 0);
+    if (list->len > 0)
+       recipient_list_truncate(list, 0);
     myfree((char *) list->info);
 }
index 364121031afdea9c9299807983c0afebe13609f4..670921fc1dce2222d9d48d998d2bc1585cc2c742 100644 (file)
 /*     Limit the number of parallel deliveries to the same destination.
 /*     The default limit is taken from the
 /*     \fBdefault_destination_concurrency_limit\fR parameter.
+/* .sp
+/*     NB: This limit is enforced by the queue manager.
 /* .IP \fBsmtp_destination_recipient_limit\fR
 /*     Limit the number of recipients per message delivery.
 /*     The default limit is taken from the
 /*     \fBdefault_destination_recipient_limit\fR parameter.
+/* .IP \fBsmtp_mx_address_limit\fR
+/*     An upper bound on the number of MX (mail exchanger) IP addresses
+/*     that the SMTP client will try to connect to, before giving up or
+/*     sending the mail to a fall-back relay host. 
+/* .sp
+/*     Specify zero to disable the limit.
+/* .IP \fBsmtp_mx_session_limit\fR
+/*     An upper bound on the number of SMTP sessions that the SMTP client
+/*     will engage in before giving up or sending the mail to a fall-back 
+/*     relay host.
+/* .sp
+/*     Specify zero to disable the limit.
+/* .IP \fBsmtp_backup_on_soft_error\fR
+/*     The types of recoverable error that qualify for sending a 
+/*     recipient to a backup mail server or to a fall-back relay host.
+/*     Specify zero or more of \fBsession\fR (SMTP handshake failure, 
+/*     connection loss), \fBmessage\fR (failure of MAIL FROM, DATA or 
+/*     "."), or \fBrecipient\fR (failure of RCPT TO).
+/* .sp
+/*     Recipients that do not qualify are deferred.
 /* .SH "Timeout controls"
 /* .ad
 /* .fi
@@ -314,6 +336,8 @@ char   *var_smtp_backup_mask;
 bool    var_smtp_quote_821_env;
 bool    var_smtp_defer_mxaddr;
 bool    var_smtp_send_xforward;
+int     var_smtp_mxaddr_limit;
+int     var_smtp_mxsess_limit;
 
  /*
   * Global variables. smtp_errno is set by the address lookup routines and by
@@ -515,6 +539,8 @@ int     main(int argc, char **argv)
     };
     static CONFIG_INT_TABLE int_table[] = {
        VAR_SMTP_LINE_LIMIT, DEF_SMTP_LINE_LIMIT, &var_smtp_line_limit, 0, 0,
+       VAR_SMTP_MXADDR_LIMIT, DEF_SMTP_MXADDR_LIMIT, &var_smtp_mxaddr_limit, 0, 0,
+       VAR_SMTP_MXSESS_LIMIT, DEF_SMTP_MXSESS_LIMIT, &var_smtp_mxsess_limit, 0, 0,
        0,
     };
     static CONFIG_BOOL_TABLE bool_table[] = {
index 04337966a74ba759501ed213c62061e045d0414b..2d61c80f30304ffa1813d10d3d1b90956d5e32c8 100644 (file)
@@ -55,7 +55,15 @@ typedef struct SMTP_STATE {
     off_t   size_limit;                        /* server limit or unknown */
     int     space_left;                        /* output length control */
     struct MIME_STATE *mime_state;     /* mime state machine */
+
+    /*
+     * Flags and counters to control the handling of mail delivery errors.
+     * There is some redundancy for sanity checking. At the end of an SMTP
+     * session all recipients should be marked one way or the other.
+     */
     int     final_server;              /* final mail server */
+    int     drop_count;                        /* recipients marked as drop */
+    int     keep_count;                        /* recipients marked as keep */
 } SMTP_STATE;
 
  /*
@@ -74,10 +82,40 @@ typedef struct SMTP_STATE {
 #define SMTP_FEATURE_XFORWARD_HELO     (1<<10)
 
  /*
-  * Application-specific per-recipient status.
+  * Application-specific per-recipient status. At the end of each delivery
+  * attempt each recipient is marked as DROP (remove from recipient list) or
+  * KEEP (deliver to backup mail server). The ones marked DROP are deleted
+  * before trying to deliver the remainder to a backup server. There's a bit
+  * of redundcancy to ensure that all recipients are marked.
+  * 
+  * The single recipient list abstraction dates from the time that the SMTP
+  * client would give up after one SMTP session, so that each recipient was
+  * either bounced, delivered or deferred. Implicitly, all recipients were
+  * marked as DROP.
+  * 
+  * This abstraction is less convenient when an SMTP client must be able to
+  * deliver left-over recipients to a backup host. It might be more natural
+  * to have an input list with recipients to deliver, and an output list with
+  * the left-over recipients.
   */
 #define SMTP_RCPT_KEEP 1               /* send to backup host */
-#define SMTP_RCPT_DROP 2               /* remove from list */
+#define SMTP_RCPT_DROP 2               /* remove from request */
+
+#define SMTP_RCPT_MARK_INIT(state) do { \
+           (state)->drop_count = (state)->keep_count = 0; \
+       } while (0)
+
+#define SMTP_RCPT_MARK_DROP(state, rcpt) do { \
+           (rcpt)->status = SMTP_RCPT_DROP; (state)->drop_count++; \
+       } while (0)
+
+#define SMTP_RCPT_MARK_KEEP(state, rcpt) do { \
+           (rcpt)->status = SMTP_RCPT_KEEP; (state)->keep_count++; \
+       } while (0)
+
+#define SMTP_RCPT_MARK_ISSET(rcpt) ((rcpt)->status != 0)
+
+extern int smtp_rcpt_mark_finish(SMTP_STATE *);
 
  /*
   * smtp.c
@@ -147,7 +185,6 @@ extern void smtp_chat_notify(SMTP_STATE *);
   * smtp_misc.c.
   */
 extern void smtp_rcpt_done(SMTP_STATE *, const char *, RECIPIENT *);
-extern int smtp_weed_request(RECIPIENT_LIST *);
 
  /*
   * smtp_trouble.c
index 9ed095c838ac869c5d8aa75be9c1107d021c7ae9..47997451508cb44ffd47e0ececb2576a653de657 100644 (file)
@@ -283,38 +283,42 @@ int     smtp_connect(SMTP_STATE *state)
     char  **cpp;
     DNS_RR *addr_list;
     DNS_RR *addr;
+    DNS_RR *next;
+    int     addr_count;
+    int     sess_count;
 
     /*
      * First try to deliver to the indicated destination, then try to deliver
      * to the optional fall-back relays.
      * 
      * Future proofing: do a null destination sanity check in case we allow the
-     * primary destination to be a list, as it could be just a bunch of
-     * separators.
+     * primary destination to be a list (it could be just separators).
      */
     sites = argv_alloc(1);
     argv_add(sites, request->nexthop, (char *) 0);
     if (sites->argc == 0)
        msg_panic("null destination: \"%s\"", request->nexthop);
-    if (*var_fallback_relay)
-       argv_split_append(sites, var_fallback_relay, ", \t\r\n");
+    argv_split_append(sites, var_fallback_relay, ", \t\r\n");
 
     /*
-     * Don't give up after a qualifying soft error until we have tried all
-     * qualifying mail servers.
-     * 
      * Don't give up after a hard host lookup error until we have tried the
      * fallback relay servers.
      * 
      * Don't bounce mail after a host lookup problem with a relayhost or with a
      * fallback relay.
      * 
+     * Don't give up after a qualifying soft error until we have tried all
+     * qualifying backup mail servers.
+     * 
      * All this means that error handling and error reporting depends on whether
-     * the error qualifies for trying more mail servers, or whether we're
-     * looking up a relayhost or fallback relay.
+     * the error qualifies for trying to deliver to a backup mail server, or
+     * whether we're looking up a relayhost or fallback relay. The challenge
+     * then is to build this into the pre-existing SMTP client without
+     * getting lost in the complexity.
      */
     for (cpp = sites->argv; (dest = *cpp) != 0; cpp++) {
        state->final_server = (cpp[1] == 0);
+       smtp_errno = SMTP_NONE;
 
        /*
         * Parse the destination. Default is to use the SMTP port. Look up
@@ -337,7 +341,8 @@ int     smtp_connect(SMTP_STATE *state)
        myfree(dest_buf);
 
        /*
-        * Don't try the fall-back relay if mail loops to myself.
+        * Don't try any backup host if mail loops to myself. That would just
+        * make the problem worse.
         */
        if (addr_list == 0 && smtp_errno == SMTP_LOOP)
            break;
@@ -346,12 +351,23 @@ int     smtp_connect(SMTP_STATE *state)
         * Connect to an SMTP server. XXX Limit the number of addresses that
         * we're willing to try for a non-fallback destination.
         * 
-        * After a soft error, weed out the recipient list and if there are any
-        * left, try again.
+        * At the start of an SMTP session, all recipients are unmarked. In the
+        * course of an SMTP session, recipients are marked as KEEP (deliver
+        * to backup mail server) or DROP (remove from recipient list). The
+        * marking policy is configurable with the smtp_backup_on_soft_error
+        * parameter. At the end of an SMTP session, weed out the recipient
+        * list. Unmark any left-over recipients and try to deliver them to a
+        * backup mail server.
         */
-       for (addr = addr_list; addr; addr = addr->next) {
+       for (sess_count = addr_count = 0, addr = addr_list; addr; addr = next) {
+           next = addr->next;
+           if (++addr_count == var_smtp_mxaddr_limit)
+               next = 0;
            if ((state->session = smtp_connect_addr(addr, port, why)) != 0) {
-               state->final_server = (cpp[1] == 0 && addr->next == 0);
+               if (++sess_count == var_smtp_mxsess_limit)
+                   next = 0;
+               SMTP_RCPT_MARK_INIT(state);
+               state->final_server = (cpp[1] == 0 && next == 0);
                state->session->best = (addr->pref == addr_list->pref);
                debug_peer_check(state->session->host, state->session->addr);
                if (smtp_helo(state) == 0)
@@ -363,7 +379,7 @@ int     smtp_connect(SMTP_STATE *state)
                /* XXX smtp_xfer() may abort in the middle of DATA. */
                smtp_session_free(state->session);
                debug_peer_restore();
-               if (smtp_weed_request(&request->rcpt_list) == 0)
+               if (smtp_rcpt_mark_finish(state) == 0)
                    break;
            } else {
                msg_info("%s (port %d)", vstring_str(why), ntohs(port));
@@ -373,17 +389,24 @@ int     smtp_connect(SMTP_STATE *state)
     }
 
     /*
-     * We still need to deliver, bounce or defer some recipients.
+     * We still need to deliver, bounce or defer some left-over recipients:
+     * either mail loops or some backup mail server was unavailable.
      * 
      * Pay attention to what could be configuration problems, and pretend that
      * these are recoverable rather than bouncing the mail.
      */
     if (request->rcpt_list.len > 0) {
-       if (smtp_errno != SMTP_RETRY) {
+       switch (smtp_errno) {
+
+       default:
+           msg_panic("smtp_connect: bad error indication %d", smtp_errno);
+
+       case SMTP_LOOP:
+       case SMTP_FAIL:
 
            /*
             * The fall-back destination did not resolve as expected, or it
-            * is refusing to talk to us.
+            * is refusing to talk to us, or mail for it loops back to us.
             */
            if (sites->argc > 1 && cpp > sites->argv) {
                msg_warn("%s configuration problem", VAR_FALLBACK_RELAY);
@@ -392,7 +415,7 @@ int     smtp_connect(SMTP_STATE *state)
 
            /*
             * The next-hop relayhost did not resolve as expected, or it is
-            * refusing to talk to us.
+            * refusing to talk to us, or mail for it loops back to us.
             */
            else if (strcmp(sites->argv[0], var_relayhost) == 0) {
                msg_warn("%s configuration problem", VAR_RELAYHOST);
@@ -400,27 +423,26 @@ int     smtp_connect(SMTP_STATE *state)
            }
 
            /*
-            * Mail for the next-hop destination loops back to myself.
+            * Mail for the next-hop destination loops back to myself. Pass
+            * the mail to the best_mx_transport or bounce it.
             */
            else if (smtp_errno == SMTP_LOOP && *var_bestmx_transp) {
                state->status = deliver_pass_all(MAIL_CLASS_PRIVATE,
                                                 var_bestmx_transp,
                                                 request);
-               smtp_errno = SMTP_NONE;
+               break;
            }
-       }
+           /* FALLTHROUGH */
 
-       /*
-        * We still need to bounce or defer some recipients. Do it now or
-        * else they would silently disappear due to lack of error
-        * indication.
-        */
-       if (smtp_errno != SMTP_NONE) {
-           if (!state->final_server)
-               msg_panic("smtp_connect: we have left-over recipients but "
-                         "we did not try to connect to the final server");
+       case SMTP_RETRY:
+
+           /*
+            * We still need to bounce or defer some left-over recipients:
+            * either mail loops or some backup mail server was unavailable.
+            */
            smtp_site_fail(state, smtp_errno == SMTP_RETRY ? 450 : 550,
                           "%s", vstring_str(why));
+           break;
        }
     }
 
index f9b2a3d7ee0f188a6ced5ed7fb09edf7cf3a0f82..509561db5f9e81d4c4197d5976fbc63dcd74dc00 100644 (file)
@@ -1,7 +1,47 @@
+/*++
+/* NAME
+/*     smtp_misc 3
+/* SUMMARY
+/*     assorted routines
+/* SYNOPSIS
+/*     #include <smtp.h>
+/*
+/*     void    smtp_rcpt_done(state, reply, rcpt)
+/*     SMTP_STATE *state;
+/*     const char *reply;
+/*     RECIPIENT *rcpt;
+/*
+/*     int     smtp_rcpt_mark_finish(SMTP_STATE *state)
+/*     SMTP_STATE *state;
+/* DESCRIPTION
+/*     smtp_rcpt_done() logs that a recipient is completed and upon
+/*     success it marks the recipient as done in the queue file.
+/*     Finally, it marks the in-memory recipient as DROP.
+/*
+/*     smtp_rcpt_mark_finish() cleans up the in-memory recipient list.
+/*     It deletes recipients marked DROP, and unmarks recipients marked KEEP.
+/*     It enforces the requirement that all recipients are marked one way
+/*     or the other. The result value is the number of left-over recipients.
+/* DIAGNOSTICS
+/*     Panic: interface violation.
+/*
+/*     When a recipient can't be logged as completed, the recipient is
+/*     logged as deferred instead.
+/* 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>
-#include <stdlib.h>                    /* smtp_weed_request  */
+#include <stdlib.h>                    /* smtp_rcpt_mark_finish  */
 
 /* Utility  library. */
 
@@ -38,44 +78,47 @@ void    smtp_rcpt_done(SMTP_STATE *state, const char *reply, RECIPIENT *rcpt)
     if (status == 0)
        if (request->flags & DEL_REQ_FLAG_SUCCESS)
            deliver_completed(state->src, rcpt->offset);
-    rcpt->status = SMTP_RCPT_DROP;
+    SMTP_RCPT_MARK_DROP(state, rcpt);
     state->status |= status;
 }
 
-/* smtp_weed_request_callback - qsort callback */
+/* smtp_rcpt_mark_finish_callback - qsort callback */
 
-static int smtp_weed_request_callback(const void *a, const void *b)
+static int smtp_rcpt_mark_finish_callback(const void *a, const void *b)
 {
     return (((RECIPIENT *) a)->status - ((RECIPIENT *) b)->status);
 }
 
-/* smtp_weed_request - purge completed recipients from request */
+/* smtp_rcpt_mark_finish - purge completed recipients from request */
 
-int     smtp_weed_request(RECIPIENT_LIST *rcpt_list)
+int     smtp_rcpt_mark_finish(SMTP_STATE *state)
 {
+    RECIPIENT_LIST *rcpt_list = &state->request->rcpt_list;
     RECIPIENT *rcpt;
-    int     nrcpt;
 
     /*
-     * Status codes one can expect to find: SMTP_RCPT_KEEP (try recipient
-     * another time), SMTP_RCPT_DROP (remove recipient from request) and zero
-     * (error: after delivery attempt, recipient status should be either KEEP
-     * or DROP).
+     * Sanity checks.
+     */
+    if (state->drop_count + state->keep_count != rcpt_list->len)
+       msg_panic("smtp_rcpt_mark_finish: recipient count mismatch: %d+%d!=%d",
+                 state->drop_count, state->keep_count, rcpt_list->len);
+
+    /*
+     * Recipients marked KEEP sort before recipients marked DROP. Skip the
+     * sorting in the common case that all recipients are marked the same.
      */
-    if (rcpt_list->len > 1)
+    if (state->drop_count > 0 && state->keep_count > 0)
        qsort((void *) rcpt_list->info, rcpt_list->len,
-             sizeof(rcpt_list->info), smtp_weed_request_callback);
-
-    for (nrcpt = 0; nrcpt < rcpt_list->len; nrcpt++) {
-       rcpt = rcpt_list->info + nrcpt;
-       if (rcpt->status == SMTP_RCPT_KEEP)
-           rcpt->status = 0;
-       if (rcpt->status == SMTP_RCPT_DROP)
-           break;
-       else
-           msg_panic("smtp_weed_request: bad status: %d for <%s>",
-                     rcpt->status, rcpt->address);
-    }
-    recipient_list_truncate(rcpt_list, nrcpt);
-    return (nrcpt);
+             sizeof(rcpt_list->info), smtp_rcpt_mark_finish_callback);
+
+    /*
+     * Truncate the recipient list and unmark the left-over recipients so
+     * that the result looks like a brand-new recipient list.
+     */
+    if (state->keep_count < rcpt_list->len)
+       recipient_list_truncate(rcpt_list, state->keep_count);
+    for (rcpt = rcpt_list->info; rcpt < rcpt_list->info + rcpt_list->len; rcpt++)
+       rcpt->status = 0;
+
+    return (rcpt_list->len);
 }
index 438cffe767faad902353489fae2455e943c70665..1d139b24068c715239189e53a48156f5c88c2537 100644 (file)
@@ -437,7 +437,7 @@ int     smtp_xfer(SMTP_STATE *state)
     if (request->rcpt_list.len <= 0)
        msg_panic("smtp_xfer: bad recipient count: %d",
                  request->rcpt_list.len);
-    if (request->rcpt_list.info->status != 0)
+    if (SMTP_RCPT_MARK_ISSET(request->rcpt_list.info))
        msg_panic("smtp_xfer: bad recipient status: %d",
                  request->rcpt_list.info->status);
 
@@ -822,7 +822,7 @@ int     smtp_xfer(SMTP_STATE *state)
                        } else {
                            for (nrcpt = 0; nrcpt < recv_rcpt; nrcpt++) {
                                rcpt = request->rcpt_list.info + nrcpt;
-                               if (rcpt->status == 0)
+                               if (!SMTP_RCPT_MARK_ISSET(rcpt))
                                    smtp_rcpt_done(state, resp->str, rcpt);
                            }
                        }
index 726feb5cef89c25fb85f19f40bd8d2b2cd08280c..8b14f0c1dac73124b9607ec60700eea584dc0e1a 100644 (file)
@@ -1,6 +1,6 @@
 /*++
 /* NAME
-/*     smtp_state 8
+/*     smtp_state 3
 /* SUMMARY
 /*     initialize/cleanup shared state
 /* SYNOPSIS
@@ -72,7 +72,6 @@ SMTP_STATE *smtp_state_alloc(void)
     state->size_limit = 0;
     state->space_left = 0;
     state->mime_state = 0;
-    state->final_server = 0;
     return (state);
 }
 
index 6281955971d71d7b15c95c0dd440fa1a125ae84a..c7d3e85597d92ebc7c9b530495f6d9961dbf8402 100644 (file)
@@ -33,9 +33,9 @@
 /*     the problem, delivery of a single message is deferred, delivery
 /*     of all messages to the same domain is deferred, or one or more
 /*     recipients are given up as non-deliverable and a bounce log is
-/*     updated. In any case, the recipient status is updated to either
-/*     SMTP_RCPT_KEEP (try again with a backup host) or SMTP_RCPT_DROP
-/*     (delete recipient from delivery request).
+/*     updated. In any case, the recipient is marked as either KEEP
+/*     (try again with a backup host) or DROP (delete recipient from 
+/*     delivery request).
 /*
 /*     In addition, when an unexpected response code is seen such
 /*     as 3xx where only 4xx or 5xx are expected, or any error code
@@ -185,9 +185,9 @@ int     smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
        msg_info("%s: %s", request->queue_id, vstring_str(why));
        for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
            rcpt = request->rcpt_list.info + nrcpt;
-           if (rcpt->status != 0)
+           if (SMTP_RCPT_MARK_ISSET(rcpt))
                continue;
-           rcpt->status = SMTP_RCPT_KEEP;
+           SMTP_RCPT_MARK_KEEP(state, rcpt);
        }
     }
 
@@ -199,7 +199,7 @@ int     smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
     else {
        for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
            rcpt = request->rcpt_list.info + nrcpt;
-           if (rcpt->status != 0)
+           if (SMTP_RCPT_MARK_ISSET(rcpt))
                continue;
            status = (soft_error ? defer_append : bounce_append)
                (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
@@ -208,7 +208,7 @@ int     smtp_site_fail(SMTP_STATE *state, int code, char *format,...)
                 request->arrival_time, "%s", vstring_str(why));
            if (status == 0)
                deliver_completed(state->src, rcpt->offset);
-           rcpt->status = SMTP_RCPT_DROP;
+           SMTP_RCPT_MARK_DROP(state, rcpt);
            state->status |= status;
        }
        /* XXX This assumes no fall-back relay. */
@@ -254,9 +254,9 @@ int     smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
        msg_info("%s: %s", request->queue_id, vstring_str(why));
        for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
            rcpt = request->rcpt_list.info + nrcpt;
-           if (rcpt->status != 0)
+           if (SMTP_RCPT_MARK_ISSET(rcpt))
                continue;
-           rcpt->status = SMTP_RCPT_KEEP;
+           SMTP_RCPT_MARK_KEEP(state, rcpt);
        }
     }
 
@@ -268,7 +268,7 @@ int     smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
     else {
        for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
            rcpt = request->rcpt_list.info + nrcpt;
-           if (rcpt->status != 0)
+           if (SMTP_RCPT_MARK_ISSET(rcpt))
                continue;
            status = (soft_error ? defer_append : bounce_append)
                (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
@@ -277,7 +277,7 @@ int     smtp_mesg_fail(SMTP_STATE *state, int code, char *format,...)
                 "%s", vstring_str(why));
            if (status == 0)
                deliver_completed(state->src, rcpt->offset);
-           rcpt->status = SMTP_RCPT_DROP;
+           SMTP_RCPT_MARK_DROP(state, rcpt);
            state->status |= status;
        }
     }
@@ -301,6 +301,12 @@ void    smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
     int     soft_error = SMTP_SOFT(code);
     va_list ap;
 
+    /*
+     * Sanity check.
+     */
+    if (SMTP_RCPT_MARK_ISSET(rcpt))
+       msg_panic("smtp_rcpt_fail: recipient <%s> is marked", rcpt->address);
+
     /*
      * Don't defer this recipient record just yet when this error qualifies
      * for trying other mail servers. Just log something informative to show
@@ -314,7 +320,7 @@ void    smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
        vstring_vsprintf(buf, format, ap);
        va_end(ap);
        msg_info("%s: %s", request->queue_id, vstring_str(buf));
-       rcpt->status = SMTP_RCPT_KEEP;
+       SMTP_RCPT_MARK_KEEP(state, rcpt);
        vstring_free(buf);
     }
 
@@ -335,7 +341,7 @@ void    smtp_rcpt_fail(SMTP_STATE *state, int code, RECIPIENT *rcpt,
        va_end(ap);
        if (status == 0)
            deliver_completed(state->src, rcpt->offset);
-       rcpt->status = SMTP_RCPT_DROP;
+       SMTP_RCPT_MARK_DROP(state, rcpt);
        state->status |= status;
     }
     smtp_check_code(state, code);
@@ -377,9 +383,9 @@ int     smtp_stream_except(SMTP_STATE *state, int code, char *description)
        msg_info("%s: %s", request->queue_id, vstring_str(why));
        for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
            rcpt = request->rcpt_list.info + nrcpt;
-           if (rcpt->status != 0)
+           if (SMTP_RCPT_MARK_ISSET(rcpt))
                continue;
-           rcpt->status = SMTP_RCPT_KEEP;
+           SMTP_RCPT_MARK_KEEP(state, rcpt);
        }
     }
 
@@ -390,7 +396,7 @@ int     smtp_stream_except(SMTP_STATE *state, int code, char *description)
     else {
        for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
            rcpt = request->rcpt_list.info + nrcpt;
-           if (rcpt->status != 0)
+           if (SMTP_RCPT_MARK_ISSET(rcpt))
                continue;
            state->status |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
                                          request->queue_id,
@@ -398,7 +404,7 @@ int     smtp_stream_except(SMTP_STATE *state, int code, char *description)
                                          rcpt->offset, session->namaddr,
                                          request->arrival_time,
                                          "%s", vstring_str(why));
-           rcpt->status = SMTP_RCPT_DROP;
+           SMTP_RCPT_MARK_DROP(state, rcpt);
        }
     }
 
diff --git a/postfix/src/smtpd/smtpd_xclient.c b/postfix/src/smtpd/smtpd_xclient.c
new file mode 100644 (file)
index 0000000..f868811
--- /dev/null
@@ -0,0 +1,94 @@
+/*++
+/* NAME
+/*     smtpd_xclient 3
+/* SUMMARY
+/*     maintain XCLIENT information
+/* SYNOPSIS
+/*     #include "smtpd.h"
+/*
+/*     void    smtpd_xclient_init(state)
+/*     SMTPD_STATE *state;
+/*
+/*     void    smtpd_xclient_reset(state)
+/*     SMTPD_STATE *state;
+/* DESCRIPTION
+/*     smtpd_xclient_init() zeroes the attributes for storage of XCLIENT
+/*     FORWARD command parameters.
+/*
+/*     smtpd_xclient_preset() takes the result from smtpd_xclient_init()
+/*     and sets all fields to the same "unknown" value that regular
+/*     client attributes would have.
+/*
+/*     smtpd_xclient_reset() restores the state from smtpd_xclient_init().
+/* 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 <mymalloc.h>
+#include <msg.h>
+
+/* Global library. */
+
+#include <mail_proto.h>
+
+/* Application-specific. */
+
+#include <smtpd.h>
+
+/* smtpd_xclient_init - initialize XCLIENT attributes */
+
+void    smtpd_xclient_init(SMTPD_STATE *state)
+{
+    state->xclient.used = 0;
+    state->xclient.name = 0;
+    state->xclient.addr = 0;
+    state->xclient.namaddr = 0;
+    state->xclient.peer_code = 0;
+    state->xclient.protocol = 0;
+    state->xclient.helo_name = 0;
+}
+
+/* smtpd_xclient_preset - set xclient attributes to "unknown" */
+
+void    smtpd_xclient_preset(SMTPD_STATE *state)
+{
+
+    /*
+     * This is a temporary solution. Unknown forwarded attributes get the
+     * same values as unknown normal attributes, so that we don't break
+     * assumptions in pre-existing code.
+     */
+    state->xclient.used = 1;
+    state->xclient.name = mystrdup(CLIENT_NAME_UNKNOWN);
+    state->xclient.addr = mystrdup(CLIENT_ADDR_UNKNOWN);
+    state->xclient.namaddr = mystrdup(CLIENT_NAMADDR_UNKNOWN);
+    state->xclient.protocol = mystrdup(CLIENT_PROTO_UNKNOWN);
+}
+
+/* smtpd_xclient_reset - reset XCLIENT attributes */
+
+void    smtpd_xclient_reset(SMTPD_STATE *state)
+{
+#define FREE_AND_WIPE(s) { if (s) myfree(s); s = 0; }
+
+    state->xclient.used = 0;
+    FREE_AND_WIPE(state->xclient.name);
+    FREE_AND_WIPE(state->xclient.addr);
+    FREE_AND_WIPE(state->xclient.namaddr);
+    state->xclient.peer_code = 0;
+    FREE_AND_WIPE(state->xclient.protocol);
+    FREE_AND_WIPE(state->xclient.helo_name);
+}
diff --git a/postfix/src/util/intv.c b/postfix/src/util/intv.c
new file mode 100644 (file)
index 0000000..774e12d
--- /dev/null
@@ -0,0 +1,117 @@
+/*++
+/* NAME
+/*     intv 3
+/* SUMMARY
+/*     integer array utilities
+/* SYNOPSIS
+/*     #include <intv.h>
+/*
+/*     INTV    *intv_alloc(len)
+/*     int     len;
+/*
+/*     INTV    *intv_free(intvp)
+/*     INTV    *intvp;
+/*
+/*     void    intv_add(intvp, count, arg, ...)
+/*     INTV    *intvp;
+/*     int     count;
+/*     int     *arg;
+/* DESCRIPTION
+/*     The functions in this module manipulate arrays of integers.
+/*     An INTV structure contains the following members:
+/* .IP len
+/*     The actual length of the \fIintv\fR array.
+/* .IP intc
+/*     The number of \fIintv\fR elements used.
+/* .IP intv
+/*     An array of integer values.
+/* .PP
+/*     intv_alloc() returns an empty integer array of the requested
+/*     length. The result is ready for use by intv_add().
+/*
+/*     intv_add() copies zero or more integers and adds them to the
+/*     specified integer array.
+/*
+/*     intv_free() releases storage for an integer array, and conveniently
+/*     returns a null pointer.
+/* SEE ALSO
+/*     msg(3) diagnostics interface
+/* DIAGNOSTICS
+/*     Fatal errors: memory allocation problem.
+/* 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 libraries. */
+
+#include <sys_defs.h>
+#include <stdlib.h>                    /* 44BSD stdarg.h uses abort() */
+#include <stdarg.h>
+
+/* Application-specific. */
+
+#include "mymalloc.h"
+#include "msg.h"
+#include "intv.h"
+
+/* intv_free - destroy integer array */
+
+INTV   *intv_free(INTV *intvp)
+{
+    myfree((char *) intvp->intv);
+    myfree((char *) intvp);
+    return (0);
+}
+
+/* intv_alloc - initialize integer array */
+
+INTV   *intv_alloc(int len)
+{
+    INTV   *intvp;
+
+    /*
+     * Sanity check.
+     */
+    if (len < 1)
+       msg_panic("intv_alloc: bad array length %d", len);
+
+    /*
+     * Initialize.
+     */
+    intvp = (INTV *) mymalloc(sizeof(*intvp));
+    intvp->len = 0;
+    intvp->intv = (int *) mymalloc(len * sizeof(intvp->intv[0]));
+    intvp->len = len;
+    intvp->intc = 0;
+    return (intvp);
+}
+
+/* intv_add - add integer to vector */
+
+void    intv_add(INTV *intvp, int count,...)
+{
+    va_list ap;
+    int     new_len;
+
+    /*
+     * Make sure that always intvp->intc < intvp->len.
+     */
+    va_start(ap, count);
+    while (count-- > 0) {
+       if (intvp->intc >= intvp->len) {
+           new_len = intvp->len * 2;
+           intvp->intv = (int *) myrealloc((char *) intvp->intv,
+                                           new_len * sizeof(int));
+           intvp->len = new_len;
+       }
+       intvp->intv[intvp->intc++] = va_arg(ap, int);
+    }
+    va_end(ap);
+}
diff --git a/postfix/src/util/intv.h b/postfix/src/util/intv.h
new file mode 100644 (file)
index 0000000..d84c5b4
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _INTV_H_INCLUDED_
+#define _INTV_H_INCLUDED_
+
+/*++
+/* NAME
+/*     intv 3h
+/* SUMMARY
+/*     string array utilities
+/* SYNOPSIS
+/*     #include "intv.h"
+ DESCRIPTION
+ .nf
+
+ /*
+  * External interface.
+  */
+typedef struct INTV {
+    int     len;                       /* number of array elements */
+    int     intc;                      /* array elements in use */
+    int    *intv;                      /* integer array */
+} INTV;
+
+extern INTV *intv_alloc(int);
+extern void intv_add(INTV *, int,...);
+extern INTV *intv_free(INTV *);
+
+/* 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
+/*--*/
+
+#endif