Suspended email accounts accept / bounce mail

mtindor

Well-Known Member
Sep 14, 2004
1,452
110
193
inside a catfish
cPanel Access Level
Root Administrator
Hello,

I just realized today that for email accounts which are suspended, cPanel accepts the email to that email account and then bounces back a notice that the account is suspended. That is bad behavior. Email that cannot be delivered due to account suspension should be rejected during SMTP rather than accepted/bounced.

If I send an email to nonexistent user [email protected], the server appropriately rejects the email during SMTP.
Code:
2016-03-31 10:02:08 [704534] H=mail-vk0-f43.google.com [209.85.213.43]:36454 I=[1.2.3.4]:25 X=TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128 CV=no SNI="somedomain.com" F=<[email protected]> rejected RCPT <[email protected]>: No such person at this address
If I send an email to an existing email account that is suspended, such as [email protected], the mail is accepted and then bounced.

Code:
2016-03-31 10:00:45 [703882] 1ald9R-002x6w-SO H=mail-vk0-f43.google.com [209.85.213.43]:34831 I=[1.2.3.4]:25 Warning: Message has been scanned: no virus or other harmful content was found
2016-03-31 10:01:00 [703882] 1ald9R-002x6w-SO H=mail-vk0-f43.google.com [209.85.213.43]:34831 I=[1.2.3.4]:25 Warning: "SpamAssassin as beefy detected message as NOT spam (-1.2)"
2016-03-31 10:01:00 [703882] 1ald9R-002x6w-SO <= [email protected] H=mail-vk0-f43.google.com [209.85.213.43]:34831 I=[1.2.3.4]:25 P=esmtps X=TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128 CV=no SNI="somedomain.com" S=4151 M8S=0 [email protected]l.com T="no way jose" from <[email protected]> for [email protected]
2016-03-31 10:01:00 [703942] cwd=/var/spool/exim 3 args: /usr/sbin/exim -Mc 1ald9R-002x6w-SO
2016-03-31 10:01:00 [703942] 1ald9R-002x6w-SO ** [email protected] F=<[email protected]> R=virtual_user_filter: This email account's owner has suspended delivery for the account.
2016-03-31 10:01:00 [703947] cwd=/var/spool/exim 7 args: /usr/sbin/exim -t -oem -oi -f <> -E1ald9R-002x6w-SO
2016-03-31 10:01:00 [703947] 1ald9g-002x7z-5O <= <> R=1ald9R-002x6w-SO U=mailnull P=local S=5408 M8S=0 T="Mail delivery failed: returning message to sender" from <> for [email protected]
2016-03-31 10:01:00 [703942] 1ald9R-002x6w-SO Completed QT=15s
This is confirmed by the fact that if I send an email to [email protected] (a bonafide email account that is suspended), I will get an email back from [email protected], and if I send an email (from my Gmail account) to [email protected] (a nonexistent email account), I will get an email back from [email protected].

Mike
 
Last edited by a moderator:
  • Like
Reactions: sneader

sneader

Well-Known Member
Aug 21, 2003
1,195
66
178
La Crosse, WI
cPanel Access Level
Root Administrator
I would definitely prefer that emails were rejected at SMTP time. This is just another "queue filler"

- Scott
 

cPanelMichael

Administrator
Staff member
Apr 11, 2011
47,884
2,250
463
Hello :)

Here's what the filter rule looks like in "/home/$username/etc/$domain/$email-user/filter"after suspending incoming email for a specific email account:

Code:
# Exim filter - auto-generated by cPanel.
#
# Do not manually edit this file; instead, use cPanel APIs to manipulate
# email filters. MANUAL CHANGES TO THIS FILE WILL BE OVERWRITTEN.
#
# SUSPEND RECEPTION OF NEW MESSAGES
fail "This email account's owner has suspended delivery for the account."

if not first_delivery and error_message then finish endif
The design decision to not reject these messages at SMTP time was based on resource efficiency. The filter files are already checked during message delivery, so it does not require additional disk I/O to implement the feature this way. Feel free to open a feature request if you would like an option to block messages at SMTP time:

Submit A Feature Request

To note, cPanel version 56 introduces the ability to disable outgoing email:

As a host, I want to be able to disable outbound email for an account when it has been compromised

Thank you.
 

sparek-3

Well-Known Member
Aug 10, 2002
2,114
254
388
cPanel Access Level
Root Administrator
I've been saying this for years, nobody seems to want to listen.

You can't fail messages after the SMTP server has already accepted the message.

This means you can't create filters - Account Level or User Level - that fail messages. It will just create a ton of bounceback messages.

If you want to fail message, you do that at SMTP time. When you do an SMTP transaction and that last period on a line by itself ("354 Enter message, ending with "." on a line by itself"). If the SMTP server sends a 250 response, then the message has been accepted. The SMTP server does not need to fail the message after that point or you're going to get bounceback backscatter.

If you really want to fail messages based on filters, then you need to read all of the filters during the SMTP transaction and generate a a 500 level response at that last period on a line by itself. I agree that would be highly CPU intensive, so I would just avoid it completely. I would suggest that you accept the messages and then silently blackhole (save /dev/null) the messages that hit filters after the SMTP transaction has been accepted.
 

sparek-3

Well-Known Member
Aug 10, 2002
2,114
254
388
cPanel Access Level
Root Administrator
Fail never should be used in any filter file (/etc/vfilters/example.tld or /home/user/etc/example.tld/email/filter). Why this concept is so hard to grasp is something I don't understand. Fortunately, because this uses a field that is mostly static (the recipient's email address) this can be made to work properly with a small adjustment to the Exim configuration and a couple of hooks.

Start by creating the necessary files and directories, needed for this.

Code:
touch /etc/suspended_incoming
chown root:mail /etc/suspended_incoming
chmod 640 /etc/suspended_incoming
mkdir /var/cpanel/hooks
Now, save the attached fixincomingsuspend.php.txt file as - /var/cpanel/hooks/fixincomingsuspend.php

Change the perissions on this file accordingly:

Code:
chmod 700 /var/cpanel/hooks/fixincomingsuspend.php
Add this to the hook registry:

Code:
/usr/local/cpanel/bin/manage_hooks add script /var/cpanel/hooks/fixincomingsuspend.php
Then finally edit the file:

/usr/local/cpanel/etc/exim/acls/ACL_RECIPIENT_BLOCK/custom_end_recipient

(this file may be empty for you, that's fine) so that it includes:

Code:
  deny condition = ${if eq{${lookup{${lc:[email protected]$domain}}lsearch{/etc/suspended_incoming}{1}{0}}}{1}}
  message = Mail to ${lc:[email protected]$domain} has been suspended
  log_message = Mail to ${lc:[email protected]$domain} has been suspended
Save the file.

Rebuild the Exim configuration:

Code:
/scripts/buildeximconf
and restart Exim

Code:
/scripts/restartsrv_exim


Now when you suspend incoming mail for an account that email address will be added to the file /etc/suspended_incoming

When someone tries to send an email to that email address, the exim configuration will check /etc/suspended_incoming for the email address at the RCPT TO stage. If it is found to be in the /etc/suspended_incoming file, the SMTP transaction is denied and does not continue.

The hook script (/var/cpanel/hooks/fixincomingsuspend.php) adds and removes these email addresses to the /etc/suspended_incoming file as end-users Suspend and Unsuspend incoming mail for an email account.


This is not necessarily all well written, it's basically meant to be used as a proof of concept for how this should be done properly.

This still doesn't fix the fact that fail should never be used in filter files (/etc/vfilters/example.tld or /home/user/etc/example.tld/email/filter). This will alleviate the problem of having incoming email suspension code in /home/user/etc/example.tld/email/filter because the Exim configuration code will stop those messages before they are ever accepted and the /home/user/etc/example.tld/email/filter code has a chance to run.

This will not apply to email accounts that already have incoming mail suspended. You would need to manually add those email accounts to /etc/suspended_incoming.
 

Attachments

  • Like
Reactions: Infopro

cPBrett

cPanel Developer
Staff member
Jul 2, 2014
10
1
78
cPanel Access Level
Root Administrator
Thanks for the information, sparek-3. We're working on an improvement here, and I wanted to share with you the current line of thinking. Any feedback would be appreciated. In etc/exim/acls/ACL_RECIPIENT_BLOCK/default_recipient we're currently testing:
Code:
  deny
  condition = ${if exists {${extract{5}{::}{${lookup passwd{${lookup{$domain}lsearch{/etc/userdomains}{$value}}}{$value}}}}/etc/\.$local_part\@$domain\.suspended_incoming}}
  message = Mail to ${lc:[email protected]$domain} has been suspended
  log_message = Mail to ${lc:[email protected]$domain} has been suspended
This is leveraging the pre-existence of a $HOME/etc/[email protected]$domain.suspended_incoming "dot" file (in addition to the generated filter) for each email address that has incoming mail suspended.

We want to hear what y'all think.

Cheers,
Brett
 
  • Like
Reactions: mtindor

sparek-3

Well-Known Member
Aug 10, 2002
2,114
254
388
cPanel Access Level
Root Administrator
Bravo if you created that condition line! Exim conditionals are always difficult for me to read, much less create. I always misplace a { or don't have a } in the right place.

That said, I didn't check this to see if it actually works. But the gist of it looking in $HOME/etc/[email protected]$domain.suspended_incoming is probably a good idea. This way you can avoid having to run escalated privileges, which is what I had to do in my hook script.

So basically you would just have to change the hook to create the $HOME/etc/[email protected]$domain.suspended_incoming file or add that into the core when a cpanel user suspends an email account.

I like it!
 
  • Like
Reactions: cPBrett

sparek-3

Well-Known Member
Aug 10, 2002
2,114
254
388
cPanel Access Level
Root Administrator
Actually I suppose $HOME/etc/[email protected]$domain.suspended_incoming is already created. I really hadn't paid that much attention. So yea, just adding the code into the exim configuration will accomplish all that needs to be done.

I definitely like this better than failing a message after it has been accepted.

Is $local_part and $domain automatically translated to lowercase in the condition? That might be my only question.
 
  • Like
Reactions: mtindor

cPanelKenneth

cPanel Development
Staff member
Apr 7, 2006
4,607
79
458
cPanel Access Level
Root Administrator
Actually I suppose $HOME/etc/[email protected]$domain.suspended_incoming is already created. I really hadn't paid that much attention. So yea, just adding the code into the exim configuration will accomplish all that needs to be done.

I definitely like this better than failing a message after it has been accepted.

Is $local_part and $domain automatically translated to lowercase in the condition? That might be my only question.
The .suspended_incoming dot file is already created when incoming email is suspended for an account. We're just changing Exim's behavior to reject at RCPT time based upon presence of that file.

I do believe both $local_part and $domain are normalized to lowercase, since we use those same variables all over the place in Exim's ACLs.

Also, I want to thank you, sparek-3, for your initial research on this which put us quickly on the right path.
 
  • Like
Reactions: mtindor and Infopro

DomineauX

Well-Known Member
PartnerNOC
Apr 12, 2003
429
11
168
Houston, TX
cPanel Access Level
Root Administrator
This seems to be broken in v86 as no suspended accounts have suspended_incoming flags and bounces are being sent such as:

Code:
2020-04-02 14:11:19 1jJzci-0003mk-Tp ** [email protected] ([email protected]) <[email protected]> R=enforce_mail_permissions: Domain suspendeddomain.tld has an outgoing mail suspension.  Message discarded.
2020-04-02 14:11:19 1jJzci-0003mk-Tp => user <[email protected]> R=virtual_user T=dovecot_virtual_delivery C="250 2.0.0 <[email protected]> gOG3GHfkhV47BwAAODq7jA Saved"
2020-04-02 14:11:19 cwd=/var/spool/exim 7 args: /usr/sbin/exim -t -oem -oi -f <> -E1jJzci-0003mk-Tp
2020-04-02 14:11:26 1jJzct-0003uZ-E5 U=mailnull Warning: "SpamAssassin as cpaneleximscanner detected OUTGOING not smtp message as NOT spam (0.9)"
2020-04-02 14:11:26 1jJzct-0003uZ-E5 <= <> R=1jJzci-0003mk-Tp U=mailnull P=local S=20532 T="Mail delivery failed: returning message to sender" for [email protected]
2020-04-02 14:11:26 1jJzci-0003mk-Tp Completed
2020-04-02 14:11:26 cwd=/var/spool/exim 3 args: /usr/sbin/exim -Mc 1jJzct-0003uZ-E5
2020-04-02 14:11:26 1jJzct-0003uZ-E5 Sender identification U=mailnull D=-system- S=mailnull
2020-04-02 14:11:26 1jJzct-0003uZ-E5 => [email protected] R=dkim_lookuphost T=dkim_remote_smtp H=mail.spoofeddomain.tld [111.111.111.111] C="250 2.6.0 message received"
2020-04-02 14:11:26 1jJzct-0003uZ-E5 Completed