Compare commits

..

5 Commits

Author SHA1 Message Date
FreddleSpl0it
2e8897c2cf Merge branch 'staging' into fix/autodiscover-passwordless 2026-01-28 11:10:28 +01:00
DerLinkman
5ca900749c autodiscover: use generalized error logging instead of specific to prevent user enumeration 2025-12-18 16:54:45 +01:00
DerLinkman
b005803fe0 Add autodiscover debug script with domain override support
- Add view_autodiscover.sh helper script for testing autodiscover responses
- Support -h/--help flag for usage information
- Support -d/--domain flag to override autodiscover target (useful for testing)
- Auto-detect xmllint availability for formatted output
- Email validation with regex
- Interactive mode if no email provided
- Display response length for debugging
2025-12-17 14:27:53 +01:00
DerLinkman
ec77406dba Fix autodiscover.php: Use random error IDs and fix SQL type casting
- Replace hardcoded error IDs with random values (1-10 billion range) for better debugging
- Cast SimpleXMLElement email to string before SQL query to prevent type errors
- Qualify ambiguous 'active' column with table names in JOIN query
- Add proper error XML response for database errors instead of die()
- Ensure all error paths return complete XML documents
2025-12-17 14:27:38 +01:00
DerLinkman
ee15721550 feat: implement passwordless autodiscover endpoint
- Remove HTTP Basic Authentication requirement from autodiscover.php
- Extract email address from XML request body instead of AUTH headers
- Validate mailbox existence and active status before returning config
- Improve security by eliminating password transmission
- Add comprehensive error handling for invalid/inactive mailboxes
- Follow industry standards (Microsoft, Google, Apple)
- Maintain backward compatibility with existing email clients
- Keep full logging functionality in Redis AUTODISCOVER_LOG

This change enhances security while improving user experience and
follows modern email client configuration best practices.
2025-12-17 13:39:05 +01:00
12 changed files with 305 additions and 208 deletions

View File

@@ -14,7 +14,7 @@ jobs:
pull-requests: write
steps:
- name: Mark/Close Stale Issues and Pull Requests 🗑️
uses: actions/stale@v10.2.0
uses: actions/stale@v10.1.1
with:
repo-token: ${{ secrets.STALE_ACTION_PAT }}
days-before-stale: 60

View File

@@ -1,6 +1,6 @@
# Whitelist generated by Postwhite v3.4 on Sun Mar 1 00:29:01 UTC 2026
# Whitelist generated by Postwhite v3.4 on Thu Jan 1 00:24:01 UTC 2026
# https://github.com/stevejenkins/postwhite/
# 2174 total rules
# 2105 total rules
2a00:1450:4000::/36 permit
2a01:111:f400::/48 permit
2a01:111:f403:2800::/53 permit
@@ -52,14 +52,10 @@
8.25.194.0/23 permit
8.25.196.0/23 permit
8.36.116.0/24 permit
8.39.54.0/23 permit
8.39.54.250/31 permit
8.39.144.0/24 permit
8.40.222.0/23 permit
8.40.222.250/31 permit
12.130.86.238 permit
13.107.213.51 permit
13.107.246.51 permit
13.107.213.38 permit
13.107.246.38 permit
13.108.16.0/20 permit
13.110.208.0/21 permit
13.110.209.0/24 permit
@@ -69,7 +65,6 @@
13.111.191.0/24 permit
13.216.7.111 permit
13.216.54.180 permit
13.247.164.219 permit
15.200.21.50 permit
15.200.44.248 permit
15.200.201.185 permit
@@ -173,7 +168,6 @@
34.215.104.144 permit
34.218.115.239 permit
34.225.212.172 permit
34.241.242.183 permit
35.83.148.184 permit
35.155.198.111 permit
35.158.23.94 permit
@@ -197,7 +191,6 @@
40.233.64.216 permit
40.233.83.78 permit
40.233.88.28 permit
43.239.212.33 permit
44.206.138.57 permit
44.210.169.44 permit
44.217.45.156 permit
@@ -279,7 +272,6 @@
50.112.246.219 permit
52.1.14.157 permit
52.5.230.59 permit
52.6.74.205 permit
52.12.53.23 permit
52.13.214.179 permit
52.26.1.71 permit
@@ -336,7 +328,6 @@
54.244.54.130 permit
54.244.242.0/24 permit
54.255.61.23 permit
56.124.6.228 permit
57.103.64.0/18 permit
57.129.93.249 permit
62.13.128.0/24 permit
@@ -402,7 +393,6 @@
65.110.161.77 permit
65.123.29.213 permit
65.123.29.220 permit
65.154.166.0/24 permit
65.212.180.36 permit
66.102.0.0/20 permit
66.119.150.192/26 permit
@@ -707,9 +697,7 @@
87.248.117.205 permit
87.253.232.0/21 permit
89.22.108.0/24 permit
91.198.2.177 permit
91.198.2.217 permit
91.198.2.222 permit
91.198.2.0/24 permit
91.211.240.0/22 permit
94.236.119.0/26 permit
95.131.104.0/21 permit
@@ -1206,9 +1194,6 @@
99.78.197.208/28 permit
103.9.96.0/22 permit
103.28.42.0/24 permit
103.84.217.15 permit
103.84.217.238 permit
103.89.75.238 permit
103.151.192.0/23 permit
103.168.172.128/27 permit
103.237.104.0/22 permit
@@ -1369,9 +1354,6 @@
117.120.16.0/21 permit
119.42.242.52/31 permit
119.42.242.156 permit
121.244.91.48 permit
121.244.91.52 permit
122.15.156.182 permit
123.126.78.64/29 permit
124.108.96.24/31 permit
124.108.96.28/31 permit
@@ -1437,21 +1419,7 @@
134.170.141.64/26 permit
134.170.143.0/24 permit
134.170.174.0/24 permit
135.84.80.0/24 permit
135.84.81.0/24 permit
135.84.82.0/24 permit
135.84.83.0/24 permit
135.84.216.0/22 permit
136.143.160.0/24 permit
136.143.161.0/24 permit
136.143.162.0/24 permit
136.143.176.0/24 permit
136.143.177.0/24 permit
136.143.178.49 permit
136.143.182.0/23 permit
136.143.184.0/24 permit
136.143.188.0/24 permit
136.143.190.0/23 permit
136.146.128.0/20 permit
136.147.128.0/20 permit
136.147.135.0/24 permit
@@ -1467,7 +1435,6 @@
139.138.46.219 permit
139.138.57.55 permit
139.138.58.119 permit
139.167.79.86 permit
139.180.17.0/24 permit
140.238.148.191 permit
141.148.55.217 permit
@@ -1556,10 +1523,8 @@
159.135.224.0/20 permit
159.135.228.10 permit
159.183.0.0/16 permit
159.183.14.233 permit
159.183.68.71 permit
159.183.79.38 permit
159.183.121.182 permit
159.183.129.172 permit
160.1.62.192 permit
161.38.192.0/20 permit
@@ -1585,10 +1550,6 @@
164.152.23.32 permit
164.152.25.241 permit
164.177.132.168/30 permit
165.173.128.0/24 permit
165.173.180.1 permit
165.173.180.250/31 permit
165.173.182.250/31 permit
166.78.68.0/22 permit
166.78.68.221 permit
166.78.69.169 permit
@@ -1618,18 +1579,6 @@
168.245.12.252 permit
168.245.46.9 permit
168.245.127.231 permit
169.148.129.0/24 permit
169.148.131.0/24 permit
169.148.138.0/24 permit
169.148.142.10 permit
169.148.142.33 permit
169.148.144.0/25 permit
169.148.144.10 permit
169.148.146.0/23 permit
169.148.175.3 permit
169.148.179.3 permit
169.148.188.0/24 permit
169.148.188.182 permit
170.9.232.254 permit
170.10.128.0/24 permit
170.10.129.0/24 permit
@@ -1663,7 +1612,8 @@
182.50.78.64/28 permit
183.240.219.64/29 permit
185.4.120.0/22 permit
185.11.255.144 permit
185.11.253.128/27 permit
185.11.255.0/24 permit
185.12.80.0/22 permit
185.28.196.0/22 permit
185.58.84.93 permit
@@ -1677,16 +1627,8 @@
185.138.56.128/25 permit
185.189.236.0/22 permit
185.211.120.0/22 permit
185.233.188.68 permit
185.233.188.75 permit
185.233.188.84 permit
185.233.188.160 permit
185.233.188.176 permit
185.233.188.247 permit
185.233.189.44 permit
185.233.189.98 permit
185.233.189.122 permit
185.233.189.228 permit
185.233.188.0/23 permit
185.233.190.0/23 permit
185.250.236.0/22 permit
185.250.239.148 permit
185.250.239.168 permit
@@ -1762,9 +1704,7 @@
193.109.254.0/23 permit
193.122.128.100 permit
193.123.56.63 permit
193.142.157.15 permit
193.142.157.125 permit
193.142.157.158 permit
193.142.157.0/24 permit
193.142.157.191 permit
193.142.157.198 permit
194.19.134.0/25 permit
@@ -1824,16 +1764,7 @@
199.16.156.0/22 permit
199.33.145.1 permit
199.33.145.32 permit
199.34.22.36 permit
199.59.148.0/22 permit
199.67.80.2 permit
199.67.80.20 permit
199.67.82.2 permit
199.67.82.20 permit
199.67.84.0/24 permit
199.67.86.0/24 permit
199.67.88.0/24 permit
199.67.90.0/24 permit
199.101.161.130 permit
199.101.162.0/25 permit
199.122.120.0/21 permit
@@ -1889,8 +1820,6 @@
204.92.114.187 permit
204.92.114.203 permit
204.92.114.204/31 permit
204.141.32.0/23 permit
204.141.42.0/23 permit
204.216.164.202 permit
204.220.160.0/21 permit
204.220.168.0/21 permit
@@ -2068,6 +1997,8 @@
212.227.126.225 permit
212.227.126.226 permit
212.227.126.227 permit
213.95.19.64/27 permit
213.95.135.4 permit
213.199.128.139 permit
213.199.128.145 permit
213.199.138.181 permit
@@ -2157,9 +2088,11 @@
2001:748:400:3301::3 permit
2001:748:400:3301::4 permit
2404:6800:4000::/36 permit
2607:13c0:0001:0000:0000:0000:0000:7000/116 permit
2607:13c0:0002:0000:0000:0000:0000:1000/116 permit
2607:13c0:0004:0000:0000:0000:0000:0000/116 permit
2603:1010:3:3::5b permit
2603:1020:201:10::10f permit
2603:1030:20e:3::23c permit
2603:1030:b:3::152 permit
2603:1030:c02:8::14 permit
2607:f8b0:4000::/36 permit
2620:109:c003:104::/64 permit
2620:109:c003:104::215 permit
@@ -2172,8 +2105,6 @@
2620:10d:c09c:400::8:1 permit
2620:119:50c0:207::/64 permit
2620:119:50c0:207::215 permit
2620:1ec:46::51 permit
2620:1ec:bdf::51 permit
2800:3f0:4000::/36 permit
49.12.4.251 permit # checks.mailcow.email
2a01:4f8:c17:7906::10 permit # checks.mailcow.email

View File

@@ -60,97 +60,25 @@ $pdo = new PDO($dsn, $database_user, $database_pass, $opt);
$iam_provider = identity_provider('init');
$iam_settings = identity_provider('get');
$login_user = strtolower(trim($_SERVER['PHP_AUTH_USER']));
$login_pass = trim(htmlspecialchars_decode($_SERVER['PHP_AUTH_PW']));
// Passwordless autodiscover - no authentication required
// Email will be extracted from the request body
$login_user = null;
$login_role = null;
if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW'])) {
$json = json_encode(
array(
"time" => time(),
"ua" => $_SERVER['HTTP_USER_AGENT'],
"user" => "none",
"ip" => $_SERVER['REMOTE_ADDR'],
"service" => "Error: must be authenticated"
)
);
$redis->lPush('AUTODISCOVER_LOG', $json);
header('WWW-Authenticate: Basic realm="' . $_SERVER['HTTP_HOST'] . '"');
header('HTTP/1.0 401 Unauthorized');
exit(0);
}
$login_role = check_login($login_user, $login_pass, array('service' => 'EAS'));
if ($login_role === "user") {
header("Content-Type: application/xml");
echo '<?xml version="1.0" encoding="utf-8" ?>' . PHP_EOL;
header("Content-Type: application/xml");
echo '<?xml version="1.0" encoding="utf-8" ?>' . PHP_EOL;
?>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
<?php
if(!$data) {
try {
$json = json_encode(
array(
"time" => time(),
"ua" => $_SERVER['HTTP_USER_AGENT'],
"user" => $_SERVER['PHP_AUTH_USER'],
"ip" => $_SERVER['REMOTE_ADDR'],
"service" => "Error: invalid or missing request data"
)
);
$redis->lPush('AUTODISCOVER_LOG', $json);
$redis->lTrim('AUTODISCOVER_LOG', 0, 100);
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'msg' => 'Redis: '.$e
);
return false;
}
list($usec, $sec) = explode(' ', microtime());
?>
<Response>
<Error Time="<?=date('H:i:s', $sec) . substr($usec, 0, strlen($usec) - 2);?>" Id="2477272013">
<ErrorCode>600</ErrorCode>
<Message>Invalid Request</Message>
<DebugData />
</Error>
</Response>
</Autodiscover>
<?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 = $MailboxData['name'];
}
else {
$displayname = $email;
}
if(!$data) {
try {
$json = json_encode(
array(
"time" => time(),
"ua" => $_SERVER['HTTP_USER_AGENT'],
"user" => $_SERVER['PHP_AUTH_USER'],
"user" => "none",
"ip" => $_SERVER['REMOTE_ADDR'],
"service" => $autodiscover_config['autodiscoverType']
"service" => "Error: invalid or missing request data"
)
);
$redis->lPush('AUTODISCOVER_LOG', $json);
@@ -163,7 +91,139 @@ if ($login_role === "user") {
);
return false;
}
if ($autodiscover_config['autodiscoverType'] == 'imap') {
list($usec, $sec) = explode(' ', microtime());
?>
<Response>
<Error Time="<?=date('H:i:s', $sec) . substr($usec, 0, strlen($usec) - 2);?>" Id="<?=rand(1000000000, 9999999999);?>">
<ErrorCode>600</ErrorCode>
<Message>Invalid Request</Message>
<DebugData />
</Error>
</Response>
</Autodiscover>
<?php
exit(0);
}
try {
$discover = new SimpleXMLElement($data);
$email = $discover->Request->EMailAddress;
} catch (Exception $e) {
// If parsing fails, return error
try {
$json = json_encode(
array(
"time" => time(),
"ua" => $_SERVER['HTTP_USER_AGENT'],
"user" => "none",
"ip" => $_SERVER['REMOTE_ADDR'],
"service" => "Error: could not parse email from request"
)
);
$redis->lPush('AUTODISCOVER_LOG', $json);
$redis->lTrim('AUTODISCOVER_LOG', 0, 100);
}
catch (RedisException $e) {
// Silently fail
}
list($usec, $sec) = explode(' ', microtime());
?>
<Response>
<Error Time="<?=date('H:i:s', $sec) . substr($usec, 0, strlen($usec) - 2);?>" Id="<?=rand(1000000000, 9999999999);?>">
<ErrorCode>600</ErrorCode>
<Message>Invalid Request</Message>
<DebugData />
</Error>
</Response>
</Autodiscover>
<?php
exit(0);
}
$username = trim((string)$email);
try {
$stmt = $pdo->prepare("SELECT `mailbox`.`name`, `mailbox`.`active` FROM `mailbox`
INNER JOIN `domain` ON `mailbox`.`domain` = `domain`.`domain`
WHERE `mailbox`.`username` = :username
AND `mailbox`.`active` = '1'
AND `domain`.`active` = '1'");
$stmt->execute(array(':username' => $username));
$MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
}
catch(PDOException $e) {
// Database error - return error response with complete XML
list($usec, $sec) = explode(' ', microtime());
?>
<Response>
<Error Time="<?=date('H:i:s', $sec) . substr($usec, 0, strlen($usec) - 2);?>" Id="<?=rand(1000000000, 9999999999);?>">
<ErrorCode>500</ErrorCode>
<Message>Database Error</Message>
<DebugData />
</Error>
</Response>
</Autodiscover>
<?php
exit(0);
}
// Mailbox not found or not active - return generic error to prevent user enumeration
if (empty($MailboxData)) {
try {
$json = json_encode(
array(
"time" => time(),
"ua" => $_SERVER['HTTP_USER_AGENT'],
"user" => $email,
"ip" => $_SERVER['REMOTE_ADDR'],
"service" => "Error: mailbox not found or inactive"
)
);
$redis->lPush('AUTODISCOVER_LOG', $json);
$redis->lTrim('AUTODISCOVER_LOG', 0, 100);
}
catch (RedisException $e) {
// Silently fail
}
list($usec, $sec) = explode(' ', microtime());
?>
<Response>
<Error Time="<?=date('H:i:s', $sec) . substr($usec, 0, strlen($usec) - 2);?>" Id="<?=rand(1000000000, 9999999999);?>">
<ErrorCode>600</ErrorCode>
<Message>Invalid Request</Message>
<DebugData />
</Error>
</Response>
</Autodiscover>
<?php
exit(0);
}
if (!empty($MailboxData['name'])) {
$displayname = $MailboxData['name'];
}
else {
$displayname = $email;
}
try {
$json = json_encode(
array(
"time" => time(),
"ua" => $_SERVER['HTTP_USER_AGENT'],
"user" => $email,
"ip" => $_SERVER['REMOTE_ADDR'],
"service" => $autodiscover_config['autodiscoverType']
)
);
$redis->lPush('AUTODISCOVER_LOG', $json);
$redis->lTrim('AUTODISCOVER_LOG', 0, 100);
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'msg' => 'Redis: '.$e
);
return false;
}
if ($autodiscover_config['autodiscoverType'] == 'imap') {
?>
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
<User>
@@ -238,6 +298,3 @@ if ($login_role === "user") {
}
?>
</Autodiscover>
<?php
}
?>

View File

@@ -1007,9 +1007,9 @@ if (isset($_GET['query'])) {
['db' => 'last_pw_change', 'dt' => 5, 'dummy' => true, 'order_subquery' => "JSON_EXTRACT(attributes, '$.passwd_update')"],
['db' => 'in_use', 'dt' => 6, 'dummy' => true, 'order_subquery' => "(SELECT SUM(bytes) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`) / `m`.`quota`"],
['db' => 'name', 'dt' => 7],
['db' => 'messages', 'dt' => 20, 'dummy' => true, 'order_subquery' => "SELECT SUM(messages) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`"],
['db' => 'tags', 'dt' => 23, 'dummy' => true, 'search' => ['join' => 'LEFT JOIN `tags_mailbox` AS `tm` ON `tm`.`username` = `m`.`username`', 'where_column' => '`tm`.`tag_name`']],
['db' => 'active', 'dt' => 24],
['db' => 'messages', 'dt' => 18, 'dummy' => true, 'order_subquery' => "SELECT SUM(messages) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`"],
['db' => 'tags', 'dt' => 20, 'dummy' => true, 'search' => ['join' => 'LEFT JOIN `tags_mailbox` AS `tm` ON `tm`.`username` = `m`.`username`', 'where_column' => '`tm`.`tag_name`']],
['db' => 'active', 'dt' => 21],
];
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/ssp.class.php';

View File

@@ -111,8 +111,7 @@
"tags": "Štítky",
"dry": "Simulovat synchronizaci",
"internal": "Interní",
"internal_info": "Interní aliasy jsou přístupné jen z vlastních domén nebo jejich aliasů.",
"sender_allowed": "Povolit jako alias pro odesílání"
"internal_info": "Interní aliasy jsou přístupné jen z vlastních domén nebo jejich aliasů."
},
"admin": {
"access": "Přístupy",
@@ -305,7 +304,7 @@
"rspamd_com_settings": "Název nastavení se vygeneruje automaticky, viz ukázky nastavení níže. Více informací viz <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Rspamd dokumentace</a>",
"rspamd_global_filters": "Mapa globálních filtrů",
"rspamd_global_filters_agree": "Budu opatrný!",
"rspamd_global_filters_info": "Mapa globálních filtrů obsahuje různé seznamy povolených a zakázaných serverů.",
"rspamd_global_filters_info": "Mapa globálních filtrů obsahuje různé seznamy povolených a zakázaných serverů",
"rspamd_global_filters_regex": "Názvy stačí k vysvětlení. Položky musejí obsahovat jen platné regulární výrazy ve tvaru \"/vyraz/parametry\" (e.g. <code>/.+@domena\\.tld/i</code>).<br>\n Každý výraz bude podroben základní kontrole, přesto je možné Rspamd 'rozbít', nebude-li syntax zcela korektní.<br>\n Rspamd se pokusí po každé změně načíst mapu znovu. V případě potíží <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">restartujte Rspamd</a>, aby se konfigurace načetla explicitně.",
"rspamd_settings_map": "Nastavení Rspamd",
"sal_level": "Úroveň 'Moo'",
@@ -781,9 +780,7 @@
"mta_sts_max_age_info": "Doba v sekundách, po niž poštovní servery mohou toho pravidlo držet v mezipaměti bez nutnosti obnovení.",
"mta_sts_mx": "Server MX",
"mta_sts_mx_info": "Dovoluje odesílání jen výslovně vypsaným poštovním serverům; odesílající server kontroluje, že server MX určený v DNS odpovídá pravidlu, a povolí doručení jen s platným certifikátem TLS (chrání přes útokem typu MITM).",
"mta_sts_mx_notice": "Lze zadat více serverů MX (oddělte čárkou).",
"sender_allowed": "Povolit jako alias pro odesílání",
"sender_allowed_info": "Není-li povoleno, lze alias použít jen pro příjem pošty. Lze také obejít v Sender ACL a nastavit konkrétní schránky, jež tento alias mohou používat"
"mta_sts_mx_notice": "Lze zadat více serverů MX (oddělte čárkou)."
},
"fido2": {
"confirm": "Potvrdit",

View File

@@ -38,7 +38,7 @@
"alias_domain": "Aizstājdomēni",
"alias_domain_info": "<small>Tikai derīgi domēna vārdi (komatu atdalīti).</small>",
"automap": "Mēģiniet automatizēt mapes (\"Nosūtītie vienumi\", \"Nosūtītie\" => \"Nosūtītie\" etc.)",
"backup_mx_options": "Releja iespējas",
"backup_mx_options": "Dublējuma MX iespējas",
"delete1": "Izdzēst no avota pēc pabeigšanas",
"delete2": "Dzēsiet ziņojumus galamērķī, kas nav avotā",
"delete2duplicates": "Izdzēst atkārtojošos vienumus galamērķī",
@@ -65,8 +65,8 @@
"relay_all": "Pārsūtīt visus saņēmējus",
"relay_all_info": "↪ Ja izvēlies <b>nepārsūtīt</b> visus saņēmējus, tad Tev būs nepieciešams pievienot (\"aklo\") pastkasti katram saņēmējam, kas būtu jāpārsūta.",
"relay_domain": "Pārsūtīt šo domēnu",
"select": "Lūgums atlasīt…",
"select_domain": "Lūgums vispirms atlasīt domēnu",
"select": "Lūdzu izvēlaties...",
"select_domain": "Lūdzu sākumā izvēlaties domēnu",
"sieve_desc": "Īss apraksts",
"sieve_type": "Filtra tips",
"skipcrossduplicates": "Izlaist dublētus ziņojumus pa mapēm (pirmais nāk, pirmais kalpo)",
@@ -153,7 +153,7 @@
"r_info": "Pelēkie/atspējotie vienumi spēkā esošo ierobežojumu sarakstā mailcow nav zināmi kā derīgi ierobežojumi, un tos nevar pārvietot. Nezināmi ierobežojumi jebkurā gadījumā parādīšanas secībā. <br>Jaunus vienumus var pievienot <code>inc/vars.local.inc.php</code>, lai varētu tos pārslēgt.",
"recipients": "Adresāts",
"refresh": "Atsvaidzināt",
"regen_api_key": "Atkārtoti izveidot API atslēgu",
"regen_api_key": "Reģenerēt API atslēgu",
"relay_from": "\"No:\" adrese",
"relay_run": "Palaist testu",
"relayhosts_hint": "Norādīt no sūtītāja atkarīgas piegādes, lai varētu tos atlasīt domēnu konfigurācijas uzvednē.<br>\n Piegādes pakalpojums vienmēr ir \"smtp\", tādējādi tiks mēģināts TLS, kad piedāvāts. Iekļautais TLS (SMTPS) netiek atbalstīts. Tiek ņemts vērā lietotāja atsevišķais izejošā TLS nosacījuma iestatījums.<br>\n Ietekmē atlasītos domēnus, tajā skaitā aizstājdomēnus.",
@@ -185,10 +185,7 @@
"login_time": "Pieteikšanās laiks",
"iam_version": "Versija",
"quarantine_max_age": "Lielākais pieļaujamais vecums dienās<br><small>Vērtībai jābūt vienādai ar vai lielākai par 1 dienu.</small>",
"quarantine_max_score": "Atmest paziņojumu, ja e-pasta ziņojuma mēstuļu novērtējums ir augstāks par šo vērtību:<br><small>Noklusējums ir 9999.0</small>",
"options": "Iespējas",
"password_reset_settings": "Paroļu atkopes iestatījumi",
"password_settings": "Paroļu iestatījumi"
"quarantine_max_score": "Atmest paziņojumu, ja e-pasta ziņojuma mēstuļu novērtējums ir augstāks par šo vērtību:<br><small>Noklusējums ir 9999.0</small>"
},
"danger": {
"access_denied": "Piekļuve liegta, vai nepareizi dati",
@@ -260,7 +257,7 @@
"active": "Aktīvs",
"alias": "Labot aizstājvārdu",
"automap": "Mēģiniet automatizēt mapes (\"Nosūtītie vienumi\", \"Nosūtītie\" => \"Nosūtītie\" utt.)",
"backup_mx_options": "Retranslācijas iespējams",
"backup_mx_options": "Dublēt MX iespējas",
"delete1": "Izdzēst no avota pēc pabeigšanas",
"delete2": "Dzēsiet ziņojumus galamērķī, kas nav avotā",
"delete2duplicates": "Izdzēst atkārtojošos vienumus galamērķī",
@@ -561,7 +558,7 @@
"key_id_totp": "Identifikators Jūsu atslēgai",
"none": "Deaktivizēt",
"scan_qr_code": "Lūdzu, skenējiet šo kodu ar savu autentifikācijas lietojumprogrammu vai ievadiet kodu manuāli.",
"select": "Lūgums atlasīt",
"select": "Lūdzu izvēlaties",
"set_tfa": "Uzstādīt difi faktoru autentifik;acijas metodi",
"tfa": "Divpakāpju pieteikšanās",
"totp": "Uz laiku bāzēta vienreizēja parole (Google Autentifikātors utt.)",

View File

@@ -111,8 +111,7 @@
"validate": "Проверить",
"validation_success": "Проверка прошла успешно",
"internal": "Внутренний",
"internal_info": "Внутренние псевдонимы доступны только из самого домена или доменов-псевдонимов.",
"sender_allowed": "Разрешить отправку с этим псевдонимом"
"internal_info": "Внутренние псевдонимы доступны только из самого домена или доменов-псевдонимов."
},
"admin": {
"access": "Настройки доступа",
@@ -782,9 +781,7 @@
"mta_sts_max_age_info": "Время в секундах, в течение которого принимающие почтовые серверы могут кэшировать эту политику перед повторной загрузкой.",
"mta_sts_mx": "Сервер MX",
"mta_sts_mx_info": "Разрешает отправку только на явно указанные имена хостов почтовых серверов; отправляющий MTA проверяет, соответствует ли DNS-имя MX-хоста списку политик, и разрешает доставку только с подлинным TLS-сертификатом (защита от MITM).",
"mta_sts_mx_notice": "Можно указать несколько MX-серверов (через запятую).",
"sender_allowed": "Разрешить отправку с этим псевдонимом",
"sender_allowed_info": "Если отключено, этот псевдоним может только принимать почту. Используйте ACL отправителя, чтобы переопределить и предоставить определенным почтовым ящикам разрешение на отправку."
"mta_sts_mx_notice": "Можно указать несколько MX-серверов (через запятую)."
},
"fido2": {
"confirm": "Подтвердить",

View File

@@ -111,8 +111,7 @@
"timeout2": "Časovna omejitev za povezavo do lokalnega gostitelja",
"dry": "Simuliraj sinhronizacijo",
"internal": "Notranje",
"internal_info": "Notranji vzdevki so dostopni samo iz lastne domene ali vzdevkov domen.",
"sender_allowed": "Dovoli pošiljanje kot ta vzdevek"
"internal_info": "Notranji vzdevki so dostopni samo iz lastne domene ali vzdevkov domen."
},
"admin": {
"access": "Dostop",
@@ -781,9 +780,7 @@
"mta_sts_mx_info": "Omogoča pošiljanje samo na izrecno navedena imena gostiteljskih strežnikov poštnih strežnikov; pošiljajoči MTA preveri, ali se ime gostitelja DNS MX ujema s seznamom pravilnikov, in dovoljuje dostavo le z veljavnim potrdilom TLS (zaščita pred MITM).",
"mta_sts_mx_notice": "Določiti je mogoče več strežnikov MX (ločenih z vejicami).",
"internal": "Notranje",
"internal_info": "Notranji vzdevki so dostopni samo iz lastne domene ali vzdevkov domen.",
"sender_allowed": "Dovoli pošiljanje kot ta vzdevek",
"sender_allowed_info": "Če je onemogočeno, lahko ta vzdevek samo prejema pošto. Za preglasitev in dodelitev dovoljenja za pošiljanje določenim poštnim predalom uporabite seznam za nadzor dostopa pošiljatelja."
"internal_info": "Notranji vzdevki so dostopni samo iz lastne domene ali vzdevkov domen."
},
"footer": {
"restart_container_info": "<b>Pomembno:</b> Eleganten ponovni zagon lahko traja nekaj časa, zato počakajte, da se konča.",

View File

@@ -111,8 +111,7 @@
"timeout2": "Thời gian chờ kết nối đến máy chủ cục bộ",
"username": "Tên người dùng",
"validate": "Xác thực",
"validation_success": "Xác thực thành công",
"sender_allowed": "Cho phép gửi dưới bí danh này"
"validation_success": "Xác thực thành công"
},
"admin": {
"access": "Truy cập",

View File

@@ -24,7 +24,7 @@
"sogo_access": "管理 SOGo 存取權",
"sogo_profile_reset": "重設 SOGo 個人資料",
"spam_alias": "臨時別名",
"spam_policy": "封鎖名單/允許名單",
"spam_policy": "名單/名單",
"spam_score": "垃圾郵件分數",
"syncjobs": "同步任務",
"tls_policy": "TLS 規則",
@@ -1180,7 +1180,7 @@
"no_last_login": "沒有最後 UI 登入訊息",
"no_record": "沒有紀錄",
"open_logs": "開啟日誌",
"open_webmail_sso": "網頁信箱",
"open_webmail_sso": "网络邮件",
"password": "密碼",
"password_now": "目前密碼 (確認更改)",
"password_repeat": "密碼 (再次輸入)",

View File

@@ -117,7 +117,7 @@ services:
- rspamd
php-fpm-mailcow:
image: ghcr.io/mailcow/phpfpm:8.2.29-1
image: ghcr.io/mailcow/phpfpm:8.2.29
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
depends_on:
- redis-mailcow
@@ -200,7 +200,7 @@ services:
- phpfpm
sogo-mailcow:
image: ghcr.io/mailcow/sogo:5.12.4-1
image: ghcr.io/mailcow/sogo:5.12.4
environment:
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
@@ -252,7 +252,7 @@ services:
- sogo
dovecot-mailcow:
image: ghcr.io/mailcow/dovecot:2.3.21.1-1
image: ghcr.io/mailcow/dovecot:2.3.21.1
depends_on:
- mysql-mailcow
- netfilter-mailcow

View File

@@ -0,0 +1,122 @@
#!/bin/bash
# Autodiscover XML Debug Script
# Usage: ./view_autodiscover.sh [OPTIONS] [email@domain.com]
# Function to display help
show_help() {
cat << EOF
Autodiscover XML Debug Script
Usage: $0 [OPTIONS] [email@domain.com]
OPTIONS:
-h, --help Show this help message
-d, --domain FQDN Override autodiscover domain (default: autodiscover.DOMAIN)
Example: -d mail.example.com
EXAMPLES:
$0 user@example.com
Test autodiscover for user@example.com using autodiscover.example.com
$0 -d mail.example.com user@example.com
Test autodiscover for user@example.com using mail.example.com
$0 -d localhost:8443 user@example.com
Test autodiscover using localhost:8443 (useful for development)
EOF
exit 0
}
# Initialize variables
EMAIL=""
DOMAIN_OVERRIDE=""
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
;;
-d|--domain)
DOMAIN_OVERRIDE="$2"
shift 2
;;
-*)
echo "Error: Unknown option $1"
echo "Use -h or --help for usage information"
exit 1
;;
*)
EMAIL="$1"
shift
;;
esac
done
# Check if xmllint is available
if ! command -v xmllint &> /dev/null; then
echo "WARNING: xmllint not found. Output will not be formatted."
echo "Install with: apt install libxml2-utils (Debian/Ubuntu) or yum install libxml2 (CentOS/RHEL)"
echo ""
USE_XMLLINT=false
else
USE_XMLLINT=true
fi
# Get email address from user input if not provided
if [ -z "$EMAIL" ]; then
read -p "Enter email address to test: " EMAIL
fi
# Validate email format
if [[ ! "$EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "Error: Invalid email address format"
exit 1
fi
# Extract domain from email
EMAIL_DOMAIN="${EMAIL#*@}"
# Determine autodiscover URL
if [ -n "$DOMAIN_OVERRIDE" ]; then
AUTODISCOVER_URL="https://${DOMAIN_OVERRIDE}/Autodiscover/Autodiscover.xml"
echo "Testing Autodiscover for: $EMAIL"
echo "Override domain: $DOMAIN_OVERRIDE"
else
AUTODISCOVER_URL="https://autodiscover.${EMAIL_DOMAIN}/Autodiscover/Autodiscover.xml"
echo "Testing Autodiscover for: $EMAIL"
fi
echo "URL: $AUTODISCOVER_URL"
echo "============================================"
echo ""
# Make the request
RESPONSE=$(curl -k -s -X POST "$AUTODISCOVER_URL" \
-H "Content-Type: text/xml" \
-d "<?xml version=\"1.0\" encoding=\"utf-8\"?>
<Autodiscover xmlns=\"http://schemas.microsoft.com/exchange/autodiscover/request/2006\">
<Request>
<EMailAddress>$EMAIL</EMailAddress>
<AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
</Request>
</Autodiscover>")
# Check if response is empty
if [ -z "$RESPONSE" ]; then
echo "Error: No response received from server"
exit 1
fi
# Format and display output
if [ "$USE_XMLLINT" = true ]; then
echo "$RESPONSE" | xmllint --format - 2>&1
else
echo "$RESPONSE"
fi
echo ""
echo "============================================"
echo "Response length: ${#RESPONSE} bytes"