From 6654683f18b0c0f41196d75d64dadf7525ab9ce2 Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Sat, 6 Oct 2001 00:00:00 -0500 Subject: [PATCH] snapshot-20011006 --- postfix/DEBUG_README | 13 +- postfix/HISTORY | 77 ++++++++- postfix/LINUX_README | 13 +- postfix/RELEASE_NOTES | 17 +- postfix/conf/main.cf | 2 +- postfix/conf/sample-misc.cf | 2 +- postfix/conf/sample-smtpd.cf | 19 +-- postfix/html/faq.html | 9 +- postfix/html/flush.8.html | 9 +- postfix/html/smtpd.8.html | 5 + postfix/html/uce.html | 54 ++++-- postfix/makedefs | 2 + postfix/man/man8/flush.8 | 6 +- postfix/man/man8/smtpd.8 | 3 + postfix/src/bounce/bounce_notify_util.c | 10 +- postfix/src/cleanup/Makefile.in | 2 +- postfix/src/flush/flush.c | 14 +- postfix/src/global/defer.c | 8 +- postfix/src/global/flush_clnt.c | 10 +- postfix/src/global/flush_clnt.h | 1 + postfix/src/global/mail_addr_map.c | 15 +- postfix/src/global/mail_params.h | 6 +- postfix/src/global/mail_version.h | 2 +- postfix/src/global/split_addr.c | 5 +- postfix/src/nqmgr/Makefile.in | 1 + postfix/src/postsuper/postsuper.c | 2 + postfix/src/qmgr/Makefile.in | 1 + postfix/src/smtpd/smtpd.c | 13 +- postfix/src/smtpd/smtpd_check.c | 211 +++++++++--------------- postfix/src/smtpstone/qmqp-source.c | 1 + postfix/src/smtpstone/smtp-sink.c | 94 +++++++++-- postfix/src/smtpstone/smtp-source.c | 4 +- postfix/src/util/Makefile.in | 34 ++-- postfix/src/util/cache.in | 26 +++ postfix/src/util/mymalloc.c | 6 + postfix/src/util/vstream.c | 2 +- 36 files changed, 468 insertions(+), 231 deletions(-) create mode 100644 postfix/src/util/cache.in diff --git a/postfix/DEBUG_README b/postfix/DEBUG_README index cd2593eb6..43b2b889e 100644 --- a/postfix/DEBUG_README +++ b/postfix/DEBUG_README @@ -44,10 +44,15 @@ a lot of activity to be logged to the syslog daemon. Some systems allow you to inspect a running process with a system call tracer. For example: - # trace -p process-id - # strace -p process-id - # truss -p process-id - # ktrace -p process-id + # trace -p process-id (SunOS 4) + # strace -p process-id (Linux and many others) + # truss -p process-id (Solaris, FreeBSD) + # ktrace -p process-id (generic 4.4BSD) + +Even more informative are traces of system library calls. Examples: + + # ltrace -p process-id (Linux, also ported to FreeBSD and BSD/OS) + # sotruss -p process-id (Solaris) See your system documentation for details. diff --git a/postfix/HISTORY b/postfix/HISTORY index fdca8a3fa..a0d8abad1 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -1616,7 +1616,7 @@ Apologies for any names omitted. wrong place. Problem tackled with help of Chip Christian. Portability: reportedly, Solaris 2.5.1 can hang waiting - for a UNIX-domain connection to be accepted, to it gets + for a UNIX-domain connection to be accepted, so it gets the same workaround that was designed for LINUX. Problem reported by Scott Cotton. @@ -5412,3 +5412,78 @@ Apologies for any names omitted. address masquerading. The default setting is backwards compatible: envelope_sender header_sender header_recipient. Files: cleanup/whatever.c. + +20010822 + + Code cleanup: the bounce daemon complained about data that + it was not going to send back anyway. Fix: stop reading + the original message when the bounce message reaches the + bounce message size limit. File: bounce/bounce_notify_util.c. + +20010826 + + Logging: postsuper now logs the queue ID when it requeues + a message, or when it deletes a message from the mail queue. + File: postsuper/postsuper.c. + +20010830 + + Safety: the SMTP server now sends a 4xx (try again later) + response when an UCE restriction is misconfigured, instead + of ignoring the bad restriction and possibly accepting mail + that it should not accept. File: smtpd/smtpd_check.c. + +20010907 + + Workaround: the Postfix qmqp-source program produced mail + not ending in newline that qmail-qmqpd accepts but that + qmail-remote was unable to deliver. Matthias Andree, + uni-dortmund.de. File: smtpstone/qmqp-source.c. + +20010910 + + Bugfix: smtp-sink broke when RCPT TO commands crossed a + network packet boundary. Problem reported by Matthias + Andree, uni-dortmund.de. File: smtpstone/smtp-sink.c. + +20010917 + + Code cleanup: permit_mx_backup implements the old behavior + (accept mail if the local MTA is MX relay), and allows an + additional restriction via the permit_mx_backup_networks + parameter (accept mail only if the primary MX hosts match + the specified list of network blocks). This second restriction + is now entirely optional, for backwards compatiblity. + + Bugfix: an address extension could be appended multiple + times to the result of a canonical or virtual map lookup. + File: global/mail_addr_map.c. Fix by Victor Duchovni, + Morgan Stanley. + + Bugfix: split_addr() would split an address even when there + was no data before the recipient delimiter. In combination + with the above bug, this could cause an address to grow + exponentially in size. Problem reported by Victor Duchovni, + Morgan Stanley. File: global/split_addr.c. + +20010918 + + Bugfix: the mail_addr_map() fix was almost but not quite + right. It took two really clever people and several iterations + of email to really fix the mail_addr_map() problem. Thanks + to Victor Duchovni and Liviu Daia. + +20011006 + + Cleanup: Postfix no longer flushes the whole deferred queue + after an ETRN request for a random domain name; the SMTP + server instead replies with "459 service unavailable". + Files: smtpd/smtpd.c, global/flush_clnt.c, flush/flush.c. + +Open problems: + + Minor: The $process_id_directory setting is not used anywhere + in Postfix. Problem reported by Michael Smith, texas.net. + + Medium: address rewriting should be configurable for envelopes + and headers. diff --git a/postfix/LINUX_README b/postfix/LINUX_README index 35a22a7a4..410cd7f08 100644 --- a/postfix/LINUX_README +++ b/postfix/LINUX_README @@ -1,16 +1,19 @@ LINUX PORTABILITY ================= -On RedHat Linux 7.0, you must install the db3-devel RPM before you +On RedHat Linux 7.0 you must install the db3-devel RPM before you can compile the Postfix source code. +On RedHat Linux 7.1 procmail no longer has permission to write the +mail spool directory. Workaround: chmod 1777 /var/spool/mail. + LINUX SYSLOGD PERFORMANCE ========================= -LINUX syslogd uses synchronous writes by default, which is very -expensive. For services such as mail it is recommended that you -disable synchronous logfile writes by editing /etc/syslog.conf and -by prepending a - to the logfile name: +LINUX syslogd uses synchronous writes by default. Because of this, +syslogd can actually use more system resources than Postfix. To +avoid such madness, disable synchronous mail logfile writes by +editing /etc/syslog.conf and by prepending a - to the logfile name: mail.* -/var/log/mail.log diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index b3d204f9f..8f2adc18a 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -1,3 +1,17 @@ +Incompatible changes with snapshot-20011007 +=========================================== + +Postfix no longer flushes the whole queue after an ETRN request +for a random domain name. Requests for random domain names are now +rejected instead. + +The permit_mx_backup feature has changed. It accepts mail when the +local machine is listed in the DNS as MX relay host for the given +destination. The optional permit_mx_backup_networks parameter can +further require that the primary MX hosts for the given destinations +match specific network blocks. This optional restriction is off by +default. + Incompatible changes with snapshot-20010808 =========================================== @@ -9,7 +23,8 @@ The permit_mx_backup feature has changed. It now accepts mail only when the primary MX hosts for the recipient match the networks that are specified with the new auth_mx_backup_networks configuration parameter. Postfix refuses to accept mail when permit_mx_backup -is used while auth_mx_backup_networks is not configured. +is used while auth_mx_backup_networks is not configured. [This +change was undone with a later release]. The protocol between Postfix master and child processes has changed. You must stop and start Postfix in order to switch between Snapshot diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf index ccd3ddaf2..a517fc830 100644 --- a/postfix/conf/main.cf +++ b/postfix/conf/main.cf @@ -109,7 +109,7 @@ mail_owner = postfix # gateway, you should also include $mydomain. Do not specify the # names of domains that this machine is backup MX host for. Specify # those names via the relay_domains or permit_mx_backup settings for -# the SMTP server (see sample-smtpd.cf. +# the SMTP server (see sample-smtpd.cf). # # The local machine is always the final destination for mail addressed # to user@[the.net.work.address] of an interface that the mail system diff --git a/postfix/conf/sample-misc.cf b/postfix/conf/sample-misc.cf index 16ca0d37f..e1d23a60f 100644 --- a/postfix/conf/sample-misc.cf +++ b/postfix/conf/sample-misc.cf @@ -175,7 +175,7 @@ max_use = 100 # gateway, you should also include $mydomain. Do not specify the # names of domains that this machine is backup MX host for. Specify # those names via the relay_domains or permit_mx_backup settings for -# the SMTP server (see sample-smtpd.cf. +# the SMTP server (see sample-smtpd.cf). # # The local machine is always the final destination for mail addressed # to user@[the.net.work.address] of an interface that the mail system diff --git a/postfix/conf/sample-smtpd.cf b/postfix/conf/sample-smtpd.cf index fc513f145..081bcb8b0 100644 --- a/postfix/conf/sample-smtpd.cf +++ b/postfix/conf/sample-smtpd.cf @@ -282,8 +282,9 @@ smtpd_sender_restrictions = # - to destinations matching $relay_domains or subdomain thereof, # except for addresses with sender-specified routing. # reject_unauth_pipelining: reject mail from improperly pipelining spamware -# permit_mx_backup: accept mail for sites whose primary MX hosts -# match the networks specified with auth_mx_backup_networks. +# permit_mx_backup: accept mail for sites that list me as MX host. +# Use the optional permit_mx_backup_networks parameter to also +# require that the primary MX hosts match a list of network blocks. # reject_unknown_recipient_domain: reject domains without A or MX record. # check_recipient_access maptype:mapname # maptype:mapname: look up recipient address, parent domain, or localpart@. @@ -310,20 +311,6 @@ smtpd_sender_restrictions = # smtpd_recipient_restrictions = permit_mynetworks,check_relay_domains -# The auth_mx_backup_networks parameter specifies a list of networks -# for which the permit_mx_backup feature (see above) can be used. -# -# By default, auth_mx_backup_networks is empty and no networks are -# authorized to use the permit_mx_backup feature. You can specify -# a complete class A network (X.0.0.0/8), a complete class B network -# (X.X.0.0/16), and so on. If you want stricter control, specify a -# list of network/mask patterns, where the mask specifies the number -# of bits in the network part of a host address. You can also specify -# the absolute pathname of a pattern file instead of listing the -# patterns here. -# -auth_mx_backup_networks = - # # ADDITIONAL UCE CONTROLS # diff --git a/postfix/html/faq.html b/postfix/html/faq.html index 734337f5b..394cb330b 100644 --- a/postfix/html/faq.html +++ b/postfix/html/faq.html @@ -409,7 +409,7 @@ implements its own private mail database system. Not for beginners.

  • Courier-Imap -provides POP3, IMAP, POP3 and IMAP, and supports access over SSL. +provides POP3 and IMAP, and supports access over SSL. This software supports the maildir-style mailbox format only (one message per file, same format as qmail). @@ -1522,9 +1522,10 @@ reject when the destination is not local.
  • permit_mx_backup: permit if the local system is listed as MX host for the recipient -domain, provided that the primary MX host for the recipient domain -is within the networks specified with auth_mx_backup_networks. +domain. Use the optional permit_mx_backup_networks +parameter to also require that the primary MX hosts match a list +of network blocks.
  • Other UCE restrictions (e.g., SMTPD access maps) are not aware of sender-provided routing information. diff --git a/postfix/html/flush.8.html b/postfix/html/flush.8.html index 3304cca19..dbd2fb0f0 100644 --- a/postfix/html/flush.8.html +++ b/postfix/html/flush.8.html @@ -44,8 +44,8 @@ FLUSH(8) FLUSH(8) undeliverable it will be added back to the logfile. If the destination is not eligible for a fast flush - logfile, this request triggers delivery of all - queued mail. + logfile, this request is rejected (see below for + status codes). TRIGGER_REQ_WAKEUP This wakeup request from the master is an alterna- @@ -82,6 +82,11 @@ FLUSH(8) FLUSH(8) FLUSH_STAT_FAIL The request failed. + FLUSH_STAT_DENY + The request was denied because the destination + domain is not eligible for fast flush service, or + because the fast flush service is disabled. + SECURITY The fast flush server is not security-sensitive. It does not talk to the network, and it does not talk to local diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 80ad4a9ab..923af8b0c 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -250,6 +250,11 @@ SMTPD(8) SMTPD(8) List of DNS domains that publish the addresses of blacklisted hosts. + permit_mx_backup_networks + Only domains whose primary MX hosts match the + listed networks are eligible for the per- + mit_mx_backup feature. + relay_domains Restrict what domains or networks this mail system will relay mail from or to. diff --git a/postfix/html/uce.html b/postfix/html/uce.html index a7c5a609e..f2cb60483 100644 --- a/postfix/html/uce.html +++ b/postfix/html/uce.html @@ -146,6 +146,14 @@ clients this system accepts SMTP connections from.

    +By default, this restriction is applied when the client sends the +RCPT TO command. In order to have the restriction take effect +as soon as possible, specify smtpd_delay_reject = yes in +the Postfix main.cf configuration file. Doing so may cause +unexpected results with poorly implemented client software. + +

    +

    Default: @@ -280,6 +288,14 @@ The smtpd_helo_restrictions parameter restricts what hostnames clients may send with the HELO (EHLO) command. Some UCE software can be stopped by being strict here. +

    + +By default, this restriction is applied when the client sends the +RCPT TO command. In order to have the restriction take effect +as soon as possible, specify smtpd_delay_reject = yes in +the Postfix main.cf configuration file. Doing so may cause +unexpected results with poorly implemented client software. +

    Default: @@ -443,6 +459,14 @@ addresses this system accepts in MAIL FROM commands.

    +By default, this restriction is applied when the client sends the +RCPT TO command. In order to have the restriction take effect +as soon as possible, specify smtpd_delay_reject = yes in +the Postfix main.cf configuration file. Doing so may cause +unexpected results with poorly implemented client software. + +

    +

    Default: @@ -722,9 +746,7 @@ code for rejected requests (default: 554).
    permit_mx_backup
    Permit the request when the local -mail system is MX host for the resolved destination, provided that -the primary MX host is within the networks specified with auth_mx_backup_networks parameter. +mail system is MX host for the resolved destination. This includes the case that the local mail system is the final destination. However, the SMTP server will not forward mail with addresses that have sender-specified routing information (example: @@ -732,9 +754,15 @@ addresses that have sender-specified routing information (example:

    +Use the optional +permit_mx_backup_networks parameter to also require that the +primary MX hosts match a list of network blocks. + +

    + Relevant configuration parameters: auth_mx_backup_networks, $mydestination, permit_mx_backup_networks, + $mydestination, $inet_interfaces.

    @@ -969,13 +997,13 @@ to speed up deliveries.

    - + -
    auth_mx_backup_networks +
    permit_mx_backup_networks -
    This parameter specifies the networks that are allowed to -use the permit_mx_backup -relay control feature. +
    Restrict the use of the +permit_mx_backup relay control feature to destinations whose +primary MX hosts match a list of network blocks.

    @@ -983,11 +1011,11 @@ relay control feature.

    Default: -
    auth_mx_backup_networks = +
    permit_mx_backup_networks =

    -That is, no networks are authorized by default. +That is, all networks are authorized by default.

    @@ -1000,7 +1028,7 @@ blocks in CIDR (network/mask) notation, for example:

    -
    auth_mx_backup_networks = 168.100.0.0/16 +
    permit_mx_backup_networks = 168.100.0.0/16
    diff --git a/postfix/makedefs b/postfix/makedefs index fc05109a3..831e8ccd5 100644 --- a/postfix/makedefs +++ b/postfix/makedefs @@ -93,6 +93,8 @@ case "$SYSTEM.$RELEASE" in ;; OpenBSD.2*) SYSTYPE=OPENBSD2 ;; + OpenBSD.3*) SYSTYPE=OPENBSD3 + ;; NetBSD.1*) SYSTYPE=NETBSD1 ;; BSD/OS.2*) SYSTYPE=BSDI2 diff --git a/postfix/man/man8/flush.8 b/postfix/man/man8/flush.8 index 57eb598ce..f11f4854b 100644 --- a/postfix/man/man8/flush.8 +++ b/postfix/man/man8/flush.8 @@ -44,7 +44,7 @@ destination's logfile, and the logfile is truncated to zero length; if mail is undeliverable it will be added back to the logfile. .sp If the destination is not eligible for a fast flush logfile, -this request triggers delivery of all queued mail. +this request is rejected (see below for status codes). .IP \fBTRIGGER_REQ_WAKEUP\fR This wakeup request from the master is an alternative way to request \fBFLUSH_REQ_REFRESH\fR. @@ -72,6 +72,10 @@ The flush server rejected the request (bad request name, bad request parameter value). .IP \fBFLUSH_STAT_FAIL\fR The request failed. +.IP \fBFLUSH_STAT_DENY\fR +The request was denied because the destination domain is not +eligible for fast flush service, or because the fast flush +service is disabled. .SH SECURITY .na .nf diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index 736c299ec..b69bb2132 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -209,6 +209,9 @@ then be used instead of the restriction lists that they represent. .IP \fBmaps_rbl_domains\fR List of DNS domains that publish the addresses of blacklisted hosts. +.IP \fBpermit_mx_backup_networks\fR +Only domains whose primary MX hosts match the listed networks +are eligible for the \fBpermit_mx_backup\fR feature. .IP \fBrelay_domains\fR Restrict what domains or networks this mail system will relay mail from or to. diff --git a/postfix/src/bounce/bounce_notify_util.c b/postfix/src/bounce/bounce_notify_util.c index efa68ce49..599d516f8 100644 --- a/postfix/src/bounce/bounce_notify_util.c +++ b/postfix/src/bounce/bounce_notify_util.c @@ -339,7 +339,7 @@ int bounce_boilerplate(VSTREAM *bounce, BOUNCE_INFO *bounce_info) "####################################################################"); post_mail_fputs(bounce, ""); post_mail_fprintf(bounce, - "Your message could not be delivered for %.1f hours.", + "Your message could not be delivered for %.1f hours.", var_delay_warn_time / 3600.0); post_mail_fprintf(bounce, "It will be retried until it is %.1f days old.", @@ -478,7 +478,7 @@ int bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info) #endif if (bounce_info->flush == 0) post_mail_fprintf(bounce, "Will-Retry-Until: %s", - mail_date(bounce_info->arrival_time + var_max_queue_time)); + mail_date(bounce_info->arrival_time + var_max_queue_time)); return (vstream_ferror(bounce)); } @@ -547,12 +547,16 @@ int bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info, if (var_bounce_limit == 0 || bounce_length < var_bounce_limit) { bounce_length += VSTRING_LEN(bounce_info->buf) + 2; status = (REC_PUT_BUF(bounce, rec_type, bounce_info->buf) != rec_type); - } + } else + break; } /* * Final MIME headers. These require -- at the end of the boundary * string. + * + * XXX This should be a separate bounce_terminate() entry so we can be + * assured that the terminator will always be sent. */ post_mail_fputs(bounce, ""); post_mail_fprintf(bounce, "--%s--", bounce_info->mime_boundary); diff --git a/postfix/src/cleanup/Makefile.in b/postfix/src/cleanup/Makefile.in index 75d74b513..3ed1de67b 100644 --- a/postfix/src/cleanup/Makefile.in +++ b/postfix/src/cleanup/Makefile.in @@ -75,7 +75,6 @@ cleanup.o: ../../include/iostuff.h cleanup.o: ../../include/mail_params.h cleanup.o: ../../include/record.h cleanup.o: ../../include/rec_type.h -cleanup.o: ../../include/mail_flow.h cleanup.o: ../../include/mail_server.h cleanup.o: cleanup.h cleanup.o: ../../include/maps.h @@ -154,6 +153,7 @@ cleanup_init.o: cleanup_init.c cleanup_init.o: ../../include/sys_defs.h cleanup_init.o: ../../include/msg.h cleanup_init.o: ../../include/iostuff.h +cleanup_init.o: ../../include/name_mask.h cleanup_init.o: ../../include/mail_addr.h cleanup_init.o: ../../include/mail_params.h cleanup_init.o: ../../include/ext_prop.h diff --git a/postfix/src/flush/flush.c b/postfix/src/flush/flush.c index c8c76c0d0..5fd7316c3 100644 --- a/postfix/src/flush/flush.c +++ b/postfix/src/flush/flush.c @@ -38,7 +38,7 @@ /* if mail is undeliverable it will be added back to the logfile. /* .sp /* If the destination is not eligible for a fast flush logfile, -/* this request triggers delivery of all queued mail. +/* this request is rejected (see below for status codes). /* .IP \fBTRIGGER_REQ_WAKEUP\fR /* This wakeup request from the master is an alternative way to /* request \fBFLUSH_REQ_REFRESH\fR. @@ -66,6 +66,10 @@ /* request parameter value). /* .IP \fBFLUSH_STAT_FAIL\fR /* The request failed. +/* .IP \fBFLUSH_STAT_DENY\fR +/* The request was denied because the destination domain is not +/* eligible for fast flush service, or because the fast flush +/* service is disabled. /* SECURITY /* .ad /* .fi @@ -243,10 +247,10 @@ static int flush_add_service(const char *site, const char *queue_id) msg_info("%s: site %s queue_id %s", myname, site, queue_id); /* - * If this site is not eligible for logging, just ignore the request. + * If this site is not eligible for logging, deny the request. */ if (flush_policy_ok(site) == 0) - return (FLUSH_STAT_OK); + return (FLUSH_STAT_DENY); /* * Map site to path and update log. @@ -319,10 +323,10 @@ static int flush_send_service(const char *site) msg_info("%s: site %s", myname, site); /* - * If this site is not eligible for logging, deliver all queued mail. + * If this site is not eligible for logging, deny the request. */ if (flush_policy_ok(site) == 0) - return (mail_flush_deferred()); + return (FLUSH_STAT_DENY); /* * Map site name to path name and flush the log. diff --git a/postfix/src/global/defer.c b/postfix/src/global/defer.c index 59cde38fa..934b289cb 100644 --- a/postfix/src/global/defer.c +++ b/postfix/src/global/defer.c @@ -158,8 +158,14 @@ int vdefer_append(int flags, const char *id, const char *recipient, * bounce/defer daemon? Well, doing it here is more robust. */ if ((rcpt_domain = strrchr(recipient, '@')) != 0 && *++rcpt_domain != 0) - if (flush_add(rcpt_domain, id) != FLUSH_STAT_OK) + switch (flush_add(rcpt_domain, id)) { + case FLUSH_STAT_OK: + case FLUSH_STAT_DENY: + break; + default: msg_warn("unable to talk to fast flush service"); + break; + } return (-1); } diff --git a/postfix/src/global/flush_clnt.c b/postfix/src/global/flush_clnt.c index 6de4b426d..b8f92dd69 100644 --- a/postfix/src/global/flush_clnt.c +++ b/postfix/src/global/flush_clnt.c @@ -46,6 +46,8 @@ /* .IP MAIL_FLUSH_BAD /* The "fast flush" server rejected the request (invalid request /* parameter). +/* .IP MAIL_FLUSH_DENY +/* The specified domain is not eligible for "fast flush" service. /* SEE ALSO /* flush(8) Postfix fast flush cache manager /* LICENSE @@ -95,7 +97,7 @@ int flush_purge(void) * Don't bother the server if the service is turned off. */ if (*var_fflush_domains == 0) - status = FLUSH_STAT_OK; + status = FLUSH_STAT_DENY; else status = mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_FLUSH, "%s", FLUSH_REQ_PURGE); @@ -120,7 +122,7 @@ int flush_refresh(void) * Don't bother the server if the service is turned off. */ if (*var_fflush_domains == 0) - status = FLUSH_STAT_OK; + status = FLUSH_STAT_DENY; else status = mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_FLUSH, "%s", FLUSH_REQ_REFRESH); @@ -145,7 +147,7 @@ int flush_send(const char *site) * Don't bother the server if the service is turned off. */ if (*var_fflush_domains == 0) - status = mail_flush_deferred(); + status = FLUSH_STAT_DENY; else status = mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_FLUSH, "%s %s", FLUSH_REQ_SEND, site); @@ -170,7 +172,7 @@ int flush_add(const char *site, const char *queue_id) * Don't bother the server if the service is turned off. */ if (*var_fflush_domains == 0) - status = FLUSH_STAT_OK; + status = FLUSH_STAT_DENY; else status = mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_FLUSH, "%s %s %s", FLUSH_REQ_ADD, site, queue_id); diff --git a/postfix/src/global/flush_clnt.h b/postfix/src/global/flush_clnt.h index 47a88558a..ee82a984c 100644 --- a/postfix/src/global/flush_clnt.h +++ b/postfix/src/global/flush_clnt.h @@ -33,6 +33,7 @@ extern int flush_purge(void); #define FLUSH_STAT_FAIL -1 /* request failed */ #define FLUSH_STAT_OK 0 /* request executed */ #define FLUSH_STAT_BAD 3 /* invalid parameter */ +#define FLUSH_STAT_DENY 4 /* request denied */ /* LICENSE diff --git a/postfix/src/global/mail_addr_map.c b/postfix/src/global/mail_addr_map.c index 5146eb080..258ea8740 100644 --- a/postfix/src/global/mail_addr_map.c +++ b/postfix/src/global/mail_addr_map.c @@ -68,6 +68,7 @@ /* Application-specific. */ #define STR vstring_str +#define LEN VSTRING_LEN /* mail_addr_map - map a canonical address */ @@ -88,7 +89,8 @@ ARGV *mail_addr_map(MAPS *path, const char *address, int propagate) if ((string = mail_addr_find(path, address, &extension)) != 0) { /* - * Prepend the original user to @otherdomain. + * Prepend the original user to @otherdomain, but do not propagate + * the unmatched address extension. */ if (*string == '@') { buffer = vstring_alloc(100); @@ -96,6 +98,8 @@ ARGV *mail_addr_map(MAPS *path, const char *address, int propagate) vstring_strncpy(buffer, address, ratsign - address); else vstring_strcpy(buffer, address); + if (extension) + vstring_truncate(buffer, LEN(buffer) - strlen(extension)); vstring_strcat(buffer, string); string = STR(buffer); } @@ -163,6 +167,15 @@ int main(int argc, char **argv) msg_fatal("chdir %s: %m", var_queue_dir); path = maps_create(argv[0], argv[1], DICT_FLAG_LOCK); while (vstring_fgets_nonl(buffer, VSTREAM_IN)) { + msg_info("=== Address extension on, extension propagation on ==="); + var_rcpt_delim = "+"; + if ((result = mail_addr_map(path, STR(buffer), 1)) != 0) + argv_free(result); + msg_info("=== Address extension on, extension propagation off ==="); + if ((result = mail_addr_map(path, STR(buffer), 0)) != 0) + argv_free(result); + msg_info("=== Address extension off ==="); + var_rcpt_delim = ""; if ((result = mail_addr_map(path, STR(buffer), 1)) != 0) argv_free(result); } diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 655ebd260..36aef3c73 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -1122,9 +1122,9 @@ extern int var_relay_code; #define PERMIT_MX_BACKUP "permit_mx_backup" -#define VAR_AUTH_MX_NETWORKS "auth_mx_backup_networks" -#define DEF_AUTH_MX_NETWORKS "" -extern char *var_auth_mx_networks; +#define VAR_PERM_MX_NETWORKS "permit_mx_backup_networks" +#define DEF_PERM_MX_NETWORKS "" +extern char *var_perm_mx_networks; #define VAR_ACCESS_MAP_CODE "access_map_reject_code" #define DEF_ACCESS_MAP_CODE 554 diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index b088beb5a..6ecf22dbe 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -15,7 +15,7 @@ * Version of this program. */ #define VAR_MAIL_VERSION "mail_version" -#define DEF_MAIL_VERSION "Snapshot-20010808" +#define DEF_MAIL_VERSION "Snapshot-20011006" extern char *var_mail_version; /* LICENSE diff --git a/postfix/src/global/split_addr.c b/postfix/src/global/split_addr.c index 3b1fbb3b3..279ad4fb6 100644 --- a/postfix/src/global/split_addr.c +++ b/postfix/src/global/split_addr.c @@ -76,7 +76,8 @@ char *split_addr(char *localpart, int delimiter) } /* - * Safe to split this address. + * Safe to split this address. Do not split the address if the result + * would have a null localpart. */ - return (split_at(localpart, delimiter)); + return (delimiter == *localpart ? 0 : split_at(localpart, delimiter)); } diff --git a/postfix/src/nqmgr/Makefile.in b/postfix/src/nqmgr/Makefile.in index 1d6b8024f..ddf61ea73 100644 --- a/postfix/src/nqmgr/Makefile.in +++ b/postfix/src/nqmgr/Makefile.in @@ -75,6 +75,7 @@ qmgr.o: ../../include/mail_conf.h qmgr.o: ../../include/mail_params.h qmgr.o: ../../include/mail_proto.h qmgr.o: ../../include/iostuff.h +qmgr.o: ../../include/mail_flow.h qmgr.o: ../../include/master_proto.h qmgr.o: ../../include/mail_server.h qmgr.o: qmgr.h diff --git a/postfix/src/postsuper/postsuper.c b/postfix/src/postsuper/postsuper.c index af4336691..5177125ac 100644 --- a/postfix/src/postsuper/postsuper.c +++ b/postfix/src/postsuper/postsuper.c @@ -337,6 +337,7 @@ static int delete_one(const char **queue_names, const char *queue_id) postremove(mail_queue_path(log_path_buf, *log_qpp, queue_id)); if (postremove(msg_path) == 0) { found = 1; + msg_info("%s: removed", queue_id); break; } /* else: maybe lost a race */ } @@ -381,6 +382,7 @@ static int requeue_one(const char **queue_names, const char *queue_id) continue; (void) mail_queue_path(new_path_buf, MAIL_QUEUE_MAILDROP, queue_id); if (postrename(old_path, STR(new_path_buf)) == 0) { + msg_info("%s: requeued", queue_id); found = 1; break; } /* else: maybe lost a race */ diff --git a/postfix/src/qmgr/Makefile.in b/postfix/src/qmgr/Makefile.in index ae85a5f20..eaddb56f5 100644 --- a/postfix/src/qmgr/Makefile.in +++ b/postfix/src/qmgr/Makefile.in @@ -73,6 +73,7 @@ qmgr.o: ../../include/mail_conf.h qmgr.o: ../../include/mail_params.h qmgr.o: ../../include/mail_proto.h qmgr.o: ../../include/iostuff.h +qmgr.o: ../../include/mail_flow.h qmgr.o: ../../include/master_proto.h qmgr.o: ../../include/mail_server.h qmgr.o: qmgr.h diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index 4e0eaefb1..113a6c30c 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -195,6 +195,9 @@ /* .IP \fBmaps_rbl_domains\fR /* List of DNS domains that publish the addresses of blacklisted /* hosts. +/* .IP \fBpermit_mx_backup_networks\fR +/* Only domains whose primary MX hosts match the listed networks +/* are eligible for the \fBpermit_mx_backup\fR feature. /* .IP \fBrelay_domains\fR /* Restrict what domains or networks this mail system will relay /* mail from or to. @@ -356,7 +359,7 @@ char *var_smtpd_sasl_opts; char *var_smtpd_sasl_realm; char *var_filter_xport; bool var_broken_auth_clients; -char *var_auth_mx_networks; +char *var_perm_mx_networks; /* * Global state, for stand-alone mode queue file cleanup. When this is @@ -1227,6 +1230,12 @@ static int etrn_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) case FLUSH_STAT_OK: smtpd_chat_reply(state, "250 Queuing started"); return (0); + case FLUSH_STAT_DENY: + msg_warn("reject: ETRN %.100s... from %s", + argv[1].strval, state->namaddr); + smtpd_chat_reply(state, "459 <%s>: service unavailable", + argv[1].strval); + return (-1); case FLUSH_STAT_BAD: msg_warn("bad ETRN %.100s... from %s", argv[1].strval, state->namaddr); smtpd_chat_reply(state, "458 Unable to queue messages"); @@ -1591,7 +1600,7 @@ int main(int argc, char **argv) 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_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0, - VAR_AUTH_MX_NETWORKS, DEF_AUTH_MX_NETWORKS, &var_auth_mx_networks, 0, 0, + VAR_PERM_MX_NETWORKS, DEF_PERM_MX_NETWORKS, &var_perm_mx_networks, 0, 0, 0, }; diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index f29b7204c..15d0e10e6 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -337,7 +337,7 @@ static MAPS *relocated_maps; */ static DOMAIN_LIST *relay_domains; static NAMADR_LIST *mynetworks; -static NAMADR_LIST *auth_mx_networks; +static NAMADR_LIST *perm_mx_networks; /* * Pre-parsed restriction lists. @@ -506,7 +506,7 @@ void smtpd_check_init(void) */ mynetworks = namadr_list_init(var_mynetworks); relay_domains = domain_list_init(var_relay_domains); - auth_mx_networks = namadr_list_init(var_auth_mx_networks); + perm_mx_networks = namadr_list_init(var_perm_mx_networks); /* * Pre-parse and pre-open the recipient maps. @@ -1058,7 +1058,7 @@ static int all_auth_mx_addr(char *host) if (msg_verbose) msg_info("%s: checking: %s", myname, inet_ntoa(addr)); - if (!namadr_list_match(auth_mx_networks, host, inet_ntoa(addr))) { + if (!namadr_list_match(perm_mx_networks, host, inet_ntoa(addr))) { /* * Reject: at least one IP address is not listed in @@ -1066,7 +1066,7 @@ static int all_auth_mx_addr(char *host) */ if (msg_verbose) msg_info("%s: address %s does not match %s", - myname, inet_ntoa(addr), VAR_AUTH_MX_NETWORKS); + myname, inet_ntoa(addr), VAR_PERM_MX_NETWORKS); dns_rr_free(addr_list); return (NOPE); } @@ -1116,137 +1116,92 @@ static int has_my_addr(const char *host) return (NOPE); } -#if 0 - -/* permit_mx_backup - permit use of me as MX backup for recipient domain */ +/* i_am_mx - is this machine listed as MX relay */ -static int permit_mx_backup(SMTPD_STATE *state, const char *recipient) +static int i_am_mx(DNS_RR *mx_list) { - char *myname = "permit_mx_backup"; - const RESOLVE_REPLY *reply; - const char *domain; - - DNS_RR *mx_list; + const char *myname = "permit_mx_backup"; DNS_RR *mx; - int dns_status; - - if (msg_verbose) - msg_info("%s: %s", myname, recipient); /* - * Resolve the address. + * Compare hostnames first. Only if no name match is found, go through + * the trouble of host address lookups. */ - reply = (const RESOLVE_REPLY *) - ctable_locate(smtpd_resolve_cache, recipient); + for (mx = mx_list; mx != 0; mx = mx->next) { + if (msg_verbose) + msg_info("%s: resolve hostname: %s", myname, (char *) mx->data); + if (resolve_local((char *) mx->data)) + return (YUP); + } /* - * If the destination is local, it is acceptable, because we are - * supposedly MX for our own address. + * Argh. Do further DNS lookups and match interface addresses. */ - if ((domain = strrchr(CONST_STR(reply->recipient), '@')) == 0) - return (SMTPD_CHECK_OK); - domain += 1; - if (resolve_local(domain) - || (*var_virtual_maps - && check_maps_find(state, recipient, virtual_maps, domain, 0)) - || (*var_virt_mailbox_maps - && check_maps_find(state, recipient, virt_mailbox_maps, domain, 0))) - return (SMTPD_CHECK_OK); - - if (msg_verbose) - msg_info("%s: not local: %s", myname, recipient); + for (mx = mx_list; mx != 0; mx = mx->next) { + if (msg_verbose) + msg_info("%s: address lookup: %s", myname, (char *) mx->data); + if (has_my_addr((char *) mx->data)) + return (YUP); + } /* - * Skip source-routed mail (uncertain destination). + * This machine is not listed as MX relay. */ - if (var_allow_untrust_route == 0 && (reply->flags & RESOLVE_FLAG_ROUTED)) - return (SMTPD_CHECK_DUNNO); + if (msg_verbose) + msg_info("%s: I am not listed as MX relay", myname); + return (NOPE); +} - /* - * Skip numerical forms that didn't match the local system. - */ - if (domain[0] == '#' - || (domain[0] == '[' && domain[strlen(domain) - 1] == ']')) - return (SMTPD_CHECK_DUNNO); +/* permit_mx_primary - authorize primary MX relays */ + +static int permit_mx_primary(DNS_RR *mx_list) +{ + DNS_RR *mx; + int best_pref; + int status; /* - * Look up the list of MX host names for this domain. If no MX host is - * found, perhaps it is a CNAME for the local machine. Clients aren't - * supposed to send CNAMEs in SMTP commands, but it happens anyway. If we - * can't look up the destination, play safe and assume it is OK. + * Find the preference of the primary MX hosts. */ - dns_status = dns_lookup(domain, T_MX, 0, &mx_list, - (VSTRING *) 0, (VSTRING *) 0); - if (dns_status == DNS_NOTFOUND) - return (has_my_addr(domain) ? SMTPD_CHECK_OK : SMTPD_CHECK_DUNNO); - if (dns_status != DNS_OK) - return (SMTPD_CHECK_TRYAGAIN); + for (best_pref = 0xffff, mx = mx_list; mx != 0; mx = mx->next) + if (mx->pref < best_pref) + best_pref = mx->pref; /* - * First, see if we match any of the MX host names listed. Only if no - * name match is found, go through the trouble of host address lookups. + * See if each best MX host has all IP addresses in + * permit_mx_backup_networks. */ for (mx = mx_list; mx != 0; mx = mx->next) { - if (msg_verbose) - msg_info("%s: resolve hostname: %s", myname, (char *) mx->data); - if (resolve_local((char *) mx->data)) { - dns_rr_free(mx_list); - return (SMTPD_CHECK_OK); + if (mx->pref != best_pref) + continue; + switch (status = all_auth_mx_addr((char *) mx->data)) { + case TRYAGAIN: + case NOPE: + return (status); } } /* - * Argh. Do further DNS lookups and match interface addresses. + * All IP addresses of the best MX hosts are within + * auth_mx_backup_networks. */ - for (mx = mx_list; mx != 0; mx = mx->next) { - if (msg_verbose) - msg_info("%s: address lookup: %s", myname, (char *) mx->data); - if (has_my_addr((char *) mx->data)) { - dns_rr_free(mx_list); - return (SMTPD_CHECK_OK); - } - } - if (msg_verbose) - msg_info("%s: no match", myname); - - dns_rr_free(mx_list); - return (SMTPD_CHECK_DUNNO); + return (YUP); } -#endif - -/* permit_auth_mx_backup - relay for authorized networks */ +/* permit_mx_backup - permit use of me as MX backup for recipient domain */ -static int permit_auth_mx_backup(SMTPD_STATE *state, const char *recipient) +static int permit_mx_backup(SMTPD_STATE *state, const char *recipient) { - char *myname = "permit_auth_mx_backup"; + char *myname = "permit_mx_backup"; const RESOLVE_REPLY *reply; const char *domain; DNS_RR *mx_list; - DNS_RR *mx; int dns_status; - int best_pref; if (msg_verbose) msg_info("%s: %s", myname, recipient); - /* - * Sanity check. - */ - if (*var_auth_mx_networks == 0) { - msg_warn("The %s feature requires that you specify authorized networks", - PERMIT_MX_BACKUP); - msg_warn("via the %s configuration parameter. See examples", - VAR_AUTH_MX_NETWORKS); - msg_warn("in the %s/sample-smtpd.cf configuration file.", - var_config_dir); - longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE, - "%d <%s>: Configuration error in %s", - 451, recipient, - VAR_AUTH_MX_NETWORKS)); - } - /* * Resolve the address. */ @@ -1286,7 +1241,8 @@ static int permit_auth_mx_backup(SMTPD_STATE *state, const char *recipient) /* * Look up the list of MX host names for this domain. If no MX host is * found, perhaps it is a CNAME for the local machine. Clients aren't - * supposed to send CNAMEs in SMTP commands, but it happens anyway. + * supposed to send CNAMEs in SMTP commands, but it happens anyway. If we + * can't look up the destination, play safe and assume it is OK. */ dns_status = dns_lookup(domain, T_MX, 0, &mx_list, (VSTRING *) 0, (VSTRING *) 0); @@ -1296,34 +1252,24 @@ static int permit_auth_mx_backup(SMTPD_STATE *state, const char *recipient) return (SMTPD_CHECK_TRYAGAIN); /* - * Find the preference of the primary MX hosts. + * First, see if we match any of the MX host names listed. */ - for (best_pref = 0xffff, mx = mx_list; mx != 0; mx = mx->next) - if (mx->pref < best_pref) - best_pref = mx->pref; + if (!i_am_mx(mx_list)) { + dns_rr_free(mx_list); + return (SMTPD_CHECK_DUNNO); + } /* - * See if each best MX host has all IP addresses in - * auth_mx_backup_networks. + * Optionally, see if the primary MX hosts are in a restricted list of + * networks. */ - for (mx = mx_list; mx != 0; mx = mx->next) { - if (mx->pref != best_pref) - continue; - switch (all_auth_mx_addr((char *) mx->data)) { - case NOPE: - dns_rr_free(mx_list); - return (SMTPD_CHECK_DUNNO); - case YUP: - continue; - case TRYAGAIN: - dns_rr_free(mx_list); - return (SMTPD_CHECK_TRYAGAIN); - } + if (*var_perm_mx_networks && !permit_mx_primary(mx_list)) { + dns_rr_free(mx_list); + return (SMTPD_CHECK_DUNNO); } /* - * All IP addresses of the best MX hosts are within - * auth_mx_backup_networks. + * The destination passed all requirements. */ dns_rr_free(mx_list); return (SMTPD_CHECK_OK); @@ -1491,7 +1437,8 @@ static int check_table_result(SMTPD_STATE *state, const char *table, table, value); msg_warn("do not specify lookup tables inside SMTPD access maps"); msg_warn("define a restriction class and specify its name instead"); - longjmp(smtpd_check_buf, -1); + longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE, + "451 Server configuration error")); } /* @@ -1500,7 +1447,8 @@ static int check_table_result(SMTPD_STATE *state, const char *table, if (state->recursion++ > 100) { msg_warn("SMTPD access map %s entry %s causes unreasonable recursion", table, value); - longjmp(smtpd_check_buf, -1); + longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE, + "451 Server configuration error")); } /* @@ -1826,7 +1774,8 @@ static int reject_maps_rbl(SMTPD_STATE *state) /* is_map_command - restriction has form: check_xxx_access type:name */ -static int is_map_command(const char *name, const char *command, char ***argp) +static int is_map_command(SMTPD_STATE *state, const char *name, + const char *command, char ***argp) { /* @@ -1840,7 +1789,8 @@ static int is_map_command(const char *name, const char *command, char ***argp) return (0); } else if (*(*argp + 1) == 0 || strchr(*(*argp += 1), ':') == 0) { msg_warn("restriction %s requires maptype:mapname", command); - longjmp(smtpd_check_buf, -1); + longjmp(smtpd_check_buf, smtpd_check_reject(state, MAIL_ERROR_SOFTWARE, + "451 Server configuration error")); } else { return (1); } @@ -1903,7 +1853,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, status = reject_unknown_client(state); } else if (strcasecmp(name, PERMIT_MYNETWORKS) == 0) { status = permit_mynetworks(state); - } else if (is_map_command(name, CHECK_CLIENT_ACL, &cpp)) { + } else if (is_map_command(state, name, CHECK_CLIENT_ACL, &cpp)) { status = check_namadr_access(state, *cpp, state->name, state->addr, FULL, &found, state->namaddr, SMTPD_NAME_CLIENT, def_acl); @@ -1914,7 +1864,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, /* * HELO/EHLO parameter restrictions. */ - else if (is_map_command(name, CHECK_HELO_ACL, &cpp)) { + else if (is_map_command(state, name, CHECK_HELO_ACL, &cpp)) { if (state->helo_name) status = check_domain_access(state, *cpp, state->helo_name, FULL, &found, state->helo_name, @@ -1958,7 +1908,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, /* * Sender mail address restrictions. */ - else if (is_map_command(name, CHECK_SENDER_ACL, &cpp)) { + else if (is_map_command(state, name, CHECK_SENDER_ACL, &cpp)) { if (state->sender && *state->sender) status = check_mail_access(state, *cpp, state->sender, &found, state->sender, @@ -1980,14 +1930,14 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, /* * Recipient mail address restrictions. */ - else if (is_map_command(name, CHECK_RECIP_ACL, &cpp)) { + else if (is_map_command(state, name, CHECK_RECIP_ACL, &cpp)) { if (state->recipient) status = check_mail_access(state, *cpp, state->recipient, &found, state->recipient, SMTPD_NAME_RECIPIENT, def_acl); } else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) { if (state->recipient) - status = permit_auth_mx_backup(state, state->recipient); + status = permit_mx_backup(state, state->recipient); } else if (strcasecmp(name, PERMIT_AUTH_DEST) == 0) { if (state->recipient) status = permit_auth_destination(state, state->recipient); @@ -2020,7 +1970,7 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, /* * ETRN domain name restrictions. */ - else if (is_map_command(name, CHECK_ETRN_ACL, &cpp)) { + else if (is_map_command(state, name, CHECK_ETRN_ACL, &cpp)) { if (state->etrn_name) status = check_domain_access(state, *cpp, state->etrn_name, FULL, &found, state->etrn_name, @@ -2040,7 +1990,8 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions, */ else { msg_warn("unknown smtpd restriction: \"%s\"", name); - break; + longjmp(smtpd_check_buf, smtpd_check_reject(state, + MAIL_ERROR_SOFTWARE, "451 Server configuration error")); } if (msg_verbose) msg_info("%s: name=%s status=%d", myname, name, status); diff --git a/postfix/src/smtpstone/qmqp-source.c b/postfix/src/smtpstone/qmqp-source.c index a06ab7591..66fd33854 100644 --- a/postfix/src/smtpstone/qmqp-source.c +++ b/postfix/src/smtpstone/qmqp-source.c @@ -549,6 +549,7 @@ int main(int argc, char **argv) VSTRING_ADDCH(buffer, 'X'); VSTRING_ADDCH(buffer, '\n'); } + STR(buffer)[message_length - 1] = '\n'; netstring_memcpy(message_buffer, STR(buffer), message_length); n = strlen(sender); diff --git a/postfix/src/smtpstone/smtp-sink.c b/postfix/src/smtpstone/smtp-sink.c index 81aab916b..67c9d9f12 100644 --- a/postfix/src/smtpstone/smtp-sink.c +++ b/postfix/src/smtpstone/smtp-sink.c @@ -77,6 +77,7 @@ typedef struct SINK_STATE { VSTREAM *stream; + VSTRING *buffer; int data_state; int (*read) (struct SINK_STATE *); int rcpts; @@ -90,9 +91,8 @@ typedef struct SINK_STATE { #define ST_CR_LF_DOT_CR_LF 5 static int var_tmout; -static int var_max_line_length; +static int var_max_line_length = 2048; static char *var_myhostname; -static VSTRING *buffer; static int command_read(SINK_STATE *); static int data_read(SINK_STATE *); static void disconnect(SINK_STATE *); @@ -197,11 +197,10 @@ static int data_read(SINK_STATE *state) struct data_trans *dp; /* - * We must avoid blocking I/O, so get out of here as soon as both the - * VSTREAM and kernel read buffers dry up. + * A read may result in EOF, but is never supposed to time out - a time + * out means that we were trying to read when no data was available. */ - while (vstream_peek(state->stream) > 0 - || peekfd(vstream_fileno(state->stream)) > 0) { + for (;;) { if ((ch = VSTREAM_GETC(state->stream)) == VSTREAM_EOF) return (-1); for (dp = data_trans; dp->state != state->data_state; dp++) @@ -224,8 +223,17 @@ static int data_read(SINK_STATE *state) msg_info("."); dot_response(state); state->read = command_read; + state->data_state = ST_ANY; break; } + + /* + * We must avoid blocking I/O, so get out of here as soon as both the + * VSTREAM and kernel read buffers dry up. + */ + if (vstream_peek(state->stream) <= 0 + && peekfd(vstream_fileno(state->stream)) <= 0) + return (0); } return (0); } @@ -258,9 +266,74 @@ static int command_read(SINK_STATE *state) { char *command; SINK_COMMAND *cmdp; + int ch; + struct cmd_trans { + int state; + int want; + int next_state; + }; + static struct cmd_trans cmd_trans[] = { + ST_ANY, '\r', ST_CR, + ST_CR, '\n', ST_CR_LF, + }; + struct cmd_trans *cp; + + /* + * A read may result in EOF, but is never supposed to time out - a time + * out means that we were trying to read when no data was available. + */ + for (;;) { + if ((ch = VSTREAM_GETC(state->stream)) == VSTREAM_EOF) + return (-1); + + /* + * Sanity check. We don't want to store infinitely long commands. + */ + if (VSTRING_LEN(state->buffer) >= var_max_line_length) { + msg_warn("command line too long"); + return (-1); + } + VSTRING_ADDCH(state->buffer, ch); + + /* + * Try to match the current character desired by the state machine. + * If that fails, try to restart the machine with a match for its + * first state. + */ + for (cp = cmd_trans; cp->state != state->data_state; cp++) + /* void */ ; + if (ch == cp->want) + state->data_state = cp->next_state; + else if (ch == cmd_trans[0].want) + state->data_state = cmd_trans[0].next_state; + else + state->data_state = ST_ANY; + if (state->data_state == ST_CR_LF) + break; + + /* + * We must avoid blocking I/O, so get out of here as soon as both the + * VSTREAM and kernel read buffers dry up. + */ + if (vstream_peek(state->stream) <= 0 + && peekfd(vstream_fileno(state->stream)) <= 0) + return (0); + } - smtp_get(buffer, state->stream, var_max_line_length); - if ((command = strtok(vstring_str(buffer), " \t")) == 0) { + /* + * Properly terminate the result, and reset the buffer write pointer for + * reading the next command. This is ugly, but not as ugly as trying to + * deal with all the early returns below. + */ + vstring_truncate(state->buffer, VSTRING_LEN(state->buffer) - 2); + VSTRING_TERMINATE(state->buffer); + state->data_state = ST_ANY; + VSTRING_RESET(state->buffer); + + /* + * Got a complete command line. Parse it. + */ + if ((command = strtok(vstring_str(state->buffer), " \t")) == 0) { smtp_printf(state->stream, "500 Error: unknown command"); return (0); } @@ -321,6 +394,7 @@ static void disconnect(SINK_STATE *state) { event_disable_readwrite(vstream_fileno(state->stream)); vstream_fclose(state->stream); + vstring_free(state->buffer); myfree((char *) state); } @@ -350,8 +424,9 @@ static void connect_event(int unused_event, char *context) non_blocking(fd, NON_BLOCKING); state = (SINK_STATE *) mymalloc(sizeof(*state)); state->stream = vstream_fdopen(fd, O_RDWR); + state->buffer = vstring_alloc(1024); state->read = command_read; - state->data_state = 0; + state->data_state = ST_ANY; smtp_timeout_setup(state->stream, var_tmout); smtp_printf(state->stream, "220 %s ESMTP", var_myhostname); event_enable_read(fd, read_event, (char *) state); @@ -409,7 +484,6 @@ int main(int argc, char **argv) /* * Initialize. */ - buffer = vstring_alloc(1024); var_myhostname = "smtp-sink"; if (strncmp(argv[optind], "unix:", 5) == 0) { sock = unix_listen(argv[optind] + 5, backlog, BLOCKING); diff --git a/postfix/src/smtpstone/smtp-source.c b/postfix/src/smtpstone/smtp-source.c index 9e69fa122..be0dff0fa 100644 --- a/postfix/src/smtpstone/smtp-source.c +++ b/postfix/src/smtpstone/smtp-source.c @@ -52,6 +52,8 @@ /* .IP "-w interval" /* Wait a fixed time between messages. /* Suspending one thread does not affect other delivery threads. +/* BUGS +/* No SMTP command pipelining support. /* LICENSE /* .ad /* .fi @@ -739,7 +741,7 @@ static void quit_done(int unused_event, char *context) static void usage(char *myname) { - msg_fatal("usage: %s -s sess -l msglen -m msgs -c -C count -d -f from -o -t to -R delay -v -w delay host[:port]", myname); + msg_fatal("usage: %s -s sess -l msglen -m msgs -c -C count -d -f from -o -t to -r rcptcount -R delay -v -w delay host[:port]", myname); } /* main - parse JCL and start the machine */ diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 04fa8037a..dd2c91542 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -200,87 +200,87 @@ fifo_rdonly_bug: fifo_rdonly_bug.c $(LIB) select_bug: select_bug.c $(LIB) $(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS) -translit: $(LIB) +translit: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -fsspace: $(LIB) +fsspace: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -exec_command: $(LIB) +exec_command: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -make_dirs: $(LIB) +make_dirs: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -mac_parse: $(LIB) +mac_parse: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -vstream_popen: $(LIB) +vstream_popen: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -fifo_trigger: $(LIB) +fifo_trigger: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -doze: $(LIB) +doze: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -mac_expand: $(LIB) +mac_expand: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -watchdog: $(LIB) +watchdog: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -unescape: $(LIB) +unescape: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -hex_quote: $(LIB) +hex_quote: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -name_mask: $(LIB) +name_mask: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -rand_sleep: $(LIB) +rand_sleep: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -sane_time: $(LIB) +sane_time: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -ctable: $(LIB) +ctable: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o -inet_addr_list: $(LIB) +inet_addr_list: $(LIB) $@.o mv $@.o junk $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o diff --git a/postfix/src/util/cache.in b/postfix/src/util/cache.in new file mode 100644 index 000000000..89974bd2c --- /dev/null +++ b/postfix/src/util/cache.in @@ -0,0 +1,26 @@ +a +1 +b +2 +c +3 +d +4 +e +5 +f +6 +f +e +d +c +b +a +1 +b +c +d +e +f +6 +f diff --git a/postfix/src/util/mymalloc.c b/postfix/src/util/mymalloc.c index 04c1fb49a..36c7d684e 100644 --- a/postfix/src/util/mymalloc.c +++ b/postfix/src/util/mymalloc.c @@ -165,6 +165,8 @@ void myfree(char *ptr) char *mystrdup(const char *str) { + if (str == 0) + msg_panic("mystrdup: null pointer argument"); return (strcpy(mymalloc(strlen(str) + 1), str)); } @@ -175,6 +177,8 @@ char *mystrndup(const char *str, int len) char *result; char *cp; + if (str == 0) + msg_panic("mystrndup: null pointer argument"); if ((cp = memchr(str, 0, len)) != 0) len = cp - str; result = memcpy(mymalloc(len + 1), str, len); @@ -186,5 +190,7 @@ char *mystrndup(const char *str, int len) char *mymemdup(const char *ptr, int len) { + if (ptr == 0) + msg_panic("mymemdup: null pointer argument"); return (memcpy(mymalloc(len), ptr, len)); } diff --git a/postfix/src/util/vstream.c b/postfix/src/util/vstream.c index c5bdbfdde..655bc0a3d 100644 --- a/postfix/src/util/vstream.c +++ b/postfix/src/util/vstream.c @@ -97,7 +97,7 @@ /* int vstream_setjmp(stream) /* VSTREAM *stream; /* -/* void longjmp(stream, val) +/* void vstream_longjmp(stream, val) /* VSTREAM *stream; /* int val; /* -- 2.47.3