Bug 40609 - prevent user from using forged sender address
prevent user from using forged sender address
Status: REOPENED
Product: UCS
Classification: Unclassified
Component: Mail
UCS 4.4
Other Linux
: P5 enhancement (vote)
: UCS 4.3-2-errata
Assigned To: Daniel Tröder
Sönke Schwardt-Krummrich
:
: 44357 (view as bug list)
Depends on: 40608 47944
Blocks:
  Show dependency treegraph
 
Reported: 2016-02-09 14:56 CET by Daniel Tröder
Modified: 2021-05-14 16:45 CEST (History)
6 users (show)

See Also:
What kind of report is it?: Feature Request
What type of bug is this?: ---
Who will be affected by this bug?: ---
How will those affected feel about the bug?: ---
User Pain:
Enterprise Customer affected?:
School Customer affected?:
ISV affected?:
Waiting Support:
Flags outvoted (downgraded) after PO Review:
Ticket number:
Bug group (optional): Roadmap discussion
Max CVSS v3 score:
troeder: Patch_Available+


Attachments
milter that prevents forged from (5.41 KB, text/x-python)
2018-08-19 12:46 CEST, Daniel Tröder
Details
systemd unit to start milter (248 bytes, text/plain)
2018-08-19 12:53 CEST, Daniel Tröder
Details
milter that prevents forged from (5.62 KB, text/x-python)
2018-08-22 12:17 CEST, Daniel Tröder
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Daniel Tröder univentionstaff 2016-02-09 14:56:23 CET
Authenticated SMTP-clients can send with any email address. A restriction should prevent that.

Ideas are:
* use a policy server
* use smtpd_sender_login_maps and smtpd_sender_restrictions=reject_sender_login_mismatch
Comment 1 Stefan Gohmann univentionstaff 2016-12-13 08:10:44 CET
The Enterprise Customer affected flag is set but neither a Ticket number is referenced nor a Customer ID is set. Please set a Ticket number or a Customer ID. Otherwise the Enterprise Customer affected flag will be reset.
Comment 2 Daniel Tröder univentionstaff 2018-08-19 12:46:24 CEST
Created attachment 9630 [details]
milter that prevents forged from
Comment 3 Daniel Tröder univentionstaff 2018-08-19 12:53:41 CEST
Created attachment 9631 [details]
systemd unit to start milter
Comment 4 Daniel Tröder univentionstaff 2018-08-19 17:08:06 CEST
The attached milter is running on a production system.
Installation instructions are in the modules doc string.
Comment 5 Daniel Tröder univentionstaff 2018-08-22 12:17:15 CEST
Created attachment 9635 [details]
milter that prevents forged from

Updated version that handles machine account password rotation.
Comment 6 Daniel Tröder univentionstaff 2018-09-13 14:06:56 CEST
I created the branch dtroeder/40609_prevent_forged_sender. It now contains the milter, libmilter and a ucs-test.

[dtroeder/40609_prevent_forged_sender] 22bbf823ef Bug #40609: prevent forged From

I now prevents authenticated users from sending mails in someone else' name.
I does not yet prevent receiving mails from other mail server with a forged "From".
Comment 7 Daniel Tröder univentionstaff 2018-09-14 06:26:49 CEST
*** Bug 44357 has been marked as a duplicate of this bug. ***
Comment 8 Daniel Tröder univentionstaff 2018-09-14 06:36:08 CEST
[dtroeder/40609_prevent_forged_sender 07f8cc80a1] Bug #40609: prevent forged From from other mail server (w/o authentication), server reload upon domain creation/deletion

Anonymous SMTP connections are now also checked (in both MAIL FROM stage and header stage). Mails with a From containing a locally hosted domain name are rejected.

The milter server is now reloaded, when new domains are created/deleted:
A HUP signal is caught and the required LDAP query is done. The systemd unit uses this for the "reload" operation. The "hosteddomains.py" listener initiated the reload when a domain is created/deleted.

The test covers all scenarios I can think of.

Is a "global switch" to en/disable the whole feature desired?
Comment 9 Daniel Tröder univentionstaff 2018-09-14 12:17:02 CEST
* Added a note to the license file about the packaged python-libmilter.
* Relicensed the concrete milter to Univention.

[dtroeder/40609_prevent_forged_sender 756c468b57] Bug #47622: add copyright for python-libmilter, relicense milter from me to Univention
Comment 10 Daniel Tröder univentionstaff 2018-09-14 12:23:07 CEST
Note to myself: when merging to master, adapt package version in univention-mail-postfix.postinst @ "dpkg --compare-versions "$2" lt 12.0.0-22".
Comment 11 Sönke Schwardt-Krummrich univentionstaff 2018-10-04 17:01:51 CEST
There are some items I would like to address:
* move python-libmilter into a separate source package
* convert UCRV mail/postfix/smtpd_milters to a list with numeric order 
  (see mail/postfix/smtpd/restrictions/recipient/...) → eases the maintenance of 
  values by different packages
* naming is inconsistent: "no_forced_from" vs "sender_check" → I would suggest 
  that we use "sender_check" for all files, UCR variables, services, ...
* turn the new feature off by default by not setting mail/postfix/smtpd_milters 
  but do start the service
* please document mail/postfix/smtpd_milters in the UCS documentation and how to 
  enable it
* we should provide a delegate function that allows users to send with the mail 
  address of specific other users (e.g. assistance of the managing director can 
  send mails with mail address of the MD):
  - at each user, there should be a multivalue field, that allows to enter 
    usernames or specific mailaddresses:
    - if a username is specified, mails can be sent with all primary/alternative 
      addresses the specified user owns
    - if a specific address is specified, mails can be sent with that mail address
Comment 12 Daniel Tröder univentionstaff 2018-10-08 15:19:34 CEST
(In reply to Sönke Schwardt-Krummrich from comment #11)
> There are some items I would like to address:
> * convert UCRV mail/postfix/smtpd_milters to a list with numeric order 
>   (see mail/postfix/smtpd/restrictions/recipient/...) → eases the
> maintenance of 
>   values by different packages
Bug #40609: support ordering of milters

> * naming is inconsistent: "no_forced_from" vs "sender_check" → I would
> suggest 
>   that we use "sender_check" for all files, UCR variables, services, ...
Bug #40609: rename no-forged-from to sender_check for consistency 1
Bug #40609: rename no-forged-from to sender_check for consistency 2

> * turn the new feature off by default by not setting
> mail/postfix/smtpd_milters 
>   but do start the service
Bug #40609: disable milter by default

> * please document mail/postfix/smtpd_milters in the UCS documentation and
> how to 
>   enable it
Bug #40609: manual section on sender_check

> * move python-libmilter into a separate source package
Bug #40609: give python-libmilter its own source package

> * we should provide a delegate function that allows users to send with the
> mail 
>   address of specific other users (e.g. assistance of the managing director
> can 
>   send mails with mail address of the MD):
>   - at each user, there should be a multivalue field, that allows to enter 
>     usernames or specific mailaddresses:
>     - if a username is specified, mails can be sent with all
> primary/alternative 
>       addresses the specified user owns
>     - if a specific address is specified, mails can be sent with that mail
> address
TODO
Comment 13 Daniel Tröder univentionstaff 2018-10-29 15:11:53 CET
A delegate function has been implemented. Legitimate sender addresses for a user are found in its LDAP object in the attributes 'mailPrimaryAddress' (MPA), `mailAlternativeAddress' (mAA) and `mailAllowedSenderAddress`.
`mailAllowedSenderAddress` may contain email addresses as well as usernames.
For each username, the corresponding users mPA and mAA are also accepted.

To make it work with the distributed UCS mail server concept (homeMailServer), e-mails from connections that are verified (using SASL) are cryptographically
signed. The signature can be verified by other UCS mail servers in the domain.

Two headers are added to emails:
'X-univention-sender-check-sig': the signature
'X-univention-sender-check-nonce': a nonce, encrypted with the public key of all UCS mail servers (actually it is encrypted with a symmetric key and that one is encrypted to all recipients - like PGP does it)

The milter runs as a daemon process. It forks a separate process for each connection. Another process holds a cache of legitimate email addresses for use (both writing and reading) by all connection handler processes. The email addresses are cached for 1 min.

Bug #40609: remove unused file
Bug #40609: fix typo
Bug #40609: add LDAP attribute 'mailAllowedSenderAddress' to mail user
Bug #40609: add UDM porperty 'mailAllowedSenderAddress' to mail user
Bug #40609: add text on mail delegation to manual
Bug #40609: add mailAllowedSenderAddress property to users/user
Bug #40609: document "sender check" feature
Bug #40609: crypto functions for sender check
Bug #40609: generalize crypto class, add en/decryption
Bug #40609: add support for symmetric encryption, store public key, support use of separate public key
Bug #40609: create cryptographic keys and store public key in LDAP
Bug #40609: cryptographically sign verified emails
Comment 14 Daniel Tröder univentionstaff 2018-10-29 18:56:18 CET
Bug #40609: rename file
Bug #40609: move create_nonce() out of class
Comment 15 Daniel Tröder univentionstaff 2018-10-30 11:47:39 CET
The milter master process created an error when a SIGINT was recieved, as the accept() was interrupted. The error message is now suppressed to not alarm customers. (The commit message is wrong: it's not the dict-manager that causes the error message.)

Bug #40609: log cache stats, handle dict-manager error on signal

A listener module now reloads the daemon in case of creation/modification/deletion of a matching settings/data object.

Bug #40609: add listener module to reload milter when settings/data object changes


BTW: The slapd now hints from time to time:
Oct 30 11:37:03 m141-ox slapd[20878]: <= mdb_equality_candidates: (univentionDataType) not indexed
Oct 30 11:37:03 m141-ox slapd[20878]: <= mdb_equality_candidates: (univentionOwnedByPackage) not indexed
Comment 16 Daniel Tröder univentionstaff 2018-11-01 13:45:59 CET
The value for univentionDataType now encodes a namespace and a data type.
Filtering by univentionOwnedByPackage is discouraged.

Bug #40609: make univentionDataType significant, don't filter by univentionOwnedByPackage
Comment 17 Sönke Schwardt-Krummrich univentionstaff 2018-11-20 12:27:34 CET
The QA is not complete yet, but I found some items we have to address:

I pushed several commits to branch dtroeder/40609_prevent_forged_sender, that fix some problem I found so far. Please check before merge.

Additionally:
1) 
TODO → the EN manual has to be updated according to the changes of the DE manual

2)
REOPEN → python-libmilter should use the same version number as the upstream github version. IIRC in this case, the version should be "1.0.3-1" instead of "1.0.0"

3)
REOPEN → There should be a UCR whitelist variable that contains mail addresses (SASL users) that are allowed to submit emails with any sender address. This is required for UCS systems without a UCS mailstack that forward their mails to a UCS mailstack. But also 3rd party apps that want or have to deliver their mails to the mailstack.

4)
REOPEN → LEGITIMATE_ADDRESSES_CACHE_TTL should be a UCR variable to make ucs-test scripts faster. In the worst case, partial data is 2*LEGITIMATE_ADDRESSES_CACHE_TTL-1 seconds old.
This is the case if UserB is entered as the mailAllowedSenderAddress for UserA and the data from UserB is already in the cache and expires in 1 second. The Cache holds the data of UserA LEGITIMATE_ADDRESSES_CACHE_TTL for seconds, so that the data of UserB is held for nearly 2*LEGITIMATE_ADDRESSES_CACHE_TTL seconds will be. Maybe we should lower the value to 30 seconds and make it a UCR variable.

5)
REOPEN → sender_check_milter:331 → for test_address in test_addresses: → test_address is unused
REOPEN → return cls.my_translate(text[text.find(']')+1:], 'spamSPAM -_*,./|´`=()!"§$%&/()={[]}\\')  → why "spamSPAM" ? → 
>>> 'PAM must pass!'.translate(None, 'spamSPAM -_*,./|´`=()!"§$%&/()={[]}\\')
'ut'
→ I would suggest to remove the subject from the signature completely.

6)
REOPEN: The post_remove-Hook of the user's extended attribute should remove the username of the deleted user at other user's mailAllowedSenderAddress, to keep the LDAP content consistent.
Comment 18 Daniel Tröder univentionstaff 2018-11-22 10:20:48 CET
Small fixes and improvements:

2d54b810df Bug #40609: dependencies for settings/data
d9a3adcbac Bug #40609: postfix-script expects file in /etc/postfix to be owned by root
52a90cbf49 Bug #40609: improve logging


(In reply to Sönke Schwardt-Krummrich from comment #17)
> The QA is not complete yet, but I found some items we have to address:
> 
> I pushed several commits to branch dtroeder/40609_prevent_forged_sender,
> that fix some problem I found so far. Please check before merge.
OK: checked commits

> Additionally:
> 1) 
> TODO → the EN manual has to be updated according to the changes of the DE
> manual
c8de064ece Bug #40609: update manual and translations

> 2)
> REOPEN → python-libmilter should use the same version number as the upstream
> github version. IIRC in this case, the version should be "1.0.3-1" instead
> of "1.0.0"
1b7c75b594 Bug #40609: make cache TTL configurable, use upstream version for python-libmilter

> 3)
> REOPEN → There should be a UCR whitelist variable that contains mail
> addresses (SASL users) that are allowed to submit emails with any sender
> address. This is required for UCS systems without a UCS mailstack that
> forward their mails to a UCS mailstack. But also 3rd party apps that want or
> have to deliver their mails to the mailstack.
A whitelist can now be configured by listing usernames in the UCRV mail/postfix/sender_check_milter_whitelist. A note about this has been added to the manual.

23dc40ae3c Bug #40609: add support for a whitelist
9b24938172 Bug #40609: add section to manual about the whitelist

> 4)
> REOPEN → LEGITIMATE_ADDRESSES_CACHE_TTL should be a UCR variable to make
> ucs-test scripts faster. In the worst case, partial data is
> 2*LEGITIMATE_ADDRESSES_CACHE_TTL-1 seconds old.
> This is the case if UserB is entered as the mailAllowedSenderAddress for
> UserA and the data from UserB is already in the cache and expires in 1
> second. The Cache holds the data of UserA LEGITIMATE_ADDRESSES_CACHE_TTL for
> seconds, so that the data of UserB is held for nearly
> 2*LEGITIMATE_ADDRESSES_CACHE_TTL seconds will be. Maybe we should lower the
> value to 30 seconds and make it a UCR variable.
The TTL is now configurable through the UCRV mail/postfix/sender_check_milter_cache_ttl.
The default was 1st lowered to 30sec but then raised back to 60sec, because:
The TTL of an entry in the cache is now calculated as the minimum of its own TTL and all of the TTLs of the cache entries of other users addresses. this eliminates the above mentioned problem.

1b7c75b594 Bug #40609: make cache TTL configurable, use upstream version for python-libmilter
909cb2533c Bug #40609: inherit cache expiration date, in recursive address lookups
3187c69e1f Bug #40609: raise default cache TTL to 60 seconds

> 5)
> REOPEN → sender_check_milter:331 → for test_address in test_addresses: →
> test_address is unused
> REOPEN → return cls.my_translate(text[text.find(']')+1:], 'spamSPAM
> -_*,./|´`=()!"§$%&/()={[]}\\')  → why "spamSPAM" ? → 
> >>> 'PAM must pass!'.translate(None, 'spamSPAM -_*,./|´`=()!"§$%&/()={[]}\\')
> 'ut'
> → I would suggest to remove the subject from the signature completely.
5a671cb179 Bug #40609: remove subject from signature

> 6)
> REOPEN: The post_remove-Hook of the user's extended attribute should remove
> the username of the deleted user at other user's mailAllowedSenderAddress,
> to keep the LDAP content consistent.
81e56be38b Bug #40609: when deleting a user, remove its username from other users mailAllowedSenderAddress list
Comment 19 Daniel Tröder univentionstaff 2018-11-22 10:50:17 CET
Note to myself: when merging to master, adapt package version in
* univention-mail-postfix.postinst @ "dpkg --compare-versions "$2" lt 12.0.0-22"
* univention-mail-postfix/debian/control for shell-univention-lib, python-univention-lib and python-univention-directory-manager
Comment 20 Sönke Schwardt-Krummrich univentionstaff 2018-12-04 15:53:52 CET
Note for QA:
- consider bounce mails (quota exceeded)
- consider systems with only univention-mail-postfix and locally created mails by e.g. nagios or cron


Reopened as discussed:
please consider a whitelist for *mail addresses* instead of/addtionally to usernames → mail/postfix/sender_check_milter_whitelist
Comment 21 Erik Damrose univentionstaff 2018-12-07 14:40:31 CET
discourse thread with a similar scenario with kopano: https://help.univention.com/t/send-email-from-other-address-restriction-check-solved/10600
Comment 22 Daniel Tröder univentionstaff 2018-12-10 18:01:43 CET
Improved logging:
13351a511b Bug #40609: remove logging of same data on every connection
6088766a5f Bug #40609: make log messages more meaningful

(In reply to Sönke Schwardt-Krummrich from comment #20)
> please consider a whitelist for *mail addresses* instead of/addtionally to
> usernames → mail/postfix/sender_check_milter_whitelist
61f8a6ee81 Bug #40609: whitelist email addresses (instead of usernames)

This commit was only half correct, and the code gets fixed in 2fd589d21c:
aa32c8634e Bug #40609: allow external mails

ucs-test to check whitelist:
3039ce2ec7 Bug #40609: test whitelist

The code was refactored to use common functionality with the non-SMTP milter. It should also make developing other milters simpler:
2fd589d21c Bug #40609: refactor: split base milter functionality and general sender check functionality from executable

> - consider systems with only univention-mail-postfix and locally created
> mails by e.g. nagios or cron
A non-SMTP milter was created the will sign *all* emails that have a sender domain that is either one of the hosted ones or the servers FQDN:
63cd170d69 Bug #40609: add milter for non-SMTP connections
Comment 23 Florian Best univentionstaff 2021-05-03 21:58:04 CEST
What is the status here? Not verified but already released?
Comment 24 Daniel Tröder univentionstaff 2021-05-04 08:37:26 CEST
The solution is ready to be build and released in git branch "dtroeder/40609_prevent_forged_sender".
Needs to be verified of course.
I think documentation is missing.

I set the status to reopen now, as it made sense during the impl/qa process, but that has been interrupted two years ago.

This is a low hanging fruit for a much wanted mail feature!