From 5f0a27f981ca0058a10a9068455a738c6f715b08 Mon Sep 17 00:00:00 2001
From: Wietse Venema
After receiving the server's announcement for XFORWARD support, -the client may send one or more XFORWARD requests at any time except -in +the client may send XFORWARD requests at any time except in the middle of a mail delivery transaction (i.e. between MAIL and RSET or DOT). The command may be pipelined when the server supports ESMTP command pipelining.
@@ -95,10 +94,6 @@ names are shown in upper case, they are in fact case insensitive. is unavailable. Address information is not enclosed with []. -When both the NAME and ADDR attributes have the value - [UNAVAILABLE], the upcoming MAIL FROM transaction corresponds - to a local submission.
-The PORT attribute specifies an up-stream client TCP port number in decimal, or [UNAVAILABLE] when the information is unavailable.
@@ -155,9 +150,8 @@ initializes all XFORWARD attributes to [UNAVAILABLE]. With each valid XFORWARD command, the server updates XFORWARD attributes with the specified values. -When the server uses XFORWARD attributes for logging purposes, -it must not mix XFORWARD attributes with attributes from the current -SMTP session.
+The server must not mix client attributes from XFORWARD with +client attributes from the current SMTP session.
At the end of each MAIL FROM transaction (i.e. RSET or DOT), the server resets all XFORWARD attributes to the undefined state, diff --git a/postfix/proto/XFORWARD_README.html b/postfix/proto/XFORWARD_README.html index 3762b537f..9e17db825 100644 --- a/postfix/proto/XFORWARD_README.html +++ b/postfix/proto/XFORWARD_README.html @@ -56,8 +56,7 @@ extension is XFORWARD. The keyword is followed by the names of the attributes that the XFORWARD implementation supports.
After receiving the server's announcement for XFORWARD support, -the client may send one or more XFORWARD requests at any time except -in +the client may send XFORWARD requests at any time except in the middle of a mail delivery transaction (i.e. between MAIL and RSET or DOT). The command may be pipelined when the server supports ESMTP command pipelining.
@@ -95,10 +94,6 @@ names are shown in upper case, they are in fact case insensitive. is unavailable. Address information is not enclosed with []. -When both the NAME and ADDR attributes have the value - [UNAVAILABLE], the upcoming MAIL FROM transaction corresponds - to a local submission.
-The PORT attribute specifies an up-stream client TCP port number in decimal, or [UNAVAILABLE] when the information is unavailable.
@@ -155,9 +150,8 @@ initializes all XFORWARD attributes to [UNAVAILABLE]. With each valid XFORWARD command, the server updates XFORWARD attributes with the specified values. -When the server uses XFORWARD attributes for logging purposes, -it must not mix XFORWARD attributes with attributes from the current -SMTP session.
+The server must not mix client attributes from XFORWARD with +client attributes from the current SMTP session.
At the end of each MAIL FROM transaction (i.e. RSET or DOT), the server resets all XFORWARD attributes to the undefined state, diff --git a/postfix/src/global/deliver_request.h b/postfix/src/global/deliver_request.h index 1d8372e0b..2c74c00f7 100644 --- a/postfix/src/global/deliver_request.h +++ b/postfix/src/global/deliver_request.h @@ -53,6 +53,12 @@ typedef struct DELIVER_REQUEST { int dsn_ret; /* DSN full/header notification */ } DELIVER_REQUEST; + /* + * Since we can't send null pointers, null strings represent unavailable + * attributes instead. They're less likely to explode in our face, too. + */ +#define DEL_REQ_ATTR_AVAIL(a) (*(a)) + /* * How to deliver, really? */ diff --git a/postfix/src/global/mail_proto.h b/postfix/src/global/mail_proto.h index a3a9fde6a..4f92c15e5 100644 --- a/postfix/src/global/mail_proto.h +++ b/postfix/src/global/mail_proto.h @@ -174,7 +174,7 @@ extern char *mail_pathname(const char *, const char *); #define MAIL_ATTR_LOG_CLIENT_PORT "log_client_port" /* client port */ #define MAIL_ATTR_LOG_HELO_NAME "log_helo_name" /* SMTP helo name */ #define MAIL_ATTR_LOG_PROTO_NAME "log_protocol_name" /* SMTP/ESMTP/QMQP */ -#define MAIL_ATTR_LOG_CLIENT_DUMMY "log_client_dummy" /* none of the above */ +#define MAIL_ATTR_LOG_ORIGIN "log_message_origin" /* name[addr]:port */ #define MAIL_ATTR_ACT_CLIENT "client"/* client name addr */ #define MAIL_ATTR_ACT_CLIENT_NAME "client_name" /* client name */ @@ -187,27 +187,9 @@ extern char *mail_pathname(const char *, const char *); #define MAIL_ATTR_ACT_FORWARD_CLIENT_NAME "forward_client_name" #define MAIL_ATTR_PROTO_STATE "protocol_state" /* MAIL/RCPT/... */ - - /* - * Local submissions do not provide an origin record. - */ -#define MAIL_ATTR_LOG_ORIGIN "log_message_origin" /* name[addr]:port */ #define MAIL_ATTR_ORG_NONE "unknown" /* origin unknown */ #define MAIL_ATTR_ORG_LOCAL "local" /* local submission */ - /* - * Non-existent attribute values are represented as empty strings (e.g. no - * remote client, or no HELO hostname). Unknown attribute values are - * represented as "unknown" (e.g., unknown remote client hostname). An empty - * string is more convenient to send than a null pointer, and is less likely - * to blow up. - */ -#define MAIL_ATTR_VAL_NONEXIST "" -#define MAIL_ATTR_VAL_UNKNOWN "unknown" - -#define MAIL_ATTR_IS_EXIST(a) (*(a)) -#define MAIL_ATTR_IS_KNOWN(a) ((*(a)) && strcmp((a), MAIL_ATTR_VAL_UNKNOWN)) - /* * XCLIENT/XFORWARD in SMTP. */ diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 0aabde098..a2cbf9e62 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,19 +20,19 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20081010" +#define MAIL_RELEASE_DATE "20081012" #define MAIL_VERSION_NUMBER "2.6" #ifdef SNAPSHOT -#define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE +# define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE #else -#define MAIL_VERSION_DATE "" +# define MAIL_VERSION_DATE "" #endif #ifdef NONPROD -#define MAIL_VERSION_PROD "-nonprod" +# define MAIL_VERSION_PROD "-nonprod" #else -#define MAIL_VERSION_PROD "" +# define MAIL_VERSION_PROD "" #endif #define VAR_MAIL_VERSION "mail_version" diff --git a/postfix/src/oqmgr/qmgr_message.c b/postfix/src/oqmgr/qmgr_message.c index 8d738d4b7..b3a7b15a1 100644 --- a/postfix/src/oqmgr/qmgr_message.c +++ b/postfix/src/oqmgr/qmgr_message.c @@ -662,8 +662,6 @@ static int qmgr_message_read(QMGR_MESSAGE *message) myfree(message->client_helo); message->client_helo = mystrdup(value); have_log_client_attr = 1; - } else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_DUMMY) == 0) { - have_log_client_attr = 1; } else if (strcmp(name, MAIL_ATTR_SASL_METHOD) == 0) { if (message->sasl_method == 0) message->sasl_method = mystrdup(value); diff --git a/postfix/src/qmgr/qmgr_message.c b/postfix/src/qmgr/qmgr_message.c index 4b1a26d9c..24a981ed7 100644 --- a/postfix/src/qmgr/qmgr_message.c +++ b/postfix/src/qmgr/qmgr_message.c @@ -703,8 +703,6 @@ static int qmgr_message_read(QMGR_MESSAGE *message) myfree(message->client_helo); message->client_helo = mystrdup(value); have_log_client_attr = 1; - } else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_DUMMY) == 0) { - have_log_client_attr = 1; } else if (strcmp(name, MAIL_ATTR_SASL_METHOD) == 0) { if (message->sasl_method == 0) message->sasl_method = mystrdup(value); diff --git a/postfix/src/qmqpd/qmqpd.c b/postfix/src/qmqpd/qmqpd.c index 30bc49d7b..bb86c614d 100644 --- a/postfix/src/qmqpd/qmqpd.c +++ b/postfix/src/qmqpd/qmqpd.c @@ -318,10 +318,18 @@ static void qmqpd_write_attributes(QMQPD_STATE *state) { /* - * Logging attribute for the Postfix 2.3+ cleanup server. + * Logging attributes, also used for XFORWARD. */ + rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_LOG_CLIENT_NAME, state->name); + rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_LOG_CLIENT_ADDR, state->rfc_addr); + rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_LOG_CLIENT_PORT, state->port); rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_LOG_ORIGIN, state->namaddr); + rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_LOG_PROTO_NAME, state->protocol); /* * For consistency with the smtpd Milter client, we need to provide the @@ -334,15 +342,16 @@ static void qmqpd_write_attributes(QMQPD_STATE *state) */ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_ACT_CLIENT_NAME, state->name); - /* XXX Backwards compatibility: include IPv6: prefix. */ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_ACT_CLIENT_ADDR, state->rfc_addr); + MAIL_ATTR_ACT_CLIENT_ADDR, state->addr); rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_ACT_CLIENT_PORT, state->port); rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%u", MAIL_ATTR_ACT_CLIENT_AF, state->addr_family); rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_ACT_PROTO_NAME, state->protocol); + MAIL_ATTR_ACT_PROTO_NAME, state->protocol); + + /* XXX What about the address rewriting context? */ } /* qmqpd_copy_recipients - copy message recipients */ diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index 26668620e..ab80bcc63 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -1221,23 +1221,20 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, */ case SMTP_STATE_XFORWARD_NAME_ADDR: vstring_strcpy(next_command, XFORWARD_CMD); - if (session->features & SMTP_FEATURE_XFORWARD_NAME) { + if ((session->features & SMTP_FEATURE_XFORWARD_NAME) + && DEL_REQ_ATTR_AVAIL(request->client_name)) { vstring_strcat(next_command, " " XFORWARD_NAME "="); - xtext_quote_append(next_command, - MAIL_ATTR_IS_KNOWN(request->client_name) ? - request->client_name : XFORWARD_UNAVAILABLE, ""); + xtext_quote_append(next_command, request->client_name, ""); } - if (session->features & SMTP_FEATURE_XFORWARD_ADDR) { + if ((session->features & SMTP_FEATURE_XFORWARD_ADDR) + && DEL_REQ_ATTR_AVAIL(request->client_addr)) { vstring_strcat(next_command, " " XFORWARD_ADDR "="); - xtext_quote_append(next_command, - MAIL_ATTR_IS_KNOWN(request->client_addr) ? - request->client_addr : XFORWARD_UNAVAILABLE, ""); + xtext_quote_append(next_command, request->client_addr, ""); } - if (session->features & SMTP_FEATURE_XFORWARD_PORT) { + if ((session->features & SMTP_FEATURE_XFORWARD_PORT) + && DEL_REQ_ATTR_AVAIL(request->client_port)) { vstring_strcat(next_command, " " XFORWARD_PORT "="); - xtext_quote_append(next_command, - MAIL_ATTR_IS_KNOWN(request->client_port) ? - request->client_port : XFORWARD_UNAVAILABLE, ""); + xtext_quote_append(next_command, request->client_port, ""); } if (session->send_proto_helo) next_state = SMTP_STATE_XFORWARD_PROTO_HELO; @@ -1247,23 +1244,20 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, case SMTP_STATE_XFORWARD_PROTO_HELO: vstring_strcpy(next_command, XFORWARD_CMD); - if (session->features & SMTP_FEATURE_XFORWARD_PROTO) { + if ((session->features & SMTP_FEATURE_XFORWARD_PROTO) + && DEL_REQ_ATTR_AVAIL(request->client_proto)) { vstring_strcat(next_command, " " XFORWARD_PROTO "="); - xtext_quote_append(next_command, - MAIL_ATTR_IS_KNOWN(request->client_proto) ? - request->client_proto : XFORWARD_UNAVAILABLE, ""); + xtext_quote_append(next_command, request->client_proto, ""); } - if (session->features & SMTP_FEATURE_XFORWARD_HELO) { + if ((session->features & SMTP_FEATURE_XFORWARD_HELO) + && DEL_REQ_ATTR_AVAIL(request->client_helo)) { vstring_strcat(next_command, " " XFORWARD_HELO "="); - xtext_quote_append(next_command, - MAIL_ATTR_IS_EXIST(request->client_helo) ? - request->client_helo : XFORWARD_UNAVAILABLE, ""); + xtext_quote_append(next_command, request->client_helo, ""); } - if (session->features & SMTP_FEATURE_XFORWARD_DOMAIN) { + if ((session->features & SMTP_FEATURE_XFORWARD_DOMAIN) + && DEL_REQ_ATTR_AVAIL(request->rewrite_context)) { vstring_strcat(next_command, " " XFORWARD_DOMAIN "="); xtext_quote_append(next_command, - MAIL_ATTR_IS_EXIST(request->rewrite_context) == 0 ? - XFORWARD_UNAVAILABLE : strcmp(request->rewrite_context, MAIL_ATTR_RWR_LOCAL) ? XFORWARD_DOM_REMOTE : XFORWARD_DOM_LOCAL, ""); } @@ -1932,24 +1926,27 @@ int smtp_xfer(SMTP_STATE *state) /* * Use XFORWARD to forward the origin of this email message across an - * SMTP-based content filter. Send client attribute information even in - * the case of local submissions, which have no client attributes. This - * fixes a minor problem that was introduced with Postfix 2.1: no client - * attribute information was sent in the case of local submissions, and - * therefore local submissions appeared to originate from the SMTP-based - * content filter. To make this work we introduced one change to the - * XFORWARD protocol: when both NAME and ADDR values are [UNAVAILABLE], - * this is a local submission. + * SMTP-based content filter. Send client attribute information only if + * it exists (i.e. remote submission). Local submissions have no client + * attributes; the mail will appear to originate from the content filter + * which is acceptable. */ send_name_addr = var_smtp_send_xforward - && (session->features & (SMTP_FEATURE_XFORWARD_NAME - | SMTP_FEATURE_XFORWARD_ADDR)); + && (((session->features & SMTP_FEATURE_XFORWARD_NAME) + && DEL_REQ_ATTR_AVAIL(request->client_name)) + || ((session->features & SMTP_FEATURE_XFORWARD_ADDR) + && DEL_REQ_ATTR_AVAIL(request->client_addr)) + || ((session->features & SMTP_FEATURE_XFORWARD_PORT) + && DEL_REQ_ATTR_AVAIL(request->client_port))); session->send_proto_helo = var_smtp_send_xforward - && (session->features & (SMTP_FEATURE_XFORWARD_PROTO - | SMTP_FEATURE_XFORWARD_HELO - | SMTP_FEATURE_XFORWARD_DOMAIN)); + && (((session->features & SMTP_FEATURE_XFORWARD_PROTO) + && DEL_REQ_ATTR_AVAIL(request->client_proto)) + || ((session->features & SMTP_FEATURE_XFORWARD_HELO) + && DEL_REQ_ATTR_AVAIL(request->client_helo)) + || ((session->features & SMTP_FEATURE_XFORWARD_DOMAIN) + && DEL_REQ_ATTR_AVAIL(request->rewrite_context))); if (send_name_addr) recv_state = send_state = SMTP_STATE_XFORWARD_NAME_ADDR; else if (session->send_proto_helo) diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 3440430c5..4d4c76239 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -1763,46 +1763,26 @@ static int mail_open_stream(SMTPD_STATE *state) if (SMTPD_STAND_ALONE(state) == 0) { /* - * Forwarded client attributes. These propagate original client - * information through an SMTP-based content filter, to improve - * the logging from an after-filter MTA. + * Attributes for logging, also used for XFORWARD. * - * In the case of a remote submission, send all client attributes, - * including ones with missing values. Otherwise, an unknown - * client hostname would be treated as a non-existent hostname - * (i.e. local submission). - * - * In the case of a forwarded local submission, specify explicitly - * that the original client attributes are non-existent. - * Otherwise, the real client attributes would be used, and mail - * would appear to come from the content filter. + * We store all client attributes, including ones with unknown + * values. Otherwise, an unknown client hostname would be treated + * as a non-existent hostname (i.e. local submission). */ - if (SMTPD_HAVE_XFORWARD_ATTR(state)) { - if (MAIL_ATTR_IS_KNOWN(state->xforward.name) - || MAIL_ATTR_IS_KNOWN(state->xforward.addr)) { - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_LOG_CLIENT_NAME, state->xforward.name); - /* XXX Backwards compatibility: include IPv6: prefix. */ - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_LOG_CLIENT_ADDR, state->xforward.rfc_addr); - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_LOG_ORIGIN, state->xforward.namaddr); - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_LOG_CLIENT_PORT, state->xforward.port); - if (state->xforward.helo_name) - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_LOG_HELO_NAME, state->xforward.helo_name); - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_LOG_PROTO_NAME, state->xforward.protocol); - } else { - /* Local submission. See also qmgr_message_read(). */ - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_LOG_CLIENT_DUMMY, "dummy"); - } - } else { + rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_LOG_CLIENT_NAME, FORWARD_NAME(state)); + /* XXX Note: state->rfc_addr, not state->addr. */ + rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_LOG_CLIENT_ADDR, FORWARD_ADDR(state)); + rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_LOG_CLIENT_PORT, FORWARD_PORT(state)); + rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_LOG_ORIGIN, FORWARD_NAMADDR(state)); + if (FORWARD_HELO(state)) rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_LOG_ORIGIN, state->namaddr); - } + MAIL_ATTR_LOG_HELO_NAME, FORWARD_HELO(state)); + rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_LOG_PROTO_NAME, FORWARD_PROTO(state)); /* * Attributes with actual client information. These are used by @@ -1818,9 +1798,9 @@ static int mail_open_stream(SMTPD_STATE *state) MAIL_ATTR_ACT_CLIENT_NAME, state->name); rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_ACT_REVERSE_CLIENT_NAME, state->reverse_name); - /* XXX Backwards compatibility: include IPv6: prefix. */ + /* XXX Note: state->addr, not state->rfc_addr. */ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_ACT_CLIENT_ADDR, state->rfc_addr); + MAIL_ATTR_ACT_CLIENT_ADDR, state->addr); rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_ACT_CLIENT_PORT, state->port); if (state->helo_name) diff --git a/postfix/src/smtpd/smtpd.h b/postfix/src/smtpd/smtpd.h index e796ac65d..cef00062f 100644 --- a/postfix/src/smtpd/smtpd.h +++ b/postfix/src/smtpd/smtpd.h @@ -228,20 +228,29 @@ extern void smtpd_state_reset(SMTPD_STATE *); #define SMTPD_CMD_UNKNOWN "UNKNOWN" /* - * Representation of missing and non-existent client information. Throughout - * Postfix, we use the "unknown" string value for missing client information - * (e.g., unknown remote client hostname), and we use the empty string or - * null pointer for non-existent client information (e.g., no HELO command, - * or local submission). + * Representation of unknown and non-existent client information. Throughout + * Postfix, we use the "unknown" string value for unknown client information + * (e.g., unknown remote client hostname), and we use the empty string, null + * pointer or "no queue file record" for non-existent client information + * (e.g., no HELO command, or local submission). * - * When XFORWARD support was introduced with Postfix 2.1, the specification - * failed to clearly distinguish between missing and non-existent client - * information. This ambiguity affected the implementation: unknown client - * hostnames could become empty strings (as if a submission was local), and - * local submissions could appear to originate from an SMTP-based content - * filter. This was corrected during the Postfix 2.6 development cycle by - * introducing one semantic change to the XFORWARD protocol: when both NAME - * and ADDR values are [UNAVAILABLE], this is a local submission. + * Inside the SMTP server, unknown real client attributes are represented by + * the string "unknown", and non-existent HELO is represented as a null + * pointer. The SMTP server uses this same representation internally for + * forwarded client attributes; the XFORWARD syntax makes no distinction + * between unknown (remote submission) and non-existent (local submission). + * + * The SMTP client sends forwarded client attributes only when upstream client + * attributes exist (i.e. remote submission). Thus, local submissions will + * appear to come from an SMTP-based content filter, which is acceptable. + * + * Known/unknown client attribute values use the SMTP server's internal + * representation in queue files, in queue manager delivery requests, and in + * delivery agent $name expansions. + * + * Non-existent attribute values are never present in queue files. Non-existent + * information is represented as empty strings in queue manager delivery + * requests and in delivery agent $name expansions. */ #define CLIENT_ATTR_UNKNOWN "unknown" @@ -299,34 +308,12 @@ extern void smtpd_peer_reset(SMTPD_STATE *state); (port), (char *) 0) /* - * Choose between normal or forwarded attributes. - * - * Inside the SMTP server, unknown real client attributes are represented by - * the string "unknown", and non-existent HELO is represented as a null - * pointer. The SMTP server uses this same representation internally for - * forwarded client attributes; the XFORWARD syntax makes no distinction - * between unknown (remote submission) and non-existent (local submission). - * The SMTP server decides between remote and local submission when it - * generates queue file records (see below) so that the correct result is - * produced with down-stream logging and with $name expansion in delivery - * agents. - * - * Known/unknown client attribute values use the SMTP server's internal - * representation in queue files, in queue manager delivery requests, and in - * delivery agent $name expansions. - * - * Non-existent attribute values are never present in queue files. The SMTP - * server stores a dummy attribute to indicate that no client attributes - * exist. Non-existent information is represented as empty strings in queue - * manager delivery requests and in delivery agent $name expansions. - * - * When forwarding client information, don't mix information from the current - * SMTP session with forwarded information from an up-stream session. + * Don't mix information from the current SMTP session with forwarded + * information from an up-stream session. */ -#define SMTPD_HAVE_XFORWARD_ATTR(s) \ - ((s)->xforward.flags & SMTPD_STATE_XFORWARD_INIT) #define FORWARD_CLIENT_ATTR(s, a) \ - (SMTPD_HAVE_XFORWARD_ATTR(s) ? (s)->xforward.a : (s)->a) + (((s)->xforward.flags & SMTPD_STATE_XFORWARD_CLIENT_MASK) ? \ + (s)->xforward.a : (s)->a) #define FORWARD_ADDR(s) FORWARD_CLIENT_ATTR((s), rfc_addr) #define FORWARD_NAME(s) FORWARD_CLIENT_ATTR((s), name)