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
master
Michael Kuron 2017-07-10 20:52:51 +02:00
parent 51660589d4
commit 5abeb313ba
5 changed files with 267 additions and 56 deletions

View File

@ -5,6 +5,16 @@ if (empty($mailcow_hostname)) {
exit(); 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'); header('Content-Type: application/xml');
?> ?>
<?= '<?xml version="1.0"?>'; ?> <?= '<?xml version="1.0"?>'; ?>
@ -15,52 +25,59 @@ header('Content-Type: application/xml');
<displayShortName>mail server</displayShortName> <displayShortName>mail server</displayShortName>
<incomingServer type="imap"> <incomingServer type="imap">
<hostname><?= $mailcow_hostname; ?></hostname> <hostname><?= $autodiscover_config['imap']['server']; ?></hostname>
<port>993</port> <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><?= $mailcow_hostname; ?></hostname> <hostname><?= $autodiscover_config['imap']['server']; ?></hostname>
<port>143</port> <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>
</incomingServer> </incomingServer>
<?php
$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'] != '') { ?>
<incomingServer type="pop3"> <incomingServer type="pop3">
<hostname><?= $mailcow_hostname; ?></hostname> <hostname><?= $autodiscover_config['pop3']['server']; ?></hostname>
<port>995</port> <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>
</incomingServer> </incomingServer>
<?php } ?>
<?php
$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'] != '') { ?>
<incomingServer type="pop3"> <incomingServer type="pop3">
<hostname><?= $mailcow_hostname; ?></hostname> <hostname><?= $autodiscover_config['pop3']['server']; ?></hostname>
<port>110</port> <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>
</incomingServer> </incomingServer>
<?php } ?>
<outgoingServer type="smtp"> <outgoingServer type="smtp">
<hostname><?= $mailcow_hostname; ?></hostname> <hostname><?= $autodiscover_config['smtp']['server']; ?></hostname>
<port>465</port> <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><?= $mailcow_hostname; ?></hostname> <hostname><?= $autodiscover_config['smtp']['server']; ?></hostname>
<port>587</port> <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>
</outgoingServer> </outgoingServer>
<enable visiturl="https://<?= $mailcow_hostname; ?>/admin.php"> <enable visiturl="https://<?= $mailcow_hostname; ?><?php if ($port != 443) echo ':'.$port; ?>/admin.php">
<instruction>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.</instruction> <instruction>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.</instruction>
<instruction lang="de">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.</instruction> <instruction lang="de">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.</instruction>
</enable> </enable>
@ -68,6 +85,6 @@ header('Content-Type: application/xml');
</emailProvider> </emailProvider>
<webMail> <webMail>
<loginPage url="https://<?= $mailcow_hostname; ?>/SOGo/" /> <loginPage url="https://<?= $mailcow_hostname; ?><?php if ($port != 443) echo ':'.$port; ?>/SOGo/" />
</webMail> </webMail>
</clientConfig> </clientConfig>

View File

@ -12,13 +12,14 @@ error_reporting(0);
$data = trim(file_get_contents("php://input")); $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')) { // desktop client if (strpos($data, 'autodiscover/outlook/responseschema') !== false) { // desktop client
$configuration['autodiscoverType'] = 'imap'; $configuration['autodiscoverType'] = 'imap';
if ($configuration['useEASforOutlook'] == 'yes' && if ($configuration['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'; $configuration['autodiscoverType'] = 'activesync';
} }
} }
@ -60,8 +61,28 @@ else {
<?php <?php
exit(0); exit(0);
} }
try {
$discover = new SimpleXMLElement($data); $discover = new SimpleXMLElement($data);
$email = $discover->Request->EMailAddress; $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') { if ($configuration['autodiscoverType'] == 'imap') {
?> ?>
@ -96,13 +117,13 @@ else {
</Protocol> </Protocol>
<Protocol> <Protocol>
<Type>CalDAV</Type> <Type>CalDAV</Type>
<Server><?=$configuration['caldav']['server'];?>/SOGo/dav/<?=$email;?>/Calendar</Server> <Server>https://<?=$configuration['caldav']['server'];?><?php if ($configuration['caldav']['port'] != 443) echo ':'.$configuration['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><?=$configuration['carddav']['server'];?>/SOGo/dav/<?=$email;?>/Contacts</Server> <Server>https://<?=$configuration['carddav']['server'];?><?php if ($configuration['caldav']['port'] != 443) echo ':'.$configuration['carddav']['port']; ?>/SOGo/dav/<?=$email;?>/Contacts</Server>
<DomainRequired>off</DomainRequired> <DomainRequired>off</DomainRequired>
<LoginName><?=$email;?></LoginName> <LoginName><?=$email;?></LoginName>
</Protocol> </Protocol>
@ -111,21 +132,6 @@ else {
<?php <?php
} }
else if ($configuration['autodiscoverType'] == 'activesync') { else if ($configuration['autodiscoverType'] == 'activesync') {
$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;
}
?> ?>
<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>

View File

@ -62,10 +62,6 @@ function hasMailboxObjectAccess($username, $role, $object) {
} }
return false; return false;
} }
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) { function pem_to_der($pem_key) {
// Need to remove BEGIN/END PUBLIC KEY // Need to remove BEGIN/END PUBLIC KEY
$lines = explode("\n", trim($pem_key)); $lines = explode("\n", trim($pem_key));
@ -73,6 +69,10 @@ function generate_tlsa_digest($hostname, $port, $starttls = null) {
unset($lines[0]); unset($lines[0]);
return base64_decode(implode('', $lines)); return base64_decode(implode('', $lines));
} }
function generate_tlsa_digest($hostname, $port, $starttls = null) {
if (!is_valid_domain_name($hostname)) {
return "Not a valid hostname";
}
if (empty($starttls)) { if (empty($starttls)) {
$context = stream_context_create(array("ssl" => array("capture_peer_cert" => true, 'verify_peer' => false, 'allow_self_signed' => true))); $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; return $error_nr . ': ' . $error_msg;
} }
$banner = fread($stream, 512 ); $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"); fwrite($stream,"HELO tlsa.generator.local\r\n");
fread($stream, 512); fread($stream, 512);
fwrite($stream,"STARTTLS\r\n"); fwrite($stream,"STARTTLS\r\n");
fread($stream, 512); fread($stream, 512);
} }
elseif (preg_match("/imap.+starttls/i", $banner)) { elseif (preg_match("/imap.+starttls/i", $banner)) { // IMAP
fwrite($stream,"A1 STARTTLS\r\n"); fwrite($stream,"A1 STARTTLS\r\n");
fread($stream, 512); fread($stream, 512);
} }
elseif (preg_match("/^\+OK/", $banner)) { elseif (preg_match("/^\+OK/", $banner)) { // POP3
fwrite($stream,"STLS\r\n"); fwrite($stream,"STLS\r\n");
fread($stream, 512); fread($stream, 512);
} }
elseif (preg_match("/^OK/m", $banner)) { // Sieve
fwrite($stream,"STARTTLS\r\n");
fread($stream, 512);
}
else { else {
return 'Unknown banner: "' . htmlspecialchars(trim($banner)) . '"'; return 'Unknown banner: "' . htmlspecialchars(trim($banner)) . '"';
} }

View File

@ -18,31 +18,48 @@ $database_name = getenv('DBNAME');
$mailcow_hostname = getenv('MAILCOW_HOSTNAME'); $mailcow_hostname = getenv('MAILCOW_HOSTNAME');
// Autodiscover settings // 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( $autodiscover_config = array(
// Enable the autodiscover service for Outlook desktop clients // Enable the autodiscover service for Outlook desktop clients
'useEASforOutlook' => 'yes', 'useEASforOutlook' => 'yes',
// General autodiscover service type: "activesync" or "imap" // General autodiscover service type: "activesync" or "imap"
'autodiscoverType' => 'activesync', '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 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( 'imap' => array(
'server' => $mailcow_hostname, '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( 'smtp' => array(
'server' => $mailcow_hostname, 'server' => $mailcow_hostname,
'port' => getenv('SMTPS_PORT'), 'port' => array_pop(explode(':', getenv('SMTPS_PORT'))),
'tlsport' => array_pop(explode(':', getenv('SUBMISSION_PORT'))),
), ),
'activesync' => array( 'activesync' => array(
'url' => 'https://'.$mailcow_hostname.'/Microsoft-Server-ActiveSync' 'url' => 'https://'.$mailcow_hostname.($https_port == 443 ? '' : ':'.$https_port).'/Microsoft-Server-ActiveSync',
), ),
'caldav' => array( 'caldav' => array(
'url' => 'https://'.$mailcow_hostname 'server' => $mailcow_hostname,
'port' => $https_port,
), ),
'carddav' => array( 'carddav' => array(
'url' => 'https://'.$mailcow_hostname 'server' => $mailcow_hostname,
) 'port' => $https_port,
),
); );
unset($https_port);
// Where to go after adding and editing objects // Where to go after adding and editing objects
// Can be "form" or "previous" // Can be "form" or "previous"

View File

@ -0,0 +1,167 @@
<?php
require_once 'inc/prerequisites.inc.php';
if (empty($mailcow_hostname)) {
exit();
}
if (!isset($_SESSION['mailcow_cc_role']) || $_SESSION['mailcow_cc_role'] != 'user') {
header("Location: index.php");
die("This page is only available to logged-in users, not admins.");
}
header('Content-Type: application/x-apple-aspen-config');
header('Content-Disposition: attachment; filename="Mailcow.mobileconfig"');
$email = $_SESSION['mailcow_cc_username'];
$domain = explode('@', $_SESSION['mailcow_cc_username'])[1];
$identifier = implode('.', array_reverse(explode('.', $domain))) . '.iphoneprofile.mailcow';
try {
$stmt = $pdo->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 '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadContent</key>
<array>
<dict>
<key>CalDAVAccountDescription</key>
<string><?php echo $domain; ?></string>
<key>CalDAVHostName</key>
<string><?php echo $autodiscover_config['caldav']['server']; ?></string>
<key>CalDAVPort</key>
<real><?php echo $autodiscover_config['caldav']['port']; ?></real>
<key>CalDAVPrincipalURL</key>
<string>/SOGo/dav/<?php echo $email; ?></string>
<key>CalDAVUseSSL</key>
<true/>
<key>CalDAVUsername</key>
<string><?php echo $email; ?></string>
<key>PayloadDescription</key>
<string>Configures CalDAV account.</string>
<key>PayloadDisplayName</key>
<string>CalDAV (<?php echo $domain; ?>)</string>
<key>PayloadIdentifier</key>
<string><?php echo $identifier; ?>.CalDAV</string>
<key>PayloadOrganization</key>
<string></string>
<key>PayloadType</key>
<string>com.apple.caldav.account</string>
<key>PayloadUUID</key>
<string>FC898573-EBA8-48AF-93BD-BFA0C9778FA7</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
<dict>
<key>EmailAccountDescription</key>
<string><?php echo $domain; ?></string>
<key>EmailAccountType</key>
<string>EmailTypeIMAP</string>
<key>EmailAccountName</key>
<string><?php echo $displayname; ?></string>
<key>EmailAddress</key>
<string><?php echo $email; ?></string>
<key>IncomingMailServerAuthentication</key>
<string>EmailAuthPassword</string>
<key>IncomingMailServerHostName</key>
<string><?php echo $autodiscover_config['imap']['server']; ?></string>
<key>IncomingMailServerPortNumber</key>
<integer><?php echo $autodiscover_config['imap']['port']; ?></integer>
<key>IncomingMailServerUseSSL</key>
<true/>
<key>IncomingMailServerUsername</key>
<string><?php echo $email; ?></string>
<key>OutgoingMailServerAuthentication</key>
<string>EmailAuthPassword</string>
<key>OutgoingMailServerHostName</key>
<string><?php echo $autodiscover_config['smtp']['server']; ?></string>
<key>OutgoingMailServerPortNumber</key>
<integer><?php echo $autodiscover_config['smtp']['port']; ?></integer>
<key>OutgoingMailServerUseSSL</key>
<true/>
<key>OutgoingMailServerUsername</key>
<string><?php echo $email; ?></string>
<key>OutgoingPasswordSameAsIncomingPassword</key>
<true/>
<key>PayloadDescription</key>
<string>Configures email account.</string>
<key>PayloadDisplayName</key>
<string>IMAP Account (<?php echo $domain; ?>)</string>
<key>PayloadIdentifier</key>
<string><?php echo $identifier; ?>.email</string>
<key>PayloadOrganization</key>
<string></string>
<key>PayloadType</key>
<string>com.apple.mail.managed</string>
<key>PayloadUUID</key>
<string>00294FBB-1016-413E-87B9-652D856D6875</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PreventAppSheet</key>
<false/>
<key>PreventMove</key>
<false/>
<key>SMIMEEnabled</key>
<false/>
</dict>
<dict>
<key>CardDAVAccountDescription</key>
<string><?php echo $domain; ?></string>
<key>CardDAVHostName</key>
<string><?php echo $autodiscover_config['carddav']['server']; ?></string>
<key>CardDAVPort</key>
<integer><?php echo $autodiscover_config['carddav']['port']; ?></integer>
<key>CardDAVPrincipalURL</key>
<string>/SOGo/dav/<?php echo $email; ?></string>
<key>CardDAVUseSSL</key>
<true/>
<key>CardDAVUsername</key>
<string><?php echo $email; ?></string>
<key>PayloadDescription</key>
<string>Configures CardDAV accounts</string>
<key>PayloadDisplayName</key>
<string>CardDAV (<?php echo $domain; ?>)</string>
<key>PayloadIdentifier</key>
<string><?php echo $identifier; ?>.carddav</string>
<key>PayloadOrganization</key>
<string></string>
<key>PayloadType</key>
<string>com.apple.carddav.account</string>
<key>PayloadUUID</key>
<string>0797EF2B-B1F1-4BC7-ABCD-4580862252B4</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</array>
<key>PayloadDescription</key>
<string>IMAP, CalDAV, CardDAV</string>
<key>PayloadDisplayName</key>
<string><?php echo $domain; ?> Mailcow</string>
<key>PayloadIdentifier</key>
<string><?php echo $identifier; ?></string>
<key>PayloadOrganization</key>
<string></string>
<key>PayloadRemovalDisallowed</key>
<false/>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>5EE248C5-ACCB-42D8-9199-8F8ED08D5624</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>