From e5b830adeaea28d7c5a79f72b72911cbda0cf668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 31 Aug 2018 23:33:55 +0200 Subject: [PATCH 1/6] [Dovecot] Fix shared namespace --- data/conf/dovecot/dovecot.conf | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/conf/dovecot/dovecot.conf b/data/conf/dovecot/dovecot.conf index dd8db8a3..5fc0024d 100644 --- a/data/conf/dovecot/dovecot.conf +++ b/data/conf/dovecot/dovecot.conf @@ -175,7 +175,7 @@ namespace { type = shared separator = / prefix = Shared/%%u/ - location = maildir:%%h/:CONTROL=~/Shared/%%u:INDEXPVT=~/Shared/%%u + location = maildir:%%h/:INDEX=~/Shared/%%u;CONTROL=~/Shared/%%u subscriptions = no list = children } diff --git a/docker-compose.yml b/docker-compose.yml index 871961a8..c1a3a1c8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -136,7 +136,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.34 + image: mailcow/sogo:1.35 build: ./data/Dockerfiles/sogo environment: - DBNAME=${DBNAME} From 8a88514dfde20b277ace76b87a126513e040fade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 7 Sep 2018 16:40:37 +0200 Subject: [PATCH 2/6] [SOGo] Declare /usr/lib/GNUstep/SOGo as volume [Nginx] Mount vols from sogo-mailcow to access /usr/lib/GNUstep/SOGo --- data/Dockerfiles/sogo/Dockerfile | 2 ++ docker-compose.yml | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/data/Dockerfiles/sogo/Dockerfile b/data/Dockerfiles/sogo/Dockerfile index 30a06d24..9d3965a7 100644 --- a/data/Dockerfiles/sogo/Dockerfile +++ b/data/Dockerfiles/sogo/Dockerfile @@ -49,4 +49,6 @@ COPY sogo-full.svg /usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-full.svg COPY acl.diff /acl.diff CMD exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf +VOLUME /usr/lib/GNUstep/SOGo/ + RUN rm -rf /tmp/* /var/tmp/* diff --git a/docker-compose.yml b/docker-compose.yml index c1a3a1c8..353772eb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -136,7 +136,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.35 + image: mailcow/sogo:1.36 build: ./data/Dockerfiles/sogo environment: - DBNAME=${DBNAME} @@ -264,6 +264,8 @@ services: - ./data/assets/ssl/:/etc/ssl/mail/:ro - ./data/conf/nginx/:/etc/nginx/conf.d/:rw - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro + volumes_from: + - sogo-mailcow ports: - "${HTTPS_BIND:-0.0.0.0}:${HTTPS_PORT:-443}:${HTTPS_PORT:-443}" - "${HTTP_BIND:-0.0.0.0}:${HTTP_PORT:-80}:${HTTP_PORT:-80}" From afc18fd46935e201a9be85ab636f0ed0b77209be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sun, 9 Sep 2018 09:47:47 +0200 Subject: [PATCH 3/6] [Rspamd] Update bad asn, move KEEP_SPAM to a custom lua function --- data/conf/rspamd/custom/bad_asn.map | 15 +++---- data/conf/rspamd/local.d/multimap.conf | 15 ------- data/conf/rspamd/lua/rspamd.local.lua | 54 ++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 22 deletions(-) diff --git a/data/conf/rspamd/custom/bad_asn.map b/data/conf/rspamd/custom/bad_asn.map index 8b7a4407..bc9e10f6 100644 --- a/data/conf/rspamd/custom/bad_asn.map +++ b/data/conf/rspamd/custom/bad_asn.map @@ -1,11 +1,10 @@ # High spam networks, disabled by default #201942:5 #Soltia Consulting SL - ipinfo.io -#16276:5 #OVH -#12876:5 #ONLINE S.A.S -#31034:5 -#12874:5 -#30823:5 -#197071:5 +#16276:2 #OVH +#12876:2 #ONLINE S.A.S +#31034:5 #ARUBA-ASN, IT +#12874:5 #FASTWEB, IT +#30823:3 #PKV spam #42831:5 #UK Dedicated Servers Ltd #29119:5 #Aire Networks del Mediterraneo S.L.U. #13335:5 #Cloudflare @@ -17,7 +16,7 @@ #14061:4 #Digitalocean #55293:4 #A2 Hosting #63018:4 #US Dedicated -#197518:2 +#197518:2 #RACKMARKT #44493:2 #46606:2 #49505:2 @@ -25,3 +24,5 @@ #197695:2 #198068:2 #43146:2 +#49100:4 +#39364:4 diff --git a/data/conf/rspamd/local.d/multimap.conf b/data/conf/rspamd/local.d/multimap.conf index da4afaf2..c27a9d63 100644 --- a/data/conf/rspamd/local.d/multimap.conf +++ b/data/conf/rspamd/local.d/multimap.conf @@ -25,13 +25,6 @@ WHITELISTED_FWD_HOST { symbols_set = ["WHITELISTED_FWD_HOST"]; } -KEEP_SPAM { - type = "ip"; - map = "redis://KEEP_SPAM"; - action = "accept"; - symbols_set = ["KEEP_SPAM"]; -} - LOCAL_BL_ASN { require_symbols = "!MAILCOW_WHITE"; type = "asn"; @@ -40,11 +33,3 @@ LOCAL_BL_ASN { description = "Sender's ASN is on the local blacklist"; symbols_set = ["LOCAL_BL_ASN"]; } - -#SPOOFED_SENDER { -# type = "rcpt"; -# filter = "email:domain:tld"; -# map = "redis://DOMAIN_MAP"; -# require_symbols = "AUTH_NA | !RCVD_VIA_SMTP_AUTH"; -# symbols_set = ["SPOOFED_SENDER"]; -#} diff --git a/data/conf/rspamd/lua/rspamd.local.lua b/data/conf/rspamd/lua/rspamd.local.lua index 7c9efbb4..92d223b1 100644 --- a/data/conf/rspamd/lua/rspamd.local.lua +++ b/data/conf/rspamd/lua/rspamd.local.lua @@ -7,6 +7,60 @@ rspamd_config.MAILCOW_AUTH = { end } +rspamd_config:register_symbol({ + name = 'KEEP_SPAM', + type = 'prefilter', + callback = function(task) + local util = require("rspamd_util") + local rspamd_logger = require "rspamd_logger" + local rspamd_ip = require 'rspamd_ip' + local uname = task:get_user() + if uname then + return false + end + local redis_params = rspamd_parse_redis_server('keep_spam') + local ip = task:get_from_ip() + local from_ip_string = ip:to_string() + ip_check_table = {from_ip_string} + local maxbits = 128 + local minbits = 32 + if ip:get_version() == 4 then + maxbits = 32 + minbits = 8 + end + for i=maxbits,minbits,-1 do + local nip = ip:apply_mask(i):to_string() .. "/" .. i + table.insert(ip_check_table, nip) + end + local function keep_spam_cb(err, data) + if err then + rspamd_logger.infox(rspamd_config, "keep_spam query request for ip %s returned invalid or empty data (\"%s\") or error (\"%s\")", ip, data, err) + return false + else + for k,v in pairs(data) do + if (v and v ~= userdata and v == '1') then + rspamd_logger.infox(rspamd_config, "found ip in keep_spam map, setting pre-result", v) + task:set_pre_result('accept', 'IP matched with forward hosts') + end + end + end + end + table.insert(ip_check_table, 1, 'KEEP_SPAM') + local redis_ret_user = rspamd_redis_make_request(task, + redis_params, -- connect params + 'KEEP_SPAM', -- hash key + false, -- is write + keep_spam_cb, --callback + 'HMGET', -- command + ip_check_table -- arguments + ) + if not redis_ret_user then + rspamd_logger.infox(rspamd_config, "cannot check keep_spam redis map") + end + end, + priority = 19 +}) + rspamd_config:register_symbol({ name = 'TAG_MOO', type = 'postfilter', From ad902f0ad8ab781d08583f4c69d6c70570531671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sun, 9 Sep 2018 09:48:11 +0200 Subject: [PATCH 4/6] [SOGo] Remove HTTP server on port 9192 --- data/Dockerfiles/sogo/supervisord.conf | 7 ------- 1 file changed, 7 deletions(-) diff --git a/data/Dockerfiles/sogo/supervisord.conf b/data/Dockerfiles/sogo/supervisord.conf index 2a889560..1c1422b3 100644 --- a/data/Dockerfiles/sogo/supervisord.conf +++ b/data/Dockerfiles/sogo/supervisord.conf @@ -16,13 +16,6 @@ command=/usr/sbin/cron -f autorestart=true priority=2 -[program:sogo-webres] -command=/usr/bin/python -u -m SimpleHTTPServer 9192 -directory=/usr/lib/GNUstep/SOGo/ -user=sogo -autorestart=true -priority=4 - [program:bootstrap-sogo] command=/bootstrap-sogo.sh stdout_logfile=/dev/stdout From ea4a26eabfbb19c04a2bcdcb3e510147ab5c65c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sun, 9 Sep 2018 09:51:37 +0200 Subject: [PATCH 5/6] [Nginx] Use SOGo web resources from local mount --- data/conf/nginx/site.conf | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/data/conf/nginx/site.conf b/data/conf/nginx/site.conf index d25d3b61..9ea4c385 100644 --- a/data/conf/nginx/site.conf +++ b/data/conf/nginx/site.conf @@ -156,44 +156,19 @@ server { } location /SOGo.woa/WebServerResources/ { - proxy_pass http://sogo:9192/WebServerResources/; - proxy_set_header Host $http_host; - proxy_cache sogo; - proxy_cache_valid 200 1d; - proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; - #alias /usr/lib/GNUstep/SOGo/WebServerResources/; - expires $expires; - allow all; + alias /usr/lib/GNUstep/SOGo/WebServerResources/; } location /.woa/WebServerResources/ { - proxy_pass http://sogo:9192/WebServerResources/; - proxy_set_header Host $http_host; - proxy_cache sogo; - proxy_cache_valid 200 1d; - proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; - #alias /usr/lib/GNUstep/SOGo/WebServerResources/; - expires $expires; - allow all; + alias /usr/lib/GNUstep/SOGo/WebServerResources/; } location /SOGo/WebServerResources/ { - proxy_pass http://sogo:9192/WebServerResources/; - proxy_set_header Host $http_host; - proxy_cache sogo; - proxy_cache_valid 200 1d; - proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; - #alias /usr/lib/GNUstep/SOGo/WebServerResources/; - allow all; + alias /usr/lib/GNUstep/SOGo/WebServerResources/; } location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$) { - proxy_pass http://sogo:9192/$1.SOGo/Resources/$2; - proxy_set_header Host $http_host; - proxy_cache sogo; - proxy_cache_valid 200 1d; - proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; - #alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2; + alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2; } include /etc/nginx/conf.d/site.*.custom; From c9554ca02291e64e56a786217de8d4b34b25544d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Sun, 9 Sep 2018 21:17:59 +0200 Subject: [PATCH 6/6] [Compose] Update watchdog image [Watchdog] Fix IP detection with multiple networks [Web] Show API field (no docs, no support, wip) [Web] haveibeenpwned.com implementation [Web] User and domain admin ACL (no docs, no support, wip) [Web] Some minor fixes --- data/Dockerfiles/watchdog/watchdog.sh | 27 ++- data/web/admin.php | 15 +- data/web/css/admin.css | 6 - data/web/css/mailbox.css | 3 - data/web/css/mailcow.css | 10 + data/web/edit.php | 68 +++++- data/web/inc/footer.inc.php | 117 ++-------- data/web/inc/functions.acl.inc.php | 216 ++++++++++++++++++ .../inc/functions.address_rewriting.inc.php | 32 +++ data/web/inc/functions.domain_admin.inc.php | 208 ++++++----------- data/web/inc/functions.inc.php | 50 +--- data/web/inc/functions.mailbox.inc.php | 17 +- data/web/inc/functions.policy.inc.php | 32 +-- data/web/inc/functions.ratelimit.inc.php | 8 + data/web/inc/init_db.inc.php | 34 ++- data/web/inc/prerequisites.inc.php | 3 +- data/web/inc/triggers.inc.php | 2 +- data/web/js/admin.js | 4 + data/web/js/api.js | 4 +- data/web/js/edit.js | 12 +- data/web/js/mailbox.js | 19 +- data/web/js/mailcow.js | 193 ++++++++++++++++ data/web/js/sha1.min.js | 1 + data/web/json_api.php | 6 + data/web/lang/lang.de.php | 23 +- data/web/lang/lang.en.php | 21 ++ data/web/mailbox.php | 15 +- data/web/modals/admin.php | 4 +- data/web/modals/mailbox.php | 7 +- data/web/modals/user.php | 4 +- data/web/quarantine.php | 2 +- data/web/user.php | 89 ++------ docker-compose.yml | 2 +- 33 files changed, 793 insertions(+), 461 deletions(-) create mode 100644 data/web/inc/functions.acl.inc.php create mode 100644 data/web/js/mailcow.js create mode 100644 data/web/js/sha1.min.js diff --git a/data/Dockerfiles/watchdog/watchdog.sh b/data/Dockerfiles/watchdog/watchdog.sh index c06abbc2..ec3d5aca 100755 --- a/data/Dockerfiles/watchdog/watchdog.sh +++ b/data/Dockerfiles/watchdog/watchdog.sh @@ -59,10 +59,10 @@ function mail_error() { log_msg "Sent notification email to ${1}" } - get_container_ip() { # ${1} is container CONTAINER_ID=() + CONTAINER_IPS=() CONTAINER_IP= LOOP_C=1 until [[ ${CONTAINER_IP} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] || [[ ${LOOP_C} -gt 5 ]]; do @@ -72,15 +72,21 @@ get_container_ip() { # returned id can have multiple elements (if scaled), shuffle for random test CONTAINER_ID=($(printf "%s\n" "${CONTAINER_ID[@]}" | shuf)) if [[ ! -z ${CONTAINER_ID} ]]; then - for matched_container in "${CONTAINER_ID[@]}"; do - CONTAINER_IP=$(curl --silent http://dockerapi:8080/containers/${matched_container}/json | jq -r '.NetworkSettings.Networks[].IPAddress') - # grep will do nothing if one of these vars is empty - [[ -z ${CONTAINER_IP} ]] && continue - [[ -z ${IPV4_NETWORK} ]] && continue - # only return ips that are part of our network - if ! grep -q ${IPV4_NETWORK} <(echo ${CONTAINER_IP}); then - CONTAINER_IP= - fi + for matched_container in "${CONTAINER_ID[@]}"; do + CONTAINER_IPS=($(curl --silent http://dockerapi:8080/containers/${matched_container}/json | jq -r '.NetworkSettings.Networks[].IPAddress')) + for ip_match in "${CONTAINER_IPS[@]}"; do + # grep will do nothing if one of these vars is empty + [[ -z ${ip_match} ]] && continue + [[ -z ${IPV4_NETWORK} ]] && continue + # only return ips that are part of our network + if ! grep -q ${IPV4_NETWORK} <(echo ${ip_match}); then + continue + else + CONTAINER_IP=${ip_match} + break + fi + done + [[ ! -z ${CONTAINER_IP} ]] && break done fi LOOP_C=$((LOOP_C + 1)) @@ -88,7 +94,6 @@ get_container_ip() { [[ ${LOOP_C} -gt 5 ]] && echo 240.0.0.0 || echo ${CONTAINER_IP} } -# Check functions nginx_checks() { err_count=0 diff_c=0 diff --git a/data/web/admin.php b/data/web/admin.php index d2734431..749c96b6 100644 --- a/data/web/admin.php +++ b/data/web/admin.php @@ -29,7 +29,7 @@ $tfa_data = get_tfa();
- +
@@ -44,7 +44,7 @@ $tfa_data = get_tfa();
-
+
:
@@ -76,12 +76,10 @@ $tfa_data = get_tfa();
- - - - diff --git a/data/web/css/admin.css b/data/web/css/admin.css index a53d721c..bc89f1dd 100644 --- a/data/web/css/admin.css +++ b/data/web/css/admin.css @@ -65,12 +65,6 @@ body.modal-open { font-size:9pt; background:transparent; } -.bootstrap-select { - width: auto!important; -} .table-condensed .input-sm { width: 100%!important; } -.full-width-select { - width: 100%!important; -} diff --git a/data/web/css/mailbox.css b/data/web/css/mailbox.css index da2e96e3..488150d3 100644 --- a/data/web/css/mailbox.css +++ b/data/web/css/mailbox.css @@ -5,9 +5,6 @@ table.footable>tbody>tr.footable-empty>td { .pagination a { text-decoration: none !important; } -.panel panel-default { - overflow: visible !important; -} .btn-group { width: max-content; } diff --git a/data/web/css/mailcow.css b/data/web/css/mailcow.css index 374688a1..04d1b874 100644 --- a/data/web/css/mailcow.css +++ b/data/web/css/mailcow.css @@ -148,3 +148,13 @@ nav .glyphicon { color: #5a5a5a; white-space: nowrap; } +.haveibeenpwned { + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.full-width-select { + width: 100%!important; +} \ No newline at end of file diff --git a/data/web/edit.php b/data/web/edit.php index c4903c28..417f2a7c 100644 --- a/data/web/edit.php +++ b/data/web/edit.php @@ -92,7 +92,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- @@ -111,7 +111,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -140,6 +140,30 @@ if (isset($_SESSION['mailcow_cc_role'])) {
+
+
+
+

ACL

+
+
+
+ +
+
+ +
+
+
+
- +

@@ -278,14 +302,14 @@ if (isset($_SESSION['mailcow_cc_role'])) {
-
+
-
+
@@ -300,14 +324,14 @@ if (isset($_SESSION['mailcow_cc_role'])) {
-
+
-
+
@@ -474,7 +498,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -527,6 +551,30 @@ if (isset($_SESSION['mailcow_cc_role'])) {
+
+
+
+

ACL

+
+
+
+ +
+
+ +
+
+
+
- +
@@ -965,7 +1013,7 @@ else { + + diff --git a/data/web/modals/admin.php b/data/web/modals/admin.php index 7e8656e5..8bca0d87 100644 --- a/data/web/modals/admin.php +++ b/data/web/modals/admin.php @@ -67,7 +67,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- ".htmlspecialchars($domain).""; @@ -79,7 +79,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- +
diff --git a/data/web/modals/mailbox.php b/data/web/modals/mailbox.php index b4a51893..160ab178 100644 --- a/data/web/modals/mailbox.php +++ b/data/web/modals/mailbox.php @@ -23,7 +23,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- ".htmlspecialchars($domain).""; @@ -48,10 +48,9 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- +
- - (Generate) +
diff --git a/data/web/modals/user.php b/data/web/modals/user.php index 62ccf1b1..5e0849e2 100644 --- a/data/web/modals/user.php +++ b/data/web/modals/user.php @@ -37,7 +37,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- +
@@ -155,7 +155,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
- +
diff --git a/data/web/quarantine.php b/data/web/quarantine.php index 87f565a1..3e193586 100644 --- a/data/web/quarantine.php +++ b/data/web/quarantine.php @@ -18,7 +18,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
-
+
- +
-
+
@@ -299,9 +280,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
- +
@@ -309,7 +288,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
-

- +
-
- +

@@ -354,26 +329,22 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
- +
-
+
-
+
- +

@@ -381,28 +352,22 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
- +
-
+
-
+
- -
- +
@@ -411,11 +376,9 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
- +
-
+
- +
diff --git a/docker-compose.yml b/docker-compose.yml index 353772eb..cd0c69f8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -330,7 +330,7 @@ services: - /lib/modules:/lib/modules:ro watchdog-mailcow: - image: mailcow/watchdog:1.19 + image: mailcow/watchdog:1.21 # Debug #command: /watchdog.sh build: ./data/Dockerfiles/watchdog