Merge pull request #449 from mkuron/autoconfig

Autoconfig/Autodiscover unification
master
André Peters 2017-07-24 12:58:53 +02:00 committed by GitHub
commit 0a6eef83bd
5 changed files with 283 additions and 62 deletions

View File

@ -1,10 +1,28 @@
<?php
require_once 'inc/vars.inc.php';
$default_autodiscover_config = $autodiscover_config;
if(file_exists('inc/vars.local.inc.php')) {
include_once 'inc/vars.local.inc.php';
}
$configuration = array_merge($default_autodiscover_config, $autodiscover_config);
error_reporting(0);
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');
?>
<?= '<?xml version="1.0"?>'; ?>
@ -15,52 +33,59 @@ header('Content-Type: application/xml');
<displayShortName>mail server</displayShortName>
<incomingServer type="imap">
<hostname><?= $mailcow_hostname; ?></hostname>
<port>993</port>
<hostname><?=$configuration['imap']['server']; ?></hostname>
<port><?=$configuration['imap']['port']; ?></port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</incomingServer>
<incomingServer type="imap">
<hostname><?= $mailcow_hostname; ?></hostname>
<port>143</port>
<hostname><?=$configuration['imap']['server']; ?></hostname>
<port><?=$configuration['imap']['tlsport']; ?></port>
<socketType>STARTTLS</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</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">
<hostname><?= $mailcow_hostname; ?></hostname>
<port>995</port>
<hostname><?=$configuration['pop3']['server']; ?></hostname>
<port><?=$configuration['pop3']['port']; ?></port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</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">
<hostname><?= $mailcow_hostname; ?></hostname>
<port>110</port>
<hostname><?=$configuration['pop3']['server']; ?></hostname>
<port><?=$configuration['pop3']['tlsport']; ?></port>
<socketType>STARTTLS</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</incomingServer>
<?php } ?>
<outgoingServer type="smtp">
<hostname><?= $mailcow_hostname; ?></hostname>
<port>465</port>
<hostname><?=$configuration['smtp']['server']; ?></hostname>
<port><?=$configuration['smtp']['port']; ?></port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</outgoingServer>
<outgoingServer type="smtp">
<hostname><?= $mailcow_hostname; ?></hostname>
<port>587</port>
<hostname><?=$configuration['smtp']['server']; ?></hostname>
<port><?=$configuration['smtp']['tlsport']; ?></port>
<socketType>STARTTLS</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</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 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>
@ -68,6 +93,6 @@ header('Content-Type: application/xml');
</emailProvider>
<webMail>
<loginPage url="https://<?= $mailcow_hostname; ?>/SOGo/" />
<loginPage url="https://<?=$mailcow_hostname; ?><?php if ($port != 443) echo ':'.$port; ?>/SOGo/" />
</webMail>
</clientConfig>

View File

@ -16,13 +16,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'])) {
preg_match('/(Outlook|Office).+1[5-9]\./', $_SERVER['HTTP_USER_AGENT'])
) {
$configuration['autodiscoverType'] = 'activesync';
}
}
@ -64,8 +65,28 @@ else {
<?php
exit(0);
}
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') {
?>
@ -100,13 +121,13 @@ else {
</Protocol>
<Protocol>
<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>
<LoginName><?=$email;?></LoginName>
</Protocol>
<Protocol>
<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>
<LoginName><?=$email;?></LoginName>
</Protocol>
@ -115,21 +136,6 @@ else {
<?php
}
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">
<Culture>en:en</Culture>

View File

@ -62,10 +62,6 @@ function hasMailboxObjectAccess($username, $role, $object) {
}
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) {
// Need to remove BEGIN/END PUBLIC KEY
$lines = explode("\n", trim($pem_key));
@ -73,6 +69,10 @@ function generate_tlsa_digest($hostname, $port, $starttls = null) {
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";
}
if (empty($starttls)) {
$context = stream_context_create(array("ssl" => array("capture_peer_cert" => true, 'verify_peer' => false, 'allow_self_signed' => true)));
$stream = stream_socket_client('tls://' . $hostname . ':' . $port, $error_nr, $error_msg, 5, STREAM_CLIENT_CONNECT, $context);
@ -87,20 +87,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)) . '"';
}

View File

@ -18,36 +18,53 @@ $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',
// 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,
),
);
// 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';
unset($https_port);
// Change default language, "de", "en", "es", "nl", "pt", "ru"
$DEFAULT_LANG = 'en';

View File

@ -0,0 +1,169 @@
<?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.");
}
error_reporting(0);
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>