From 96ed94dedde26cf914f6a665ac0b74cce6248e14 Mon Sep 17 00:00:00 2001 From: Michael Kuron Date: Sun, 2 Jul 2017 13:44:05 +0200 Subject: [PATCH 1/3] Client configuration guides - iOS mobileconfig generator - non-443 HTTPS ports in autoconfig etc. - disabling POP service via SRV record - fix display name in Outlook IMAP autodiscover - allow multiple calls to TLSA generator and support Sieve STARTTLS --- data/Dockerfiles/sogo/Dockerfile | 1 + data/web/autoconfig.php | 47 +++-- data/web/autodiscover.php | 54 ++--- data/web/clientconfig.php | 185 ++++++++++++++++++ data/web/inc/functions.inc.php | 24 ++- data/web/inc/vars.inc.php | 27 ++- data/web/lang/lang.de.php | 1 + data/web/lang/lang.en.php | 1 + data/web/mobileconfig.php | 167 ++++++++++++++++ data/web/thunderbird-plugins/build-plugins.sh | 6 +- data/web/user.php | 1 + docker-compose.yml | 2 +- 12 files changed, 460 insertions(+), 56 deletions(-) create mode 100644 data/web/clientconfig.php create mode 100644 data/web/mobileconfig.php diff --git a/data/Dockerfiles/sogo/Dockerfile b/data/Dockerfiles/sogo/Dockerfile index a3a1308d..b9db3c1c 100644 --- a/data/Dockerfiles/sogo/Dockerfile +++ b/data/Dockerfiles/sogo/Dockerfile @@ -8,6 +8,7 @@ ENV GOSU_VERSION 1.9 # Prerequisites RUN apt-get update && apt-get install -y --no-install-recommends \ apt-transport-https \ + bind9-host \ ca-certificates \ cron \ gnupg \ diff --git a/data/web/autoconfig.php b/data/web/autoconfig.php index d01bc724..523d6183 100644 --- a/data/web/autoconfig.php +++ b/data/web/autoconfig.php @@ -5,6 +5,16 @@ if (empty($mailcow_hostname)) { exit(); } +$domain_dot = strpos($_SERVER['HTTP_HOST'], '.'); +$domain_port = strpos($_SERVER['HTTP_HOST'], ':'); +if ($domain_port === FALSE) { + $domain = substr($_SERVER['HTTP_HOST'], $domain_dot+1); + $port = 443; +} else { + $domain = substr($_SERVER['HTTP_HOST'], $domain_dot+1, $domain_port-$domain_dot-1); + $port = substr($_SERVER['HTTP_HOST'], $domain_port+1); +} + header('Content-Type: application/xml'); ?> '; ?> @@ -15,52 +25,59 @@ header('Content-Type: application/xml'); mail server - - 993 + + SSL %EMAILADDRESS% password-cleartext - - 143 + + STARTTLS %EMAILADDRESS% password-cleartext + - - 995 + + SSL %EMAILADDRESS% password-cleartext + + - - 110 + + STARTTLS %EMAILADDRESS% password-cleartext + - - 465 + + SSL %EMAILADDRESS% password-cleartext - - - 587 + + STARTTLS %EMAILADDRESS% password-cleartext - + If you didn't change the password given to you by the administrator or if you didn't change it in a long time, please consider doing that now. Sollten Sie das Ihnen durch den Administrator vergebene Passwort noch nicht geändert haben, empfehlen wir dies nun zu tun. Auch ein altes Passwort sollte aus Sicherheitsgründen geändert werden. @@ -68,6 +85,6 @@ header('Content-Type: application/xml'); - + diff --git a/data/web/autodiscover.php b/data/web/autodiscover.php index fd8cd641..7f6081ae 100644 --- a/data/web/autodiscover.php +++ b/data/web/autodiscover.php @@ -12,13 +12,14 @@ error_reporting(0); $data = trim(file_get_contents("php://input")); // Desktop client needs IMAP, unless it's Outlook 2013 or higher on Windows -if (strpos($data, 'autodiscover/outlook/responseschema')) { // desktop client +if (strpos($data, 'autodiscover/outlook/responseschema') !== false) { // desktop client $configuration['autodiscoverType'] = 'imap'; if ($configuration['useEASforOutlook'] == 'yes' && - // Office for macOS does not support EAS - strpos($_SERVER['HTTP_USER_AGENT'], 'Mac') === false && - // Outlook 2013 (version 15) or higher - preg_match('/(Outlook|Office).+1[5-9]\./', $_SERVER['HTTP_USER_AGENT'])) { + // Office for macOS does not support EAS + strpos($_SERVER['HTTP_USER_AGENT'], 'Mac') === false && + // Outlook 2013 (version 15) or higher + preg_match('/(Outlook|Office).+1[5-9]\./', $_SERVER['HTTP_USER_AGENT']) + ) { $configuration['autodiscoverType'] = 'activesync'; } } @@ -60,8 +61,28 @@ else { Request->EMailAddress; + try { + $discover = new SimpleXMLElement($data); + $email = $discover->Request->EMailAddress; + } catch (Exception $e) { + $email = $_SERVER['PHP_AUTH_USER']; + } + + $username = trim($email); + try { + $stmt = $pdo->prepare("SELECT `name` FROM `mailbox` WHERE `username`= :username"); + $stmt->execute(array(':username' => $username)); + $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC); + } + catch(PDOException $e) { + die("Failed to determine name from SQL"); + } + if (!empty($MailboxData['name'])) { + $displayname = utf8_encode($MailboxData['name']); + } + else { + $displayname = $email; + } if ($configuration['autodiscoverType'] == 'imap') { ?> @@ -96,13 +117,13 @@ else { CalDAV - /SOGo/dav//Calendar + https:///SOGo/dav//Calendar off CardDAV - /SOGo/dav//Contacts + https:///SOGo/dav//Contacts off @@ -111,21 +132,6 @@ else { prepare("SELECT `name` FROM `mailbox` WHERE `username`= :username"); - $stmt->execute(array(':username' => $username)); - $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC); - } - catch(PDOException $e) { - die("Failed to determine name from SQL"); - } - if (!empty($MailboxData['name'])) { - $displayname = utf8_encode($MailboxData['name']); - } - else { - $displayname = $email; - } ?> en:en diff --git a/data/web/clientconfig.php b/data/web/clientconfig.php new file mode 100644 index 00000000..68722a89 --- /dev/null +++ b/data/web/clientconfig.php @@ -0,0 +1,185 @@ +prepare("SELECT `name` FROM `mailbox` WHERE `username`= :username"); + $stmt->execute(array(':username' => $username)); + $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC); +} +catch(PDOException $e) { + die("Failed to determine name from SQL"); +} +if (!empty($MailboxData['name'])) { + $displayname = utf8_encode($MailboxData['name']); +} +else { + $displayname = $email; +} +?> +
+

Client Configuration Guide

+

Select your email client or operating system below to view a step-by-step guide to setting up your email account.

+ +

Apple macOS / iOS

+ + +

Android

+ + +

eM Client

+ + +

KDE Kontact

+ + +

Microsoft Outlook

+ + +

Mozilla Thunderbird

+ + +

Windows

+ + +

Windows Phone

+ +
+ + diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 8e7b7cfd..ffca2bea 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -62,17 +62,17 @@ function hasMailboxObjectAccess($username, $role, $object) { } return false; } +function pem_to_der($pem_key) { + // Need to remove BEGIN/END PUBLIC KEY + $lines = explode("\n", trim($pem_key)); + unset($lines[count($lines)-1]); + unset($lines[0]); + return base64_decode(implode('', $lines)); +} function generate_tlsa_digest($hostname, $port, $starttls = null) { if (!is_valid_domain_name($hostname)) { return "Not a valid hostname"; } - function pem_to_der($pem_key) { - // Need to remove BEGIN/END PUBLIC KEY - $lines = explode("\n", trim($pem_key)); - unset($lines[count($lines)-1]); - unset($lines[0]); - return base64_decode(implode('', $lines)); - } if (empty($starttls)) { $context = stream_context_create(array("ssl" => array("capture_peer_cert" => true, 'verify_peer' => false, 'allow_self_signed' => true))); @@ -88,20 +88,24 @@ function generate_tlsa_digest($hostname, $port, $starttls = null) { return $error_nr . ': ' . $error_msg; } $banner = fread($stream, 512 ); - if (preg_match("/^220/i", $banner)) { + if (preg_match("/^220/i", $banner)) { // SMTP fwrite($stream,"HELO tlsa.generator.local\r\n"); fread($stream, 512); fwrite($stream,"STARTTLS\r\n"); fread($stream, 512); } - elseif (preg_match("/imap.+starttls/i", $banner)) { + elseif (preg_match("/imap.+starttls/i", $banner)) { // IMAP fwrite($stream,"A1 STARTTLS\r\n"); fread($stream, 512); } - elseif (preg_match("/^\+OK/", $banner)) { + elseif (preg_match("/^\+OK/", $banner)) { // POP3 fwrite($stream,"STLS\r\n"); fread($stream, 512); } + elseif (preg_match("/^OK/m", $banner)) { // Sieve + fwrite($stream,"STARTTLS\r\n"); + fread($stream, 512); + } else { return 'Unknown banner: "' . htmlspecialchars(trim($banner)) . '"'; } diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php index a52442db..05ef25dd 100644 --- a/data/web/inc/vars.inc.php +++ b/data/web/inc/vars.inc.php @@ -18,31 +18,48 @@ $database_name = getenv('DBNAME'); $mailcow_hostname = getenv('MAILCOW_HOSTNAME'); // Autodiscover settings +$https_port = strpos($_SERVER['HTTP_HOST'], ':'); +if ($https_port === FALSE) { + $https_port = 443; +} else { + $https_port = substr($_SERVER['HTTP_HOST'], $https_port+1); +} $autodiscover_config = array( // Enable the autodiscover service for Outlook desktop clients 'useEASforOutlook' => 'yes', // General autodiscover service type: "activesync" or "imap" 'autodiscoverType' => 'activesync', - // Please don't use STARTTLS-enabled service ports here. + // Please don't use STARTTLS-enabled service ports in the "port" variable. // The autodiscover service will always point to SMTPS and IMAPS (TLS-wrapped services). + // The autoconfig service will additionally announce the STARTTLS-enabled ports, specified in the "tlsport" variable. 'imap' => array( 'server' => $mailcow_hostname, 'port' => getenv('IMAPS_PORT'), + 'tlsport' => getenv('IMAP_PORT'), + ), + 'pop3' => array( + 'server' => $mailcow_hostname, + 'port' => getenv('POPS_PORT'), + 'tlsport' => getenv('POP_PORT'), ), 'smtp' => array( 'server' => $mailcow_hostname, 'port' => getenv('SMTPS_PORT'), + 'tlsport' => getenv('SUBMISSION_PORT'), ), 'activesync' => array( - 'url' => 'https://'.$mailcow_hostname.'/Microsoft-Server-ActiveSync' + 'url' => 'https://'.$mailcow_hostname.($https_port == 443 ? '' : ':'.$https_port).'/Microsoft-Server-ActiveSync', ), 'caldav' => array( - 'url' => 'https://'.$mailcow_hostname + 'server' => $mailcow_hostname, + 'port' => $https_port, ), 'carddav' => array( - 'url' => 'https://'.$mailcow_hostname - ) + 'server' => $mailcow_hostname, + 'port' => $https_port, + ), ); +unset($https_port); // Where to go after adding and editing objects // Can be "form" or "previous" diff --git a/data/web/lang/lang.de.php b/data/web/lang/lang.de.php index eef13b3f..8706e4ba 100644 --- a/data/web/lang/lang.de.php +++ b/data/web/lang/lang.de.php @@ -108,6 +108,7 @@ $lang['user']['user_settings'] = 'Benutzereinstellungen'; $lang['user']['mailbox_settings'] = 'Mailbox-Einstellungen'; $lang['user']['mailbox_details'] = 'Mailbox-Details'; $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']['save_changes'] = 'Änderungen speichern'; $lang['user']['password_now'] = 'Aktuelles Passwort (Änderungen bestätigen)'; diff --git a/data/web/lang/lang.en.php b/data/web/lang/lang.en.php index 3be72fec..fceef80f 100644 --- a/data/web/lang/lang.en.php +++ b/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_details'] = 'Mailbox details'; $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']['save_changes'] = 'Save changes'; $lang['user']['password_now'] = 'Current password (confirm changes)'; diff --git a/data/web/mobileconfig.php b/data/web/mobileconfig.php new file mode 100644 index 00000000..198fa4d7 --- /dev/null +++ b/data/web/mobileconfig.php @@ -0,0 +1,167 @@ +prepare("SELECT `name` FROM `mailbox` WHERE `username`= :username"); + $stmt->execute(array(':username' => $email)); + $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC); +} +catch(PDOException $e) { + die("Failed to determine name from SQL"); +} +if (!empty($MailboxData['name'])) { + $displayname = utf8_encode($MailboxData['name']); +} +else { + $displayname = $email; +} + +echo '' . "\n"; +?> + + + + PayloadContent + + + CalDAVAccountDescription + + CalDAVHostName + + CalDAVPort + + CalDAVPrincipalURL + /SOGo/dav/ + CalDAVUseSSL + + CalDAVUsername + + PayloadDescription + Configures CalDAV account. + PayloadDisplayName + CalDAV () + PayloadIdentifier + .CalDAV + PayloadOrganization + + PayloadType + com.apple.caldav.account + PayloadUUID + FC898573-EBA8-48AF-93BD-BFA0C9778FA7 + PayloadVersion + 1 + + + EmailAccountDescription + + EmailAccountType + EmailTypeIMAP + EmailAccountName + + EmailAddress + + IncomingMailServerAuthentication + EmailAuthPassword + IncomingMailServerHostName + + IncomingMailServerPortNumber + + IncomingMailServerUseSSL + + IncomingMailServerUsername + + OutgoingMailServerAuthentication + EmailAuthPassword + OutgoingMailServerHostName + + OutgoingMailServerPortNumber + + OutgoingMailServerUseSSL + + OutgoingMailServerUsername + + OutgoingPasswordSameAsIncomingPassword + + PayloadDescription + Configures email account. + PayloadDisplayName + IMAP Account () + PayloadIdentifier + .email + PayloadOrganization + + PayloadType + com.apple.mail.managed + PayloadUUID + 00294FBB-1016-413E-87B9-652D856D6875 + PayloadVersion + 1 + PreventAppSheet + + PreventMove + + SMIMEEnabled + + + + CardDAVAccountDescription + + CardDAVHostName + + CardDAVPort + + CardDAVPrincipalURL + /SOGo/dav/ + CardDAVUseSSL + + CardDAVUsername + + PayloadDescription + Configures CardDAV accounts + PayloadDisplayName + CardDAV () + PayloadIdentifier + .carddav + PayloadOrganization + + PayloadType + com.apple.carddav.account + PayloadUUID + 0797EF2B-B1F1-4BC7-ABCD-4580862252B4 + PayloadVersion + 1 + + + PayloadDescription + IMAP, CalDAV, CardDAV + PayloadDisplayName + Mailcow + PayloadIdentifier + + PayloadOrganization + + PayloadRemovalDisallowed + + PayloadType + Configuration + PayloadUUID + 5EE248C5-ACCB-42D8-9199-8F8ED08D5624 + PayloadVersion + 1 + + diff --git a/data/web/thunderbird-plugins/build-plugins.sh b/data/web/thunderbird-plugins/build-plugins.sh index 03986b78..53199e61 100755 --- a/data/web/thunderbird-plugins/build-plugins.sh +++ b/data/web/thunderbird-plugins/build-plugins.sh @@ -16,11 +16,15 @@ tar --strip-components=1 -C connector -xf connector.tar.gz # build custom integrator while read DOMAIN; do echo "Building SOGo Integrator for $DOMAIN hosted on $MAILHOST" + PORT_NUM=$(dig -t srv _autodiscover._tcp.$DOMAIN +short | tail -n 1 | awk '{print $3}') + if [[ -z ${PORT_NUM} ]]; then + PORT_NUM=443 + fi cd integrator echo > defaults/preferences/site.js mkdir -p custom/${DOMAIN} cp -r custom/sogo-demo/* custom/${DOMAIN}/ - sed -i "s/http:\/\/sogo-demo\.inverse\.ca/https:\/\/${MAILHOST}/g" custom/${DOMAIN}/chrome/content/extensions.rdf + sed -i "s/http:\/\/sogo-demo\.inverse\.ca/https:\/\/${MAILHOST}:${PORT_NUM}/g" custom/${DOMAIN}/chrome/content/extensions.rdf sed -i "s/plugins\/updates\.php[?]/thunderbird-plugins.php?domain=${DOMAIN}\&/g" custom/${DOMAIN}/chrome/content/extensions.rdf echo 'pref("sogo-integrator.autocomplete.server.urlid", "'${DOMAIN}'");' > custom/${DOMAIN}/defaults/preferences/site.js echo 'pref("mail.collect_email_address_outgoing", false);' >> custom/${DOMAIN}/defaults/preferences/site.js diff --git a/data/web/user.php b/data/web/user.php index 77ccc62d..ba7678e2 100644 --- a/data/web/user.php +++ b/data/web/user.php @@ -74,6 +74,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '

[]

+

[]


diff --git a/docker-compose.yml b/docker-compose.yml index 853dbc36..e8a7e0c4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -143,7 +143,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.0 + image: mailcow/sogo:1.1 build: ./data/Dockerfiles/sogo depends_on: unbound-mailcow: From b88190988e3b154b2b93e875f6266e8f6a4d131f Mon Sep 17 00:00:00 2001 From: Michael Kuron Date: Tue, 4 Jul 2017 19:58:30 +0200 Subject: [PATCH 2/3] Autodiscover: Strip bind addresses off of port environment variables --- data/web/inc/vars.inc.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php index 05ef25dd..775af1e1 100644 --- a/data/web/inc/vars.inc.php +++ b/data/web/inc/vars.inc.php @@ -34,18 +34,18 @@ $autodiscover_config = array( // The autoconfig service will additionally announce the STARTTLS-enabled ports, specified in the "tlsport" variable. 'imap' => array( 'server' => $mailcow_hostname, - 'port' => getenv('IMAPS_PORT'), - 'tlsport' => getenv('IMAP_PORT'), + 'port' => array_pop(explode(':', getenv('IMAPS_PORT'))), + 'tlsport' => array_pop(explode(':', getenv('IMAP_PORT'))), ), 'pop3' => array( 'server' => $mailcow_hostname, - 'port' => getenv('POPS_PORT'), - 'tlsport' => getenv('POP_PORT'), + 'port' => array_pop(explode(':', getenv('POPS_PORT'))), + 'tlsport' => array_pop(explode(':', getenv('POP_PORT'))), ), 'smtp' => array( 'server' => $mailcow_hostname, - 'port' => getenv('SMTPS_PORT'), - 'tlsport' => getenv('SUBMISSION_PORT'), + 'port' => array_pop(explode(':', getenv('SMTPS_PORT'))), + 'tlsport' => array_pop(explode(':', getenv('SUBMISSION_PORT'))), ), 'activesync' => array( 'url' => 'https://'.$mailcow_hostname.($https_port == 443 ? '' : ':'.$https_port).'/Microsoft-Server-ActiveSync', From 8946d692742bdf37814ad953c96ba5c3b4f41cde Mon Sep 17 00:00:00 2001 From: Michael Kuron Date: Wed, 5 Jul 2017 20:11:07 +0200 Subject: [PATCH 3/3] Fix merge conflict --- data/Dockerfiles/sogo/Dockerfile | 1 - data/web/thunderbird-plugins/build-plugins.sh | 6 +----- docker-compose.yml | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/data/Dockerfiles/sogo/Dockerfile b/data/Dockerfiles/sogo/Dockerfile index b9db3c1c..a3a1308d 100644 --- a/data/Dockerfiles/sogo/Dockerfile +++ b/data/Dockerfiles/sogo/Dockerfile @@ -8,7 +8,6 @@ ENV GOSU_VERSION 1.9 # Prerequisites RUN apt-get update && apt-get install -y --no-install-recommends \ apt-transport-https \ - bind9-host \ ca-certificates \ cron \ gnupg \ diff --git a/data/web/thunderbird-plugins/build-plugins.sh b/data/web/thunderbird-plugins/build-plugins.sh index 53199e61..03986b78 100755 --- a/data/web/thunderbird-plugins/build-plugins.sh +++ b/data/web/thunderbird-plugins/build-plugins.sh @@ -16,15 +16,11 @@ tar --strip-components=1 -C connector -xf connector.tar.gz # build custom integrator while read DOMAIN; do echo "Building SOGo Integrator for $DOMAIN hosted on $MAILHOST" - PORT_NUM=$(dig -t srv _autodiscover._tcp.$DOMAIN +short | tail -n 1 | awk '{print $3}') - if [[ -z ${PORT_NUM} ]]; then - PORT_NUM=443 - fi cd integrator echo > defaults/preferences/site.js mkdir -p custom/${DOMAIN} cp -r custom/sogo-demo/* custom/${DOMAIN}/ - sed -i "s/http:\/\/sogo-demo\.inverse\.ca/https:\/\/${MAILHOST}:${PORT_NUM}/g" custom/${DOMAIN}/chrome/content/extensions.rdf + sed -i "s/http:\/\/sogo-demo\.inverse\.ca/https:\/\/${MAILHOST}/g" custom/${DOMAIN}/chrome/content/extensions.rdf sed -i "s/plugins\/updates\.php[?]/thunderbird-plugins.php?domain=${DOMAIN}\&/g" custom/${DOMAIN}/chrome/content/extensions.rdf echo 'pref("sogo-integrator.autocomplete.server.urlid", "'${DOMAIN}'");' > custom/${DOMAIN}/defaults/preferences/site.js echo 'pref("mail.collect_email_address_outgoing", false);' >> custom/${DOMAIN}/defaults/preferences/site.js diff --git a/docker-compose.yml b/docker-compose.yml index e8a7e0c4..853dbc36 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -143,7 +143,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.1 + image: mailcow/sogo:1.0 build: ./data/Dockerfiles/sogo depends_on: unbound-mailcow: