diff --git a/dovecot/.dockerignore b/dovecot/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..68eb57dbfc589324ae08b8ba30d0eee0dab636c8 --- /dev/null +++ b/dovecot/.dockerignore @@ -0,0 +1,4 @@ +* +!*.sieve +!entrypoint +!patch.diff diff --git a/dovecot/Dockerfile b/dovecot/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..746b646f01555c65c8ec220338be1df2e6448c69 --- /dev/null +++ b/dovecot/Dockerfile @@ -0,0 +1,35 @@ +FROM buildpack-deps:buster as delete_to_trash +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y dovecot-dev && \ + git clone https://github.com/pali/dovecot_deleted_to_trash && \ + cd dovecot_deleted_to_trash && \ + make + +FROM debian:buster-slim +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + dovecot-ldap \ + dovecot-lmtpd \ + dovecot-imapd \ + dovecot-sieve \ + patch \ + ssl-cert \ + time \ + && \ + rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* /var/cache/apt/archives/* +COPY --from=delete_to_trash /dovecot_deleted_to_trash/lib_deleted_to_trash_plugin.so /usr/lib/dovecot/modules/ +COPY --from=delete_to_trash /dovecot_deleted_to_trash/95-deleted_to_trash_plugin.conf /etc/dovecot/conf.d/ +COPY --chown=root:root entrypoint /entrypoint +COPY patch.diff /root/ +RUN patch --strip 0 --verbose --directory /etc/dovecot --input /root/patch.diff && \ + doveconf +COPY --chown=mail:mail *.sieve /var/lib/dovecot/sieve.d/ +RUN cd /var/lib/dovecot/sieve.d/ && \ + ls *.sieve | xargs -tn1 sievec && \ + rm *.svbin +VOLUME /var/mail +VOLUME /run/dovecot +EXPOSE 993 25 +ENTRYPOINT [ "/entrypoint" ] +CMD [ "dovecot", "-F" ] +HEALTHCHECK CMD doveadm service status || exit 1 diff --git a/dovecot/README.md b/dovecot/README.md new file mode 100644 index 0000000000000000000000000000000000000000..adb13d067ddb7d519df3500024cb9d85437bbec8 --- /dev/null +++ b/dovecot/README.md @@ -0,0 +1,30 @@ +# Dovecot + +> Dovecot container image. + +## Exposed interfaces + +The containers exposes TCP ports 25 (LMTP) and 993 (IMAPS) and the `lmtp` Unix +socket in the `/run/dovecot` volume (for LTMP submission). + +## Environment variables + +Name | Description +--- | --- +`LDAP_URIS` | LDAP URI (eg, `ldapi:///`). +`LDAP_BASEDN` | LDAP base DN (eg, `dc=example,dc=com`). + +## Persistence + +The mbox files are stored at `/var/mail`. + +## License + +This software is licensed under the MIT license (see `LICENSE.txt`). + +## Author Information + +Nimrod Adar, [contact me](mailto:nimrod@shore.co.il) or visit my [website]( +https://www.shore.co.il/). Patches are welcome via [`git send-email`]( +http://git-scm.com/book/en/v2/Git-Commands-Email). The repository is located +at: <https://www.shore.co.il/git/>. diff --git a/dovecot/before.sieve b/dovecot/before.sieve new file mode 100644 index 0000000000000000000000000000000000000000..ee9cb0cee36a765cb920f3517a3009c4ebd8ea44 --- /dev/null +++ b/dovecot/before.sieve @@ -0,0 +1,6 @@ +require ["fileinto", "envelope"]; +if anyof (header :contains "X-Spam-Status" "Yes", + header :contains "X-Virus-Status" "infected") +{ + fileinto "Junk"; +} diff --git a/dovecot/entrypoint b/dovecot/entrypoint new file mode 100755 index 0000000000000000000000000000000000000000..b3905bf5be7ff5d32513777cefe62ec342e5ca07 --- /dev/null +++ b/dovecot/entrypoint @@ -0,0 +1,16 @@ +#!/bin/sh +set -eux + +install -d -m 755 -o dovecot -g root /var/run/dovecot +install -d -m 775 -o root -g dovecot /var/mail +install -d -m 775 -o root -g dovecot /run/dovecot +time openssl dhparam -out /usr/share/dovecot/dh.pem 4096 +DEBIAN_FRONTEND=noninteractive time make-ssl-cert generate-default-snakeoil --force-overwrite + +# I don't know why environment variables aren't expanded and I'm too interested +# to find out. + +sed -i "s@%{env:LDAP_URIS}@$LDAP_URIS@g" /etc/dovecot/dovecot-ldap.conf.ext +sed -i "s@%{env:LDAP_BASEDN}@$LDAP_BASEDN@g" /etc/dovecot/dovecot-ldap.conf.ext + +eval exec "$@" diff --git a/dovecot/nimrod.sieve b/dovecot/nimrod.sieve new file mode 100644 index 0000000000000000000000000000000000000000..44a693c15e04110b06b353a19dd73c02c7d7c67e --- /dev/null +++ b/dovecot/nimrod.sieve @@ -0,0 +1,85 @@ +require ["fileinto", "envelope", "imap4flags"]; +if address :is "from" "nimrod@shore.co.il" { setflag "\\seen"; } + +if address :is :domain "from" [ "drushim.co.il", "indeed.com", "picaro.co.il", "jobnet.co.il", "cps.co.il", "seev.co.il", "yad2jobs.co.il", "mindu.co.il", "korentec.co.il", "ethosia.com", "ethosia.co.il", "nisha.co.il", "alljob.co.il", "alljobs.co.il", "propel.co.il", "simplyfind.co.il", "jobby.co.il", "niloosoft.com", "qhr.co.il", "dialog.co.il", "taldor.co.il", "linkedin.com", "*.linkedin.com", "hire.withgoogle.com" , "hunterhrms.com", "triplebyte.com", "gun.io", "lever.co", "*.lever.co", "logica-it.co.il" ] +{ + fileinto "Wanted"; +} +elsif anyof ( + address :is :domain "from" [ "puppetlabs.com", "drivehq.com", "bsdmag.org", "macecraft.com", "rol.co.il", "pointmail.co.za", "agora.co.il", "bsdmag.com", "check.me", "dvorak.org", "perlmaven.com", "itnewsletter.co.il", "aerofs.com", "lastpass.com", "openstack-israel.org", "sdjournal.org", "htisrael.co.il", "github.com", "marriott-email.com", "meetup.com", "8662244.co.il", "software.com.pl", "heroku.com", "eg-innovations.net", "email-marriott.com", "info.docker.com", "docker.com", "docker.io", "onedrive.microsoft.com", "aerofs.com", "m.aerofs.com", "airbnb.com", "circleci.com", "bugs.debian.org", "getcloudify.com", "mqg.org.il", "samerica.co.il", "gigaspaces.com", "getcloudify.org", "email.aol.com", "maccabi-news.co.il", "microfocus.com", "*.microfocus.com", "statscraft.org.il", "novell.com" ], + address :is "from" [ "ecomeshek@gmail.com", "ironethaifa@haifa.muni.il" ], + address :is :domain "to" [ "openbsd.org", "meetup.com" ]) +{ + fileinto "Mailing lists"; +} +elsif address :is :domain "from" [ "paypal.co.il", "paypal.com", "*.paypal.co.il", "*.paypal.com" ] +{ + fileinto "PayPal"; +} +elsif address :is :domain "from" [ "amazon.com", "*.amazon.com" ] +{ + fileinto "Amazon"; +} +elsif anyof (address :is :domain "from" [ "travelbird.be", "nitzan-hr.com", "ispc.co.il", "meckano.co.il", "kustonline.be", "freefax.co.il", "summary.com", "twoomail.com", "thephonehouse.es", "*.thephonehouse.es" ], + address :is "from" [ "rsnc.office@gmail.com", "zelba100@gmail.com" ]) +{ + fileinto "Junk"; +} +elsif address :is :domain "from" [ "migdal.co.il", "bezeqint.co.il", "youphone.co.il", "bezeq.co.il", "bezeqint.net", "icount.co.il", "kali.co.il", "ari-ins.co.il", "altshul.co.il", "*.migdal.co.il", "moran-fin.com" ] +{ + fileinto "Saved"; +} +elsif address :is :domain "from" [ "unilink.co.il", "malam.com" ] +{ + fileinto "Unilink"; +} +elsif anyof (address :is "from" [ "or.siniminis@gmail.com", "hastudio.theater@gmail.com", "hastudiotheatre@gmail.com" ], + address :is :domain "from" "ayalagroup.co.il") +{ + setflag "\\seen"; + fileinto "Cinematheque"; +} +elsif address :is :domain "from" [ "startcom.org", "davidcpa.co.il" ] +{ + fileinto "Shore"; +} +elsif address :is :domain "from" "bigpanda.io" +{ + fileinto "bigpanda"; +} +elsif address :is :domain "from" [ "wiser.com", "wisepricer.com" ] +{ + fileinto "Wiser"; +} +elsif address :is :domain "from" [ "scaleway.com", "*.scaleway.com", "online.net", "*.online.net" ] +{ + fileinto "scaleway"; +} +elsif address :is :domain "from" [ "spot.im" ] +{ + fileinto "spot.im"; +} +elsif address :is :domain "from" [ "ebay.com", "*.ebay.com", "ebay.co.il", "*.ebay.co.il" ] +{ + fileinto "ebay"; +} +elsif anyof (address :is :domain "from" [ "endlessm.com", "*.endlessm.com" ], address :is "to" "nimrod@endlessm.com") +{ + fileinto "Endless"; +} +elsif address :is "to" [ "abuse@shore.co.il", "clamav@shore.co.il", "ftp@shore.co.il", "hostmaster@shore.co.il", "mailer-daemon@shore.co.il", "news@shore.co.il", "nobody@shore.co.il", "noc@shore.co.il", "postmaster@shore.co.il", "root@shore.co.il", "security@shore.co.il", "usenet@shore.co.il", "webmaster@shore.co.il", "www@shore.co.il" ] +{ + fileinto "Root"; +} +elsif address :is :domain "from" [ "studentsvillage.org" ] +{ + fileinto "StudentVillage"; +} +elsif address :is :domain "from" [ "google.com", "*.google.com" ] +{ + fileinto "Google"; +} +elsif address :is :domain "from" [ "leumi.co.il", "*.leumi.co.il", "leumi-card.co.il", "*.leumi-card.co.il", "leumicard.co.il", "*.leumicard.co.il" ] +{ + fileinto "Leumi"; +} diff --git a/dovecot/patch.diff b/dovecot/patch.diff new file mode 100644 index 0000000000000000000000000000000000000000..992e94c19d467e32e502be8d7cc134b73f7f67fe --- /dev/null +++ b/dovecot/patch.diff @@ -0,0 +1,183 @@ +--- conf.d/10-auth.conf 2019-01-23 12:05:58.000000000 +0200 ++++ conf.d/10-auth.conf 2019-03-04 11:54:04.477652365 +0200 +@@ -48,7 +48,7 @@ + # the standard variables here, eg. %Lu would lowercase the username, %n would + # drop away the domain if it was given, or "%n-AT-%d" would change the '@' into + # "-AT-". This translation is done after auth_username_translation changes. +-#auth_username_format = %Lu ++auth_username_format = %Ln + + # If you want to allow master users to log in by specifying the master + # username within the normal username string (ie. not using SASL mechanism's +@@ -119,9 +119,9 @@ + #!include auth-deny.conf.ext + #!include auth-master.conf.ext + +-!include auth-system.conf.ext ++#!include auth-system.conf.ext + #!include auth-sql.conf.ext +-#!include auth-ldap.conf.ext ++!include auth-ldap.conf.ext + #!include auth-passwdfile.conf.ext + #!include auth-checkpassword.conf.ext + #!include auth-vpopmail.conf.ext +--- conf.d/10-mail.conf 2019-03-04 11:47:29.000000000 +0200 ++++ conf.d/10-mail.conf 2019-03-04 11:55:06.813149374 +0200 +@@ -27,7 +27,7 @@ + # + # <doc/wiki/MailLocation.txt> + # +-mail_location = mbox:~/mail:INBOX=/var/mail/%u ++mail_location = mbox:/var/mail/%Ln:INBOX=/var/mail/%Ln/Inbox + + # If you need to set multiple mailbox locations or want to change default + # namespace settings, you can do it by defining namespace sections. +--- conf.d/10-ssl.conf 2019-03-04 11:47:29.000000000 +0200 ++++ conf.d/10-ssl.conf 2019-03-04 11:53:30.871608777 +0200 +@@ -57,6 +57,7 @@ + #ssl_cipher_list = ALL:!kRSA:!SRP:!kDHd:!DSS:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!RC4:!ADH:!LOW@STRENGTH + # To disable non-EC DH, use: + #ssl_cipher_list = ALL:!DH:!kRSA:!SRP:!kDHd:!DSS:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!RC4:!ADH:!LOW@STRENGTH ++ssl_cipher_list=!kRSA:!3DES:!RC4:!DES:!MD5:!aNULL:!NULL:AESGCM+ECDH:AES256+ECDH:AES128:+SHA1 + + # Colon separated list of elliptic curves to use. Empty value (the default) + # means use the defaults from the SSL library. P-521:P-384:P-256 would be an +--- conf.d/20-lmtp.conf 2019-01-23 12:05:58.000000000 +0200 ++++ conf.d/20-lmtp.conf 2019-03-04 13:25:51.061844327 +0200 +@@ -20,6 +20,12 @@ + # when a mail has multiple recipients. + #lmtp_hdr_delivery_address = final + ++recipient_delimiter =+ ++lmtp_save_to_detail_mailbox = yes ++lda_mailbox_autocreate = yes ++lda_mailbox_autosubscribe = yes ++ ++ + protocol lmtp { + # Space separated list of plugins to load (default is global mail_plugins). + #mail_plugins = $mail_plugins +--- conf.d/90-sieve.conf 2019-03-05 21:15:58.905790954 +0200 ++++ conf.d/90-sieve.conf 2019-03-05 21:19:18.160059384 +0200 +@@ -36,7 +36,7 @@ + # active script symlink is located. + # For other types: use the ';name=' parameter to specify the name of the + # default/active script. +- sieve = file:~/sieve;active=~/.dovecot.sieve ++ sieve = /var/lib/dovecot/sieve.d/%Ln.sieve + + # The default Sieve script when the user has none. This is the location of a + # global sieve script file, which gets executed ONLY if user's personal Sieve +@@ -73,7 +73,7 @@ + # to the script execution sequence in the specified order. Reading the + # numbered sieve_before settings stops at the first missing setting, so no + # numbers may be skipped. +- #sieve_before = /var/lib/dovecot/sieve.d/ ++ sieve_before = /var/lib/dovecot/sieve.d/before.sieve + #sieve_before2 = ldap:/etc/sieve-ldap.conf;name=ldap-domain + #sieve_before3 = (etc...) + +--- conf.d/10-logging.conf 2019-03-05 21:43:01.097279575 +0200 ++++ conf.d/10-logging.conf 2019-03-05 22:17:49.041027765 +0200 +@@ -4,7 +4,7 @@ + + # Log file to use for error messages. "syslog" logs to syslog, + # /dev/stderr logs to stderr. +-#log_path = syslog ++log_path = /dev/stderr + + # Log file to use for informational messages. Defaults to log_path. + #info_log_path = +@@ -41,7 +41,7 @@ + #log_core_filter = + + # Log unsuccessful authentication attempts and the reasons why they failed. +-#auth_verbose = no ++auth_verbose = yes + + # In case of password mismatches, log the attempted password. Valid values are + # no, plain and sha1. sha1 can be useful for detecting brute force password +--- dovecot.conf 2019-04-29 23:35:05.000000000 +0300 ++++ dovecot.conf 2019-05-12 00:20:17.908388214 +0300 +@@ -75,7 +75,7 @@ + # Space separated list of environment variables that are preserved on Dovecot + # startup and passed down to all of its child processes. You can also give + # key=value pairs to always set specific settings. +-#import_environment = TZ ++import_environment = $import_environment LDAP_URIS LDAP_BASEDN + + ## + ## Dictionary server settings +--- dovecot-ldap.conf.ext 2019-01-23 12:05:58.000000000 +0200 ++++ dovecot-ldap.conf.ext 2019-06-29 19:09:54.704490949 +0300 +@@ -21,7 +21,7 @@ + + # LDAP URIs to use. You can use this instead of hosts list. Note that this + # setting isn't supported by all LDAP libraries. +-#uris = ++uris = %{env:LDAP_URIS} + + # Distinguished Name - the username used to login to the LDAP server. + # Leave it commented out to bind anonymously (useful with auth_bind=yes). +@@ -66,7 +66,7 @@ + # The pass_filter is used to find the DN for the user. Note that the pass_attrs + # is still used, only the password field is ignored in it. Before doing any + # search, the binding is switched back to the default DN. +-#auth_bind = no ++auth_bind = yes + + # If authentication binding is used, you can save one LDAP request per login + # if users' DN can be specified with a common template. The template can use +@@ -89,7 +89,7 @@ + + # LDAP base. %variables can be used here. + # For example: dc=mail, dc=example, dc=org +-base = ++base = %{env:LDAP_BASEDN} + + # Dereference: never, searching, finding, always + #deref = never +@@ -127,8 +127,8 @@ + # userdb prefetch instead of userdb ldap in dovecot.conf. In that case you'll + # also have to include user_attrs in pass_attrs field prefixed with "userdb_" + # string. For example: +-#pass_attrs = uid=user,userPassword=password,\ +-# homeDirectory=userdb_home,uidNumber=userdb_uid,gidNumber=userdb_gid ++pass_attrs = uid=user,userPassword=password,\ ++ homeDirectory=userdb_home,uidNumber=userdb_uid,gidNumber=userdb_gid + + # Filter for password lookups + #pass_filter = (&(objectClass=posixAccount)(uid=%u)) +--- conf.d/10-master.conf 2019-06-30 15:30:20.955944241 +0300 ++++ conf.d/10-master.conf 2019-06-30 15:30:20.959944142 +0300 +@@ -19,8 +19,8 @@ + #port = 143 + } + inet_listener imaps { +- #port = 993 +- #ssl = yes ++ port = 993 ++ ssl = yes + } + + # Number of connections to handle before starting a new process. Typically +@@ -53,15 +53,15 @@ + + service lmtp { + unix_listener lmtp { +- #mode = 0666 ++ mode = 0666 + } + + # Create inet listener only if you can't use the above UNIX socket +- #inet_listener lmtp { ++ inet_listener lmtp { + # Avoid making LMTP visible for the entire internet + #address = +- #port = +- #} ++ port = 25 ++ } + } + + service imap {