diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 615cc80e..3fcdd463 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -427,14 +427,21 @@ Thanks goes to these wonderful people ✨ Jarrod Smith + + + jsonn +
+ Joerg Sonnenberger +
+ + pbek
Patrizio Bekerle
- - + Rubytastic2 @@ -469,15 +476,15 @@ Thanks goes to these wonderful people ✨
Null
- + + kamuri
Null
- - + davidszp @@ -512,15 +519,15 @@ Thanks goes to these wonderful people ✨
Null
- + + elbracht
Alexander Elbracht
- - + aminvakil @@ -555,15 +562,15 @@ Thanks goes to these wonderful people ✨
Christian Raue
- + + danielpanteleit
Daniel Panteleit
- - + dmcgrandle @@ -598,15 +605,15 @@ Thanks goes to these wonderful people ✨
FL42
- + + ipernet
Guillaume Simon
- - + H4R0 @@ -641,15 +648,15 @@ Thanks goes to these wonderful people ✨
Jeremy Shipman
- + + spacecowboy
Jonas Kalderstam
- - + artonge @@ -684,15 +691,15 @@ Thanks goes to these wonderful people ✨
Pablo Castorino
- + + p-fruck
Philipp Fruck
- - + Rillke @@ -727,15 +734,15 @@ Thanks goes to these wonderful people ✨
Vincent Ducamps
- + + andymel123
Andymel
- - + bigpigeon @@ -770,15 +777,15 @@ Thanks goes to these wonderful people ✨
Null
- + + GoliathLabs
Felix
- - + yogo1212 @@ -813,15 +820,15 @@ Thanks goes to these wonderful people ✨
0xflotus
- + + ifokeev
Johan Fokeev
- - + 20th @@ -856,15 +863,15 @@ Thanks goes to these wonderful people ✨
Adrian Pistol
- + + kachkaev
Alexander Kachkaev
- - + alexanderneu @@ -899,15 +906,15 @@ Thanks goes to these wonderful people ✨
Andrey Likhodievskiy
- + + iRhonin
Arash Fatahzade
- - + MrFreezeex @@ -942,15 +949,15 @@ Thanks goes to these wonderful people ✨
Bogdan
- + + erdos4d
Charles Harris
- - + crash7 @@ -985,15 +992,15 @@ Thanks goes to these wonderful people ✨
Damian Moore
- + + espitall
Null
- - + dkarski @@ -1028,15 +1035,15 @@ Thanks goes to these wonderful people ✨
Dmitry R.
- + + aydodo
Dorian Ayllón
- - + vedtam @@ -1071,15 +1078,15 @@ Thanks goes to these wonderful people ✨
Erik Brakkee
- + + huncode
Huncode
- - + felixn @@ -1109,20 +1116,20 @@ Thanks goes to these wonderful people ✨ - - frugan-it + + frugan-dev
Frugan
- + + Marsu31
Gabriel Euzet
- - + glandais @@ -1157,15 +1164,15 @@ Thanks goes to these wonderful people ✨
Ian Andrews
- + + Influencer
Influencer
- - + jcalfee @@ -1200,13 +1207,6 @@ Thanks goes to these wonderful people ✨
Jiří Kozlovský
- - - - jsonn -
- Joerg Sonnenberger -
@@ -1639,6 +1639,13 @@ Thanks goes to these wonderful people ✨ + + + Zepmann +
+ Null +
+ allddd @@ -1673,15 +1680,15 @@ Thanks goes to these wonderful people ✨
Null
- + + dborowy
Null
- - + dimalo @@ -1716,15 +1723,15 @@ Thanks goes to these wonderful people ✨
Null
- + + i-C-o-d-e-r
Null
- - + idaadi @@ -1759,15 +1766,15 @@ Thanks goes to these wonderful people ✨
Null
- + + landergate
Null
- - + callmemagnus @@ -1802,15 +1809,15 @@ Thanks goes to these wonderful people ✨
Jason Miller
- + + mplx
Null
- - + odinis @@ -1845,15 +1852,15 @@ Thanks goes to these wonderful people ✨
Null
- + + presocratics
Null
- - + rhyst @@ -1888,15 +1895,15 @@ Thanks goes to these wonderful people ✨
Null
- + + sportshead
Null
- - + squash @@ -1931,15 +1938,15 @@ Thanks goes to these wonderful people ✨
Null
- + + wolkenschieber
Null
- - + worldworm diff --git a/docs/content/config/advanced/kubernetes.md b/docs/content/config/advanced/kubernetes.md index 93cc0884..8a47bffc 100644 --- a/docs/content/config/advanced/kubernetes.md +++ b/docs/content/config/advanced/kubernetes.md @@ -190,7 +190,10 @@ spec: imagePullPolicy: IfNotPresent securityContext: - allowPrivilegeEscalation: false + # Required to support SGID via `postdrop` executable + # in `/var/mail-state` for Postfix (maildrop + public dirs): + # https://github.com/docker-mailserver/docker-mailserver/pull/3625 + allowPrivilegeEscalation: true readOnlyRootFilesystem: false runAsUser: 0 runAsGroup: 0 diff --git a/docs/content/config/advanced/optional-config.md b/docs/content/config/advanced/optional-config.md index 94097a8e..8a43e4db 100644 --- a/docs/content/config/advanced/optional-config.md +++ b/docs/content/config/advanced/optional-config.md @@ -12,7 +12,7 @@ This is a list of all configuration files and directories which are optional or - **sieve-pipe:** directory for sieve pipe scripts. (Docs: [Sieve][docs-sieve]) - **opendkim:** DKIM directory. Auto-configurable via [`setup.sh config dkim`][docs-setupsh]. (Docs: [DKIM][docs-dkim]) - **ssl:** SSL Certificate directory if `SSL_TYPE` is set to `self-signed` or `custom`. (Docs: [SSL][docs-ssl]) -- **Rspamd:** Override directory for custom settings when using Rspamd (Docs: [Rspamd][docs-rspamd-override-d]) +- **rspamd:** Override directory for custom settings when using Rspamd (Docs: [Rspamd][docs-rspamd-override-d]) ## Files diff --git a/docs/content/config/debugging.md b/docs/content/config/debugging.md index a17fd5ff..24e41566 100644 --- a/docs/content/config/debugging.md +++ b/docs/content/config/debugging.md @@ -29,22 +29,29 @@ These links may advise how the provider can unblock the port through additional 1. **Increase log verbosity**: Very helpful for troubleshooting problems during container startup. Set the environment variable [`LOG_LEVEL`][docs-environment-log-level] to `debug` or `trace`. 2. **Use error logs as a search query**: Try [finding an _existing issue_][gh-issues] or _search engine result_ from any errors in your container log output. Often you'll find answers or more insights. If you still need to open an issue, sharing links from your search may help us assist you. The mail server log can be acquired by running `docker log ` (_or `docker logs -f ` if you want to follow the log_). -3. **Understand the basics of mail servers**: Especially for beginners, make sure you read our [Introduction][docs-introduction] and [Usage][docs-usage] articles. -4. **Search the whole FAQ**: Our [FAQ][docs-faq] contains answers for common problems. Make sure you go through the list. -5. **Reduce the scope**: Ensure that you can run a basic setup of DMS first. Then incrementally restore parts of your original configuration until the problem is reproduced again. If you're new to DMS, it is common to find the cause is misunderstanding how to configure a minimal setup. +3. **Inspect the logs of the service that is failing**: We provide a dedicated paragraph on this topic [further down below](#logs). +4. **Understand the basics of mail servers**: Especially for beginners, make sure you read our [Introduction][docs-introduction] and [Usage][docs-usage] articles. +5. **Search the whole FAQ**: Our [FAQ][docs-faq] contains answers for common problems. Make sure you go through the list. +6. **Reduce the scope**: Ensure that you can run a basic setup of DMS first. Then incrementally restore parts of your original configuration until the problem is reproduced again. If you're new to DMS, it is common to find the cause is misunderstanding how to configure a minimal setup. ### Debug a running container -To get a shell inside the container run: `docker exec -it bash`. +#### General -If you need more flexibility than `docker logs` offers, within the container `/var/log/mail/mail.log` and `/var/log/supervisor/` are the most useful locations to get relevant DMS logs. Use the `tail` or `cat` commands to view their contents. - -To install additional software: +To get a shell inside the container run: `docker exec -it bash`. To install additional software, run: 1. `apt-get update` to update repository metadata. -2. `apt-get install ` +2. `apt-get install ` to install a package, e.g., `apt-get install neovim` if you want to use NeoVim instead of `nano` (which is shipped by default). -For example a text editor you can use in the terminal: `apt-get install nano` +#### Logs + +If you need more flexibility than what the `docker logs` command offers, then the most useful locations to get relevant DMS logs within the container are: + +- `/var/log/mail/mail.log` +- `/var/log/mail/mail/.log` +- `/var/log/supervisor/.log` + +You may use `nano` (a text editor) to edit files, while `less` (a file viewer) and `tail`/`cat` are useful tools to inspect the contents of logs. ## Compatibility diff --git a/docs/content/config/environment.md b/docs/content/config/environment.md index 982c3c12..0734d31a 100644 --- a/docs/content/config/environment.md +++ b/docs/content/config/environment.md @@ -586,8 +586,10 @@ Note: activate this only if you are confident in your bayes database for identif ##### FETCHMAIL_PARALLEL - **0** => `fetchmail` runs with a single config file `/etc/fetchmailrc` - **1** => `/etc/fetchmailrc` is split per poll entry. For every poll entry a separate fetchmail instance is started to allow having multiple imap idle configurations defined. +- **0** => `fetchmail` runs with a single config file `/etc/fetchmailrc` +- 1 => `/etc/fetchmailrc` is split per poll entry. For every poll entry a separate fetchmail instance is started to [allow having multiple imap idle connections per server][fetchmail-imap-workaround] (_when poll entries reference the same IMAP server_). + +[fetchmail-imap-workaround]: https://otremba.net/wiki/Fetchmail_(Debian)#Immediate_Download_via_IMAP_IDLE Note: The defaults of your fetchmailrc file need to be at the top of the file. Otherwise it won't be added correctly to all separate `fetchmail` instances. #### Getmail diff --git a/docs/content/config/security/rspamd.md b/docs/content/config/security/rspamd.md index 5867b1e8..442e5e78 100644 --- a/docs/content/config/security/rspamd.md +++ b/docs/content/config/security/rspamd.md @@ -71,7 +71,7 @@ DMS does not supply custom values for DNS servers to Rspamd. If you need to use ### Logs -You can find the Rspamd logs at `/var/log/mail/rspamd.log`, and the corresponding logs for [Redis](#persistence-with-redis), if it is enabled, at `/var/log/supervisor/rspamd-redis.log`. We recommend inspecting these logs (with `docker exec -it cat /var/log/mail/rspamd.log`) in case Rspamd does not work as expected. +You can find the Rspamd logs at `/var/log/mail/rspamd.log`, and the corresponding logs for [Redis](#persistence-with-redis), if it is enabled, at `/var/log/supervisor/rspamd-redis.log`. We recommend inspecting these logs (with `docker exec -it less /var/log/mail/rspamd.log`) in case Rspamd does not work as expected. ### Modules diff --git a/docs/content/examples/use-cases/auth-lua.md b/docs/content/examples/use-cases/auth-lua.md new file mode 100644 index 00000000..82586885 --- /dev/null +++ b/docs/content/examples/use-cases/auth-lua.md @@ -0,0 +1,162 @@ +--- +title: 'Examples | Use Cases | Lua Authentication' +--- + +## Introduction + +Dovecot has the ability to let users create their own custom user provisioning and authentication providers in [Lua](https://en.wikipedia.org/wiki/Lua_(programming_language)#Syntax). This allows any data source that can be approached from Lua to be used for authentication, including web servers. It is possible to do more with Dovecot and Lua, but other use cases fall outside of the scope of this documentation page. + +!!! warning "Community contributed guide" + Dovecot authentication via Lua scripting is not officially supported in DMS. No assistance will be provided should you encounter any issues. + + DMS provides the required packages to support this guide. Note that these packages will be removed should they introduce any future maintenance burden. + + The example in this guide relies on the current way in which DMS works with Dovecot configuration files. Changes to this to accommodate new authentication methods such as OpenID Connect will likely break this example in the future. This guide is updated on a best-effort base. + +Dovecot's Lua support can be used for user provisioning (userdb functionality) and/or password verification (passdb functionality). Consider using other userdb and passdb options before considering Lua, since Lua does require the use of additional (unsupported) program code that might require maintenance when updating DMS. + +Each implementation of Lua-based authentication is custom. Therefore it is impossible to write documentation that covers every scenario. Instead, this page describes a single example scenario. If that scenario is followed, you will learn vital aspects that are necessary to kickstart your own Lua development: + +- How to override Dovecot's default configuration to disable parts that conflict with your scenario. +- How to make Dovecot use your Lua script. +- How to add your own Lua script and any libraries it uses. +- How to debug your Lua script. + +## The example scenario + +This scenario starts with [DMS being configured to use LDAP][docs::auth-ldap] for mailbox identification, user authorization and user authentication. In this scenario, [Nextcloud](https://nextcloud.com/) is also a service that uses the same LDAP server for user identification, authorization and authentication. + +The goal of this scenario is to have Dovecot not authenticate the user against LDAP, but against Nextcloud using an [application password](https://docs.nextcloud.com/server/latest/user_manual/en/session_management.html#managing-devices). The idea behind this is that a compromised mailbox password does not compromise the user's account entirely. To make this work, Nextcloud is configured to [deny the use of account passwords by clients](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/config_sample_php_parameters.html#token-auth-enforced) and to [disable account password reset through mail verification](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/config_sample_php_parameters.html#lost-password-link). + +If the application password is configured correctly, an adversary can only use it to access the user's mailbox on DMS, and CalDAV and CardDAV data on Nextcloud. File access through WebDAV can be disabled for the application password used to access mail. Having CalDAV and CardDAV compromised by the same password is a minor setback. If an adversary gets access to a Nextcloud application password through a device of the user, it is likely that the adversary also gets access to the user's calendars and contact lists anyway (locally or through the same account settings used for mail and CalDAV/CardDAV synchronization). The user's stored files in Nextcloud, the LDAP account password and any other services that rely on it would still be protected. A bonus is that a user is able to revoke and renew the mailbox password in Nextcloud for whatever reason, through a friendly user interface with all the security measures with which the Nextcloud instance is configured (e.g. verification of the current account password). + +A drawback of this method is that any (compromised) Nextcloud application password can be used to access the user's mailbox. This introduces a risk that a Nextcloud application password used for something else (e.g. WebDAV file access) is compromised and used to access the user's mailbox. Discussion of that risk and possible mitigations fall outside of the scope of this scenario. + +To answer the questions asked earlier for this specific scenario: + +1. Do I want to use Lua to identify mailboxes and verify that users are are authorized to use mail services? **No. Provisioning is done through LDAP.** +1. Do I want to use Lua to verify passwords that users authenticate with for IMAP/POP3/SMTP in their mail clients? **Yes. Password authentication is done through Lua against Nextcloud.** +1. If the answer is 'yes' to question 1 or 2: are there other methods that better facilitate my use case instead of custom scripts which rely on me being a developer and not just a user? **No. Only HTTP can be used to authenticate against Nextcloud, which is not supported natively by Dovecot or DMS.** + +While it is possible to extend the authentication methods which Nextcloud can facilitate with [Nextcloud apps](https://apps.nextcloud.com/), there is currently a mismatch between what DMS supports and what Nextcloud applications can provide. This might change in the future. For now, Lua will be used to bridge the gap between DMS and Nextcloud for authentication only (Dovecot passdb), while LDAP will still be used to identify mailboxes and verify authorization (Dovecot userdb). + +## Modify Dovecot's configuration + +???+ example "Add to DMS volumes in `compose.yaml`" + + ```yaml + # All new volumes are marked :ro to configure them as read-only, since their contents are not changed from inside the container + volumes: + # Configuration override to disable LDAP authentication + - ./docker-data/dms/config/dovecot/auth-ldap.conf.ext:/etc/dovecot/conf.d/auth-ldap.conf.ext:ro + # Configuration addition to enable Lua authentication + - ./docker-data/dms/config/dovecot/auth-lua-httpbasic.conf:/etc/dovecot/conf.d/auth-lua-httpbasic.conf:ro + # Directory containing Lua scripts + - ./docker-data/dms/config/dovecot/lua/:/etc/dovecot/lua/:ro + ``` + +Create a directory for Lua scripts: +```bash +mkdir -p ./docker-data/dms/config/dovecot/lua +``` + +Create configuration file `./docker-data/dms/config/dovecot/auth-ldap.conf.ext` for LDAP user provisioning: +``` +userdb { + driver = ldap + args = /etc/dovecot/dovecot-ldap.conf.ext +} +``` + +Create configuration file `./docker-data/dms/config/dovecot/auth-lua-httpbasic.conf` for Lua user authentication: +``` +passdb { + driver = lua + args = file=/etc/dovecot/lua/auth-httpbasic.lua blocking=yes +} +``` + +That is all for configuring Dovecot. + +## Create the Lua script + +Create Lua file `./docker-data/dms/config/dovecot/lua/auth-httpbasic.lua` with contents: + +```lua +local http_url = "https://nextcloud.example.com/remote.php/dav/" +local http_method = "PROPFIND" +local http_status_ok = 207 +local http_status_failure = 401 +local http_header_forwarded_for = "X-Forwarded-For" + +package.path = package.path .. ";/etc/dovecot/lua/?.lua" +local base64 = require("base64") + +local http_client = dovecot.http.client { + timeout = 1000; + max_attempts = 1; + debug = false; +} + +function script_init() + return 0 +end + +function script_deinit() +end + +function auth_passdb_lookup(req) + local auth_request = http_client:request { + url = http_url; + method = http_method; + } + auth_request:add_header("Authorization", "Basic " .. (base64.encode(req.user .. ":" .. req.password))) + auth_request:add_header(http_header_forwarded_for, req.remote_ip) + local auth_response = auth_request:submit() + local resp_status = auth_response:status() + local reason = auth_response:reason() + + local returnStatus = dovecot.auth.PASSDB_RESULT_INTERNAL_FAILURE + local returnDesc = http_method .. " - " .. http_url .. " - " .. resp_status .. " " .. reason + if resp_status == http_status_ok + then + returnStatus = dovecot.auth.PASSDB_RESULT_OK + returnDesc = "nopassword=y" + elseif resp_status == http_status_failure + then + returnStatus = dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH + returnDesc = "" + end + return returnStatus, returnDesc +end +``` + +Replace the hostname in the URL to the actual hostname of Nextcloud. + +Dovecot [provides an HTTP client for use in Lua](https://doc.dovecot.org/admin_manual/lua/#dovecot.http.client). Aside of that, Lua by itself is pretty barebones. It chooses library compactness over included functionality. You can see that in that a separate library is referenced to add support for Base64 encoding, which is required for [HTTP basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication). This library (also a Lua script) is not included. It must be downloaded and stored in the same directory: + +```bash +cd ./docker-data/dms/config/dovecot/lua +curl -JLO https://raw.githubusercontent.com/iskolbin/lbase64/master/base64.lua +``` + +Only use native (pure Lua) libraries as dependencies if possible, such as `base64.lua` from the example. This ensures maximum compatibility. Performance is less of an issue since Lua scripts written for Dovecot probably won't be long or complex, and there won't be a lot of data processing by Lua itself. + +## Debugging a Lua script + +To see which Lua version is used by Dovecot if you plan to do something that is version dependent, run: + +```bash +docker exec CONTAINER_NAME strings /usr/lib/dovecot/libdovecot-lua.so|grep '^LUA_' +``` + +While Dovecot logs the status of authentication attempts for any passdb backend, Dovecot will also log Lua scripting errors and messages sent to Dovecot's [Lua API log functions](https://doc.dovecot.org/admin_manual/lua/#dovecot.i_debug). The combined DMS log (including that of Dovecot) can be viewed using `docker logs CONTAINER_NAME`. If the log is too noisy (_due to other processes in the container also logging to it_), `docker exec CONTAINER_NAME cat /var/log/mail/mail.log` can be used to view the log of Dovecot and Postfix specifically. + +If working with HTTP in Lua, setting `debug = true;` when initiating `dovecot.http.client` will create debug log messages for every HTTP request and response. + +Note that Lua runs compiled bytecode, and that scripts will be compiled when they are initially started. Once compiled, the bytecode is cached and changes in the Lua script will not be processed automatically. Dovecot will reload its configuration and clear its cached Lua bytecode when running `docker exec CONTAINER_NAME dovecot reload`. A (changed) Lua script will be compiled to bytecode the next time it is executed after running the Dovecot reload command. + +[docs::auth-ldap]: ../../config/advanced/auth-ldap.md +[docs::dovecot-override-configuration]: ../../config/advanced/override-defaults/dovecot.md#override-configuration +[docs::dovecot-add-configuration]: ../../config/advanced/override-defaults/dovecot.md#add-configuration +[docs::faq-alter-running-dms-instance-without-container-relaunch]: ../../faq.md#how-to-alter-a-running-dms-instance-without-relaunching-the-container diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index ab731b67..56a922d2 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -164,6 +164,7 @@ nav: - 'Forward-Only Mail-Server with LDAP': examples/use-cases/forward-only-mailserver-with-ldap-authentication.md - 'Customize IMAP Folders': examples/use-cases/imap-folders.md - 'iOS Mail Push Support': examples/use-cases/ios-mail-push-support.md + - 'Lua Authentication': examples/use-cases/auth-lua.md - 'FAQ' : faq.md - 'Contributing': - 'General Information': contributing/general.md diff --git a/mailserver.env b/mailserver.env index a7aa6402..ffbbe94c 100644 --- a/mailserver.env +++ b/mailserver.env @@ -403,6 +403,10 @@ ENABLE_FETCHMAIL=0 # The interval to fetch mail in seconds FETCHMAIL_POLL=300 +# Use multiple fetchmail instances (1 per poll entry in fetchmail.cf) +# Supports multiple IMAP IDLE connections when a server is used across multiple poll entries +# https://otremba.net/wiki/Fetchmail_(Debian)#Immediate_Download_via_IMAP_IDLE +FETCHMAIL_PARALLEL=0 # Enable or disable `getmail`. # diff --git a/target/bin/rspamd-dkim b/target/bin/rspamd-dkim index 357c2a9c..6dfcc1a0 100755 --- a/target/bin/rspamd-dkim +++ b/target/bin/rspamd-dkim @@ -62,13 +62,6 @@ ${ORANGE}EXIT STATUS${RESET} " } -function __do_as_rspamd_user() { - local COMMAND=${1:?Command required when using __do_as_rspamd_user} - _log 'trace' "Running '${*}' as user '_rspamd' now" - shift 1 - su -l '_rspamd' -s "$(command -v "${COMMAND}")" -- "${@}" -} - function _parse_arguments() { FORCE=0 KEYTYPE='rsa' diff --git a/target/scripts/build/packages.sh b/target/scripts/build/packages.sh index 099752bf..7b980dde 100644 --- a/target/scripts/build/packages.sh +++ b/target/scripts/build/packages.sh @@ -95,13 +95,19 @@ function _install_packages() { function _install_dovecot() { declare -a DOVECOT_PACKAGES + # Dovecot packages for officially supported features. DOVECOT_PACKAGES=( dovecot-core dovecot-imapd dovecot-ldap dovecot-lmtpd dovecot-managesieved dovecot-pop3d dovecot-sieve dovecot-solr ) - if [[ ${DOVECOT_COMMUNITY_REPO} -eq 1 ]]; then + # Dovecot packages for community supported features. + DOVECOT_PACKAGES+=(dovecot-auth-lua) + + # Dovecot's deb community repository only provides x86_64 packages, so do not include it + # when building for another architecture. + if [[ ${DOVECOT_COMMUNITY_REPO} -eq 1 ]] && [[ "$(uname --machine)" == "x86_64" ]]; then _log 'trace' 'Using Dovecot community repository' curl https://repo.dovecot.org/DOVECOT-REPO-GPG | gpg --import gpg --export ED409DA1 > /etc/apt/trusted.gpg.d/dovecot.gpg @@ -109,6 +115,9 @@ function _install_dovecot() { _log 'trace' 'Updating Dovecot package signatures' apt-get "${QUIET}" update + + # Additional community package needed for Lua support if the Dovecot community repository is used. + DOVECOT_PACKAGES+=(dovecot-lua) fi _log 'debug' 'Installing Dovecot' diff --git a/target/scripts/helpers/rspamd.sh b/target/scripts/helpers/rspamd.sh index 868e3d3a..2f4dcc46 100644 --- a/target/scripts/helpers/rspamd.sh +++ b/target/scripts/helpers/rspamd.sh @@ -2,6 +2,18 @@ # shellcheck disable=SC2034 # VAR appears unused. +# Perform a specific command as the Rspamd user (`_rspamd`). This is useful +# in case you want to have correct permissions on newly created files or if +# you want to check whether Rspamd can perform a specific action. +function __do_as_rspamd_user() { + _log 'trace' "Running '${*}' as user '_rspamd'" + su _rspamd -s /bin/bash -c "${*}" +} + +# Calling this function brings common Rspamd-related environment variables +# into the current context. The environment variables are `readonly`, i.e. +# they cannot be modified. Use this function when you require common directory +# names, file names, etc. function _rspamd_get_envs() { readonly RSPAMD_LOCAL_D='/etc/rspamd/local.d' readonly RSPAMD_OVERRIDE_D='/etc/rspamd/override.d' diff --git a/target/scripts/startup/setup.d/mail_state.sh b/target/scripts/startup/setup.d/mail_state.sh index a20b81af..9963bbcc 100644 --- a/target/scripts/startup/setup.d/mail_state.sh +++ b/target/scripts/startup/setup.d/mail_state.sh @@ -107,10 +107,10 @@ function _setup_save_states() { # These two require the postdrop(103) group: chgrp -R postdrop "${STATEDIR}"/spool-postfix/{maildrop,public} - # After changing the group, special bits (set-gid, sticky) may be stripped, restore them: - # Ref: https://github.com/docker-mailserver/docker-mailserver/pull/3149#issuecomment-1454981309 - chmod 1730 "${STATEDIR}/spool-postfix/maildrop" - chmod 2710 "${STATEDIR}/spool-postfix/public" + # These permissions rely on the `postdrop` binary having the SGID bit set. + # Ref: https://github.com/docker-mailserver/docker-mailserver/pull/3625 + chmod 730 "${STATEDIR}/spool-postfix/maildrop" + chmod 710 "${STATEDIR}/spool-postfix/public" elif [[ ${ONE_DIR} -eq 1 ]]; then _log 'warn' "'ONE_DIR=1' but no volume was mounted to '${STATEDIR}'" else diff --git a/target/scripts/startup/setup.d/security/rspamd.sh b/target/scripts/startup/setup.d/security/rspamd.sh index 19ce75dc..239397e5 100644 --- a/target/scripts/startup/setup.d/security/rspamd.sh +++ b/target/scripts/startup/setup.d/security/rspamd.sh @@ -23,6 +23,9 @@ function _setup_rspamd() { __rspamd__setup_check_authenticated _rspamd_handle_user_modules_adjustments # must run last + # only performing checks, no further setup handled from here onwards + __rspamd__check_dkim_permissions + __rspamd__log 'trace' '---------- Setup finished ----------' else _log 'debug' 'Rspamd is disabled' @@ -280,6 +283,12 @@ function __rspamd__setup_hfilter_group() { fi } +# If 'RSPAMD_CHECK_AUTHENTICATED' is enabled, then content checks for all users, i.e. +# also for authenticated users, are performed. +# +# The default that DMS ships does not check authenticated users. In case the checks are +# enabled, this function will remove the part of the Rspamd configuration that disables +# checks for authenticated users. function __rspamd__setup_check_authenticated() { local MODULE_FILE="${RSPAMD_LOCAL_D}/settings.conf" readonly MODULE_FILE @@ -294,3 +303,35 @@ function __rspamd__setup_check_authenticated() { "${MODULE_FILE}" fi } + +# This function performs a simple check: go through DKIM configuration files, acquire +# all private key file locations and check whether they exist and whether they can be +# accessed by Rspamd. +function __rspamd__check_dkim_permissions() { + local DKIM_CONF_FILES DKIM_KEY_FILES + [[ -f ${RSPAMD_LOCAL_D}/dkim_signing.conf ]] && DKIM_CONF_FILES+=("${RSPAMD_LOCAL_D}/dkim_signing.conf") + [[ -f ${RSPAMD_OVERRIDE_D}/dkim_signing.conf ]] && DKIM_CONF_FILES+=("${RSPAMD_OVERRIDE_D}/dkim_signing.conf") + + # Here, we populate DKIM_KEY_FILES which we later iterate over. DKIM_KEY_FILES + # contains all keys files configured by the user. + local FILE + for FILE in "${DKIM_CONF_FILES[@]}"; do + readarray -t DKIM_KEY_FILES_TMP < <(grep -o -E 'path = .*' "${FILE}" | cut -d '=' -f 2 | tr -d ' ";') + DKIM_KEY_FILES+=("${DKIM_KEY_FILES_TMP[@]}") + done + + for FILE in "${DKIM_KEY_FILES[@]}"; do + if [[ -f ${FILE} ]]; then + __rspamd__log 'trace' "Checking DKIM file '${FILE}'" + # See https://serverfault.com/a/829314 for an explanation on `-exec false {} +` + # We additionally resolve symbolic links to check the permissions of the actual files + if find "$(realpath -eL "${FILE}")" -user _rspamd -or -group _rspamd -or -perm -o=r -exec false {} +; then + __rspamd__log 'warn' "Rspamd DKIM private key file '${FILE}' does not appear to have correct permissions/ownership for Rspamd to use it" + else + __rspamd__log 'trace' "DKIM file '${FILE}' permissions and ownership appear correct" + fi + else + __rspamd__log 'warn' "Rspamd DKIM private key file '${FILE}' is configured for usage, but does not appear to exist" + fi + done +}