From: Wietse Venema Date: Sat, 3 Aug 2002 05:00:00 +0000 (-0500) Subject: postfix-1.1.11-20020803 X-Git-Tag: v2.0.0~51 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8e187fcc01ac18e753d8ecac26970cb97d66d0e8;p=thirdparty%2Fpostfix.git postfix-1.1.11-20020803 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 86c5a4732..47fd82113 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -6723,6 +6723,46 @@ Apologies for any names omitted. Bugfix: garbage in verbose "flush" server logging. Victor Duchovni. File: flush/flush.c. + Incompatibility: smtpd_sasl_local_domain now defaults to + the null string. File: smtpd/smtpd.c, smtpd/smtpd_sasl_glue.c. + +20020726 + + Documentation: added GDB debugging instructions for sites + that do not have X installed on the Postfix machine. Henrik + Larsson, spambox.dk. + +20020729 + + Weird: installed RedHat 3.03 inside VMware, and no change + was needed to build Postfix, except to recognize the Linux + version. + + Bugfix: some mailers will announce ESMTP features in their + HELO (not EHLO) response. Postfix did not ignore them. + File: smtp/smtp_proto.c. + +20020731 + + Cleanup: permit_naked_ip_address is unsafe and will go + away. Postfix logs a warning. File: smtpd/smtpd_check.c. + +20020801 + + Cleanup: the warning message for matched header/body + content was misleading. File: cleanup/cleanup_message.c. + + Safety: moved the "postsuper -r ALL" operation after the + "postsuper -s" check that makes queue file names match + inode numbers. This avoids loss of mail in the unlikely + case that someone runs "postsuper -sr ALL" on a queue that + was copied from another place. + + Feature: "postsuper -h" to put mail "on hold" and "postsuper + -H" to release mail that was placed "on hold". This involves + a new queue, which is appropriately named "hold". Files: + postsuper/postsuper.c, showq/showq.c. + Open problems: Medium: should permit_mx_backup defer delivery if DNS diff --git a/postfix/README_FILES/DEBUG_README b/postfix/README_FILES/DEBUG_README index 43b2b889e..8d9a43d82 100644 --- a/postfix/README_FILES/DEBUG_README +++ b/postfix/README_FILES/DEBUG_README @@ -97,16 +97,24 @@ that it invokes the debugger of your choice, for example: PATH=/usr/bin:/usr/X11R6/bin xxgdb $daemon_directory/$process_name $process_id & sleep 5 -If you use xxgdb, be sure that gdb is in the command search path. +If you do not have X on the Postfix machine, then xxgdb isn't going +to work. Instead, you can try to run gdb in non-interactive mode: -Export XAUTHORITY so that X access control works, for example: + debugger_command = + PATH=/bin:/usr/bin:/usr/local/bin; export PATH; (echo cont; + echo where) | gdb $daemon_directory/$process_name $process_id 2>&1 + >$config_directory/$process_name.$process_id.log & sleep 5 + +If you use xxgdb, be sure that gdb is in the command search path, +and export XAUTHORITY so that X access control works, for example: % setenv XAUTHORITY ~/.Xauthority Stop and start the Postfix system. Whenever the suspect daemon process is started, a debugger window -pops up and you can watch in detail what happens. +pops up and you can watch in detail what happens (when using xxgdb) +or a file is created (if using gdb in non-interactive mode). 7 - Unreasonable behavior ========================= diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index ef0baea09..6b31fbfe7 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -12,6 +12,12 @@ snapshot release). Patches change the patchlevel and the release date. Snapshots change only the release date, unless they include the same bugfixes as a patch release. +Incompatible changes with Postfix snapshot 1.1.11-200208XX +========================================================== + +In mailq output, the queue ID is followed by the ! character when +the message is in the "hold" queue. + Incompatible changes with Postfix snapshot 1.1.11-20020717 ========================================================== diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf index 29416c489..579916cfa 100644 --- a/postfix/conf/main.cf +++ b/postfix/conf/main.cf @@ -509,9 +509,15 @@ debug_peer_level = 2 # set up your XAUTHORITY environment variable before starting Postfix. # debugger_command = - PATH=/usr/bin:/usr/X11R6/bin + PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin xxgdb $daemon_directory/$process_name $process_id & sleep 5 +# If you don't have X installed on the Postfix machine, try: +# debugger_command = +# PATH=/bin:/usr/bin:/usr/local/bin; export PATH; (echo cont; +# echo where) | gdb $daemon_directory/$process_name $process_id 2>&1 +# >$config_directory/$process_name.$process_id.log & sleep 5 + # INSTALL-TIME CONFIGURATION INFORMATION # # The following parameters are used when installing a new Postfix version. diff --git a/postfix/conf/postfix-files b/postfix/conf/postfix-files index 4bc0d72fe..3616c652d 100644 --- a/postfix/conf/postfix-files +++ b/postfix/conf/postfix-files @@ -47,9 +47,9 @@ $queue_directory/corrupt:d:$mail_owner:-:700:ucr $queue_directory/defer:d:$mail_owner:-:700:ucr $queue_directory/deferred:d:$mail_owner:-:700:ucr $queue_directory/flush:d:$mail_owner:-:700:ucr +$queue_directory/hold:d:$mail_owner:-:700:ucr $queue_directory/incoming:d:$mail_owner:-:700:ucr $queue_directory/private:d:$mail_owner:-:700:uc -$queue_directory/saved:d:$mail_owner:-:700:ucr $queue_directory/maildrop:d:$mail_owner:$setgid_group:730:uc $queue_directory/public:d:$mail_owner:$setgid_group:710:uc $queue_directory/pid:d:root:-:755:uc diff --git a/postfix/conf/sample-smtpd.cf b/postfix/conf/sample-smtpd.cf index 87273646e..671b3aa74 100644 --- a/postfix/conf/sample-smtpd.cf +++ b/postfix/conf/sample-smtpd.cf @@ -444,6 +444,13 @@ relay_domains = $mydestination # access_map_reject_code = 550 +# The defer_code parameter specifies the SMTP server response code +# when an SMTP client request is rejected by the "defer" restriction. +# +# Do not change this unless you have a complete understanding of RFC 821. +# +defer_code = 450 + # The invalid_hostname_reject_code parameter specifies the SMTP server # response when a client violates the reject_invalid_hostname anti-UCE # restriction. diff --git a/postfix/html/local.8.html b/postfix/html/local.8.html index d08a2ffa5..801c4f09c 100644 --- a/postfix/html/local.8.html +++ b/postfix/html/local.8.html @@ -1,5 +1,4 @@
-
 LOCAL(8)                                                 LOCAL(8)
 
 NAME
@@ -440,6 +439,5 @@ LOCAL(8)                                                 LOCAL(8)
        P.O. Box 704
        Yorktown Heights, NY 10598, USA
 
-                                                                1
-
+                                                         LOCAL(8)
 
diff --git a/postfix/html/postsuper.1.html b/postfix/html/postsuper.1.html index 44642dbb6..7b08e7eff 100644 --- a/postfix/html/postsuper.1.html +++ b/postfix/html/postsuper.1.html @@ -5,8 +5,8 @@ POSTSUPER(1) POSTSUPER(1) postsuper - Postfix superintendent SYNOPSIS - postsuper [-psv] [-d queue_id] [-r queue_id] [directory - ...] + postsuper [-psv] [-d queue_id] [-h queue_id] [-H queue_id] + [-r queue_id] [directory ...] DESCRIPTION The postsuper command does maintenance jobs on the Postfix @@ -22,9 +22,15 @@ POSTSUPER(1) POSTSUPER(1) -d queue_id Delete one message with the named queue ID from the - named mail queue(s) (default: incoming, active and - deferred). If a queue_id of - is specified, the - program reads queue IDs from standard input. + named mail queue(s) (default: hold, incoming, + active and deferred). If a queue_id of - is speci- + fied, the program reads queue IDs from standard + input. For example, to delete all mail from or to + user@example.com: + + mailq | awk 'BEGIN { RS = "" } \ + / user@example\.com$/ { print $1 } \ + ' | postsuper -d - Specify -d ALL to remove all messages; for example, specify -d ALL deferred to delete mail in the @@ -55,16 +61,42 @@ POSTSUPER(1) POSTSUPER(1) of the old message that it should have deleted. + -h queue_id + Put mail "on hold" so that no attempt is made to + deliver it. Move one message with the named queue + ID from the named mail queue(s) (default: incoming, + active and deferred) to the hold queue. If a + queue_id of - is specified, the program reads queue + IDs from standard input. + + Specify -h ALL to hold all messages; for example, + specify -h ALL deferred to hold mail in the + deferred queue. As a safety measure, the word ALL + must be specified in upper case. + + Note: mail that is put "on hold" will not expire. + + -H queue_id + Release mail that was put "on hold". Move one mes- + sage with the named queue ID from the named mail + queue(s) (default: hold) to the deferred queue. If + a queue_id of - is specified, the program reads + queue IDs from standard input. + + Specify -H ALL to release all mail that is "on + hold". As a safety measure, the word ALL must be + specified in upper case. + -p Purge old temporary files that are left over after system or software crashes. -r queue_id Requeue the message with the named queue ID from - the named mail queue(s) (default: incoming, active - and deferred). To requeue multiple messages, spec- - ify multiple -r command-line options. Alterna- - tively, if a queue_id of - is specified, the pro- - gram reads queue IDs from standard input. + the named mail queue(s) (default: hold, incoming, + active and deferred). To requeue multiple mes- + sages, specify multiple -r command-line options. + Alternatively, if a queue_id of - is specified, the + program reads queue IDs from standard input. Specify -r ALL to requeue all messages. As a safety measure, the word ALL must be specified in upper @@ -113,19 +145,23 @@ POSTSUPER(1) POSTSUPER(1) report is written to the standard error stream and to sys- logd. +BUGS + Mail that is not sanitized by Postfix (i.e. mail in the + maildrop queue) cannot be placed "on hold". + CONFIGURATION PARAMETERS - See the Postfix main.cf file for syntax details and for + See the Postfix main.cf file for syntax details and for default values. hash_queue_depth Number of subdirectory levels for hashed queues. hash_queue_names - The names of queues that are organized into multi- + The names of queues that are organized into multi- ple levels of subdirectories. LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/html/sendmail.1.html b/postfix/html/sendmail.1.html index 8b0033dc6..b273b0e31 100644 --- a/postfix/html/sendmail.1.html +++ b/postfix/html/sendmail.1.html @@ -34,7 +34,15 @@ SENDMAIL(1) SENDMAIL(1) mail could not be delivered upon the last attempt, the reason for failure is shown. This mode of oper- ation is implemented by executing the postqueue(1) - command. + command. The queue ID string is followed by an + optional status character: + + * The message is in the active queue, i.e. the + message is selected for delivery. + + ! The message is in the hold queue, i.e. no + further delivery attempt will be made until + the mail is taken off hold. newaliases Initialize the alias database. If no input file is @@ -313,6 +321,7 @@ SENDMAIL(1) SENDMAIL(1) SEE ALSO pickup(8) mail pickup daemon + postsuper(1) queue maintenance postalias(1) maintain alias database postdrop(1) mail posting utility postfix(1) mail system control diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 1676d4dec..c7f2a0e69 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -290,33 +290,37 @@ SMTPD(8) SMTPD(8) Server response when a client violates an access database restriction. + defer_code + Server response when a client request is rejected + by the defer restriction. + invalid_hostname_reject_code - Server response when a client violates the + Server response when a client violates the reject_invalid_hostname restriction. maps_rbl_reject_code - Server response when a client violates the + Server response when a client violates the maps_rbl_domains restriction. reject_code - Response code when the client matches a reject + Response code when the client matches a reject restriction. relay_domains_reject_code - Server response when a client attempts to violate + Server response when a client attempts to violate the mail relay policy. unknown_address_reject_code - Server response when a client violates the + Server response when a client violates the reject_unknown_address restriction. unknown_client_reject_code - Server response when a client without address to - name mapping violates the reject_unknown_clients + Server response when a client without address to + name mapping violates the reject_unknown_clients restriction. unknown_hostname_reject_code - Server response when a client violates the + Server response when a client violates the reject_unknown_hostname restriction. SEE ALSO @@ -325,7 +329,7 @@ SMTPD(8) SMTPD(8) syslogd(8) system logging LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/html/uce.html b/postfix/html/uce.html index 883df41ed..e04e44781 100644 --- a/postfix/html/uce.html +++ b/postfix/html/uce.html @@ -342,6 +342,8 @@ rejected requests (default: 554).
permit +
defer +
reject
warn_if_reject @@ -513,6 +515,8 @@ the response code for REJECT results (default: 554).
permit +
defer +
reject
warn_if_reject @@ -692,6 +696,8 @@ client login name doesn't own the MAIL FROM address according to
permit +
defer +
reject
warn_if_reject @@ -966,6 +972,8 @@ response code to rejected requests (default: 504).
permit +
defer +
reject
warn_if_reject @@ -1066,6 +1074,8 @@ the result code for rejected requests (default: 554).
permit +
defer +
reject
warn_if_reject @@ -1102,6 +1112,14 @@ policy explicit.

+ + +

defer
Defer the request. The client is told to +try again later. This restriction is useful at the end of a +restriction list, to make the default policy explicit. + +

+

reject
Reject the request. This restriction diff --git a/postfix/makedefs b/postfix/makedefs index 19b77ed74..f8f5300fc 100644 --- a/postfix/makedefs +++ b/postfix/makedefs @@ -170,6 +170,10 @@ case "$SYSTEM.$RELEASE" in ;; *) echo "Unknown AIX version: `uname -v`." 1>&2; exit 1;; esac;; + # Tested with RedHat 3.03 on 20020729. + Linux.1*) SYSTYPE=LINUX1 + SYSLIBS="-ldb" + ;; Linux.2*) SYSTYPE=LINUX2 # Postfix no longer needs DB 1.85 compatibility if [ -f /usr/include/db.h ] diff --git a/postfix/man/man1/postsuper.1 b/postfix/man/man1/postsuper.1 index 229d42f32..fe4d085a2 100644 --- a/postfix/man/man1/postsuper.1 +++ b/postfix/man/man1/postsuper.1 @@ -10,6 +10,7 @@ Postfix superintendent .nf .fi \fBpostsuper\fR [\fB-psv\fR] [\fB-d \fIqueue_id\fR] +[\fB-h \fIqueue_id\fR] [\fB-H \fIqueue_id\fR] [\fB-r \fIqueue_id\fR] [\fIdirectory ...\fR] .SH DESCRIPTION .ad @@ -26,10 +27,17 @@ directories - this includes the \fBincoming\fR, \fBactive\fR and Options: .IP "\fB-d \fIqueue_id\fR" Delete one message with the named queue ID from the named -mail queue(s) (default: \fBincoming\fR, \fBactive\fR and +mail queue(s) (default: \fBhold\fR, \fBincoming\fR, \fBactive\fR and \fBdeferred\fR). If a \fIqueue_id\fR of \fB-\fR is specified, the program reads -queue IDs from standard input. +queue IDs from standard input. For example, to delete all mail +from or to \fBuser@example.com\fR: +.sp +mailq | awk \'BEGIN { RS = "" } \e +.ti +4 +/ user@example\e.com$/ { print $1 } \e +.br +\' | postsuper -d - .sp Specify \fB-d ALL\fR to remove all messages; for example, specify \fB-d ALL deferred\fR to delete mail in the \fBdeferred\fR queue. @@ -59,12 +67,36 @@ can distinguish within a second). \fBpostsuper\fR deletes the new message, instead of the old message that it should have deleted. .RE +.IP "\fB-h \fIqueue_id\fR" +Put mail "on hold" so that no attempt is made to deliver it. +Move one message with the named queue ID from the named +mail queue(s) (default: \fBincoming\fR, \fBactive\fR and +\fBdeferred\fR) to the \fBhold\fR queue. +If a \fIqueue_id\fR of \fB-\fR is specified, the program reads +queue IDs from standard input. +.sp +Specify \fB-h ALL\fR to hold all messages; for example, specify +\fB-h ALL deferred\fR to hold mail in the \fBdeferred\fR queue. +As a safety measure, the word \fBALL\fR must be specified in upper +case. +.sp +Note: mail that is put "on hold" will not expire. +.IP "\fB-H \fIqueue_id\fR" +Release mail that was put "on hold". +Move one message with the named queue ID from the named +mail queue(s) (default: \fBhold\fR) to the \fBdeferred\fR queue. +If a \fIqueue_id\fR of \fB-\fR is specified, the program reads +queue IDs from standard input. +.sp +Specify \fB-H ALL\fR to release all mail that is "on hold". +As a safety measure, the word \fBALL\fR must be specified in upper +case. .IP \fB-p\fR Purge old temporary files that are left over after system or software crashes. .IP "\fB-r \fIqueue_id\fR" Requeue the message with the named queue ID from the named -mail queue(s) (default: \fBincoming\fR, \fBactive\fR and +mail queue(s) (default: \fBhold\fR, \fBincoming\fR, \fBactive\fR and \fBdeferred\fR). To requeue multiple messages, specify multiple \fB-r\fR command-line options. @@ -113,6 +145,11 @@ Problems are reported to the standard error stream and to the number of messages requeued with \fB-r\fR, and the number of messages whose queue file name was fixed with \fB-s\fR. The report is written to the standard error stream and to \fBsyslogd\fR. +.SH BUGS +.ad +.fi +Mail that is not sanitized by Postfix (i.e. mail in the \fBmaildrop\fR +queue) cannot be placed "on hold". .SH CONFIGURATION PARAMETERS .na .nf diff --git a/postfix/man/man1/sendmail.1 b/postfix/man/man1/sendmail.1 index 5ada1f489..2aa43d9a8 100644 --- a/postfix/man/man1/sendmail.1 +++ b/postfix/man/man1/sendmail.1 @@ -36,7 +36,16 @@ List the mail queue. Each entry shows the queue file ID, message size, arrival time, sender, and the recipients that still need to be delivered. If mail could not be delivered upon the last attempt, the reason for failure is shown. This mode of operation is implemented -by executing the \fBpostqueue\fR(1) command. +by executing the \fBpostqueue\fR(1) command. The queue ID string +is followed by an optional status character: +.RS +.IP \fB*\fR +The message is in the \fBactive\fR queue, i.e. the message is +selected for delivery. +.IP \fB!\fR +The message is in the \fBhold\fR queue, i.e. no further delivery +attempt will be made until the mail is taken off hold. +.RE .IP \fBnewaliases\fR Initialize the alias database. If no input file is specified (with the \fB-oA\fR option, see below), the program processes the file(s) @@ -262,6 +271,7 @@ The characters that Postfix accepts as VERP delimiter characters. .na .nf pickup(8) mail pickup daemon +postsuper(1) queue maintenance postalias(1) maintain alias database postdrop(1) mail posting utility postfix(1) mail system control diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index c4e690633..be3c719c3 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -238,6 +238,9 @@ mail from or to. .fi .IP \fBaccess_map_reject_code\fR Server response when a client violates an access database restriction. +.IP \fBdefer_code\fR +Server response when a client request is rejected by the \fBdefer\fR +restriction. .IP \fBinvalid_hostname_reject_code\fR Server response when a client violates the \fBreject_invalid_hostname\fR restriction. diff --git a/postfix/src/bounce/Makefile.in b/postfix/src/bounce/Makefile.in index 2769ab7b5..8eed9c27c 100644 --- a/postfix/src/bounce/Makefile.in +++ b/postfix/src/bounce/Makefile.in @@ -1,8 +1,10 @@ SHELL = /bin/sh SRCS = bounce.c bounce_append_service.c bounce_notify_service.c \ - bounce_cleanup.c bounce_notify_util.c bounce_notify_verp.c + bounce_cleanup.c bounce_notify_util.c bounce_notify_verp.c \ + bounce_one_service.c OBJS = bounce.o bounce_append_service.o bounce_notify_service.o \ - bounce_cleanup.o bounce_notify_util.o bounce_notify_verp.o + bounce_cleanup.o bounce_notify_util.o bounce_notify_verp.o \ + bounce_one_service.o HDRS = TESTSRC = WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ @@ -159,3 +161,18 @@ bounce_notify_verp.o: ../../include/mail_error.h bounce_notify_verp.o: ../../include/verp_sender.h bounce_notify_verp.o: bounce_service.h bounce_notify_verp.o: ../../include/bounce_log.h +bounce_one_service.o: bounce_one_service.c +bounce_one_service.o: ../../include/sys_defs.h +bounce_one_service.o: ../../include/msg.h +bounce_one_service.o: ../../include/vstream.h +bounce_one_service.o: ../../include/vbuf.h +bounce_one_service.o: ../../include/name_mask.h +bounce_one_service.o: ../../include/mail_params.h +bounce_one_service.o: ../../include/mail_queue.h +bounce_one_service.o: ../../include/vstring.h +bounce_one_service.o: ../../include/post_mail.h +bounce_one_service.o: ../../include/cleanup_user.h +bounce_one_service.o: ../../include/mail_addr.h +bounce_one_service.o: ../../include/mail_error.h +bounce_one_service.o: bounce_service.h +bounce_one_service.o: ../../include/bounce_log.h diff --git a/postfix/src/bounce/bounce.c b/postfix/src/bounce/bounce.c index 00c40cd2d..f176e222f 100644 --- a/postfix/src/bounce/bounce.c +++ b/postfix/src/bounce/bounce.c @@ -283,6 +283,52 @@ static int bounce_verp_proto(char *service_name, VSTREAM *client, int flush) STR(sender), STR(verp_delims), flush)); } +/* bounce_one_proto - bounce_one server protocol */ + +static int bounce_one_proto(char *service_name, VSTREAM *client) +{ + int unused_flags; + + /* + * Read and validate the client request. + */ + if (mail_command_server(client, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &unused_flags, + ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, + ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding, + ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, + ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient, + ATTR_TYPE_STR, MAIL_ATTR_WHY, why, + ATTR_TYPE_END) != 7) { + msg_warn("malformed request"); + return (-1); + } + if (strcmp(service_name, MAIL_SERVICE_BOUNCE) != 0) { + msg_warn("wrong service name \"%s\" for one-recipient bouncing", + service_name); + return (-1); + } + if (mail_queue_name_ok(STR(queue_name)) == 0) { + msg_warn("malformed queue name: %s", printable(STR(queue_name), '?')); + return (-1); + } + if (mail_queue_id_ok(STR(queue_id)) == 0) { + msg_warn("malformed queue id: %s", printable(STR(queue_id), '?')); + return (-1); + } + if (msg_verbose) + msg_info("bounce_one_proto: queue=%s id=%s encoding=%s sender=%s recipient=%s why=%s", + STR(queue_name), STR(queue_id), STR(encoding), + STR(sender), STR(recipient), STR(why)); + + /* + * Execute the request. + */ + return (bounce_one_service(STR(queue_name), STR(queue_id), STR(encoding), + STR(sender), STR(recipient), STR(why))); +} + /* bounce_service - parse bounce command type and delegate */ static void bounce_service(VSTREAM *client, char *service_name, char **argv) @@ -318,6 +364,8 @@ static void bounce_service(VSTREAM *client, char *service_name, char **argv) status = bounce_notify_proto(service_name, client, JUST_WARN); } else if (command == BOUNCE_CMD_APPEND) { status = bounce_append_proto(service_name, client); + } else if (command == BOUNCE_CMD_ONE) { + status = bounce_one_proto(service_name, client); } else { msg_warn("unknown command: %d", command); status = -1; diff --git a/postfix/src/bounce/bounce_notify_util.c b/postfix/src/bounce/bounce_notify_util.c index 1c6485630..b8970025b 100644 --- a/postfix/src/bounce/bounce_notify_util.c +++ b/postfix/src/bounce/bounce_notify_util.c @@ -20,6 +20,14 @@ /* const char *encoding; /* int flush; /* +/* BOUNCE_INFO *bounce_mail_one_init(queue_name, queue_id, +/* encoding, orig_recipient, why) +/* const char *queue_name; +/* const char *queue_id; +/* const char *encoding; +/* const char *orig_recipient; +/* const char *why; +/* /* void bounce_mail_free(bounce_info) /* BOUNCE_INFO *bounce_info; /* @@ -66,6 +74,9 @@ /* structure contains all the necessary information about an /* undeliverable message. /* +/* bounce_mail_one_init() provides the same function for only +/* one recipient that is not read from bounce logfile. +/* /* bounce_mail_free() releases memory allocated by bounce_mail_init() /* and closes any files opened by bounce_mail_init(). /* @@ -163,11 +174,14 @@ #define STR vstring_str -/* bounce_mail_init - initialize */ +/* bounce_mail_alloc - initialize */ -BOUNCE_INFO *bounce_mail_init(const char *service, const char *queue_name, - const char *queue_id, - const char *encoding, int flush) +static BOUNCE_INFO *bounce_mail_alloc(const char *service, + const char *queue_name, + const char *queue_id, + const char *encoding, + int flush, + BOUNCE_LOG *log_handle) { BOUNCE_INFO *bounce_info; int rec_type; @@ -194,6 +208,7 @@ BOUNCE_INFO *bounce_mail_init(const char *service, const char *queue_name, bounce_info->buf = vstring_alloc(100); bounce_info->arrival_time = 0; bounce_info->orig_offs = 0; + bounce_info->log_handle = log_handle; /* * Compute a supposedly unique boundary string. This assumes that a queue @@ -204,21 +219,6 @@ BOUNCE_INFO *bounce_mail_init(const char *service, const char *queue_name, queue_id, (unsigned long) event_time(), var_myhostname); bounce_info->mime_boundary = mystrdup(STR(bounce_info->buf)); - /* - * If the bounce log cannot be found, do not raise a fatal run-time - * error. There is nothing we can do about the error, and all we are - * doing is to inform the sender of a delivery problem, Bouncing a - * message does not have to be a perfect job. But if the system IS - * running out of resources, raise a fatal run-time error and force a - * backoff. - */ - if ((bounce_info->log_handle = bounce_log_open(bounce_info->service, - bounce_info->queue_id, - O_RDWR, 0)) == 0 - && errno != ENOENT) - msg_fatal("open %s %s: %m", bounce_info->service, - bounce_info->queue_id); - /* * If the original message cannot be found, do not raise a run-time * error. There is nothing we can do about the error, and all we are @@ -252,6 +252,56 @@ BOUNCE_INFO *bounce_mail_init(const char *service, const char *queue_name, return (bounce_info); } +/* bounce_mail_init - initialize */ + +BOUNCE_INFO *bounce_mail_init(const char *service, + const char *queue_name, + const char *queue_id, + const char *encoding, + int flush) +{ + BOUNCE_INFO *bounce_info; + BOUNCE_LOG *log_handle; + + /* + * Initialize the bounce_info structure. If the bounce log cannot be + * found, do not raise a fatal run-time error. There is nothing we can do + * about the error, and all we are doing is to inform the sender of a + * delivery problem, Bouncing a message does not have to be a perfect + * job. But if the system IS running out of resources, raise a fatal + * run-time error and force a backoff. + */ + if ((log_handle = bounce_log_open(service, queue_id, O_RDWR, 0)) == 0 + && errno != ENOENT) + msg_fatal("open %s %s: %m", service, queue_id); + bounce_info = bounce_mail_alloc(service, queue_name, queue_id, + encoding, flush, log_handle); + return (bounce_info); +} + +/* bounce_mail_one_init - initialize */ + +BOUNCE_INFO *bounce_mail_one_init(const char *queue_name, + const char *queue_id, + const char *encoding, + const char *orig_recipient, + const char *why) +{ + BOUNCE_INFO *bounce_info; + BOUNCE_LOG *log_handle; + + /* + * Initialize the bounce_info structure. Forge a logfile record for just + * one recipient. + */ +#define REALLY_BOUNCE 1 + + log_handle = bounce_log_forge(orig_recipient, "5.0.0", why); + bounce_info = bounce_mail_alloc("none", queue_name, queue_id, + encoding, REALLY_BOUNCE, log_handle); + return (bounce_info); +} + /* bounce_mail_free - undo bounce_mail_init */ void bounce_mail_free(BOUNCE_INFO *bounce_info) diff --git a/postfix/src/bounce/bounce_one_service.c b/postfix/src/bounce/bounce_one_service.c new file mode 100644 index 000000000..a654b8324 --- /dev/null +++ b/postfix/src/bounce/bounce_one_service.c @@ -0,0 +1,221 @@ +/*++ +/* NAME +/* bounce_one_service 3 +/* SUMMARY +/* send non-delivery report to sender, server side +/* SYNOPSIS +/* #include "bounce_service.h" +/* +/* int bounce_one_service(queue_name, queue_id, encoding, +/* orig_sender, orig_recipient, why) +/* char *queue_name; +/* char *queue_id; +/* char *encoding; +/* char *orig_sender; +/* char *orig_recipient; +/* char *why; +/* DESCRIPTION +/* This module implements the server side of the bounce_one() +/* (send bounce message for one recipient) request. +/* +/* When a message bounces, a full copy is sent to the originator, +/* and an optional copy of the diagnostics with message headers is +/* sent to the postmaster. The result is non-zero when the operation +/* should be tried again. +/* +/* When a bounce is sent, the sender address is the empty +/* address. When a bounce bounces, an optional double bounce +/* with the entire undeliverable mail is sent to the postmaster, +/* with as sender address the double bounce address. +/* DIAGNOSTICS +/* Fatal error: error opening existing file. Warnings: corrupt +/* message file. A corrupt message is saved to the "corrupt" +/* queue for further inspection. +/* BUGS +/* SEE ALSO +/* bounce(3) basic bounce service client interface +/* 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 +#include +#include +#include +#include + +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif + +/* Utility library. */ + +#include +#include +#include + +/* Global library. */ + +#include +#include +#include +#include + +/* Application-specific. */ + +#include "bounce_service.h" + +#define STR vstring_str + +/* bounce_one_service - send a bounce for one recipient */ + +int bounce_one_service(char *queue_name, char *queue_id, char *encoding, + char *orig_sender, char *orig_recipient, + char *why) +{ + BOUNCE_INFO *bounce_info; + int bounce_status = 1; + int postmaster_status = 1; + VSTREAM *bounce; + int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks, + var_notify_classes); + + /* + * Initialize. Open queue file, bounce log, etc. + */ + bounce_info = bounce_mail_one_init(queue_name, queue_id, + encoding, orig_recipient, why); + +#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */ +#define NULL_CLEANUP_FLAGS 0 +#define BOUNCE_HEADERS 1 +#define BOUNCE_ALL 0 + + /* + * The choice of bounce sender address depends on the original sender + * address. For a single bounce (a non-delivery notification to the + * message originator), the sender address is the empty string. For a + * double bounce (typically a failed single bounce, or a postmaster + * notification that was produced by any of the mail processes) the + * sender address is defined by the var_double_bounce_sender + * configuration variable. When a double bounce cannot be delivered, the + * queue manager blackholes the resulting triple bounce message. + */ + + /* + * Double bounce failed. Never send a triple bounce. + * + * However, this does not prevent double bounces from bouncing on other + * systems. In order to cope with this, either the queue manager must + * recognize the double-bounce original sender address and discard mail, + * or every delivery agent must recognize the double-bounce sender + * address and substitute something else so mail does not come back at + * us. + */ + if (strcasecmp(orig_sender, mail_addr_double_bounce()) == 0) { + msg_warn("%s: undeliverable postmaster notification discarded", + queue_id); + bounce_status = 0; + } + + /* + * Single bounce failed. Optionally send a double bounce to postmaster. + */ +#define ANY_BOUNCE (MAIL_ERROR_2BOUNCE | MAIL_ERROR_BOUNCE) +#define SKIP_IF_BOUNCE ((notify_mask & ANY_BOUNCE) == 0) + + else if (*orig_sender == 0) { + if (SKIP_IF_BOUNCE) { + bounce_status = 0; + } else { + if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), + var_2bounce_rcpt, + NULL_CLEANUP_FLAGS)) != 0) { + + /* + * Double bounce to Postmaster. This is the last opportunity + * for this message to be delivered. Send the text with + * reason for the bounce, and the headers of the original + * message. Don't bother sending the boiler-plate text. + */ + if (!bounce_header(bounce, bounce_info, var_2bounce_rcpt) + && bounce_recipient_log(bounce, bounce_info) == 0 + && bounce_header_dsn(bounce, bounce_info) == 0 + && bounce_recipient_dsn(bounce, bounce_info) == 0) + bounce_original(bounce, bounce_info, BOUNCE_ALL); + bounce_status = post_mail_fclose(bounce); + } + } + } + + /* + * Non-bounce failed. Send a single bounce. + */ + else { + if ((bounce = post_mail_fopen_nowait(NULL_SENDER, orig_sender, + NULL_CLEANUP_FLAGS)) != 0) { + + /* + * Send the bounce message header, some boilerplate text that + * pretends that we are a polite mail system, the text with + * reason for the bounce, and a copy of the original message. + */ + if (bounce_header(bounce, bounce_info, orig_sender) == 0 + && bounce_boilerplate(bounce, bounce_info) == 0 + && bounce_recipient_log(bounce, bounce_info) == 0 + && bounce_header_dsn(bounce, bounce_info) == 0 + && bounce_recipient_dsn(bounce, bounce_info) == 0) + bounce_original(bounce, bounce_info, BOUNCE_ALL); + bounce_status = post_mail_fclose(bounce); + } + + /* + * Optionally, send a postmaster notice. + * + * This postmaster notice is not critical, so if it fails don't + * retransmit the bounce that we just generated, just log a warning. + */ +#define WANT_IF_BOUNCE ((notify_mask & MAIL_ERROR_BOUNCE)) + + if (bounce_status == 0 && (WANT_IF_BOUNCE) + && strcasecmp(orig_sender, mail_addr_double_bounce()) != 0) { + + /* + * Send the text with reason for the bounce, and the headers of + * the original message. Don't bother sending the boiler-plate + * text. This postmaster notice is not critical, so if it fails + * don't retransmit the bounce that we just generated, just log a + * warning. + */ + if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), + var_bounce_rcpt, + NULL_CLEANUP_FLAGS)) != 0) { + if (bounce_header(bounce, bounce_info, var_bounce_rcpt) == 0 + && bounce_recipient_log(bounce, bounce_info) == 0 + && bounce_header_dsn(bounce, bounce_info) == 0 + && bounce_recipient_dsn(bounce, bounce_info) == 0) + bounce_original(bounce, bounce_info, BOUNCE_HEADERS); + postmaster_status = post_mail_fclose(bounce); + } + if (postmaster_status) + msg_warn("postmaster notice failed while bouncing to %s", + orig_sender); + } + } + + /* + * Cleanup. + */ + bounce_mail_free(bounce_info); + + return (bounce_status); +} diff --git a/postfix/src/bounce/bounce_service.h b/postfix/src/bounce/bounce_service.h index 889e8e9d6..22636e8c7 100644 --- a/postfix/src/bounce/bounce_service.h +++ b/postfix/src/bounce/bounce_service.h @@ -33,6 +33,11 @@ extern int bounce_notify_service(char *, char *, char *, char *, char *, int); */ extern int bounce_notify_verp(char *, char *, char *, char *, char *, char *, int); + /* + * bounce_one_service.c + */ +extern int bounce_one_service(char *, char *, char *, char *, char *, char *); + /* * bounce_cleanup.c */ @@ -61,6 +66,7 @@ typedef struct { } BOUNCE_INFO; extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, const char *, int); +extern BOUNCE_INFO *bounce_mail_one_init(const char *, const char *, const char *, const char *, const char *); extern void bounce_mail_free(BOUNCE_INFO *); extern int bounce_header(VSTREAM *, BOUNCE_INFO *, const char *); extern int bounce_boilerplate(VSTREAM *, BOUNCE_INFO *); diff --git a/postfix/src/cleanup/cleanup_message.c b/postfix/src/cleanup/cleanup_message.c index 752e8479e..e93eb91c9 100644 --- a/postfix/src/cleanup/cleanup_message.c +++ b/postfix/src/cleanup/cleanup_message.c @@ -293,8 +293,7 @@ static int cleanup_act(CLEANUP_STATE *state, char *context, const char *buf, msg_info("%s: warning: %s %.200s; from=<%s> to=<%s>: %s", state->queue_id, context, buf, state->sender, state->recip ? state->recip : "unknown", - *optional_text ? optional_text : - cleanup_strerror(CLEANUP_STAT_CONT)); + *optional_text ? optional_text : "content matched"); return (CLEANUP_ACT_KEEP); } if (STREQUAL(value, "FILTER", command_len)) { diff --git a/postfix/src/global/bounce.c b/postfix/src/global/bounce.c index 05648cbc3..14b74f84b 100644 --- a/postfix/src/global/bounce.c +++ b/postfix/src/global/bounce.c @@ -29,6 +29,31 @@ /* const char *id; /* const char *encoding; /* const char *sender; +/* +/* int bounce_one(flags, queue, id, encoding, sender, +/* recipient, relay, entry, format, ...) +/* int flags; +/* const char *queue; +/* const char *id; +/* const char *encoding; +/* const char *sender; +/* const char *recipient; +/* const char *relay; +/* time_t entry; +/* const char *format; +/* +/* int vbounce_one(flags, queue, id, encoding, sender, +/* recipient, relay, entry, format, ap) +/* int flags; +/* const char *queue; +/* const char *id; +/* const char *encoding; +/* const char *sender; +/* const char *recipient; +/* const char *relay; +/* time_t entry; +/* const char *format; +/* va_list ap; /* DESCRIPTION /* This module implements the client interface to the message /* bounce service, which maintains a per-message log of status @@ -43,6 +68,15 @@ /* the specified sender, including the bounce log that was /* built with bounce_append(). /* +/* bounce_one() bounces one recipient and immediately sends a +/* notification to the sender. This procedure does not append +/* the recipient and reason to the per-message bounce log, and +/* should be used when a delivery agent changes the error +/* return address in a manner that depends on the recipient +/* address. +/* +/* vbounce_one() implements an alternative interface. +/* /* Arguments: /* .IP flags /* The bitwise OR of zero or more of the following (specify @@ -159,7 +193,7 @@ int vbounce_append(int flags, const char *id, const char *recipient, vstring_str(why)); status = (var_soft_bounce ? -1 : 0); } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) { - status = defer_append(flags, id, recipient, "bounce", delay, + status = defer_append(flags, id, recipient, "bounce", entry, "bounce failed"); } else { status = -1; @@ -196,3 +230,64 @@ int bounce_flush(int flags, const char *queue, const char *id, return (-1); } } + +/* bounce_one - send notice for one recipient */ + +int bounce_one(int flags, const char *queue, const char *id, + const char *encoding, const char *sender, + const char *recipient, const char *relay, + time_t entry, const char *fmt,...) +{ + va_list ap; + int status; + + va_start(ap, fmt); + status = vbounce_one(flags, queue, id, encoding, sender, + recipient, relay, entry, fmt, ap); + va_end(ap); + return (status); +} + +/* vbounce_one - send notice for one recipient */ + +int vbounce_one(int flags, const char *queue, const char *id, + const char *encoding, const char *sender, + const char *recipient, const char *relay, + time_t entry, const char *fmt, va_list ap) +{ + VSTRING *why; + int status; + int delay; + + /* + * When we're not bouncing, then use the standard logfile based + * procedure. + */ + if (var_soft_bounce) + return (vbounce_append(flags, id, recipient, relay, entry, fmt, ap)); + + why = vstring_alloc(100); + delay = time((time_t *) 0) - entry; + vstring_vsprintf(why, fmt, ap); + if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service, + ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_ONE, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags, + ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, + ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding, + ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, + ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient, + ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why), + ATTR_TYPE_END) == 0) { + msg_info("%s: to=<%s>, relay=%s, delay=%d, status=bounced (%s)", + id, recipient, relay, delay, vstring_str(why)); + status = 0; + } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) { + status = defer_append(flags, id, recipient, "bounce", entry, + "bounce failed"); + } else { + status = -1; + } + vstring_free(why); + return (status); +} diff --git a/postfix/src/global/bounce.h b/postfix/src/global/bounce.h index 11b91eaf5..301ba72d1 100644 --- a/postfix/src/global/bounce.h +++ b/postfix/src/global/bounce.h @@ -26,14 +26,13 @@ extern int PRINTFLIKE(6, 7) bounce_append(int, const char *, const char *, extern int vbounce_append(int, const char *, const char *, const char *, time_t, const char *, va_list); extern int bounce_flush(int, const char *, const char *, const char *, const char *); - -extern int PRINTFLIKE(8, 9) bounce_recip(int, const char *, const char *, - const char *, const char *, - const char *, time_t, - const char *,...); -extern int vbounce_recip(int, const char *, const char *, const char *, - const char *, const char *, time_t, - const char *, va_list); +extern int PRINTFLIKE(9, 10) bounce_one(int, const char *, const char *, + const char *, const char *, + const char *, const char *, + time_t, const char *,...); +extern int vbounce_one(int, const char *, const char *, const char *, + const char *, const char *, const char *, + time_t, const char *, va_list); /* * Bounce/defer protocol commands. @@ -42,6 +41,7 @@ extern int vbounce_recip(int, const char *, const char *, const char *, #define BOUNCE_CMD_FLUSH 1 /* send log */ #define BOUNCE_CMD_WARN 2 /* send warning, don't delete log */ #define BOUNCE_CMD_VERP 3 /* send log, verp style */ +#define BOUNCE_CMD_ONE 4 /* send one recipient notice */ /* * Flags. diff --git a/postfix/src/global/bounce_log.c b/postfix/src/global/bounce_log.c index f0f841532..a063ede95 100644 --- a/postfix/src/global/bounce_log.c +++ b/postfix/src/global/bounce_log.c @@ -30,6 +30,11 @@ /* void bounce_log_rewind(bp) /* BOUNCE_LOG *bp; /* +/* BOUNCE_LOG *bounce_log_forge(recipient, dsn, why) +/* const char *recipient; +/* const char *status; +/* const char *why; +/* /* void bounce_log_close(bp) /* BOUNCE_LOG *bp; /* DESCRIPTION @@ -57,6 +62,11 @@ /* are marked as done). The result is 0 in case of success, -1 in case /* of problems. /* +/* bounce_log_forge() forges one recipient status record +/* without actually accessing a logfile. +/* The result cannot be used for any logfile access operation +/* and must be disposed of by passing it to bounce_log_close(). +/* /* bounce_log_close() closes an open bounce or defer logfile and /* releases memory for the specified handle. The result is non-zero /* in case of I/O errors. @@ -117,12 +127,32 @@ #define STR(x) vstring_str(x) +/* bounce_log_init - initialize structure */ + +static BOUNCE_LOG *bounce_log_init(VSTREAM *fp, + VSTRING *buf, + const char *recipient, + const char *status, + const char *text, + long offset) +{ + BOUNCE_LOG *bp; + + bp = (BOUNCE_LOG *) mymalloc(sizeof(*bp)); + bp->fp = fp; + bp->buf = buf; + bp->recipient = recipient; + bp->status = status; + bp->text = text; + bp->offset = offset; + return (bp); +} + /* bounce_log_open - open bounce read stream */ BOUNCE_LOG *bounce_log_open(const char *queue_name, const char *queue_id, int flags, int mode) { - BOUNCE_LOG *bp; VSTREAM *fp; #define STREQ(x,y) (strcmp((x),(y)) == 0) @@ -135,12 +165,13 @@ BOUNCE_LOG *bounce_log_open(const char *queue_name, const char *queue_id, if ((fp = mail_queue_open(queue_name, queue_id, flags, mode)) == 0) { return (0); } else { - bp = (BOUNCE_LOG *) mymalloc(sizeof(*bp)); - bp->fp = fp; - bp->buf = vstring_alloc(100); - bp->status = STREQ(queue_name, MAIL_QUEUE_DEFER) ? "4.0.0" : "5.0.0"; - bp->offset = 0; - return (bp); + return (bounce_log_init(fp, /* stream */ + vstring_alloc(100), /* buffer */ + (const char *) 0, /* recipient */ + STREQ(queue_name, MAIL_QUEUE_DEFER) ? + "4.0.0" : "5.0.0", /* status */ + (const char *) 0, /* text */ + 0)); /* offset */ } } @@ -214,14 +245,27 @@ BOUNCE_LOG *bounce_log_delrcpt(BOUNCE_LOG *bp) return (bp); } +/* bounce_log_forge - forge one recipient status record */ + +BOUNCE_LOG *bounce_log_forge(const char *recipient, const char *status, + const char *text) +{ + return (bounce_log_init((VSTREAM *) 0, (VSTRING *) 0, + recipient, status, text, 0)); +} + /* bounce_log_close - close bounce reader stream */ int bounce_log_close(BOUNCE_LOG *bp) { int ret; - ret = vstream_fclose(bp->fp); - vstring_free(bp->buf); + if (bp->fp) + ret = vstream_fclose(bp->fp); + else + ret = 0; + if (bp->buf) + vstring_free(bp->buf); myfree((char *) bp); return (ret); } diff --git a/postfix/src/global/bounce_log.h b/postfix/src/global/bounce_log.h index 0f91c6f8d..a478b7486 100644 --- a/postfix/src/global/bounce_log.h +++ b/postfix/src/global/bounce_log.h @@ -34,6 +34,7 @@ typedef struct { extern BOUNCE_LOG *bounce_log_open(const char *, const char *, int, int); extern BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *); extern BOUNCE_LOG *bounce_log_delrcpt(BOUNCE_LOG *); +extern BOUNCE_LOG *bounce_log_forge(const char *, const char *, const char *); extern int bounce_log_close(BOUNCE_LOG *); #define bounce_log_rewind(bp) vstream_fseek((bp)->fp, 0L, SEEK_SET) diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 3c2347061..7c6cce559 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -1131,6 +1131,11 @@ extern bool var_allow_untrust_route; #define DEF_REJECT_CODE 554 extern int var_reject_code; +#define DEFER_ALL "defer" +#define VAR_DEFER_CODE "defer_code" +#define DEF_DEFER_CODE 450 +extern int var_defer_code; + #define REJECT_UNKNOWN_CLIENT "reject_unknown_client" #define VAR_UNK_CLIENT_CODE "unknown_client_reject_code" #define DEF_UNK_CLIENT_CODE 450 diff --git a/postfix/src/global/mail_queue.h b/postfix/src/global/mail_queue.h index 9486eb8ff..f18fb4516 100644 --- a/postfix/src/global/mail_queue.h +++ b/postfix/src/global/mail_queue.h @@ -21,6 +21,7 @@ * Mail queue names. */ #define MAIL_QUEUE_MAILDROP "maildrop" +#define MAIL_QUEUE_HOLD "hold" #define MAIL_QUEUE_INCOMING "incoming" #define MAIL_QUEUE_ACTIVE "active" #define MAIL_QUEUE_DEFERRED "deferred" diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 554c1a950..36fa490b7 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 "20020719" +#define MAIL_RELEASE_DATE "20020803" #define VAR_MAIL_VERSION "mail_version" #define DEF_MAIL_VERSION "1.1.11-" MAIL_RELEASE_DATE diff --git a/postfix/src/local/Makefile.in b/postfix/src/local/Makefile.in index b07e17fb8..e38a38a35 100644 --- a/postfix/src/local/Makefile.in +++ b/postfix/src/local/Makefile.in @@ -113,6 +113,8 @@ command.o: ../../include/resolve_clnt.h command.o: ../../include/deliver_request.h command.o: ../../include/recipient_list.h command.o: ../../include/mbox_conf.h +command.o: ../../include/maps.h +command.o: ../../include/dict.h deliver_attr.o: deliver_attr.c deliver_attr.o: ../../include/sys_defs.h deliver_attr.o: ../../include/msg.h @@ -128,6 +130,8 @@ deliver_attr.o: ../../include/deliver_request.h deliver_attr.o: ../../include/recipient_list.h deliver_attr.o: ../../include/mbox_conf.h deliver_attr.o: ../../include/argv.h +deliver_attr.o: ../../include/maps.h +deliver_attr.o: ../../include/dict.h delivered.o: delivered.c delivered.o: ../../include/sys_defs.h delivered.o: ../../include/msg.h @@ -151,6 +155,8 @@ delivered.o: ../../include/deliver_request.h delivered.o: ../../include/recipient_list.h delivered.o: ../../include/mbox_conf.h delivered.o: ../../include/argv.h +delivered.o: ../../include/maps.h +delivered.o: ../../include/dict.h dotforward.o: dotforward.c dotforward.o: ../../include/sys_defs.h dotforward.o: ../../include/msg.h @@ -178,6 +184,8 @@ dotforward.o: ../../include/deliver_request.h dotforward.o: ../../include/recipient_list.h dotforward.o: ../../include/mbox_conf.h dotforward.o: ../../include/argv.h +dotforward.o: ../../include/maps.h +dotforward.o: ../../include/dict.h file.o: file.c file.o: ../../include/sys_defs.h file.o: ../../include/msg.h @@ -203,6 +211,8 @@ file.o: ../../include/tok822.h file.o: ../../include/resolve_clnt.h file.o: ../../include/deliver_request.h file.o: ../../include/recipient_list.h +file.o: ../../include/maps.h +file.o: ../../include/dict.h forward.o: forward.c forward.o: ../../include/sys_defs.h forward.o: ../../include/msg.h @@ -231,6 +241,8 @@ forward.o: ../../include/resolve_clnt.h forward.o: ../../include/deliver_request.h forward.o: ../../include/recipient_list.h forward.o: ../../include/mbox_conf.h +forward.o: ../../include/maps.h +forward.o: ../../include/dict.h include.o: include.c include.o: ../../include/sys_defs.h include.o: ../../include/msg.h @@ -255,6 +267,8 @@ include.o: ../../include/deliver_request.h include.o: ../../include/recipient_list.h include.o: ../../include/mbox_conf.h include.o: ../../include/argv.h +include.o: ../../include/maps.h +include.o: ../../include/dict.h indirect.o: indirect.c indirect.o: ../../include/sys_defs.h indirect.o: ../../include/msg.h @@ -273,6 +287,8 @@ indirect.o: ../../include/deliver_request.h indirect.o: ../../include/recipient_list.h indirect.o: ../../include/mbox_conf.h indirect.o: ../../include/argv.h +indirect.o: ../../include/maps.h +indirect.o: ../../include/dict.h local.o: local.c local.o: ../../include/sys_defs.h local.o: ../../include/msg.h @@ -294,6 +310,7 @@ local.o: ../../include/mail_addr.h local.o: ../../include/mail_conf.h local.o: ../../include/been_here.h local.o: ../../include/ext_prop.h +local.o: ../../include/maps.h local.o: ../../include/mail_server.h local.o: local.h local.o: ../../include/tok822.h @@ -316,6 +333,8 @@ local_expand.o: ../../include/deliver_request.h local_expand.o: ../../include/recipient_list.h local_expand.o: ../../include/mbox_conf.h local_expand.o: ../../include/argv.h +local_expand.o: ../../include/maps.h +local_expand.o: ../../include/dict.h mailbox.o: mailbox.c mailbox.o: ../../include/sys_defs.h mailbox.o: ../../include/msg.h @@ -375,6 +394,8 @@ maildir.o: ../../include/deliver_request.h maildir.o: ../../include/recipient_list.h maildir.o: ../../include/mbox_conf.h maildir.o: ../../include/argv.h +maildir.o: ../../include/maps.h +maildir.o: ../../include/dict.h recipient.o: recipient.c recipient.o: ../../include/sys_defs.h recipient.o: ../../include/msg.h @@ -401,6 +422,7 @@ recipient.o: ../../include/resolve_clnt.h recipient.o: ../../include/deliver_request.h recipient.o: ../../include/recipient_list.h recipient.o: ../../include/mbox_conf.h +recipient.o: ../../include/maps.h resolve.o: resolve.c resolve.o: ../../include/sys_defs.h resolve.o: ../../include/msg.h @@ -421,6 +443,8 @@ resolve.o: ../../include/deliver_request.h resolve.o: ../../include/recipient_list.h resolve.o: ../../include/mbox_conf.h resolve.o: ../../include/argv.h +resolve.o: ../../include/maps.h +resolve.o: ../../include/dict.h token.o: token.c token.o: ../../include/sys_defs.h token.o: ../../include/msg.h @@ -442,6 +466,8 @@ token.o: ../../include/deliver_request.h token.o: ../../include/recipient_list.h token.o: ../../include/mbox_conf.h token.o: ../../include/argv.h +token.o: ../../include/maps.h +token.o: ../../include/dict.h unknown.o: unknown.c unknown.o: ../../include/sys_defs.h unknown.o: ../../include/msg.h @@ -464,3 +490,5 @@ unknown.o: ../../include/deliver_request.h unknown.o: ../../include/recipient_list.h unknown.o: ../../include/mbox_conf.h unknown.o: ../../include/argv.h +unknown.o: ../../include/maps.h +unknown.o: ../../include/dict.h diff --git a/postfix/src/local/alias.c b/postfix/src/local/alias.c index af0fcf355..717f9f57b 100644 --- a/postfix/src/local/alias.c +++ b/postfix/src/local/alias.c @@ -129,7 +129,6 @@ int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, const char *alias_result; char *expansion; char *owner; - static MAPS *maps; char **cpp; uid_t alias_uid; struct mypasswd *alias_pwd; @@ -145,12 +144,6 @@ int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, if (msg_verbose) MSG_LOG_STATE(myname, state); - /* - * Do this only once. - */ - if (maps == 0) - maps = maps_create("aliases", var_alias_maps, DICT_FLAG_LOCK); - /* * DUPLICATE/LOOP ELIMINATION * @@ -195,7 +188,7 @@ int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, * * Don't match aliases that are based on regexps. */ - for (cpp = maps->argv->argv; *cpp; cpp++) { + for (cpp = alias_maps->argv->argv; *cpp; cpp++) { if ((dict = dict_handle(*cpp)) == 0) msg_panic("%s: dictionary not found: %s", myname, *cpp); if ((dict->flags & DICT_FLAG_FIXED) == 0) { @@ -252,7 +245,7 @@ int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, expansion = mystrdup(alias_result); if (OWNER_ASSIGN(owner) != 0 - && (owner_rhs = maps_find(maps, owner, DICT_FLAG_FIXED)) != 0) { + && (owner_rhs = maps_find(alias_maps, owner, DICT_FLAG_FIXED)) != 0) { canon_owner = canon_addr_internal(vstring_alloc(10), var_exp_own_alias ? owner_rhs : owner); SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level); diff --git a/postfix/src/local/local.c b/postfix/src/local/local.c index dc13ca166..fb00a3b75 100644 --- a/postfix/src/local/local.c +++ b/postfix/src/local/local.c @@ -435,6 +435,7 @@ #include #include #include +#include /* Single server skeleton. */ @@ -478,6 +479,7 @@ int local_file_deliver_mask; int local_ext_prop_mask; int local_deliver_hdr_mask; int local_mbox_lock_mask; +MAPS *alias_maps; /* local_deliver - deliver message with extreme prejudice */ @@ -661,6 +663,7 @@ static void pre_init(char *unused_name, char **unused_argv) VAR_MAILBOX_LIMIT, VAR_MESSAGE_LIMIT); set_file_limit(var_mailbox_limit); } + alias_maps = maps_create("aliases", var_alias_maps, DICT_FLAG_LOCK); } /* main - pass control to the single-threaded skeleton */ diff --git a/postfix/src/local/local.h b/postfix/src/local/local.h index 302ea5419..75fa5b0b3 100644 --- a/postfix/src/local/local.h +++ b/postfix/src/local/local.h @@ -22,6 +22,7 @@ #include #include #include +#include /* * User attributes: these control the privileges for delivery to external @@ -210,6 +211,12 @@ int local_expand(VSTRING *, const char *, LOCAL_STATE *, USER_ATTR *, const #define LOCAL_EXP_EXTENSION_MATCHED (1< #include #include +#include /* Application-specific. */ #include "local.h" +#define STR(x) vstring_str(x) + /* deliver_switch - branch on recipient type */ static int deliver_switch(LOCAL_STATE state, USER_ATTR usr_attr) @@ -211,14 +214,6 @@ int deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr) state.level, state.msg_attr.recipient)) return (0); - /* - * With each level of recursion, detect and break external message - * forwarding loops. - */ - if (delivered_find(state.loop_info, state.msg_attr.recipient)) - return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), - "mail forwarding loop for %s", state.msg_attr.recipient)); - /* * Set up the recipient-specific attributes. If this is forwarded mail, * leave the delivered attribute alone, so that the forwarded message @@ -254,6 +249,42 @@ int deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr) return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), "null username in %s", state.msg_attr.recipient)); + /* + * With each level of recursion, detect and break external message + * forwarding loops. If the looping recipient address has an owner- + * alias, then assume the error report should be sent there instead. + * + * XXX A delivery agent cannot change the envelope sender address for + * bouncing, that would break multi-recipient mail. The fix would be to + * change the delivery agent to bounce service protocol. The bounce + * daemon would have to record in the bounce logfile for each bounced + * recipient the sender address that the recipient would have to be + * bounced to. This could simplify VERP implementation, at the cost of + * greatly complicating the normal bounce sending procedure. + */ + if (delivered_find(state.loop_info, state.msg_attr.delivered)) { + VSTRING *canon_owner = 0; + + if (var_ownreq_special) { + char *owner; + const char *owner_rhs; + + owner = concatenate("owner-", state.msg_attr.user, (char *) 0); + owner_rhs = maps_find(alias_maps, owner, ALIAS_DICT_FLAGS); + if (owner_rhs != 0) { + canon_owner = canon_addr_internal(vstring_alloc(10), + var_exp_own_alias ? owner_rhs : owner); + SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level); + } + myfree(owner); + } + rcpt_stat = bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), + "mail forwarding loop for %s", state.msg_attr.recipient); + if (canon_owner) + vstring_free(canon_owner); + return (rcpt_stat); + } + /* * Run the recipient through the delivery switch. */ diff --git a/postfix/src/postsuper/postsuper.c b/postfix/src/postsuper/postsuper.c index 3b62ab972..ed07f3a98 100644 --- a/postfix/src/postsuper/postsuper.c +++ b/postfix/src/postsuper/postsuper.c @@ -6,6 +6,7 @@ /* SYNOPSIS /* .fi /* \fBpostsuper\fR [\fB-psv\fR] [\fB-d \fIqueue_id\fR] +/* [\fB-h \fIqueue_id\fR] [\fB-H \fIqueue_id\fR] /* [\fB-r \fIqueue_id\fR] [\fIdirectory ...\fR] /* DESCRIPTION /* The \fBpostsuper\fR command does maintenance jobs on the Postfix @@ -13,17 +14,24 @@ /* /* By default, \fBpostsuper\fR performs the operations requested with the /* \fB-s\fR and \fB-p\fR command-line options on all Postfix queue -/* directories - this includes the \fBincoming\fR, \fBactive\fR and +/* directories - this includes the \fBincoming\fR, \fBactive\fR and /* \fBdeferred\fR directories with mail files and the \fBbounce\fR, /* \fBdefer\fR and \fBflush\fR directories with log files. /* /* Options: /* .IP "\fB-d \fIqueue_id\fR" -/* Delete one message with the named queue ID from the named -/* mail queue(s) (default: \fBincoming\fR, \fBactive\fR and -/* \fBdeferred\fR). +/* Delete one message with the named queue ID from the named +/* mail queue(s) (default: \fBhold\fR, \fBincoming\fR, \fBactive\fR and +/* \fBdeferred\fR). /* If a \fIqueue_id\fR of \fB-\fR is specified, the program reads -/* queue IDs from standard input. +/* queue IDs from standard input. For example, to delete all mail +/* from or to \fBuser@example.com\fR: +/* .sp +/* mailq | awk \'BEGIN { RS = "" } \e +/* .ti +4 +/* / user@example\e.com$/ { print $1 } \e +/* .br +/* \' | postsuper -d - /* .sp /* Specify \fB-d ALL\fR to remove all messages; for example, specify /* \fB-d ALL deferred\fR to delete mail in the \fBdeferred\fR queue. @@ -53,16 +61,40 @@ /* \fBpostsuper\fR deletes the new message, instead of the old /* message that it should have deleted. /* .RE +/* .IP "\fB-h \fIqueue_id\fR" +/* Put mail "on hold" so that no attempt is made to deliver it. +/* Move one message with the named queue ID from the named +/* mail queue(s) (default: \fBincoming\fR, \fBactive\fR and +/* \fBdeferred\fR) to the \fBhold\fR queue. +/* If a \fIqueue_id\fR of \fB-\fR is specified, the program reads +/* queue IDs from standard input. +/* .sp +/* Specify \fB-h ALL\fR to hold all messages; for example, specify +/* \fB-h ALL deferred\fR to hold mail in the \fBdeferred\fR queue. +/* As a safety measure, the word \fBALL\fR must be specified in upper +/* case. +/* .sp +/* Note: mail that is put "on hold" will not expire. +/* .IP "\fB-H \fIqueue_id\fR" +/* Release mail that was put "on hold". +/* Move one message with the named queue ID from the named +/* mail queue(s) (default: \fBhold\fR) to the \fBdeferred\fR queue. +/* If a \fIqueue_id\fR of \fB-\fR is specified, the program reads +/* queue IDs from standard input. +/* .sp +/* Specify \fB-H ALL\fR to release all mail that is "on hold". +/* As a safety measure, the word \fBALL\fR must be specified in upper +/* case. /* .IP \fB-p\fR /* Purge old temporary files that are left over after system or /* software crashes. /* .IP "\fB-r \fIqueue_id\fR" -/* Requeue the message with the named queue ID from the named -/* mail queue(s) (default: \fBincoming\fR, \fBactive\fR and -/* \fBdeferred\fR). -/* To requeue multiple messages, specify multiple \fB-r\fR +/* Requeue the message with the named queue ID from the named +/* mail queue(s) (default: \fBhold\fR, \fBincoming\fR, \fBactive\fR and +/* \fBdeferred\fR). +/* To requeue multiple messages, specify multiple \fB-r\fR /* command-line options. -/* Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, +/* Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, /* the program reads queue IDs from standard input. /* .sp /* Specify \fB-r ALL\fR to requeue all messages. As a safety @@ -70,8 +102,8 @@ /* .sp /* A requeued message is moved to the \fBmaildrop\fR queue, from /* where it is copied by the pickup daemon to a new file whose name -/* is guaranteed to match the new queue file inode number. The -/* new queue file is subjected again to mail address rewriting and +/* is guaranteed to match the new queue file inode number. The +/* new queue file is subjected again to mail address rewriting and /* substitution. This is useful when rewriting rules or virtual /* mappings have changed. /* .sp @@ -105,6 +137,9 @@ /* the number of messages requeued with \fB-r\fR, and the number of /* messages whose queue file name was fixed with \fB-s\fR. The report /* is written to the standard error stream and to \fBsyslogd\fR. +/* BUGS +/* Mail that is not sanitized by Postfix (i.e. mail in the \fBmaildrop\fR +/* queue) cannot be placed "on hold". /* CONFIGURATION PARAMETERS /* .ad /* .fi @@ -171,9 +206,27 @@ #define ACTION_DELETE_ALL (1<<3) /* delete all queue file(s) */ #define ACTION_REQUEUE_ONE (1<<4) /* requeue named queue file(s) */ #define ACTION_REQUEUE_ALL (1<<5) /* requeue all queue file(s) */ +#define ACTION_HOLD_ONE (1<<6) /* put named queue file(s) on hold */ +#define ACTION_HOLD_ALL (1<<7) /* put all messages on hold */ +#define ACTION_RELEASE_ONE (1<<8) /* release named queue file(s) */ +#define ACTION_RELEASE_ALL (1<<9) /* release all "on hold" mail */ #define ACTION_DEFAULT (ACTION_STRUCT | ACTION_PURGE) + /* + * Actions that operate on individually named queue files. These must never + * be done when queue file names are changed to match their inode number. + */ +#define ACTIONS_BY_QUEUE_ID (ACTION_DELETE_ONE | ACTION_REQUEUE_ONE \ + | ACTION_HOLD_ONE | ACTION_RELEASE_ONE) + + /* + * Mass rename operations that are postponed to a second pass after queue + * file names are changed to match their inode number. + */ +#define ACTIONS_AFTER_INUM_FIX (ACTION_REQUEUE_ALL | ACTION_HOLD_ALL \ + | ACTION_RELEASE_ALL) + /* * Information about queue directories and what we expect to do there. If a * file has unexpected owner permissions and is older than some threshold, @@ -195,6 +248,7 @@ static struct queue_info queue_info[] = { MAIL_QUEUE_INCOMING, MAIL_QUEUE_STAT_READY, RECURSE, MAIL_QUEUE_ACTIVE, MAIL_QUEUE_STAT_READY, RECURSE, MAIL_QUEUE_DEFERRED, MAIL_QUEUE_STAT_READY, RECURSE, + MAIL_QUEUE_HOLD, MAIL_QUEUE_STAT_READY, RECURSE, MAIL_QUEUE_DEFER, 0600, RECURSE, MAIL_QUEUE_BOUNCE, 0600, RECURSE, MAIL_QUEUE_FLUSH, 0600, RECURSE, @@ -224,6 +278,8 @@ const char *log_queue_names[] = { * multiple results from a function. */ static int message_requeued = 0; /* requeued messages */ +static int message_held = 0; /* messages put on hold */ +static int message_released = 0; /* messages released from hold */ static int message_deleted = 0; /* deleted messages */ static int inode_fixed = 0; /* queue id matched to inode number */ static int inode_mismatch = 0; /* queue id inode mismatch */ @@ -391,6 +447,97 @@ static int requeue_one(const char **queue_names, const char *queue_id) return (found); } +/* hold_one - put "on hold" one message instance */ + +static int hold_one(const char **queue_names, const char *queue_id) +{ + struct stat st; + const char **msg_qpp; + const char *old_path; + VSTRING *new_path_buf; + int found; + int tries; + + /* + * Sanity check. No early returns beyond this point. + */ + if (!mail_queue_id_ok(queue_id)) { + msg_warn("invalid mail queue id: %s", queue_id); + return (0); + } + new_path_buf = vstring_alloc(100); + + /* + * Skip meta file directories. Like the mass requeue operation, we not + * delete defer or bounce logfiles, to avoid losing a race where the + * queue manager decides to bounce mail after all recipients have been + * tried. + * + * XXX We must not put maildrop mail on hold because that would mix already + * sanitized mail with mail that still needs to be sanitized. + */ + for (found = 0, tries = 0; found == 0 && tries < 2; tries++) { + for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) { + if (strcmp(*msg_qpp, MAIL_QUEUE_MAILDROP) == 0) + continue; + if (strcmp(*msg_qpp, MAIL_QUEUE_HOLD) == 0) + continue; + if (!MESSAGE_QUEUE(find_queue_info(*msg_qpp))) + continue; + if (mail_open_ok(*msg_qpp, queue_id, &st, &old_path) != MAIL_OPEN_YES) + continue; + (void) mail_queue_path(new_path_buf, MAIL_QUEUE_HOLD, queue_id); + if (postrename(old_path, STR(new_path_buf)) == 0) { + msg_info("%s: placed on hold", queue_id); + found = 1; + break; + } /* else: maybe lost a race */ + } + } + vstring_free(new_path_buf); + return (found); +} + +/* release_one - release one message instance that was placed "on hold" */ + +static int release_one(const char **queue_names, const char *queue_id) +{ + struct stat st; + const char **msg_qpp; + const char *old_path; + VSTRING *new_path_buf; + int found; + + /* + * Sanity check. No early returns beyond this point. + */ + if (!mail_queue_id_ok(queue_id)) { + msg_warn("invalid mail queue id: %s", queue_id); + return (0); + } + new_path_buf = vstring_alloc(100); + + /* + * Skip inapplicable directories. This can happen when -H is combined + * with other operations. + */ + found = 0; + for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) { + if (strcmp(*msg_qpp, MAIL_QUEUE_HOLD) != 0) + continue; + if (mail_open_ok(*msg_qpp, queue_id, &st, &old_path) != MAIL_OPEN_YES) + continue; + (void) mail_queue_path(new_path_buf, MAIL_QUEUE_DEFERRED, queue_id); + if (postrename(old_path, STR(new_path_buf)) == 0) { + msg_info("%s: released from hold", queue_id); + found = 1; + break; + } + } + vstring_free(new_path_buf); + return (found); +} + /* operate_stream - operate on queue IDs given on stream */ static int operate_stream(VSTREAM *fp, @@ -547,8 +694,8 @@ static void super(const char **queues, int action) continue; /* - * Remove alien directories. If maildrop is world writable, then - * we cannot abort just because we cannot remove someone's + * Remove alien directories. If maildrop is compromised, then we + * cannot abort just because we cannot remove someone's * directory. */ if (S_ISDIR(st.st_mode)) { @@ -565,11 +712,9 @@ static void super(const char **queues, int action) /* * Mass deletion. We count the deletion of mail that this system - * has taken responsibility for. XXX This option does not use the - * mail_queue(3) API, so that it can be run on a queue that does - * not have files in the "right" place. It would be terribly - * inefficient to first have to rename files into place before - * deleting them. + * has taken responsibility for. XXX This option does not use + * mail_queue_remove(), so that it can avoid having to first move + * queue files to the "right" subdirectory level. */ if (action & ACTION_DELETE_ALL) { if (postremove(STR(actual_path)) == 0) @@ -594,22 +739,16 @@ static void super(const char **queues, int action) continue; } - /* - * Skip temporary message files that aren't old enough. - */ - if (MESSAGE_QUEUE(qp) && !READY_MESSAGE(st)) - /* No further work on this object is possible. */ - continue; - /* * Fix queueid#FIX names that were left from a previous pass over * the queue where message queue file names were matched to their - * inode number. This requires that the file is already in the - * proper directory so that we only have to strip the suffix. - * Make sure that the name minus suffix is well formed and that - * the name matches the file inode number. + * inode number. We strip the suffix and move the file into the + * proper subdirectory level. Make sure that the name minus + * suffix is well formed and that the name matches the file inode + * number. */ - if (strcmp(path + (strlen(path) - SUFFIX_LEN), SUFFIX) == 0) { + if ((action & ACTION_STRUCT) + && strcmp(path + (strlen(path) - SUFFIX_LEN), SUFFIX) == 0) { path[strlen(path) - SUFFIX_LEN] = 0; /* XXX */ if (!mail_queue_id_ok(path)) { msg_warn("bogus file name: %s", STR(actual_path)); @@ -625,8 +764,7 @@ static void super(const char **queues, int action) continue; } } - vstring_strncpy(wanted_path, STR(actual_path), - strlen(STR(actual_path)) - SUFFIX_LEN); + (void) mail_queue_path(wanted_path, queue_name, path); if (postrename(STR(actual_path), STR(wanted_path)) < 0) { /* No further work on this object is possible. */ continue; @@ -647,25 +785,6 @@ static void super(const char **queues, int action) continue; } - /* - * Mass requeuing. The pickup daemon will copy requeued mail to a - * new queue file, so that address rewriting is applied again. - * XXX This option does not use the mail_queue(3) API, so that it - * can be run on a queue that does not have the files in the - * "right" place. It would be terribly inefficient to first have - * to rename files into place before requeuing them. Like the - * requeue_one() routine, this code does not touch logfiles. - */ - if ((action & ACTION_REQUEUE_ALL) - && MESSAGE_QUEUE(qp) - && strcmp(queue_name, MAIL_QUEUE_MAILDROP) != 0) { - (void) mail_queue_path(wanted_path, MAIL_QUEUE_MAILDROP, path); - if (postrename(STR(actual_path), STR(wanted_path)) == 0) - message_requeued++; - /* At this point, path and actual_path are invalidated. */ - continue; - } - /* * See if the file name matches the file inode number. Skip meta * file directories. This option requires that meta files be put @@ -675,11 +794,9 @@ static void super(const char **queues, int action) * upon the second pass the #FIX is stripped off the name. Of * course we have to be prepared that the program is interrupted * before it completes, so any left-over newqueueid#FIX files - * have to be handled properly. XXX This option does not use the - * mail_queue(3) API for message queue files, so that it can be - * run on a queue that does not have message queue files in the - * "right" place. It would be terribly inefficient to first have - * to rename files into place before fixing the file names. + * have to be handled properly. XXX This option cannot use + * mail_queue_rename(), because the queue file name violates + * normal queue file syntax. */ if ((action & ACTION_STRUCT) != 0 && MESSAGE_QUEUE(qp)) { if (sscanf(path + 5, "%lx", &inum) != 1) { @@ -688,16 +805,73 @@ static void super(const char **queues, int action) } if (inum != (unsigned long) st.st_ino) { inode_mismatch++; /* before we fix */ + action &= ~ACTIONS_AFTER_INUM_FIX; fix_queue_id(STR(actual_path), queue_name, path, st.st_ino); /* At this point, path and actual_path are invalidated. */ continue; } } + /* + * Mass requeuing. The pickup daemon will copy requeued mail to a + * new queue file, so that address rewriting is applied again. + * XXX This option does not use mail_queue_rename(), so that it + * can avoid having to first move queue files to the "right" + * subdirectory level. Like the requeue_one() routine, this code + * does not touch logfiles. + */ + if ((action & ACTION_REQUEUE_ALL) + && MESSAGE_QUEUE(qp) + && strcmp(queue_name, MAIL_QUEUE_MAILDROP) != 0) { + (void) mail_queue_path(wanted_path, MAIL_QUEUE_MAILDROP, path); + if (postrename(STR(actual_path), STR(wanted_path)) == 0) + message_requeued++; + /* At this point, path and actual_path are invalidated. */ + continue; + } + + /* + * Mass renaming to the "on hold" queue. XXX This option does not + * use mail_queue_rename(), so that it can avoid having to first + * move queue files to the "right" subdirectory level. Like the + * hold_one() routine, this code does not touch logfiles, and + * must not touch files in the maildrop queue, because maildrop + * files contain data that has not yet been sanitized and therefore + * must not be mixed with already sanitized mail. + */ + if ((action & ACTION_HOLD_ALL) + && MESSAGE_QUEUE(qp) + && strcmp(queue_name, MAIL_QUEUE_MAILDROP) != 0 + && strcmp(queue_name, MAIL_QUEUE_HOLD) != 0) { + (void) mail_queue_path(wanted_path, MAIL_QUEUE_HOLD, path); + if (postrename(STR(actual_path), STR(wanted_path)) == 0) + message_held++; + /* At this point, path and actual_path are invalidated. */ + continue; + } + + /* + * Mass release from the "on hold" queue. XXX This option does + * not use mail_queue_rename(), so that it can avoid having to + * first move queue files to the "right" subdirectory level. Like + * the release_one() routine, this code must not touch logfiles. + */ + if ((action & ACTION_RELEASE_ALL) + && strcmp(queue_name, MAIL_QUEUE_HOLD) == 0) { + (void) mail_queue_path(wanted_path, MAIL_QUEUE_DEFERRED, path); + if (postrename(STR(actual_path), STR(wanted_path)) == 0) + message_released++; + /* At this point, path and actual_path are invalidated. */ + continue; + } + /* * See if this file sits in the right place in the file system * hierarchy. Its place may be wrong after a change to the - * hash_queue_{names,depth} parameter settings. + * hash_queue_{names,depth} parameter settings. This requires + * that the bounce/defer logfiles be at the right subdirectory + * level first, otherwise we would fail to properly rename + * bounce/defer logfiles. */ if (action & ACTION_STRUCT) { (void) mail_queue_path(wanted_path, queue_name, path); @@ -745,10 +919,16 @@ int main(int argc, char **argv) int c; ARGV *requeue_names = 0; ARGV *delete_names = 0; + ARGV *hold_names = 0; + ARGV *release_names = 0; char **cpp; /* - * Defaults. + * Defaults. The structural checks must fix the directory levels of "log + * file" directories (bounce, defer) before doing structural checks on + * the "message file" directories, so that we can find the logfiles in + * the right place when message files need to be renamed to match their + * inode number. */ static char *default_queues[] = { MAIL_QUEUE_DEFER, /* before message directories */ @@ -757,9 +937,20 @@ int main(int argc, char **argv) MAIL_QUEUE_INCOMING, MAIL_QUEUE_ACTIVE, MAIL_QUEUE_DEFERRED, + MAIL_QUEUE_HOLD, MAIL_QUEUE_FLUSH, 0, }; + static char *default_hold_queues[] = { + MAIL_QUEUE_INCOMING, + MAIL_QUEUE_ACTIVE, + MAIL_QUEUE_DEFERRED, + 0, + }; + static char *default_release_queues[] = { + MAIL_QUEUE_HOLD, + 0, + }; /* * Be consistent with file permissions. @@ -827,11 +1018,14 @@ int main(int argc, char **argv) /* * Parse JCL. */ - while ((c = GETOPT(argc, argv, "d:pr:sv")) > 0) { + while ((c = GETOPT(argc, argv, "d:h:H:pr:sv")) > 0) { switch (c) { default: - msg_fatal("usage: %s [-d queue_id (delete)] [-p (purge temporary files)] [-r queue_id (requeue)] [-s (structure fix)]", - argv[0]); + msg_fatal("usage: %s [-d queue_id (delete)] " + "[-h queue_id (hold)] [-H queue_id (un-hold)] " + "[-p (purge temporary files)] [-r queue_id (requeue)] " + "[-s (structure fix)] [-v (verbose)] " + "[queue...]", argv[0]); case 'd': if (delete_names == 0) delete_names = argv_alloc(1); @@ -839,6 +1033,20 @@ int main(int argc, char **argv) action |= (strcmp(optarg, "ALL") == 0 ? ACTION_DELETE_ALL : ACTION_DELETE_ONE); break; + case 'h': + if (hold_names == 0) + hold_names = argv_alloc(1); + argv_add(hold_names, optarg, (char *) 0); + action |= (strcmp(optarg, "ALL") == 0 ? + ACTION_HOLD_ALL : ACTION_HOLD_ONE); + break; + case 'H': + if (release_names == 0) + release_names = argv_alloc(1); + argv_add(release_names, optarg, (char *) 0); + action |= (strcmp(optarg, "ALL") == 0 ? + ACTION_RELEASE_ALL : ACTION_RELEASE_ONE); + break; case 'p': action |= ACTION_PURGE; break; @@ -858,20 +1066,46 @@ int main(int argc, char **argv) } } + /* + * Sanity checks. + */ + if ((action & ACTION_DELETE_ALL) && (action & ACTION_DELETE_ONE)) { + msg_warn("option \"-d ALL\" will ignore other command line queue IDs"); + action &= ~ACTION_DELETE_ONE; + } + if ((action & ACTION_REQUEUE_ALL) && (action & ACTION_REQUEUE_ONE)) { + msg_warn("option \"-r ALL\" will ignore other command line queue IDs"); + action &= ~ACTION_REQUEUE_ONE; + } + if ((action & ACTION_HOLD_ALL) && (action & ACTION_HOLD_ONE)) { + msg_warn("option \"-h ALL\" will ignore other command line queue IDs"); + action &= ~ACTION_HOLD_ONE; + } + if ((action & ACTION_RELEASE_ALL) && (action & ACTION_RELEASE_ONE)) { + msg_warn("option \"-H ALL\" will ignore other command line queue IDs"); + action &= ~ACTION_RELEASE_ONE; + } + /* * Execute the explicitly specified (or default) action, on the * explicitly specified (or default) queues. * * XXX Work around gcc const brain damage. + * + * XXX The file name/inode number fix should always run over all message + * file directories, and should always be preceded by a subdirectory + * level check of the bounce and defer logfile directories. */ if (action == 0) action = ACTION_DEFAULT; - if (argv[optind] == 0) - queues = (const char **) default_queues; - else + if (argv[optind] != 0) queues = (const char **) argv + optind; - -#define ACTIONS_BY_QUEUE_ID (ACTION_DELETE_ONE | ACTION_REQUEUE_ONE) + else if (action == ACTION_HOLD_ALL) + queues = (const char **) default_hold_queues; + else if (action == ACTION_RELEASE_ALL) + queues = (const char **) default_release_queues; + else + queues = (const char **) default_queues; /* * Basic queue maintenance, as well as mass deletion, mass requeuing, and @@ -879,15 +1113,27 @@ int main(int argc, char **argv) * right place before the file-by-name operations are done. */ if (action & ~ACTIONS_BY_QUEUE_ID) - super(queues, action & ~ACTIONS_BY_QUEUE_ID); + super(queues, action); /* * If any file names needed changing to match the message file inode * number, those files were named newqeueid#FIX. We need a second pass to - * strip the suffix from the new queue ID. + * strip the suffix from the new queue ID, and to complete any requested + * operations that had to be skipped in the first pass. */ if (inode_mismatch > 0) - super(queues, 0); + super(queues, action); + + /* + * Don't do actions by queue file name if any queue files changed name + * because they did not match the queue file inode number. We could be + * acting on the wrong queue file and lose mail. + */ + if ((action & ACTIONS_BY_QUEUE_ID) + && (inode_mismatch > 0 || inode_fixed > 0)) { + msg_error("QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS"); + msg_fatal("CHECK YOUR QUEUE IDS AND RE-ISSUE THE COMMAND"); + } /* * Delete queue files by name. This must not be done when queue file @@ -895,11 +1141,9 @@ int main(int argc, char **argv) * because we could be deleting the wrong message. */ if (action & ACTION_DELETE_ONE) { - if (inode_mismatch > 0 || inode_fixed > 0) { - msg_error("QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS"); - msg_fatal("CHECK YOUR QUEUE IDS AND RE-ISSUE THE COMMAND"); - } argv_terminate(delete_names); + queues = (const char **) + (argv[optind] ? argv + optind : default_queues); for (cpp = delete_names->argv; *cpp; cpp++) { if (strcmp(*cpp, "ALL") == 0) continue; @@ -917,11 +1161,9 @@ int main(int argc, char **argv) * because we could be requeuing the wrong message. */ if (action & ACTION_REQUEUE_ONE) { - if (inode_mismatch > 0 || inode_fixed > 0) { - msg_error("QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS"); - msg_fatal("CHECK YOUR QUEUE IDS AND RE-ISSUE THE COMMAND"); - } argv_terminate(requeue_names); + queues = (const char **) + (argv[optind] ? argv + optind : default_queues); for (cpp = requeue_names->argv; *cpp; cpp++) { if (strcmp(*cpp, "ALL") == 0) continue; @@ -933,6 +1175,46 @@ int main(int argc, char **argv) } } + /* + * Put on hold queue files by name. This must not be done when queue file + * names have changed names as a result of inode number mismatches, + * because we could put on hold the wrong message. + */ + if (action & ACTION_HOLD_ONE) { + argv_terminate(hold_names); + queues = (const char **) + (argv[optind] ? argv + optind : default_hold_queues); + for (cpp = hold_names->argv; *cpp; cpp++) { + if (strcmp(*cpp, "ALL") == 0) + continue; + if (strcmp(*cpp, "-") == 0) + message_held += + operate_stream(VSTREAM_IN, hold_one, queues); + else + message_held += hold_one(queues, *cpp); + } + } + + /* + * Take "off hold" queue files by name. This must not be done when queue + * file names have changed names as a result of inode number mismatches, + * because we could take off hold the wrong message. + */ + if (action & ACTION_RELEASE_ONE) { + argv_terminate(release_names); + queues = (const char **) + (argv[optind] ? argv + optind : default_release_queues); + for (cpp = release_names->argv; *cpp; cpp++) { + if (strcmp(*cpp, "ALL") == 0) + continue; + if (strcmp(*cpp, "-") == 0) + message_released += + operate_stream(VSTREAM_IN, release_one, queues); + else + message_released += release_one(queues, *cpp); + } + } + /* * Report. */ @@ -942,6 +1224,12 @@ int main(int argc, char **argv) if (message_deleted > 0) msg_info("Deleted: %d message%s", message_deleted, message_deleted > 1 ? "s" : ""); + if (message_held > 0) + msg_info("Placed on hold: %d message%s", + message_held, message_held > 1 ? "s" : ""); + if (message_released > 0) + msg_info("Released from hold: %d message%s", + message_released, message_released > 1 ? "s" : ""); if (inode_fixed > 0) msg_info("Renamed to match inode number: %d message%s", inode_fixed, inode_fixed > 1 ? "s" : ""); @@ -955,6 +1243,10 @@ int main(int argc, char **argv) argv_free(requeue_names); if (delete_names) argv_free(delete_names); + if (hold_names) + argv_free(hold_names); + if (release_names) + argv_free(release_names); exit(0); } diff --git a/postfix/src/sendmail/sendmail.c b/postfix/src/sendmail/sendmail.c index 899e45cba..679bd5ddb 100644 --- a/postfix/src/sendmail/sendmail.c +++ b/postfix/src/sendmail/sendmail.c @@ -30,7 +30,16 @@ /* size, arrival time, sender, and the recipients that still need to /* be delivered. If mail could not be delivered upon the last attempt, /* the reason for failure is shown. This mode of operation is implemented -/* by executing the \fBpostqueue\fR(1) command. +/* by executing the \fBpostqueue\fR(1) command. The queue ID string +/* is followed by an optional status character: +/* .RS +/* .IP \fB*\fR +/* The message is in the \fBactive\fR queue, i.e. the message is +/* selected for delivery. +/* .IP \fB!\fR +/* The message is in the \fBhold\fR queue, i.e. no further delivery +/* attempt will be made until the mail is taken off hold. +/* .RE /* .IP \fBnewaliases\fR /* Initialize the alias database. If no input file is specified (with /* the \fB-oA\fR option, see below), the program processes the file(s) @@ -244,6 +253,7 @@ /* The characters that Postfix accepts as VERP delimiter characters. /* SEE ALSO /* pickup(8) mail pickup daemon +/* postsuper(1) queue maintenance /* postalias(1) maintain alias database /* postdrop(1) mail posting utility /* postfix(1) mail system control diff --git a/postfix/src/showq/showq.c b/postfix/src/showq/showq.c index c8c70855b..8ccd4f31c 100644 --- a/postfix/src/showq/showq.c +++ b/postfix/src/showq/showq.c @@ -114,7 +114,8 @@ static void showq_report(VSTREAM *client, char *queue, char *id, long msg_size = 0; BOUNCE_LOG *logfile; HTABLE *dup_filter = 0; - char status = (strcmp(queue, MAIL_QUEUE_ACTIVE) == 0 ? '*' : ' '); + char status = (strcmp(queue, MAIL_QUEUE_ACTIVE) == 0 ? '*' : + strcmp(queue, MAIL_QUEUE_HOLD) == 0 ? '!' : ' '); long offset; /* @@ -246,6 +247,7 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv) MAIL_QUEUE_INCOMING, mail_scan_dir_next, MAIL_QUEUE_ACTIVE, mail_scan_dir_next, MAIL_QUEUE_DEFERRED, mail_scan_dir_next, + MAIL_QUEUE_HOLD, mail_scan_dir_next, 0, }; diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index 5cbf38da7..c402bc4ad 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -230,6 +230,7 @@ int smtp_helo(SMTP_STATE *state) "host %s refused to talk to me: %s", session->namaddr, translit(resp->str, "\n", " "))); + return (0); } /* diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index cf2adfb46..91e7b6dee 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -224,6 +224,9 @@ /* .fi /* .IP \fBaccess_map_reject_code\fR /* Server response when a client violates an access database restriction. +/* .IP \fBdefer_code\fR +/* Server response when a client request is rejected by the \fBdefer\fR +/* restriction. /* .IP \fBinvalid_hostname_reject_code\fR /* Server response when a client violates the \fBreject_invalid_hostname\fR /* restriction. @@ -358,6 +361,7 @@ int var_access_map_code; char *var_maps_rbl_domains; int var_helo_required; int var_reject_code; +int var_defer_code; int var_smtpd_err_sleep; int var_non_fqdn_code; char *var_always_bcc; @@ -1577,6 +1581,7 @@ int main(int argc, char **argv) VAR_MAPS_RBL_CODE, DEF_MAPS_RBL_CODE, &var_maps_rbl_code, 0, 0, VAR_ACCESS_MAP_CODE, DEF_ACCESS_MAP_CODE, &var_access_map_code, 0, 0, VAR_REJECT_CODE, DEF_REJECT_CODE, &var_reject_code, 0, 0, + VAR_DEFER_CODE, DEF_DEFER_CODE, &var_defer_code, 0, 0, VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code, 0, 0, VAR_SMTPD_JUNK_CMD, DEF_SMTPD_JUNK_CMD, &var_smtpd_junk_cmd_limit, 1, 0, VAR_SMTPD_HIST_THRSH, DEF_SMTPD_HIST_THRSH, &var_smtpd_hist_thrsh, 1, 0, @@ -1617,7 +1622,7 @@ int main(int argc, char **argv) VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps, 0, 0, VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0, VAR_SMTPD_SASL_OPTS, DEF_SMTPD_SASL_OPTS, &var_smtpd_sasl_opts, 0, 0, - VAR_SMTPD_SASL_REALM, DEF_SMTPD_SASL_REALM, &var_smtpd_sasl_realm, 1, 0, + VAR_SMTPD_SASL_REALM, DEF_SMTPD_SASL_REALM, &var_smtpd_sasl_realm, 0, 0, VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0, VAR_PERM_MX_NETWORKS, DEF_PERM_MX_NETWORKS, &var_perm_mx_networks, 0, 0, VAR_SMTPD_SND_AUTH_MAPS, DEF_SMTPD_SND_AUTH_MAPS, &var_smtpd_snd_auth_maps, 0, 0, diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index 27ed4fb76..abde395c8 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -53,8 +53,9 @@ /* Restrictions that can appear in some or all restriction /* lists: /* .IP reject +/* .IP defer /* .IP permit -/* Reject or permit the request unconditionally. This is to be used +/* Reject, defer or permit the request unconditionally. This is to be used /* at the end of a restriction list in order to make the default /* action explicit. /* .IP reject_unknown_client @@ -516,6 +517,7 @@ void smtpd_check_init(void) CHECK_RELAY_DOMAINS, REJECT_UNAUTH_DEST, REJECT_ALL, + DEFER_ALL, 0, }; @@ -2057,6 +2059,13 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, if (cpp[1] != 0 && state->warn_if_reject == 0) msg_warn("restriction `%s' after `%s' is ignored", cpp[1], PERMIT_ALL); + } else if (strcasecmp(name, DEFER_ALL) == 0) { + status = smtpd_check_reject(state, MAIL_ERROR_POLICY, + "%d <%s>: %s rejected: Try again later", + var_defer_code, reply_name, reply_class); + if (cpp[1] != 0 && state->warn_if_reject == 0) + msg_warn("restriction `%s' after `%s' is ignored", + cpp[1], DEFER_ALL); } else if (strcasecmp(name, REJECT_ALL) == 0) { status = smtpd_check_reject(state, MAIL_ERROR_POLICY, "%d <%s>: %s rejected: Access denied", @@ -2110,6 +2119,8 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, state->helo_name, SMTPD_NAME_HELO); } } else if (strcasecmp(name, PERMIT_NAKED_IP_ADDR) == 0) { + msg_warn("restriction %s is deprecated. Use %s instead", + PERMIT_NAKED_IP_ADDR, PERMIT_MYNETWORKS); if (state->helo_name) { if (state->helo_name[strspn(state->helo_name, "0123456789.")] == 0 && (status = reject_invalid_hostaddr(state, state->helo_name, diff --git a/postfix/src/smtpd/smtpd_sasl_glue.c b/postfix/src/smtpd/smtpd_sasl_glue.c index a112245e9..c05b7d672 100644 --- a/postfix/src/smtpd/smtpd_sasl_glue.c +++ b/postfix/src/smtpd/smtpd_sasl_glue.c @@ -255,6 +255,7 @@ void smtpd_sasl_connect(SMTPD_STATE *state) */ #define NO_SECURITY_LAYERS (0) #define NO_SESSION_CALLBACKS ((sasl_callback_t *) 0) +#define NO_AUTH_REALM ((char *) 0) #if SASL_VERSION_MAJOR >= 2 && defined(USE_SASL_IP_AUTH) @@ -273,7 +274,8 @@ void smtpd_sasl_connect(SMTPD_STATE *state) client_address = 0; #endif - if (SASL_SERVER_NEW("smtp", var_myhostname, var_smtpd_sasl_realm, + if (SASL_SERVER_NEW("smtp", var_myhostname, *var_smtpd_sasl_realm ? + var_smtpd_sasl_realm : NO_AUTH_REALM, server_address, client_address, NO_SESSION_CALLBACKS, NO_SECURITY_LAYERS, &state->sasl_conn) != SASL_OK) diff --git a/postfix/src/util/dict_ldap.c b/postfix/src/util/dict_ldap.c index 970738569..eab1c20f3 100644 --- a/postfix/src/util/dict_ldap.c +++ b/postfix/src/util/dict_ldap.c @@ -94,6 +94,13 @@ #ifdef HAS_LDAP + /* + * Older APIs have weird memory freeing behavior. + */ +#if !defined(LDAP_API_VERSION) || (LDAP_API_VERSION < 2000) +#error "Your LDAP version is too old" +#endif + #include #include #include diff --git a/postfix/src/util/sys_defs.h b/postfix/src/util/sys_defs.h index 37a4d8acf..fd837dd25 100644 --- a/postfix/src/util/sys_defs.h +++ b/postfix/src/util/sys_defs.h @@ -502,6 +502,34 @@ extern int initgroups(const char *, int); #define NATIVE_NEWALIAS_PATH "/usr/bin/newaliases" #define NATIVE_COMMAND_DIR "/usr/sbin" #define NATIVE_DAEMON_DIR "/usr/libexec/postfix" +#endif + +#ifdef LINUX1 +#define SUPPORTED +#include +#define USE_PATHS_H +#define HAS_FLOCK_LOCK +#define HAS_FCNTL_LOCK +#define INTERNAL_LOCK MYFLOCK_STYLE_FLOCK +#define DEF_MAILBOX_LOCK "flock, dotlock" /* unverified */ +#define HAS_FSYNC +#define HAS_DB +#define DEF_DB_TYPE "hash" +#define ALIAS_DB_MAP "hash:/etc/aliases" +#define HAS_NIS +#define GETTIMEOFDAY(t) gettimeofday(t,(struct timezone *) 0) +#define ROOT_PATH "/bin:/usr/bin:/sbin:/usr/sbin" +#define FIONREAD_IN_TERMIOS_H /* maybe unnecessary */ +#define USE_STATFS +#define STATFS_IN_SYS_VFS_H +#define UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT /* unverified */ +#define PREPEND_PLUS_TO_OPTSTRING +#define HAS_POSIX_REGEXP +#define NATIVE_SENDMAIL_PATH "/usr/sbin/sendmail" +#define NATIVE_MAILQ_PATH "/usr/bin/mailq" +#define NATIVE_NEWALIAS_PATH "/usr/bin/newaliases" +#define NATIVE_COMMAND_DIR "/usr/sbin" +#define NATIVE_DAEMON_DIR "/usr/libexec/postfix" #endif /* diff --git a/postfix/src/virtual/Makefile.in b/postfix/src/virtual/Makefile.in index 1bec47276..c2f9a2ae4 100644 --- a/postfix/src/virtual/Makefile.in +++ b/postfix/src/virtual/Makefile.in @@ -6,7 +6,7 @@ TESTSRC = WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ -Wunused -DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) -I.. +DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) PROG = virtual TESTPROG=