From 24b758c34cbb9d75fa1c64d035d7878c7e83e7e7 Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Fri, 21 Jul 2006 00:00:00 -0500 Subject: [PATCH] postfix-2.4-20060721 --- postfix/HISTORY | 19 ++ postfix/Makefile.in | 2 + postfix/README_FILES/MILTER_README | 5 +- postfix/README_FILES/RELEASE_NOTES | 114 +----------- postfix/html/MILTER_README.html | 5 +- postfix/implementation-notes/MILTER | 255 +++++++++++++++++++++++++++ postfix/proto/MILTER_README.html | 5 +- postfix/src/cleanup/cleanup.h | 1 + postfix/src/cleanup/cleanup_milter.c | 17 +- postfix/src/cleanup/cleanup_state.c | 1 + postfix/src/global/mail_version.h | 2 +- postfix/src/pickup/pickup.c | 9 + postfix/src/smtpd/smtpd.c | 7 +- postfix/src/smtpd/smtpd.h | 1 + postfix/src/smtpd/smtpd_milter.c | 9 + postfix/src/smtpd/smtpd_state.c | 1 + 16 files changed, 332 insertions(+), 121 deletions(-) mode change 100644 => 120000 postfix/README_FILES/RELEASE_NOTES create mode 100644 postfix/implementation-notes/MILTER diff --git a/postfix/HISTORY b/postfix/HISTORY index 1ea8da4d3..5ba3c211f 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -12582,6 +12582,25 @@ Apologies for any names omitted. Compatibility: replace %% in milter replies by %, and strip single (i.e. invalid) % characters. File: milter/milter8.c. + Compatibility: $_ macro support for Milter applications. + Files: smtpd/smtpd.c, smtpd/smtpd_milter.c, + cleanup/cleanup_state.c, cleanup/cleanup_milter.c. + +20060721 + + Safety: disable Milter processing after "postsuper -r". If + the mail has been filtered there is no need to do it again. + Moreover, when mail has passed through an external content + filter, we don't have sufficient information to reproduce + the exact same SMTP events and Sendmail macros that Milters + received when the mail originally arrived in Postfix. File: + pickup/pickup.c. + + Bugfix: Milters received a truncated ORCPT=xxx parameter + due to destructive parsing of something that didn't have + to be preserved before Milter support was added to Postfix. + File: smtpd/smtpd.c. + Wish list: Add M flag (enable multi-recipient delivery) to pipe daemon. diff --git a/postfix/Makefile.in b/postfix/Makefile.in index e3d75e6ef..5dadb462c 100644 --- a/postfix/Makefile.in +++ b/postfix/Makefile.in @@ -61,6 +61,8 @@ depend_update: tidy: clean rm -f Makefile */Makefile src/*/Makefile cp Makefile.init Makefile + rm -f README_FILES/RELEASE_NOTES + ln -s ../RELEASE_NOTES README_FILES rm -f bin/[!CRS]* lib/[!CRS]* include/[!CRS]* libexec/[!CRS]* \ junk */junk */*/junk \ *core */*core */*/*core \ diff --git a/postfix/README_FILES/MILTER_README b/postfix/README_FILES/MILTER_README index 659e23a06..ca95394f6 100644 --- a/postfix/README_FILES/MILTER_README +++ b/postfix/README_FILES/MILTER_README @@ -104,7 +104,7 @@ On other platforms you have two options: Sendmail source code instead: $ ggzzccaatt sseennddmmaaiill--xx..yy..zz..ttaarr..ggzz || ttaarr xxff -- - $ ccdd sseennddmmaaiill--xx..yy..zz + $ ccdd sseennddmmaaiill--xx..yy..zz//lliibbmmiilltteerr $ mmaakkee [...lots of output omitted...] @@ -316,6 +316,9 @@ workarounds section below for solutions. |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |j |Always |value of myhostname | |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | + |_ |Always |The validated client name | + | | |and address | + |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |{auth_authen} |MAIL, DATA, EOM |SASL login name | |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ | |{auth_author} |MAIL, DATA, EOM |SASL sender | diff --git a/postfix/README_FILES/RELEASE_NOTES b/postfix/README_FILES/RELEASE_NOTES deleted file mode 100644 index ef08d6de5..000000000 --- a/postfix/README_FILES/RELEASE_NOTES +++ /dev/null @@ -1,113 +0,0 @@ -The stable Postfix release is called postfix-2.2.x where 2=major -release number, 2=minor release number, x=patchlevel. The stable -release never changes except for patches that address bugs or -emergencies. Patches change the patchlevel and the release date. - -New features are developed in snapshot releases. These are called -postfix-2.3-yyyymmdd where yyyymmdd is the release date (yyyy=year, -mm=month, dd=day). Patches are never issued for snapshot releases; -instead, a new snapshot is released. - -The mail_release_date configuration parameter (format: yyyymmdd) -specifies the release date of a stable release or snapshot release. - -Incompatibility with Postfix 2.1 and earlier -============================================ - -If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2 -before proceeding. - -Major changes with snapshot 20050510 -==================================== - -This release improves usability of DSN (enhanced status codes) in -Postfix access tables, RBL reply templates and in transport maps -that use the error(8) delivery agent. - -- When the SMTP server rejects a sender address, it transforms a - recipient DSN status (e.g., 4.1.1-4.1.6) into the corresponding - sender DSN status, and vice versa. - -- When the SMTP server rejects non-address information (such as the - HELO command parameter or the client hostname/address), it - transforms a sender or recipient DSN status into a generic - non-address DSN status (e.g., 4.0.0). - -These transformations are needed when the same access table or RBL -reply template are used for client, helo, sender, or recipient -restrictions; or when the same error(8) mailer information is used -for both senders and recipients. - -Incompatibility with snapshot 20050503 -====================================== - -The format of some "warning:" messages in the maillog has changed -so that they are easier to sort: - -- The logging now talks about "access table", instead of using three -different expressions "access table", "access map" and "SMTPD access -map" for the same thing. - -- "non-SMTP command" is now logged BEFORE the client name/address -and the offending client input, instead of at the end. - -Major change with snapshot 20050427+DSN -======================================= - -This is experimental DSN support added to snapshot 20050427. The -code is not for production purposes; it is not fully tested, some -names and interfaces are still rough around the edges, and it does -not update the oqmgr so you have to use qmgr instead. Some -implementation notes and open issues are described in the -DSN_SUPPORT_README file (top-level directory). - -Incompatibility with snapshot 20050329 -====================================== - -If you use TLS, you need to execute "postfix reload" because the -TLS manager protocol has changed. - -Incompatibility with snapshot 20050328 -====================================== - -The logging format has changed. Postfix delivery agents now log the -RFC 3463 enhanced status code as "dsn=x.y.z" where y and z can be -up to three digits each. See the file pfloggsum-dsn-patch for an -update to the pfloggsum script. - -After you upgrade from Postfix 2.2 or 2.3 you need to execute -"postfix reload", otherwise you will keep running the old Postfix -queue manager, which gives no special treatment to the enhanced -status codes that it receives from Postfix delivery agents. - -Major changes with snapshot 20050328 -==================================== - -This release introduces support for RFC 3463 enhanced status codes. -For example, status code 5.1.1 means "recipient unknown". Postfix -recognizes enhanced status codes in remote server replies, generates -enhanced status codes while handling email, and reports enhanced -status codes in non-delivery notifications. This improves the user -interaction with mail clients that hide the text of error messages -from users. - -You can, but don't have to, specify RFC 3463 enhanced status codes -in the output from commands that receive mail from a pipe. If a -command terminates with non-zero exit status, and an enhanced status -code is present at the beginning of the command output, then that -status code takes precedence over the non-zero exit status. - -You can, but don't have to, specify RFC 3463 enhanced status codes -in Postfix access maps, header/body_checks REJECT actions, or in -RBL replies. For example: - - REJECT 5.7.1 You can't go here from there - -The status 5.7.1 means "no authorization, message refused", and is -the default for access maps, header/body_checks REJECT actions, and -for RBL replies. - -If you specify your own enhanced status code, the Postfix SMTP -server will automatically change a leading '5' digit (hard error) -into '4' where appropriate. This is needed, for example, with -soft_bounce=yes. diff --git a/postfix/README_FILES/RELEASE_NOTES b/postfix/README_FILES/RELEASE_NOTES new file mode 120000 index 000000000..577eefe81 --- /dev/null +++ b/postfix/README_FILES/RELEASE_NOTES @@ -0,0 +1 @@ +../RELEASE_NOTES \ No newline at end of file diff --git a/postfix/html/MILTER_README.html b/postfix/html/MILTER_README.html index 9f8a5151b..2619bab66 100644 --- a/postfix/html/MILTER_README.html +++ b/postfix/html/MILTER_README.html @@ -228,7 +228,7 @@ library from Sendmail source code instead:

 $ gzcat sendmail-x.y.z.tar.gz | tar xf -
-$ cd sendmail-x.y.z
+$ cd sendmail-x.y.z/libmilter
 $ make
 [...lots of output omitted...]
 
@@ -521,6 +521,9 @@ href="#workarounds">workarounds section below for solutions. j Always value of myhostname + _ Always The validated client name +and address + {auth_authen} MAIL, DATA, EOM SASL login name diff --git a/postfix/implementation-notes/MILTER b/postfix/implementation-notes/MILTER new file mode 100644 index 000000000..587500cff --- /dev/null +++ b/postfix/implementation-notes/MILTER @@ -0,0 +1,255 @@ +Distribution of Milter responsibility +===================================== + +Milters look at the SMTP commands as well as the message content. +In Postfix these are handled by different processes: + +- smtpd(8) (the SMTP server) focuses on the SMTP commands, strips + the SMTP encapsulation, and passes envelope information and message + content to the cleanup server. + +- the cleanup(8) server parses the message content (it understands + headers, body, and MIME structure), and creates a queue file with + envelope and content information. The cleanup server adds additional + envelope records, such as when to send a "delayed mail" notice. + +If we want to support message modifications (add/delete recipient, +add/delete/replace header, replace body) then it pretty much has +to be implemented in the cleanup server, if we want to avoid extra +temporary files. + +Network versus local submission +=============================== + +As of Sendmail 8.12, all mail is received via SMTP, so all mail is +subject to Miltering (local submissions are queued in a submission +queue and then delivered via SMTP to the main MTA). In Postfix, +local submissions are received by the pickup server, which feeds +the mail into the cleanup server after doing some sanity checks. + +How do we set up the Milters with SMTP mail versus local submissions? + +- SMTP mail: smtpd creates Milter contexts, and sends them, including + their sockets, to the cleanup server. The smtpd is responsible + for sending the Milter abort and close messages. Both smtpd and + cleanup are responsible for closing their Milter socket. Since + smtpd and cleanup inspect mail at different times, there is no + conflict with access to the Milter socket. + +- Local submission: the cleanup server creates Milter contexts. + The cleanup server provides dummy connect and helo information, + or perhaps none at all, and provides sender and recipient events. + The cleanup server is responsible for sending the Milter abort + and close messages, and for closing the Milter socket. + +A special case of local submission is "sendmail -t". This creates +a record stream in which recipients appear after content. However, +Milters expect to receive envelope information before content, not +after. This is not a problem: just like a queue manager, the +cleanup-side Milter client can jump around through the queue file +and send the information to the Milter in the expected order. + +Interaction with XCLIENT, "postsuper -r", and external content filters +====================================================================== + +Milter applications expect that the MTA supplies context information +in the form of Sendmail-like macros (j=hostname, {client_name}=the +SMTP client hostname, etc.). Not all these macros have a Postfix +equivalent. Postfix 2.3 makes a subset available. + +If Postfix does not implement a specific macro, people can usually +work around it. But we should avoid inconsistency. If Postfix can +make macro X available at Milter protocol stage Y, then it must +also be able to make that macro available at all later Milter +protocol stages, even those that are handled by a different Postfix +process. + +Thus, when adding Milter support for a specific Sendmail-like macro +to the SMTP server: + +- We may have to update the XCLIENT protocol, so that Milter + applications can be tested with XCLIENT. If not, then we must + prominently document everywhere that XCLIENT does not provide + 100% accurate simulation for Milters. An additional complication + is that the SMTP command length is limited, and that each XCLIENT + command resets the SMTP server to the 220 stage and generates + "connect" events for anvil(8) and for Milters. + +- The SMTP server has to send the corresponding attribute to the + cleanup server. The cleanup server then stores the attribute in + the queue file, so that Milters produce consistent results when + mail is re-queued with "postsuper -r". + +But wait, there is more. If mail is filtered by an external content +filter, then it needs to preserve all the Milter attributes so that +after "postsuper -r", Milters produce the exact same result as when +mail was received originally by Postfix. Specifically, after +"postsuper -r" a signing Milter must not sign mail that it did not +sign on the first pass through Postfix, and it must not reject mail +that it accepted on the first pass through Postfix. + +Instead of trying to re-create the Milter execution environment +after "postsuper -r" we simply disable Milter processing. The +rationale for this is: if mail was Miltered before it was written +to queue file, then there is no need to Milter it again. + +We might want to take a similar approach with external (signing or +blocking) content filters: don't filter mail that has already been +filtered. Unfortunately, this is complicated by the fact that mail +can make multiple iterations through Postfix (for example, when +multiple external content filters are configured). Mail that was +caught by "postsuper -r" somewhere in the middle if this trip should +not be allowed to slip past any filters. To achieve this, we would +have to preserve its current "content_filter" record that specifies +what needs to be done next. This is the opposite of normal "postsuper +-r" usage, which is most often intended to remove unwanted +"content_filter" records. We could add a postsuper command-line +option to re-queue and preserve "content_filter" records, but is +is unlikely that humans will ever be able to use this correctly. + +Message envelope or content modifications +========================================= + +Milters can send modification requests after receiving the end of +the message body. If we can implement all the header/body-related +Milter operations in the cleanup server, then we can try to edit +the queue file in place, without ever having to make a temporary +copy. Once a Milter is done editing, the queue file can be used as +input for the next Milter, and so on. Finally, the cleanup server +calls fsync() and waits for successful return. + +To implement in-place queue file edits, we need to introduce +surprisingly little change to the existing Postfix queue file +structure. All we need is a way to specify a jump from one place +in the file to another. + +Postfix does not store queue files as plain text files. Instead all +information is stored in records with an explicit type and length +for sender, recipient, arrival time, and so on. Even the content +that makes up the message header and body is stored as records with +an explicit type and length. This organization makes it very easy +to introduce pointer records, which is what we will use to jump +from one place in a queue file to another place. + +- Deleting a recipient or header record is easy - just mark the + record as killed. When deleting a recipient, we must kill all + recipient records that result from virtual alias expansion of the + original recipient address. When deleting a very long header or + body line, multiple queue file records may need to be killed. We + won't try to reuse the deleted space for other purposes. + +- Replacing header or body records involves pointer records. + Basically, a record is replaced by overwriting it with a forward + pointer to space after the end of the queue file, putting the new + record there, followed by a reverse pointer to the record that + follows the replaced information. If the replaced record is shorter + than a pointer record, we relocate the records that follow it to + the new area, until we have enough space for the forward pointer + record. See below for a discussion on what it takes to make this + safe. + + Postfix queue files are segmented. The first segment is for + envelope records, the second for message header and body content, + and the third segment is for information that was extracted or + generated from the message header and body content. Each segment + is terminated by a marker record. For now we don't want to change + their location. In particular, we want to avoid moving the start + of a segment. + + To ensure that we can always replace a header or body record by + a pointer record, without having to relocate a marker record, the + cleanup server always places a dummy pointer record at the end + of the headers and at the end of the body. + + When a Milter wants to replace an entire body, we have the option + to overwrite existing body records until we run out of space, and + then writing a pointer to space at the end of the queue file, + followed by the remainder of the body, and a pointer to the marker + that ends the message content segment. + +- Appending a recipient or header record involves pointer records + as well. This requires that the queue file already contains a + dummy pointer record at the place where we want to append recipient + or header content (Milters currently do not replace individual + body records, but we could add this if need be). To append, + change the dummy pointer into a forward pointer to space after + the end of a message, put the new record there, followed by a + reverse pointer to the record that follows the forward pointer. + + To append another record, replace the reverse pointer by a forward + pointer to space after the end of a message, put the new record + there, followed by the value of the reverse pointer that we + replace. Thus, there is no one-to-one correspondence between + forward and backward pointers! In fact, there can be multiple + forward pointers for one reverse pointer. + +When relocating a record we must not relocate the target of a jump +================================================================== + +As discussed above, when replacing an existing record, we overwrite +it with a forward pointer to the new information. If the old record +is too small we relocate one or more records that follow the record +that's being replaced, until we have enough space for the forward +pointer record. + +Now we have to become really careful. Could we end up relocating a +record that is the target of a forward or reverse pointer, and thus +corrupt the queue file? The answer is NO. + +- We never relocate end-of-segment marker records. Instead, the + cleanup server writes dummy pointer records to guarantee that + there is always space for a pointer. + +- When a record is the target of a forward pointer, it is "edited" + information that is preceded either by the end-of-queue-file + marker record, or it is preceded by the reverse pointer at the + end of earlier written "edited" information. Thus, the target of + a forward pointer will not be relocated to make space for a pointer + record. + +- When a record is the target of a reverse pointer, it is always + preceded by a forward pointer record (or by a forward pointer + record followed by some unused space). Thus, the target of a + reverse pointer will not be relocated to make space for a pointer + record. + +Could we end up relocating a pointer record? Yes, but that is OK, +as long as pointers contain absolute offsets. + +Pointer records introduce the possibility of loops +================================================== + +When a queue file is damaged, a bogus pointer value may send Postfix +into a loop. This must not happen. + +Detecting loops is not trivial: + +- A sequence of multiple forward pointers may be followed by one + legitimate reverse pointer to the location after the first forward + pointer. See above for a discussion of how to append a record to + an appended record. + +- We do know, however, that there will not be more reverse pointers + than forward pointers. But this does not help much. + +Perhaps we can include a record count at the start of the queue +file, so that the record walking code knows that it's looking at +some records more than once, and return an error indication. + +How many bytes do we need for a pointer record? +=============================================== + +A pointer record would look like this: + + type (1 byte) + offset (see below) + +Postfix uses long for queue file size/offset information, and stores +them as %15ld in the SIZE record at the start of the queue file. +This is somewhat less than a 64-bit long, but it is enough for a +some time to come, and it is easily changed without breaking forward +or backward compatibility. + +It does mean, however, that a pointer record can easily exceed the +length of a header record. This is why we go through the trouble +of record relocation and dummy records. diff --git a/postfix/proto/MILTER_README.html b/postfix/proto/MILTER_README.html index 7005e0986..3fcf83da2 100644 --- a/postfix/proto/MILTER_README.html +++ b/postfix/proto/MILTER_README.html @@ -228,7 +228,7 @@ library from Sendmail source code instead:

 $ gzcat sendmail-x.y.z.tar.gz | tar xf -
-$ cd sendmail-x.y.z
+$ cd sendmail-x.y.z/libmilter
 $ make
 [...lots of output omitted...]
 
@@ -521,6 +521,9 @@ href="#workarounds">workarounds section below for solutions. j Always value of myhostname + _ Always The validated client name +and address + {auth_authen} MAIL, DATA, EOM SASL login name diff --git a/postfix/src/cleanup/cleanup.h b/postfix/src/cleanup/cleanup.h index c3b5dd612..12b1d77dc 100644 --- a/postfix/src/cleanup/cleanup.h +++ b/postfix/src/cleanup/cleanup.h @@ -91,6 +91,7 @@ typedef struct CLEANUP_STATE { #endif MILTERS *milters; /* mail filters */ const char *client_name; /* real or ersatz client */ + const char *reverse_name; /* real or ersatz client */ const char *client_addr; /* real or ersatz client */ int client_af; /* real or ersatz client */ const char *client_port; /* real or ersatz client */ diff --git a/postfix/src/cleanup/cleanup_milter.c b/postfix/src/cleanup/cleanup_milter.c index beacd8249..152c5c484 100644 --- a/postfix/src/cleanup/cleanup_milter.c +++ b/postfix/src/cleanup/cleanup_milter.c @@ -1215,12 +1215,21 @@ static const char *cleanup_milter_eval(const char *name, void *ptr) /* * Connect macros. */ + if (strcmp(name, S8_MAC__) == 0) { + vstring_sprintf(state->temp1, "%s [%s]", + state->reverse_name, state->client_addr); + if (strcasecmp(state->client_name, state->reverse_name) != 0) + vstring_strcat(state->temp1, " (may be forged)"); + return (STR(state->temp1)); + } if (strcmp(name, S8_MAC_J) == 0) return (var_myhostname); if (strcmp(name, S8_MAC_CLIENT_ADDR) == 0) - return (nvtable_find(state->attr, MAIL_ATTR_ACT_CLIENT_ADDR)); + return (state->client_addr); if (strcmp(name, S8_MAC_CLIENT_NAME) == 0) - return (nvtable_find(state->attr, MAIL_ATTR_ACT_CLIENT_NAME)); + return (state->client_name); + if (strcmp(name, S8_MAC_CLIENT_PTR) == 0) + return (state->reverse_name); /* * MAIL FROM macros. @@ -1373,6 +1382,8 @@ static void cleanup_milter_client_init(CLEANUP_STATE *state) #define NO_CLIENT_PORT "0" state->client_name = nvtable_find(state->attr, MAIL_ATTR_ACT_CLIENT_NAME); + state->reverse_name = + nvtable_find(state->attr, MAIL_ATTR_ACT_REVERSE_CLIENT_NAME); state->client_addr = nvtable_find(state->attr, MAIL_ATTR_ACT_CLIENT_ADDR); state->client_port = nvtable_find(state->attr, MAIL_ATTR_ACT_CLIENT_PORT); proto_attr = nvtable_find(state->attr, MAIL_ATTR_ACT_CLIENT_AF); @@ -1384,6 +1395,8 @@ static void cleanup_milter_client_init(CLEANUP_STATE *state) state->client_af = AF_INET; } else state->client_af = atoi(proto_attr); + if (state->reverse_name == 0) + state->reverse_name = state->client_name; if (state->client_port == 0) state->client_port = NO_CLIENT_PORT; } diff --git a/postfix/src/cleanup/cleanup_state.c b/postfix/src/cleanup/cleanup_state.c index d1fc37203..2cbd73ec2 100644 --- a/postfix/src/cleanup/cleanup_state.c +++ b/postfix/src/cleanup/cleanup_state.c @@ -109,6 +109,7 @@ CLEANUP_STATE *cleanup_state_alloc(VSTREAM *src) state->verp_delims = 0; state->milters = 0; state->client_name = 0; + state->reverse_name = 0; state->client_addr = 0; state->client_af = 0; state->client_port = 0; diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index aefe5c413..083656c3f 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 "20060720" +#define MAIL_RELEASE_DATE "20060721" #define MAIL_VERSION_NUMBER "2.4" #ifdef SNAPSHOT diff --git a/postfix/src/pickup/pickup.c b/postfix/src/pickup/pickup.c index bb1704e4f..1cc8bb424 100644 --- a/postfix/src/pickup/pickup.c +++ b/postfix/src/pickup/pickup.c @@ -442,6 +442,13 @@ static int pickup_file(PICKUP_INFO *info) * bounces its copy of the message. because the original input file is * not readable by the bounce service. * + * If mail is re-injected with "postsuper -r", disable Milter applications. + * If they were run before the mail was queued then there is no need to + * run them again. Moreover, the queue file does not contain enough + * information to reproduce the exact same SMTP events and Sendmail + * macros that Milters received when the mail originally arrived in + * Postfix. + * * The actual message copying code is in a separate routine, so that it is * easier to implement the many possible error exits without forgetting * to close files, or to release memory. @@ -449,6 +456,8 @@ static int pickup_file(PICKUP_INFO *info) cleanup_flags = input_transp_cleanup(CLEANUP_FLAG_BOUNCE | CLEANUP_FLAG_MASK_EXTERNAL, pickup_input_transp_mask); + if (info->st.st_uid == var_owner_uid && (info->st.st_mode & S_IROTH) == 0) + cleanup_flags &= ~CLEANUP_FLAG_MILTER; cleanup = mail_connect_wait(MAIL_CLASS_PUBLIC, var_cleanup_service); if (attr_scan(cleanup, ATTR_FLAG_STRICT, diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 1f6dfdfd8..00098b56e 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -1699,6 +1699,8 @@ static int mail_open_stream(SMTPD_STATE *state) */ rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", 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); rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_ACT_CLIENT_ADDR, state->addr); if (state->helo_name) @@ -2246,10 +2248,11 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "501 5.7.1 DSN support is disabled"); return (-1); } + vstring_strcpy(state->dsn_orcpt_buf, arg + 6); if (dsn_orcpt_addr - || (coded_addr = split_at(arg + 6, ';')) == 0 + || (coded_addr = split_at(STR(state->dsn_orcpt_buf), ';')) == 0 || xtext_unquote(state->dsn_buf, coded_addr) == 0 - || *(dsn_orcpt_type = arg + 6) == 0) { + || *(dsn_orcpt_type = STR(state->dsn_orcpt_buf)) == 0) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "501 5.5.4 Error: Bad ORCPT parameter syntax"); diff --git a/postfix/src/smtpd/smtpd.h b/postfix/src/smtpd/smtpd.h index 6f3f324d2..44478605c 100644 --- a/postfix/src/smtpd/smtpd.h +++ b/postfix/src/smtpd/smtpd.h @@ -145,6 +145,7 @@ typedef struct SMTPD_STATE { char *dsn_envid; /* temporary MAIL FROM state */ int dsn_ret; /* temporary MAIL FROM state */ VSTRING *dsn_buf; /* scratch space for xtext expansion */ + VSTRING *dsn_orcpt_buf; /* scratch space for ORCPT parsing */ /* * Pass-through proxy client. diff --git a/postfix/src/smtpd/smtpd_milter.c b/postfix/src/smtpd/smtpd_milter.c index bf322c949..2b4df40a9 100644 --- a/postfix/src/smtpd/smtpd_milter.c +++ b/postfix/src/smtpd/smtpd_milter.c @@ -78,6 +78,15 @@ const char *smtpd_milter_eval(const char *name, void *ptr) /* * Connect macros. */ + if (strcmp(name, S8_MAC__) == 0) { + if (state->expand_buf == 0) + state->expand_buf = vstring_alloc(10); + vstring_sprintf(state->expand_buf, "%s [%s]", + state->reverse_name, state->addr); + if (strcasecmp(state->name, state->reverse_name) != 0) + vstring_strcat(state->expand_buf, " (may be forged)"); + return (STR(state->expand_buf)); + } if (strcmp(name, S8_MAC_J) == 0) return (var_myhostname); if (strcmp(name, S8_MAC_CLIENT_ADDR) == 0) diff --git a/postfix/src/smtpd/smtpd_state.c b/postfix/src/smtpd/smtpd_state.c index fd8fb5640..64aa5a72e 100644 --- a/postfix/src/smtpd/smtpd_state.c +++ b/postfix/src/smtpd/smtpd_state.c @@ -137,6 +137,7 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream, #endif state->dsn_envid = 0; state->dsn_buf = vstring_alloc(100); + state->dsn_orcpt_buf = vstring_alloc(100); #ifdef USE_TLS state->tls_use_tls = 0; state->tls_enforce_tls = 0;