Selaa lähdekoodia

Merge branch 'dev'

andryyy 8 vuotta sitten
vanhempi
sitoutus
26e2baa131

+ 15 - 7
data/Dockerfiles/acme/docker-entrypoint.sh

@@ -50,7 +50,8 @@ if [[ -f ${ACME_BASE}/cert.pem ]] && [[ -f ${ACME_BASE}/key.pem ]]; then
 	ISSUER=$(openssl x509 -in ${ACME_BASE}/cert.pem -noout -issuer)
 	ISSUER=$(openssl x509 -in ${ACME_BASE}/cert.pem -noout -issuer)
 	if [[ ${ISSUER} != *"Let's Encrypt"* && ${ISSUER} != *"mailcow"* ]]; then
 	if [[ ${ISSUER} != *"Let's Encrypt"* && ${ISSUER} != *"mailcow"* ]]; then
 		echo "Found certificate with issuer other than mailcow snake-oil CA and Let's Encrypt, skipping ACME client..."
 		echo "Found certificate with issuer other than mailcow snake-oil CA and Let's Encrypt, skipping ACME client..."
-		exit 0
+		sleep 3650d
+		exec $(readlink -f "$0")
 	else
 	else
 		declare -a SAN_ARRAY_NOW
 		declare -a SAN_ARRAY_NOW
 		SAN_NAMES=$(openssl x509 -noout -text -in ${ACME_BASE}/cert.pem | awk '/X509v3 Subject Alternative Name/ {getline;gsub(/ /, "", $0); print}' | tr -d "DNS:")
 		SAN_NAMES=$(openssl x509 -noout -text -in ${ACME_BASE}/cert.pem | awk '/X509v3 Subject Alternative Name/ {getline;gsub(/ /, "", $0); print}' | tr -d "DNS:")
@@ -79,7 +80,8 @@ fi
 while true; do
 while true; do
 	if [[ "${SKIP_LETS_ENCRYPT}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
 	if [[ "${SKIP_LETS_ENCRYPT}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
 		echo "SKIP_LETS_ENCRYPT=y, skipping Let's Encrypt..."
 		echo "SKIP_LETS_ENCRYPT=y, skipping Let's Encrypt..."
-		exit 0
+		sleep 3650d
+		exec $(readlink -f "$0")
 	fi
 	fi
 	if [[ "${SKIP_IP_CHECK}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
 	if [[ "${SKIP_IP_CHECK}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
 		SKIP_IP_CHECK=y
 		SKIP_IP_CHECK=y
@@ -164,8 +166,10 @@ while true; do
   # Unique elements
   # Unique elements
 	ALL_VALIDATED=(${VALIDATED_MAILCOW_HOSTNAME} $(echo ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs))
 	ALL_VALIDATED=(${VALIDATED_MAILCOW_HOSTNAME} $(echo ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs))
 	if [[ -z ${ALL_VALIDATED[*]} ]]; then
 	if [[ -z ${ALL_VALIDATED[*]} ]]; then
-		echo "Cannot validate hostnames, skipping Let's Encrypt..."
-		exit 0
+		echo "Cannot validate hostnames, skipping Let's Encrypt for 1 hour."
+		echo "Use SKIP_LETS_ENCRYPT=y in mailcow.conf to skip it permanently."
+		sleep 1h
+		exec $(readlink -f "$0")
 	fi
 	fi
 
 
 	ORPHANED_SAN=($(echo ${SAN_ARRAY_NOW[*]} ${ALL_VALIDATED[*]} | tr ' ' '\n' | sort | uniq -u ))
 	ORPHANED_SAN=($(echo ${SAN_ARRAY_NOW[*]} ${ALL_VALIDATED[*]} | tr ' ' '\n' | sort | uniq -u ))
@@ -219,7 +223,10 @@ while true; do
 				TRIGGER_RESTART=1
 				TRIGGER_RESTART=1
 			fi
 			fi
 			[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
 			[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
-			exit 1;;
+			echo "Retrying in 30 minutes..."
+			sleep 30m
+			exec $(readlink -f "$0")
+            ;;
 		2) # no change
 		2) # no change
 			if ! diff ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem; then
 			if ! diff ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem; then
 				echo "Certificate was not changed, but active certificate does not match the verified certificate, fixing and restarting containers..."
 				echo "Certificate was not changed, but active certificate does not match the verified certificate, fixing and restarting containers..."
@@ -253,10 +260,11 @@ while true; do
 				TRIGGER_RESTART=1
 				TRIGGER_RESTART=1
 			fi
 			fi
 			[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
 			[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
-			exit 1;;
+			sleep 3650d
+			;;
 	esac
 	esac
 
 
 	echo "ACME certificate validation done. Sleeping for another day."
 	echo "ACME certificate validation done. Sleeping for another day."
-	sleep 86400
+	sleep 1d
 
 
 done
 done

+ 3 - 3
data/Dockerfiles/rspamd/Dockerfile

@@ -18,9 +18,9 @@ RUN apt-get update && apt-get install -y \
 	&& mkdir -p /run/rspamd \
 	&& mkdir -p /run/rspamd \
 	&& chown _rspamd:_rspamd /run/rspamd
 	&& chown _rspamd:_rspamd /run/rspamd
 
 
-COPY settings.conf /etc/rspamd/modules.d/settings.conf
-COPY ratelimit.lua /usr/share/rspamd/lua/ratelimit.lua
-COPY lua_util.lua /usr/share/rspamd/lib/lua_util.lua
+#COPY settings.conf /etc/rspamd/modules.d/settings.conf
+#COPY ratelimit.lua /usr/share/rspamd/lua/ratelimit.lua
+#COPY lua_util.lua /usr/share/rspamd/lib/lua_util.lua
 COPY docker-entrypoint.sh /docker-entrypoint.sh
 COPY docker-entrypoint.sh /docker-entrypoint.sh
 
 
 ENTRYPOINT ["/docker-entrypoint.sh"]
 ENTRYPOINT ["/docker-entrypoint.sh"]

+ 4 - 4
data/conf/rspamd/dynmaps/settings.php

@@ -191,8 +191,8 @@ while ($row = array_shift($rows)) {
 	$grouped_lists = $stmt->fetchAll(PDO::FETCH_COLUMN);
 	$grouped_lists = $stmt->fetchAll(PDO::FETCH_COLUMN);
 	$value_sane = preg_replace("/\.\./", ".", (preg_replace("/\*/", ".*", $grouped_lists[0])));
 	$value_sane = preg_replace("/\.\./", ".", (preg_replace("/\*/", ".*", $grouped_lists[0])));
 ?>
 ?>
-		request_header = {
-			"From" = "(<?=$value_sane;?>)";
+		header = {
+			"From" = "/(<?=$value_sane;?>)/i";
 		}
 		}
 <?php
 <?php
 	if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
 	if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
@@ -283,8 +283,8 @@ while ($row = array_shift($rows)) {
 	$grouped_lists = $stmt->fetchAll(PDO::FETCH_COLUMN);
 	$grouped_lists = $stmt->fetchAll(PDO::FETCH_COLUMN);
 	$value_sane = preg_replace("/\.\./", ".", (preg_replace("/\*/", ".*", $grouped_lists[0])));
 	$value_sane = preg_replace("/\.\./", ".", (preg_replace("/\*/", ".*", $grouped_lists[0])));
 ?>
 ?>
-		request_header = {
-			"From" = "(<?=$value_sane;?>)";
+		header = {
+			"From" = "/(<?=$value_sane;?>)/i";
 		}
 		}
 <?php
 <?php
 	if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
 	if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {

+ 4 - 1
data/web/admin.php

@@ -157,6 +157,7 @@ $tfa_data = get_tfa();
               </div>
               </div>
               <div class="col-xs-9">
               <div class="col-xs-9">
                   <pre><?=$dkim['dkim_txt'];?></pre>
                   <pre><?=$dkim['dkim_txt'];?></pre>
+                  <p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="<?=$dkim['privkey'];?>"><small>↪ Private key</small></p>
               </div>
               </div>
             </div>
             </div>
           <?php
           <?php
@@ -186,6 +187,7 @@ $tfa_data = get_tfa();
                 </div>
                 </div>
                 <div class="col-xs-9">
                 <div class="col-xs-9">
                   <pre><?=$dkim['dkim_txt'];?></pre>
                   <pre><?=$dkim['dkim_txt'];?></pre>
+                  <p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="<?=$dkim['privkey'];?>"><small>↪ Private key</small></p>
                 </div>
                 </div>
               </div>
               </div>
             <?php
             <?php
@@ -197,7 +199,7 @@ $tfa_data = get_tfa();
               <div class="col-xs-1 col-xs-offset-1">
               <div class="col-xs-1 col-xs-offset-1">
                 <p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br /></small><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
                 <p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br /></small><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
               </div>
               </div>
-            <div class="col-xs-9"><pre>-</pre></div>
+              <div class="col-xs-9"><pre>-</pre></div>
             </div>
             </div>
             <?php
             <?php
             }
             }
@@ -217,6 +219,7 @@ $tfa_data = get_tfa();
                 </div>
                 </div>
                 <div class="col-xs-9">
                 <div class="col-xs-9">
                   <pre><?=$dkim['dkim_txt'];?></pre>
                   <pre><?=$dkim['dkim_txt'];?></pre>
+                  <p data-toggle="modal" data-target="#showDKIMprivKey" id="dkim_priv" style="cursor:pointer;margin-top:-8pt" data-priv-key="<?=$dkim['privkey'];?>"><small>↪ Private key</small></p>
                 </div>
                 </div>
             </div>
             </div>
           <?php
           <?php

+ 13 - 13
data/web/autoconfig.php

@@ -4,7 +4,7 @@ $default_autodiscover_config = $autodiscover_config;
 if(file_exists('inc/vars.local.inc.php')) {
 if(file_exists('inc/vars.local.inc.php')) {
   include_once 'inc/vars.local.inc.php';
   include_once 'inc/vars.local.inc.php';
 }
 }
-$configuration = array_merge($default_autodiscover_config, $autodiscover_config);
+$autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);
 
 
 error_reporting(0);
 error_reporting(0);
 
 
@@ -33,15 +33,15 @@ header('Content-Type: application/xml');
       <displayShortName>mail server</displayShortName>
       <displayShortName>mail server</displayShortName>
 
 
       <incomingServer type="imap">
       <incomingServer type="imap">
-         <hostname><?=$configuration['imap']['server']; ?></hostname>
-         <port><?=$configuration['imap']['port']; ?></port>
+         <hostname><?=$autodiscover_config['imap']['server']; ?></hostname>
+         <port><?=$autodiscover_config['imap']['port']; ?></port>
          <socketType>SSL</socketType>
          <socketType>SSL</socketType>
          <username>%EMAILADDRESS%</username>
          <username>%EMAILADDRESS%</username>
          <authentication>password-cleartext</authentication>
          <authentication>password-cleartext</authentication>
       </incomingServer>
       </incomingServer>
       <incomingServer type="imap">
       <incomingServer type="imap">
-         <hostname><?=$configuration['imap']['server']; ?></hostname>
-         <port><?=$configuration['imap']['tlsport']; ?></port>
+         <hostname><?=$autodiscover_config['imap']['server']; ?></hostname>
+         <port><?=$autodiscover_config['imap']['tlsport']; ?></port>
          <socketType>STARTTLS</socketType>
          <socketType>STARTTLS</socketType>
          <username>%EMAILADDRESS%</username>
          <username>%EMAILADDRESS%</username>
          <authentication>password-cleartext</authentication>
          <authentication>password-cleartext</authentication>
@@ -51,8 +51,8 @@ header('Content-Type: application/xml');
 $records = dns_get_record('_pop3s._tcp.' . $domain, DNS_SRV); // check if POP3 is announced as "not provided" via SRV record
 $records = dns_get_record('_pop3s._tcp.' . $domain, DNS_SRV); // check if POP3 is announced as "not provided" via SRV record
 if (count($records) == 0 || $records[0]['target'] != '') { ?>
 if (count($records) == 0 || $records[0]['target'] != '') { ?>
       <incomingServer type="pop3">
       <incomingServer type="pop3">
-         <hostname><?=$configuration['pop3']['server']; ?></hostname>
-         <port><?=$configuration['pop3']['port']; ?></port>
+         <hostname><?=$autodiscover_config['pop3']['server']; ?></hostname>
+         <port><?=$autodiscover_config['pop3']['port']; ?></port>
          <socketType>SSL</socketType>
          <socketType>SSL</socketType>
          <username>%EMAILADDRESS%</username>
          <username>%EMAILADDRESS%</username>
          <authentication>password-cleartext</authentication>
          <authentication>password-cleartext</authentication>
@@ -62,8 +62,8 @@ if (count($records) == 0 || $records[0]['target'] != '') { ?>
 $records = dns_get_record('_pop3._tcp.' . $domain, DNS_SRV); // check if POP3 is announced as "not provided" via SRV record
 $records = dns_get_record('_pop3._tcp.' . $domain, DNS_SRV); // check if POP3 is announced as "not provided" via SRV record
 if (count($records) == 0 || $records[0]['target'] != '') { ?>
 if (count($records) == 0 || $records[0]['target'] != '') { ?>
       <incomingServer type="pop3">
       <incomingServer type="pop3">
-         <hostname><?=$configuration['pop3']['server']; ?></hostname>
-         <port><?=$configuration['pop3']['tlsport']; ?></port>
+         <hostname><?=$autodiscover_config['pop3']['server']; ?></hostname>
+         <port><?=$autodiscover_config['pop3']['tlsport']; ?></port>
          <socketType>STARTTLS</socketType>
          <socketType>STARTTLS</socketType>
          <username>%EMAILADDRESS%</username>
          <username>%EMAILADDRESS%</username>
          <authentication>password-cleartext</authentication>
          <authentication>password-cleartext</authentication>
@@ -71,15 +71,15 @@ if (count($records) == 0 || $records[0]['target'] != '') { ?>
 <?php } ?>
 <?php } ?>
 
 
       <outgoingServer type="smtp">
       <outgoingServer type="smtp">
-         <hostname><?=$configuration['smtp']['server']; ?></hostname>
-         <port><?=$configuration['smtp']['port']; ?></port>
+         <hostname><?=$autodiscover_config['smtp']['server']; ?></hostname>
+         <port><?=$autodiscover_config['smtp']['port']; ?></port>
          <socketType>SSL</socketType>
          <socketType>SSL</socketType>
          <username>%EMAILADDRESS%</username>
          <username>%EMAILADDRESS%</username>
          <authentication>password-cleartext</authentication>
          <authentication>password-cleartext</authentication>
       </outgoingServer>
       </outgoingServer>
       <outgoingServer type="smtp">
       <outgoingServer type="smtp">
-         <hostname><?=$configuration['smtp']['server']; ?></hostname>
-         <port><?=$configuration['smtp']['tlsport']; ?></port>
+         <hostname><?=$autodiscover_config['smtp']['server']; ?></hostname>
+         <port><?=$autodiscover_config['smtp']['tlsport']; ?></port>
          <socketType>STARTTLS</socketType>
          <socketType>STARTTLS</socketType>
          <username>%EMAILADDRESS%</username>
          <username>%EMAILADDRESS%</username>
          <authentication>password-cleartext</authentication>
          <authentication>password-cleartext</authentication>

+ 14 - 14
data/web/autodiscover.php

@@ -5,7 +5,7 @@ $default_autodiscover_config = $autodiscover_config;
 if(file_exists('inc/vars.local.inc.php')) {
 if(file_exists('inc/vars.local.inc.php')) {
   include_once 'inc/vars.local.inc.php';
   include_once 'inc/vars.local.inc.php';
 }
 }
-$configuration = array_merge($default_autodiscover_config, $autodiscover_config);
+$autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);
 
 
 // Redis
 // Redis
 $redis = new Redis();
 $redis = new Redis();
@@ -17,14 +17,14 @@ $data = trim(file_get_contents("php://input"));
 
 
 // Desktop client needs IMAP, unless it's Outlook 2013 or higher on Windows
 // Desktop client needs IMAP, unless it's Outlook 2013 or higher on Windows
 if (strpos($data, 'autodiscover/outlook/responseschema') !== false) { // desktop client
 if (strpos($data, 'autodiscover/outlook/responseschema') !== false) { // desktop client
-  $configuration['autodiscoverType'] = 'imap';
-  if ($configuration['useEASforOutlook'] == 'yes' &&
+  $autodiscover_config['autodiscoverType'] = 'imap';
+  if ($autodiscover_config['useEASforOutlook'] == 'yes' &&
     // Office for macOS does not support EAS
     // Office for macOS does not support EAS
     strpos($_SERVER['HTTP_USER_AGENT'], 'Mac') === false &&
     strpos($_SERVER['HTTP_USER_AGENT'], 'Mac') === false &&
     // Outlook 2013 (version 15) or higher
     // Outlook 2013 (version 15) or higher
     preg_match('/(Outlook|Office).+1[5-9]\./', $_SERVER['HTTP_USER_AGENT'])
     preg_match('/(Outlook|Office).+1[5-9]\./', $_SERVER['HTTP_USER_AGENT'])
   ) {
   ) {
-    $configuration['autodiscoverType'] = 'activesync';
+    $autodiscover_config['autodiscoverType'] = 'activesync';
   }
   }
 }
 }
 
 
@@ -88,7 +88,7 @@ else {
         $displayname = $email;
         $displayname = $email;
       }
       }
 
 
-      if ($configuration['autodiscoverType'] == 'imap') {
+      if ($autodiscover_config['autodiscoverType'] == 'imap') {
 ?>
 ?>
   <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
   <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
     <User>
     <User>
@@ -99,8 +99,8 @@ else {
       <Action>settings</Action>
       <Action>settings</Action>
       <Protocol>
       <Protocol>
         <Type>IMAP</Type>
         <Type>IMAP</Type>
-        <Server><?=$configuration['imap']['server'];?></Server>
-        <Port><?=$configuration['imap']['port'];?></Port>
+        <Server><?=$autodiscover_config['imap']['server'];?></Server>
+        <Port><?=$autodiscover_config['imap']['port'];?></Port>
         <DomainRequired>off</DomainRequired>
         <DomainRequired>off</DomainRequired>
         <LoginName><?=$email;?></LoginName>
         <LoginName><?=$email;?></LoginName>
         <SPA>off</SPA>
         <SPA>off</SPA>
@@ -109,8 +109,8 @@ else {
       </Protocol>
       </Protocol>
       <Protocol>
       <Protocol>
         <Type>SMTP</Type>
         <Type>SMTP</Type>
-        <Server><?=$configuration['smtp']['server'];?></Server>
-        <Port><?=$configuration['smtp']['port'];?></Port>
+        <Server><?=$autodiscover_config['smtp']['server'];?></Server>
+        <Port><?=$autodiscover_config['smtp']['port'];?></Port>
         <DomainRequired>off</DomainRequired>
         <DomainRequired>off</DomainRequired>
         <LoginName><?=$email;?></LoginName>
         <LoginName><?=$email;?></LoginName>
         <SPA>off</SPA>
         <SPA>off</SPA>
@@ -121,13 +121,13 @@ else {
       </Protocol>
       </Protocol>
       <Protocol>
       <Protocol>
         <Type>CalDAV</Type>
         <Type>CalDAV</Type>
-        <Server>https://<?=$configuration['caldav']['server'];?><?php if ($configuration['caldav']['port'] != 443) echo ':'.$configuration['caldav']['port']; ?>/SOGo/dav/<?=$email;?>/Calendar</Server>
+        <Server>https://<?=$autodiscover_config['caldav']['server'];?><?php if ($autodiscover_config['caldav']['port'] != 443) echo ':'.$autodiscover_config['caldav']['port']; ?>/SOGo/dav/<?=$email;?>/Calendar</Server>
         <DomainRequired>off</DomainRequired>
         <DomainRequired>off</DomainRequired>
         <LoginName><?=$email;?></LoginName>
         <LoginName><?=$email;?></LoginName>
       </Protocol>
       </Protocol>
       <Protocol>
       <Protocol>
         <Type>CardDAV</Type>
         <Type>CardDAV</Type>
-        <Server>https://<?=$configuration['carddav']['server'];?><?php if ($configuration['caldav']['port'] != 443) echo ':'.$configuration['carddav']['port']; ?>/SOGo/dav/<?=$email;?>/Contacts</Server>
+        <Server>https://<?=$autodiscover_config['carddav']['server'];?><?php if ($autodiscover_config['caldav']['port'] != 443) echo ':'.$autodiscover_config['carddav']['port']; ?>/SOGo/dav/<?=$email;?>/Contacts</Server>
         <DomainRequired>off</DomainRequired>
         <DomainRequired>off</DomainRequired>
         <LoginName><?=$email;?></LoginName>
         <LoginName><?=$email;?></LoginName>
       </Protocol>
       </Protocol>
@@ -135,7 +135,7 @@ else {
   </Response>
   </Response>
 <?php
 <?php
       }
       }
-      else if ($configuration['autodiscoverType'] == 'activesync') {
+      else if ($autodiscover_config['autodiscoverType'] == 'activesync') {
 ?>
 ?>
   <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006">
   <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/mobilesync/responseschema/2006">
     <Culture>en:en</Culture>
     <Culture>en:en</Culture>
@@ -147,8 +147,8 @@ else {
       <Settings>
       <Settings>
         <Server>
         <Server>
         <Type>MobileSync</Type>
         <Type>MobileSync</Type>
-        <Url><?=$configuration['activesync']['url'];?></Url>
-        <Name><?=$configuration['activesync']['url'];?></Name>
+        <Url><?=$autodiscover_config['activesync']['url'];?></Url>
+        <Name><?=$autodiscover_config['activesync']['url'];?></Name>
         </Server>
         </Server>
       </Settings>
       </Settings>
     </Action>
     </Action>

+ 8 - 0
data/web/inc/functions.dkim.inc.php

@@ -187,6 +187,14 @@ function dkim($_action, $_data = null) {
         }
         }
         $dkimdata['dkim_txt'] = 'v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data;
         $dkimdata['dkim_txt'] = 'v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data;
         $dkimdata['dkim_selector'] = $redis->hGet('DKIM_SELECTORS', $_data);
         $dkimdata['dkim_selector'] = $redis->hGet('DKIM_SELECTORS', $_data);
+        $dkimdata['privkey'] = $redis->hGet('DKIM_PRIV_KEYS', $dkimdata['dkim_selector'] . $_data);
+        if ($GLOBALS['SHOW_DKIM_PRIV_KEYS'] === true) {
+          $dkimdata['privkey'] = base64_encode($redis->hGet('DKIM_PRIV_KEYS', $dkimdata['dkim_selector'] . '.' . $_data));
+        }
+        else {
+          $dkimdata['privkey'] = base64_encode('Please set $SHOW_DKIM_PRIV_KEYS to true to show DKIM private keys.');
+        }
+        
       }
       }
       return $dkimdata;
       return $dkimdata;
     break;
     break;

+ 3 - 1
data/web/inc/prerequisites.inc.php

@@ -1,8 +1,10 @@
 <?php
 <?php
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.inc.php';
+require_once 'inc/vars.inc.php';
+$default_autodiscover_config = $autodiscover_config;
 if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php')) {
 if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php')) {
   include_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php';
   include_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php';
 }
 }
+$autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);
 
 
 require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
 require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
 
 

+ 3 - 0
data/web/inc/vars.inc.php

@@ -82,6 +82,9 @@ $DEFAULT_THEME = 'lumen';
 // Password complexity as regular expression
 // Password complexity as regular expression
 $PASSWD_REGEP = '.{4,}';
 $PASSWD_REGEP = '.{4,}';
 
 
+// Show DKIM private keys - false by default
+$SHOW_DKIM_PRIV_KEYS = false;
+
 // mailcow Apps - buttons on login screen
 // mailcow Apps - buttons on login screen
 $MAILCOW_APPS = array(
 $MAILCOW_APPS = array(
   array(
   array(

+ 102 - 0
data/web/js/admin.js

@@ -1,3 +1,96 @@
+var Base64 = {
+    _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
+    encode: function(e) {
+        var t = "";
+        var n, r, i, s, o, u, a;
+        var f = 0;
+        e = Base64._utf8_encode(e);
+        while (f < e.length) {
+            n = e.charCodeAt(f++);
+            r = e.charCodeAt(f++);
+            i = e.charCodeAt(f++);
+            s = n >> 2;
+            o = (n & 3) << 4 | r >> 4;
+            u = (r & 15) << 2 | i >> 6;
+            a = i & 63;
+            if (isNaN(r)) {
+                u = a = 64
+            } else if (isNaN(i)) {
+                a = 64
+            }
+            t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) +
+                this._keyStr.charAt(u) + this._keyStr.charAt(a)
+        }
+        return t
+    },
+    decode: function(e) {
+        var t = "";
+        var n, r, i;
+        var s, o, u, a;
+        var f = 0;
+        e = e.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+        while (f < e.length) {
+            s = this._keyStr.indexOf(e.charAt(f++));
+            o = this._keyStr.indexOf(e.charAt(f++));
+            u = this._keyStr.indexOf(e.charAt(f++));
+            a = this._keyStr.indexOf(e.charAt(f++));
+            n = s << 2 | o >> 4;
+            r = (o & 15) << 4 | u >> 2;
+            i = (u & 3) << 6 | a;
+            t = t + String.fromCharCode(n);
+            if (u != 64) {
+                t = t + String.fromCharCode(r)
+            }
+            if (a != 64) {
+                t = t + String.fromCharCode(i)
+            }
+        }
+        t = Base64._utf8_decode(t);
+        return t
+    },
+    _utf8_encode: function(e) {
+        e = e.replace(/\r\n/g, "\n");
+        var t = "";
+        for (var n = 0; n < e.length; n++) {
+            var r = e.charCodeAt(n);
+            if (r < 128) {
+                t += String.fromCharCode(r)
+            } else if (r > 127 && r < 2048) {
+                t += String.fromCharCode(r >> 6 | 192);
+                t += String.fromCharCode(r & 63 | 128)
+            } else {
+                t += String.fromCharCode(r >> 12 | 224);
+                t += String.fromCharCode(r >> 6 & 63 | 128);
+                t += String.fromCharCode(r & 63 | 128)
+            }
+        }
+        return t
+    },
+    _utf8_decode: function(e) {
+        var t = "";
+        var n = 0;
+        var r = c1 = c2 = 0;
+        while (n < e.length) {
+            r = e.charCodeAt(n);
+            if (r < 128) {
+                t += String.fromCharCode(r);
+                n++
+            } else if (r > 191 && r < 224) {
+                c2 = e.charCodeAt(n + 1);
+                t += String.fromCharCode((r & 31) << 6 | c2 & 63);
+                n += 2
+            } else {
+                c2 = e.charCodeAt(n + 1);
+                c3 = e.charCodeAt(n + 2);
+                t += String.fromCharCode((r & 15) << 12 | (c2 & 63) <<
+                    6 | c3 & 63);
+                n += 3
+            }
+        }
+        return t
+    }
+}
+
 jQuery(function($){
 jQuery(function($){
   // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
   // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
   var entityMap = {
   var entityMap = {
@@ -560,6 +653,15 @@ jQuery(function($){
     }
     }
   })
   })
 
 
+  $('#showDKIMprivKey').on('show.bs.modal', function (e) {
+    $('#priv_key_pre').text("-");
+    p_related = $(e.relatedTarget)
+    if (p_related != null) {
+      var decoded_key = Base64.decode((p_related.data('priv-key')));
+      $('#priv_key_pre').text(decoded_key);
+    }
+  })
+
   $('#test_relayhost').on('click', function (e) {
   $('#test_relayhost').on('click', function (e) {
     e.preventDefault();
     e.preventDefault();
     prev = $('#test_relayhost').text();
     prev = $('#test_relayhost').text();

+ 1 - 0
data/web/lang/lang.de.php

@@ -108,6 +108,7 @@ $lang['user']['user_settings'] = 'Benutzereinstellungen';
 $lang['user']['mailbox_settings'] = 'Mailbox-Einstellungen';
 $lang['user']['mailbox_settings'] = 'Mailbox-Einstellungen';
 $lang['user']['mailbox_details'] = 'Mailbox-Details';
 $lang['user']['mailbox_details'] = 'Mailbox-Details';
 $lang['user']['change_password'] = 'Passwort ändern';
 $lang['user']['change_password'] = 'Passwort ändern';
+$lang['user']['client_configuration'] = 'Konfigurationsanleitungen für E-Mail-Programme und Smartphones anzeigen';
 $lang['user']['new_password'] = 'Neues Passwort';
 $lang['user']['new_password'] = 'Neues Passwort';
 $lang['user']['save_changes'] = 'Änderungen speichern';
 $lang['user']['save_changes'] = 'Änderungen speichern';
 $lang['user']['password_now'] = 'Aktuelles Passwort (Änderungen bestätigen)';
 $lang['user']['password_now'] = 'Aktuelles Passwort (Änderungen bestätigen)';

+ 1 - 0
data/web/lang/lang.en.php

@@ -110,6 +110,7 @@ $lang['user']['user_settings'] = 'User settings';
 $lang['user']['mailbox_settings'] = 'Mailbox settings';
 $lang['user']['mailbox_settings'] = 'Mailbox settings';
 $lang['user']['mailbox_details'] = 'Mailbox details';
 $lang['user']['mailbox_details'] = 'Mailbox details';
 $lang['user']['change_password'] = 'Change password';
 $lang['user']['change_password'] = 'Change password';
+$lang['user']['client_configuration'] = 'Show configuration guides for email clients and smartphones';
 $lang['user']['new_password'] = 'New password';
 $lang['user']['new_password'] = 'New password';
 $lang['user']['save_changes'] = 'Save changes';
 $lang['user']['save_changes'] = 'Save changes';
 $lang['user']['password_now'] = 'Current password (confirm changes)';
 $lang['user']['password_now'] = 'Current password (confirm changes)';

+ 14 - 0
data/web/modals/admin.php

@@ -91,3 +91,17 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
     </div>
     </div>
   </div>
   </div>
 </div><!-- test relayhost modal -->
 </div><!-- test relayhost modal -->
+<!-- priv key modal -->
+<div class="modal fade" id="showDKIMprivKey" tabindex="-1" role="dialog" aria-hidden="true">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+        <h3 class="modal-title"><span class="glyphicon glyphicon-lock"></span> Private key</h3>
+      </div>
+      <div class="modal-body">
+      <pre id="priv_key_pre"></pre>
+      </div>
+    </div>
+  </div>
+</div><!-- priv key modal -->

+ 20 - 3
data/web/user.php

@@ -60,10 +60,26 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
   / USER
   / USER
   */
   */
 
 
-	require_once("inc/header.inc.php");
-	$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
-	$username = $_SESSION['mailcow_cc_username'];
+  require_once("inc/header.inc.php");
+  $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
+  $username = $_SESSION['mailcow_cc_username'];
   $mailboxdata = mailbox('get', 'mailbox_details', $username);
   $mailboxdata = mailbox('get', 'mailbox_details', $username);
+
+  $clientconfigstr = "host=" . urlencode($mailcow_hostname) . "&email=" . urlencode($username) . "&name=" . urlencode($mailboxdata['name']) . "&port=" . urlencode($autodiscover_config['caldav']['port']);
+  if ($autodiscover_config['useEASforOutlook'] == 'yes')
+  $clientconfigstr .= "&outlookEAS=1";
+  if (file_exists('thunderbird-plugins/version.csv')) {
+    $fh = fopen('thunderbird-plugins/version.csv', 'r');
+    if ($fh) {
+      while (($row = fgetcsv($fh, 1000, ';')) !== FALSE) {
+        if ($row[0] == 'sogo-integrator@inverse.ca') {
+          $clientconfigstr .= "&integrator=" . urlencode($row[1]);
+        }
+      }
+      fclose($fh);
+    }
+  }
+
 ?>
 ?>
 <div class="container">
 <div class="container">
 <h3><?=$lang['user']['user_settings'];?></h3>
 <h3><?=$lang['user']['user_settings'];?></h3>
@@ -74,6 +90,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
   <div class="row">
   <div class="row">
     <div class="col-sm-offset-3 col-sm-9">
     <div class="col-sm-offset-3 col-sm-9">
       <p><a href="#pwChangeModal" data-toggle="modal">[<?=$lang['user']['change_password'];?>]</a></p>
       <p><a href="#pwChangeModal" data-toggle="modal">[<?=$lang['user']['change_password'];?>]</a></p>
+      <p><a target="_blank" href="https://mailcow.github.io/mailcow-dockerized-docs/client/#<?=$clientconfigstr;?>">[<?=$lang['user']['client_configuration'];?>]</a></p>
     </div>
     </div>
   </div>
   </div>
   <hr>
   <hr>

+ 13 - 35
docker-compose.yml

@@ -1,18 +1,14 @@
-version: '2.1'
+version: '2.3'
 services:
 services:
 
 
     unbound-mailcow:
     unbound-mailcow:
       image: mailcow/unbound:1.0
       image: mailcow/unbound:1.0
       build: ./data/Dockerfiles/unbound
       build: ./data/Dockerfiles/unbound
       command: /usr/sbin/unbound
       command: /usr/sbin/unbound
+      init: true
       depends_on:
       depends_on:
         mysql-mailcow:
         mysql-mailcow:
           condition: service_healthy
           condition: service_healthy
-      healthcheck:
-        test: ["CMD", "nslookup", "mailcow.email", "127.0.0.1"]
-        interval: 30s
-        timeout: 3s
-        retries: 10
       volumes:
       volumes:
         - ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro
         - ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro
       restart: always
       restart: always
@@ -38,6 +34,7 @@ services:
         - MYSQL_DATABASE=${DBNAME}
         - MYSQL_DATABASE=${DBNAME}
         - MYSQL_USER=${DBUSER}
         - MYSQL_USER=${DBUSER}
         - MYSQL_PASSWORD=${DBPASS}
         - MYSQL_PASSWORD=${DBPASS}
+      init: true
       restart: always
       restart: always
       dns:
       dns:
         - 172.22.1.254
         - 172.22.1.254
@@ -50,9 +47,6 @@ services:
 
 
     redis-mailcow:
     redis-mailcow:
       image: redis:alpine
       image: redis:alpine
-      depends_on:
-        unbound-mailcow:
-          condition: service_healthy
       volumes:
       volumes:
         - redis-vol-1:/data/
         - redis-vol-1:/data/
       restart: always
       restart: always
@@ -66,11 +60,12 @@ services:
             - redis
             - redis
 
 
     clamd-mailcow:
     clamd-mailcow:
-      image: mailcow/clamd:1.2
+      image: mailcow/clamd:1.3
       build: ./data/Dockerfiles/clamd
       build: ./data/Dockerfiles/clamd
       restart: on-failure
       restart: on-failure
       environment:
       environment:
         - SKIP_CLAMD=${SKIP_CLAMD:-n}
         - SKIP_CLAMD=${SKIP_CLAMD:-n}
+      init: true
       dns:
       dns:
         - 172.22.1.254
         - 172.22.1.254
       dns_search: mailcow-network
       dns_search: mailcow-network
@@ -80,13 +75,9 @@ services:
             - clamd
             - clamd
 
 
     rspamd-mailcow:
     rspamd-mailcow:
-      image: mailcow/rspamd:1.6
+      image: mailcow/rspamd:1.7
       build: ./data/Dockerfiles/rspamd
       build: ./data/Dockerfiles/rspamd
-      command: > 
-        /bin/bash -c "
-        sleep 5;
-        /usr/bin/rspamd -f -u _rspamd -g _rspamd
-        "
+      command: "/usr/bin/rspamd -f -u _rspamd -g _rspamd"
       depends_on:
       depends_on:
         - nginx-mailcow
         - nginx-mailcow
       volumes:
       volumes:
@@ -97,6 +88,7 @@ services:
         - dkim-vol-1:/data/dkim
         - dkim-vol-1:/data/dkim
         - rspamd-vol-1:/var/lib/rspamd
         - rspamd-vol-1:/var/lib/rspamd
       restart: always
       restart: always
+      init: true
       dns:
       dns:
         - 172.22.1.254
         - 172.22.1.254
       dns_search: mailcow-network
       dns_search: mailcow-network
@@ -142,9 +134,6 @@ services:
     sogo-mailcow:
     sogo-mailcow:
       image: mailcow/sogo:1.8
       image: mailcow/sogo:1.8
       build: ./data/Dockerfiles/sogo
       build: ./data/Dockerfiles/sogo
-      depends_on:
-        unbound-mailcow:
-          condition: service_healthy
       environment:
       environment:
         - DBNAME=${DBNAME}
         - DBNAME=${DBNAME}
         - DBUSER=${DBUSER}
         - DBUSER=${DBUSER}
@@ -166,9 +155,6 @@ services:
     dovecot-mailcow:
     dovecot-mailcow:
       image: mailcow/dovecot:1.8
       image: mailcow/dovecot:1.8
       build: ./data/Dockerfiles/dovecot
       build: ./data/Dockerfiles/dovecot
-      depends_on:
-        unbound-mailcow:
-          condition: service_healthy
       volumes:
       volumes:
         - ./data/conf/dovecot:/usr/local/etc/dovecot
         - ./data/conf/dovecot:/usr/local/etc/dovecot
         - ./data/assets/ssl:/etc/ssl/mail/:ro
         - ./data/assets/ssl:/etc/ssl/mail/:ro
@@ -204,9 +190,6 @@ services:
     postfix-mailcow:
     postfix-mailcow:
       image: mailcow/postfix:1.4
       image: mailcow/postfix:1.4
       build: ./data/Dockerfiles/postfix
       build: ./data/Dockerfiles/postfix
-      depends_on:
-        unbound-mailcow:
-          condition: service_healthy
       volumes:
       volumes:
         - ./data/conf/postfix:/opt/postfix/conf
         - ./data/conf/postfix:/opt/postfix/conf
         - ./data/assets/ssl:/etc/ssl/mail/:ro
         - ./data/assets/ssl:/etc/ssl/mail/:ro
@@ -232,9 +215,6 @@ services:
 
 
     memcached-mailcow:
     memcached-mailcow:
       image: memcached:alpine
       image: memcached:alpine
-      depends_on:
-        unbound-mailcow:
-          condition: service_healthy
       restart: always
       restart: always
       dns:
       dns:
         - 172.22.1.254
         - 172.22.1.254
@@ -249,15 +229,11 @@ services:
         - sogo-mailcow
         - sogo-mailcow
         - php-fpm-mailcow
         - php-fpm-mailcow
       image: nginx:mainline-alpine
       image: nginx:mainline-alpine
-      healthcheck:
-        test: ["CMD", "ping", "php-fpm-mailcow", "-c", "5"]
-        interval: 5s
-        timeout: 5s
-        retries: 10
       command: /bin/sh -c "envsubst < /etc/nginx/conf.d/templates/listen_plain.template > /etc/nginx/conf.d/listen_plain.active &&
       command: /bin/sh -c "envsubst < /etc/nginx/conf.d/templates/listen_plain.template > /etc/nginx/conf.d/listen_plain.active &&
         envsubst < /etc/nginx/conf.d/templates/listen_ssl.template > /etc/nginx/conf.d/listen_ssl.active &&
         envsubst < /etc/nginx/conf.d/templates/listen_ssl.template > /etc/nginx/conf.d/listen_ssl.active &&
         envsubst < /etc/nginx/conf.d/templates/server_name.template > /etc/nginx/conf.d/server_name.active &&
         envsubst < /etc/nginx/conf.d/templates/server_name.template > /etc/nginx/conf.d/server_name.active &&
-        nginx -g 'daemon off;'"
+        until ping phpfpm -c1 > /dev/null; do sleep 1; done &&
+        exec nginx -g 'daemon off;'"
       environment:
       environment:
         - HTTPS_PORT=${HTTPS_PORT:-443}
         - HTTPS_PORT=${HTTPS_PORT:-443}
         - HTTP_PORT=${HTTP_PORT:-80}
         - HTTP_PORT=${HTTP_PORT:-80}
@@ -283,8 +259,9 @@ services:
     acme-mailcow:
     acme-mailcow:
       depends_on:
       depends_on:
         - nginx-mailcow
         - nginx-mailcow
-      image: mailcow/acme:1.16
+      image: mailcow/acme:1.17
       build: ./data/Dockerfiles/acme
       build: ./data/Dockerfiles/acme
+      init: true
       dns:
       dns:
         - 172.22.1.254
         - 172.22.1.254
       dns_search: mailcow-network
       dns_search: mailcow-network
@@ -319,6 +296,7 @@ services:
         - redis-mailcow
         - redis-mailcow
       restart: always
       restart: always
       privileged: true
       privileged: true
+      init: true
       environment:
       environment:
         - TZ=${TZ}
         - TZ=${TZ}
         - SKIP_FAIL2BAN=${SKIP_FAIL2BAN:-no}
         - SKIP_FAIL2BAN=${SKIP_FAIL2BAN:-no}