From 5abeb313bad795f9005367416f4edacff05a078a Mon Sep 17 00:00:00 2001 From: Michael Kuron Date: Mon, 10 Jul 2017 20:52:51 +0200 Subject: [PATCH 1/5] Autoconfig harmonization - use $autodiscover_config everywhere - 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 - iOS mobileconfig generator --- data/web/autoconfig.php | 47 +++++++--- data/web/autodiscover.php | 54 ++++++----- data/web/inc/functions.inc.php | 24 +++-- data/web/inc/vars.inc.php | 31 ++++-- data/web/mobileconfig.php | 167 +++++++++++++++++++++++++++++++++ 5 files changed, 267 insertions(+), 56 deletions(-) create mode 100644 data/web/mobileconfig.php diff --git a/data/web/autoconfig.php b/data/web/autoconfig.php index d01bc724e..523d61830 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 fd8cd641f..7f6081aed 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/inc/functions.inc.php b/data/web/inc/functions.inc.php index b34205308..af93794b5 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 a52442dbb..775af1e14 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'), + 'port' => array_pop(explode(':', getenv('IMAPS_PORT'))), + 'tlsport' => array_pop(explode(':', getenv('IMAP_PORT'))), + ), + 'pop3' => array( + 'server' => $mailcow_hostname, + 'port' => array_pop(explode(':', getenv('POPS_PORT'))), + 'tlsport' => array_pop(explode(':', getenv('POP_PORT'))), ), 'smtp' => array( 'server' => $mailcow_hostname, - 'port' => getenv('SMTPS_PORT'), + 'port' => array_pop(explode(':', getenv('SMTPS_PORT'))), + 'tlsport' => array_pop(explode(':', 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/mobileconfig.php b/data/web/mobileconfig.php new file mode 100644 index 000000000..198fa4d77 --- /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 + + From b295bedf5340a29862895544bf25b7e1c1cdfad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Peters?= Date: Mon, 24 Jul 2017 12:28:48 +0200 Subject: [PATCH 2/5] Update autoconfig.php --- data/web/autoconfig.php | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/data/web/autoconfig.php b/data/web/autoconfig.php index 523d61830..59f079077 100644 --- a/data/web/autoconfig.php +++ b/data/web/autoconfig.php @@ -1,5 +1,12 @@ mail server - - + + SSL %EMAILADDRESS% password-cleartext - - + + STARTTLS %EMAILADDRESS% password-cleartext @@ -43,8 +50,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 if (count($records) == 0 || $records[0]['target'] != '') { ?> - - + + SSL %EMAILADDRESS% password-cleartext @@ -54,8 +61,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 if (count($records) == 0 || $records[0]['target'] != '') { ?> - - + + STARTTLS %EMAILADDRESS% password-cleartext @@ -63,15 +70,15 @@ if (count($records) == 0 || $records[0]['target'] != '') { ?> - - + + SSL %EMAILADDRESS% password-cleartext - - + + STARTTLS %EMAILADDRESS% password-cleartext From bfa2e83803395ae0c66e654484fc02e4ded32dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Peters?= Date: Mon, 24 Jul 2017 12:35:04 +0200 Subject: [PATCH 3/5] Add more help text, remove obsolete variable --- data/web/inc/vars.inc.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php index 775af1e14..c5447725c 100644 --- a/data/web/inc/vars.inc.php +++ b/data/web/inc/vars.inc.php @@ -18,12 +18,17 @@ $database_name = getenv('DBNAME'); $mailcow_hostname = getenv('MAILCOW_HOSTNAME'); // Autodiscover settings +// === +// Auto-detect HTTPS port => $https_port = strpos($_SERVER['HTTP_HOST'], ':'); if ($https_port === FALSE) { $https_port = 443; } else { $https_port = substr($_SERVER['HTTP_HOST'], $https_port+1); } +// Alternatively select port here => +//$https_port = 1234; +// Other settings => $autodiscover_config = array( // Enable the autodiscover service for Outlook desktop clients 'useEASforOutlook' => 'yes', @@ -61,11 +66,6 @@ $autodiscover_config = array( ); unset($https_port); -// Where to go after adding and editing objects -// Can be "form" or "previous" -// "form" will stay in the current form, "previous" will redirect to previous page -$FORM_ACTION = 'previous'; - // Change default language, "de", "en", "es", "nl", "pt", "ru" $DEFAULT_LANG = 'en'; From 27c169dbe182ef7d6abd5d2d6fc62551a00e6ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Peters?= Date: Mon, 24 Jul 2017 12:35:56 +0200 Subject: [PATCH 4/5] Update mobileconfig.php --- data/web/mobileconfig.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/web/mobileconfig.php b/data/web/mobileconfig.php index 198fa4d77..8d3d26555 100644 --- a/data/web/mobileconfig.php +++ b/data/web/mobileconfig.php @@ -9,6 +9,8 @@ if (!isset($_SESSION['mailcow_cc_role']) || $_SESSION['mailcow_cc_role'] != 'use die("This page is only available to logged-in users, not admins."); } +error_reporting(0); + header('Content-Type: application/x-apple-aspen-config'); header('Content-Disposition: attachment; filename="Mailcow.mobileconfig"'); From 1b719a8668c85a59c75dc759d509673fb32c19a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Peters?= Date: Mon, 24 Jul 2017 12:37:02 +0200 Subject: [PATCH 5/5] Update autoconfig.php --- data/web/autoconfig.php | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/data/web/autoconfig.php b/data/web/autoconfig.php index 59f079077..c905c3258 100644 --- a/data/web/autoconfig.php +++ b/data/web/autoconfig.php @@ -17,7 +17,8 @@ $domain_port = strpos($_SERVER['HTTP_HOST'], ':'); if ($domain_port === FALSE) { $domain = substr($_SERVER['HTTP_HOST'], $domain_dot+1); $port = 443; -} else { +} +else { $domain = substr($_SERVER['HTTP_HOST'], $domain_dot+1, $domain_port-$domain_dot-1); $port = substr($_SERVER['HTTP_HOST'], $domain_port+1); } @@ -26,21 +27,21 @@ header('Content-Type: application/xml'); ?> '; ?> - + %EMAILDOMAIN% A mailcow mail server mail server - - + + SSL %EMAILADDRESS% password-cleartext - - + + STARTTLS %EMAILADDRESS% password-cleartext @@ -50,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 if (count($records) == 0 || $records[0]['target'] != '') { ?> - - + + SSL %EMAILADDRESS% password-cleartext @@ -61,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 if (count($records) == 0 || $records[0]['target'] != '') { ?> - - + + STARTTLS %EMAILADDRESS% password-cleartext @@ -70,21 +71,21 @@ if (count($records) == 0 || $records[0]['target'] != '') { ?> - - + + SSL %EMAILADDRESS% password-cleartext - - + + 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. @@ -92,6 +93,6 @@ if (count($records) == 0 || $records[0]['target'] != '') { ?> - +