Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Restrict access to user's home #1039

Open
ngortheone opened this issue Mar 25, 2020 · 15 comments
Open

[Question] Restrict access to user's home #1039

ngortheone opened this issue Mar 25, 2020 · 15 comments

Comments

@ngortheone
Copy link
Contributor

Hi Gilles, I am using systemd to restrict smtpd process. In particular I hide user directories and mount the rest of the filesystem read-only (with exception of /var/spool/smpd )

ProtectSystem=strict
ProtectHome=yes

I often get warning in the log:
warn: smtpd: parent_forward_open: /home/ngor: No such file or directory when accepting mail.

Although I have setup smtpd to deliver through lmtp socket. So the question is why smptd trying to access user's directory?

My config:

pki mail.antonovs.family cert "/etc/letsencrypt/live/mail.antonovs.family/fullchain.pem"
pki mail.antonovs.family key "/etc/letsencrypt/live/mail.antonovs.family/privkey.pem"

filter check_dyndns phase connect match rdns regex { '.*\.dyn\..*', '.*\.dsl\..*' } \
    disconnect "550 GO AWAY"
filter check_rdns phase connect match !rdns \
    disconnect "550 GO AWAY"
filter check_fcrdns phase connect match !fcrdns \
    disconnect "550 GO AWAY"
filter senderscore \
    proc-exec "filter-senderscore -blockBelow 10 -junkBelow 70 -slowFactor 5000"
filter rspamd proc-exec "filter-rspamd"
table aliases file:/etc/aliases

listen on ens5 inet4 port 25 tls pki mail.antonovs.family \
    filter { check_dyndns, check_rdns, check_fcrdns, rspamd }

listen on ens5 inet4 port submission tls-require pki mail.antonovs.family auth filter rspamd

action "local_mail" lmtp "/var/run/dovecot/lmtp" alias <aliases>
action "outbound" relay helo mail.antonovs.family

match from any for domain "antonovs.family" action "local_mail"
match from local for local action "local_mail"

match from any auth for any action "outbound"
match from local for any action "outbound"

More complete log excerpt of mail delivery:

d59db3a40bcc5abe smtp connected address=96.47.72.81 host=mx2.freebsd.org
debug: looking up pki "mail.antonovs.family"
debug: session_start_ssl: switching to SSL
debug: pony: rsae_priv_enc
d59db3a40bcc5abe smtp tls ciphers=TLSv1.3:TLS_AES_256_GCM_SHA384:256
smtp: 0x564c6e62efb0: smtp_cert_verify_cb: no-client-cert
debug: smtp: SIZE in MAIL FROM command
debug: aliases_get: returned 1 aliases

warn: smtpd: parent_forward_open: /home/ngor: No such file or directory

smtp: 0x564c6e62efb0: fd 15 from queue
smtp: 0x564c6e62efb0: message fd 15
smtp: 0x564c6e62efb0: fd 16 from lka
smtp: 0x564c6e62efb0: filter fd 16
smtp: 0x564c6e62efb0: message begin
debug: 0x564c6e62efb0: end of message, error=0
d59db3a40bcc5abe smtp message msgid=c15b0b74 size=8929 nrcpt=1 proto=ESMTP
debug: scheduler: evp:c15b0b74dc005874 scheduled (mda)
d59db3a40bcc5abe smtp envelope evpid=c15b0b74dc005874 from=<[email protected]> to=<[email protected]>
mda: new user d59db3a53ea5ee2d for "<getpwnam>:ngor"
debug: lka: userinfo <getpwnam>:ngor
debug: mda: new session d59db3a6a263ef67 for user "<getpwnam>:ngor" evpid c15b0b74dc005874
debug: mda: no more envelope for "<getpwnam>:ngor"
debug: mda: got message fd 15 for session d59db3a6a263ef67 evpid c15b0b74dc005874
debug: mda: querying mda fd for session d59db3a6a263ef67 evpid c15b0b74dc005874
debug: smtpd: forking mda for session d59db3a6a263ef67: ngor as ngor
debug: mda: got mda fd 16 for session d59db3a6a263ef67 evpid c15b0b74dc005874
debug: mda: end-of-file for session d59db3a6a263ef67 evpid c15b0b74dc005874
debug: mda: all data sent for session d59db3a6a263ef67 evpid c15b0b74dc005874
d59db3a40bcc5abe smtp disconnected reason=quit
debug: smtpd: mda process done for session d59db3a6a263ef67: exited okay
d59db3a53ea5ee2d mda delivery evpid=c15b0b74dc005874 from=<[email protected]> to=<[email protected]> rcpt=<[email protected]> user=ngor delay=3s result=Ok stat=Delivered

Full systemd unit:

[Unit]
Description=OpenSMTPD
Documentation=man:smtpd(8)
Requires=network-online.target
After=network-online.target

[Service]
Type=forking
ExecStart=/usr/sbin/smtpd -v
ExecStop=/bin/kill -15 $MAINPID

## Filesystem
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
RestrictSUIDSGID=yes

ReadWritePaths=/var/spool/mail
ReadWritePaths=/var/spool/smtpd
ReadWritePaths=/run
ReadWritePaths=/var/run

## Kernel
KeyringMode=private
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
RestrictRealtime=yes
MemoryDenyWriteExecute=yes
SystemCallArchitectures=native

# Capabilities
CapabilityBoundingSet=CAP_SYS_CHROOT
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_SETUID
CapabilityBoundingSet=CAP_SETGID
CapabilityBoundingSet=CAP_CHOWN

## Other
ProtectHostname=yes
NoNewPrivileges=yes
Personality=x86-64
LockPersonality=yes
@whataboutpereira
Copy link

I suspect it's trying to read the .forward file.

@poolpOrg
Copy link
Member

Yes, it is to read the user ~/.forward file

@ngortheone
Copy link
Contributor Author

I see, so failure to read ~/.forward is not critical, and mail is still delivered.
I wonder if there is an option to disable forward file lookup, or change it's default location?

@ngortheone
Copy link
Contributor Author

It may actually be a bug. What if lmtp is a network socket and home directories are on a different host?
I think smtpd should not try to access user's directory if lmtp delivery is specified. @poolpOrg what do you think?

@poolpOrg
Copy link
Member

I see, so failure to read ~/.forward is not critical, and mail is still delivered.
I wonder if there is an option to disable forward file lookup, or change it's default location?

This is no option to disable forward file lookup but that would be a good idea in my opinion.

It may actually be a bug. What if lmtp is a network socket and home directories are on a different host?
I think smtpd should not try to access user's directory if lmtp delivery is specified. @poolpOrg what do you think?

I don't know as I'm not an LMTP user myself but to me we have to differentiate local and relay actions.

In local actions, we are expecting a local account and user may use own MDA while in relay actions, we are expecting the mail to be relayed elsewhere.

I don't know if the best option here is local LMTP with a new nodotforward option or a relay action, this should be put to discussion.

@ngortheone
Copy link
Contributor Author

@poolpOrg @ericfaurot

I don't know if the best option here is local LMTP with a new nodotforward option or a relay action, this should be put to discussion.

any news on this discussion?

@poolpOrg
Copy link
Member

no news as we're focusing on 6.7 release and no new features until tagged but I have it in my mind to submit a diff to introduce a no-forward action for local-only deliveries

@whataboutpereira
Copy link

I see, so failure to read ~/.forward is not critical, and mail is still delivered.
I wonder if there is an option to disable forward file lookup, or change it's default location?

I'm experimenting with the hardened unit file, and I adopted ProtectHome=read-only.

There also seems to be a capability missing for CentOS 8 system and I'm getting this:

CapabilityBoundingSet=CAP_SYS_CHROOT
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_SETUID
CapabilityBoundingSet=CAP_SETGID
CapabilityBoundingSet=CAP_CHOWN
May  2 13:17:04 centos8 smtpd[2913]: warn: purge_task: opendir: Permission denied

Did you settle on these capabilities or did you have to add more?

For now I adopted these to get rid of the error:

CapabilityBoundingSet=~CAP_NET_ADMIN CAP_SYS_ADMIN CAP_SYS_BOOT CAP_SYS_MODULE

@ngortheone
Copy link
Contributor Author

Hey @whataboutpereira

This is what I currently have in my unit file

# Needed
CapabilityBoundingSet=CAP_SYS_CHROOT
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_SETUID
CapabilityBoundingSet=CAP_SETGID
CapabilityBoundingSet=CAP_CHOWN
CapabilityBoundingSet=CAP_DAC_OVERRIDE

# Maybe not needed?
CapabilityBoundingSet=CAP_FOWNER
CapabilityBoundingSet=CAP_FSETID

I have settled on this set of capabilitites, and I don't think opensmtpd needs more.
CAP_NET_BIND_SERVICE is needed to open port 25 (below 1024)
CAP_SYS_CHROOT - to chroot child processes in their home directories
CAP_SETGID and CAP_SETUID to drop root privileges on child processes
CAP_CHOWN - this one seems to be really needed only when you run opensmtpd for the first time - to create folder for child processes and change ownership of those folders
CAP_DAC_OVERRIDE is needed to allow root (parent smtpd process) to access directories of its children

And I am not 100% sure that CAP_FOWNER and CAP_FSETID are really needed at all.

@dfateyev
Copy link

dfateyev commented May 3, 2020

Thank you all for ideas on capabilities options set! To be honest, I barely use local deliveries, but think we definitely need some minimal caps set in Fedora and RHEL7,8.
I'm going to implement it there when time permits; meanwhile more opinions and feedback are appreciated.

@whataboutpereira
Copy link

CapabilityBoundingSet=CAP_DAC_OVERRIDE

Maybe not needed?

CapabilityBoundingSet=CAP_FOWNER
CapabilityBoundingSet=CAP_FSETID

I can confirm that CAP_DAC_OVERRIDE and CAP_FOWNER are needed on CentOS 8 to get rid of a combination of errors:

May  2 13:17:04 centos8 smtpd[2913]: warn: purge_task: opendir: Permission denied
May  4 14:36:45 centos8 smtpd[57915]: chmod: /var/spool/smtpd/temporary: Operation not permitted
May  4 14:36:05 centos8 smtpd[57742]: /var/spool/smtpd/temporary must be rwx------ (700)

CAP_FSETID didn't seem to have an effect.

@whataboutpereira
Copy link

My full opensmtpd.service file that I'm running on CentOS 8 now:

[Unit]
Description=OpenSMTPD mail daemon
Documentation=man:smtpd(8)
Documentation=https://www.opensmtpd.org/manual.html
After=syslog.target network.target
Conflicts=sendmail.service postfix.service exim.service

[Service]
Type=forking
ExecStart=/usr/sbin/smtpd
Restart=on-failure
RestartSec=5

# Filesystem
#
ProtectSystem=strict
ProtectHome=read-only

PrivateTmp=yes
PrivateDevices=yes

ReadWritePaths=/var/spool/mail
ReadWritePaths=/var/spool/smtpd
ReadWritePaths=/var/run
ReadWritePaths=/run

# Kernel
#
KeyringMode=private
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictRealtime=yes
MemoryDenyWriteExecute=yes
SystemCallArchitectures=native

# Capabilities
#
# General
#
# CapabilityBoundingSet=~CAP_NET_ADMIN CAP_SYS_ADMIN CAP_SYS_BOOT CAP_SYS_MODULE

# Stricter
#
CapabilityBoundingSet=CAP_SYS_CHROOT
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_SETUID
CapabilityBoundingSet=CAP_SETGID
CapabilityBoundingSet=CAP_CHOWN
CapabilityBoundingSet=CAP_DAC_OVERRIDE
CapabilityBoundingSet=CAP_FOWNER

# Other
#
NoNewPrivileges=yes
Personality=x86-64
LockPersonality=yes

[Install]
WantedBy=multi-user.target

@poolpOrg
Copy link
Member

A diff has been sent to OpenBSD for adding a forward-file option:

https://marc.info/?l=openbsd-tech&m=160841747511126&w=2

If this gets committed, then by default there will be no touch of the user home directories unless the admin explicitly stated there may be .forward files in there.

@mischapeters
Copy link

mischapeters commented Jun 24, 2021

Hi @poolpOrg I saw the whole email thread and it looks like nothing was committed. Is there something to do about that check/error message? Besides "grep -v" :)
I am seeing it with local-delivery (no lmtp) by opensmtpd on OpenBSD for virtual users.

@dfateyev
Copy link

dfateyev commented Oct 8, 2021

If anyone interested: I have scheduled most of the suggestions above to the upcoming RHEL8 (EPEL8) and Fedora 34+ updates.
Scratch builds for testing:
https://koji.fedoraproject.org/koji/taskinfo?taskID=76890841 Fedora 34
https://koji.fedoraproject.org/koji/taskinfo?taskID=76890866 EPEL8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants