2

We encounter security problems with our mail server and would like some advice.

The story behind it

On our mail server (Postfix 2.9.6 + Dovecot 2.1.7) we would like to be able to create restricted email accounts. Those accounts (used by the trainees) would be able to send/receive emails to/from the local domains only (for security reasons we don't want them to be able to send or receive emails to other mail servers). To make it simple, we created a specific sub-domain for the restricted email accounts.

On our infrastructure, all email accounts are LDAP based, the config files are included hereunder.

What we did

In postfix, it is possible to create restriction rules in file /etc/postfix/main.cf and so we added rules:

check_sender_access ldap:/etc/postfix/ldap_restricted_senders.cf
check_recipient_access ldap:/etc/postfix/ldap_restricted_recipients.cf

to section:

smtpd_recipient_restrictions

For sure, following lines were also added :

smtpd_restriction_classes =
  local_only,
  insiders_only

local_only = check_recipient_access ldap:/etc/postfix/ldap_virtual_domains_restrict.cf, reject
insiders_only = check_sender_access ldap:/etc/postfix/ldap_virtual_domains_restrict.cf, reject

Content of /etc/postfix/ldap_restricted_senders.cf is:

bind = yes
bind_dn = uid=postfix,ou=service,dc=example,dc=com
bind_pw = *******
server_host = ldap://127.0.0.1:389
search_base = ou=domain,dc=example,dc=com
query_filter = (&(ObjectClass=DNSDomain)(dc=%s))
result_attribute = description

This returns "ok" when the domain is allowed to send emails outside.


Content of /etc/postfix/ldap_restricted_recipients.cf is:

bind = yes
bind_dn = uid=postfix,ou=service,dc=example,dc=com
bind_pw = ******
server_host = ldap://127.0.0.1:389
search_base = ou=domain,dc=example,dc=com
query_filter = (&(description=local_only)(dc=%s))
result_attribute = description
result_filter = insiders_only

This returns "insiders_only" when the domain can be reached by only local domains.


Content of /etc/postfix/ldap_virtual_domains_restrict.cf is:

bind = yes
bind_dn = uid=postfix,ou=service,dc=example,dc=com
bind_pw = ******
server_host = ldap://127.0.0.1:389
search_base = ou=domain,dc=example,dc=com
query_filter = (&(ObjectClass=dNSDomain)(dc=%s))
result_attribute = dc
result_filter = OK

This returns "ok" when the domain is local (can send emails to the restricted sub-domain).


For more precision, the postfix smtpd_recipient_restrictions section contains:

smtpd_recipient_restrictions =
  permit_mynetworks,
  reject_sender_login_mismatch
  check_sender_access ldap:/etc/postfix/ldap_restricted_senders.cf
  check_recipient_access ldap:/etc/postfix/ldap_restricted_recipients.cf
  permit_sasl_authenticated,
  reject_non_fqdn_hostname,
  reject_non_fqdn_sender,
  reject_non_fqdn_recipient,
  reject_unauth_destination,
  reject_unauth_pipelining,
  reject_invalid_hostname,
  check_policy_service unix:private/policy-spf

This works fine in the sens that all emails from the subdomain can send emails only to other local domains and can only receive emails from local domains.

BUT...

Since we enable this we noticed that people could use the mail server to send SPAM (so we temporary removed it).

We noticed the problem because the log file /var/log/mail.log contained lines like:

Jul 22 11:59:24 mail postfix/qmgr[366]: F342F42AE4: from=<[email protected]>, size=2171, nrcpt=11 (queue active)
Jul 22 11:59:24 mail postfix/smtp[382]: 1344D42ACC: to=<iraci@*******>, relay=127.0.0.1[127.0.0.1]:10024, delay=1197348, delays=1197334/12/0.17/2.2, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as F342F42AE4)
Jul 22 11:59:24 mail postfix/smtp[382]: 1344D42ACC: to=<hugocesar_007@*******>, relay=127.0.0.1[127.0.0.1]:10024, delay=1197348, delays=1197334/12/0.17/2.2, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as F342F42AE4)
Jul 22 11:59:24 mail postfix/smtp[382]: 1344D42ACC: to=<reginadanielian@*******>, relay=127.0.0.1[127.0.0.1]:10024, delay=1197348, delays=1197334/12/0.17/2.2, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as F342F42AE4)
Jul 22 11:59:24 mail postfix/smtp[382]: 1344D42ACC: to=<thais_jp@*******>, relay=127.0.0.1[127.0.0.1]:10024, delay=1197348, delays=1197334/12/0.17/2.2, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as F342F42AE4)
Jul 22 11:59:24 mail postfix/smtp[382]: 1344D42ACC: to=<tropicalfmcomerciais@*******>, relay=127.0.0.1[127.0.0.1]:10024, delay=1197348, delays=1197334/12/0.17/2.2, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as F342F42AE4)
Jul 22 11:59:24 mail postfix/smtp[382]: 1344D42ACC: to=<valeria.x@*******>, relay=127.0.0.1[127.0.0.1]:10024, delay=1197348, delays=1197334/12/0.17/2.2, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as F342F42AE4)
Jul 22 11:59:24 mail postfix/smtp[382]: 1344D42ACC: to=<veloso1071@*******>, relay=127.0.0.1[127.0.0.1]:10024, delay=1197348, delays=1197334/12/0.17/2.2, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as F342F42AE4)
Jul 22 11:59:24 mail postfix/smtp[382]: 1344D42ACC: to=<termopiso@*******>, relay=127.0.0.1[127.0.0.1]:10024, delay=1197348, delays=1197334/12/0.17/2.2, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as F342F42AE4)
Jul 22 11:59:24 mail postfix/smtp[382]: 1344D42ACC: to=<rafaelpm84@*******>, relay=127.0.0.1[127.0.0.1]:10024, delay=1197348, delays=1197334/12/0.17/2.2, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as F342F42AE4)
Jul 22 11:59:24 mail postfix/smtp[382]: 1344D42ACC: to=<vanessyca@*******>, relay=127.0.0.1[127.0.0.1]:10024, delay=1197348, delays=1197334/12/0.17/2.2, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as F342F42AE4)
Jul 22 11:59:24 mail postfix/qmgr[366]: 1344D42ACC: removed

What we suppose

As the restriction we setup matches only the domain (for the sender) someone was using our server as relay with with emails where sender was forged to match [email protected] and would so be accepted.

We are going to change the settings to make the rule match the whole email instead but we are not sure that it will prevent the spoofing.

What do you think about it? Have we done something wrong ? Is there another way (or functionality) to have such a restriction ?

PS: We can post more information if needed

1
  • i am trying to implement a similar thing. we have some email addresses that are only allowed to be reached from local addresses. could you help?
    – Tobi
    Nov 6, 2017 at 2:41

3 Answers 3

3

As the restriction we setup matches only the domain (for the sender) someone was using our server as relay with with emails where sender was forged to match [email protected] and would so be accepted.

Yes, this is caused by this restriction in smtpd_recipient_restrictions

check_sender_access ldap:/etc/postfix/ldap_restricted_senders.cf

You said above, this query will return "OK", when sender allowed to send outgoing email. This means postfix will allow the email and bypass the restriction below it

  check_recipient_access ldap:/etc/postfix/ldap_restricted_recipients.cf
  permit_sasl_authenticated,
  reject_non_fqdn_hostname,
  reject_non_fqdn_sender,
  reject_non_fqdn_recipient,
  reject_unauth_destination,
  reject_unauth_pipelining,
  reject_invalid_hostname,
  check_policy_service unix:private/policy-spf

Perhaps the solution is replace "OK" query result with "DUNNO". The differences between those two parameters is,

  • When OK, postfix terminates the restriction checking list
  • When DUNNO, postfix will move to next restriction checking list

See also man 5 access.

OK Accept the address etc. that matches the pattern.

DUNNO Pretend that the lookup key was not found. This prevents Postfix from trying substrings of the lookup key (such as a subdomain name, or a network address subnetwork).

This feature is available in Postfix 2.0 and later.

1
  • This is the perfect answer ! It works fine with "DUNNO" instead of "OK"... We didn't know that this option would make postfix check next rules, very usefull. Thank you !
    – user301825
    Jul 31, 2015 at 13:38
2

For people interessed in implementing a similar restriction:

This works fine only if an extra file is created, for example /etc/postfix/ldap_virtual_domains_restrict_access.cf with following content

bind = yes
bind_dn = uid=postfix,ou=service,dc=example,dc=com
bind_pw = xxxxxx
server_host = ldap://127.0.0.1:389
search_base = ou=domain,dc=example,dc=com
query_filter = (&(ObjectClass=dNSDomain)(dc=%s))
result_attribute = dc
result_filter = dunno
result_format = OK

Then, in file /etc/postfix/main.cf change lines as:

local_only = check_recipient_access ldap:/etc/postfix/ldap_virtual_domains_restrict_access.cf, reject
insiders_only = check_sender_access ldap:/etc/postfix/ldap_virtual_domains_restrict_access.cf, reject

This way, the request feature works fine ! Otherwise, when matching "local_only" or "insiders_only", if result of ldap query is "DUNNO" then sender or recipient is rejected (as after the request next rule is "reject).

With result_format = OK when the result is "DUNNO" then the result of ldap request is "OK".

Hope this helps others

0

Related /etc/postfix/main.cf seems restriction works also with only:

smtpd_sender_restrictions =
 check_sender_access ldap:/etc/postfix/ldap_restricted_senders.cf, reject

my ldap_restricted_senders.cf example:

bind = yes                                                              
bind_dn = cn=admin,dc=example,dc=com                                         
bind_pw = mySecretPass                                                        
server_host = ldap://localhost/                                         
search_base = dc=example,dc=com                                    
query_filter = (&(&(objectClass=VirtualMailAccount)(mail=%s))(accountActive=TRUE)(delete=FALSE)(smtpAuth=TRUE))
result_attribute = smtpAuth                                             
result_filter = TRUE                                                    
result_format = OK 

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .