Skip to content

Commit 7a31d67

Browse files
committed
oxdisco: emit proper homeservers for config-v1.1.xml
1 parent 70a66a5 commit 7a31d67

File tree

1 file changed

+36
-15
lines changed

1 file changed

+36
-15
lines changed

exch/oxdisco.cpp

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: AGPL-3.0-or-later
2-
// SPDX-FileCopyrightText: 2022-2024 grommunio GmbH
2+
// SPDX-FileCopyrightText: 2022-2025 grommunio GmbH
33
// This file is part of Gromox.
44
#include <algorithm>
55
#include <cctype>
@@ -83,7 +83,7 @@ class OxdiscoPlugin {
8383
http_status resp_json(int, const char *) const;
8484
static void resp_mh(XMLElement *, const char *home, const char *dom, const std::string &, const std::string &, const std::string &, const std::string &, bool);
8585
void resp_rpch(XMLElement *, const char *home, const char *dom, const std::string &ews_url, const std::string &oab_url, const std::string &ecp_url, std::string &&serverdn, std::string &&mdbdn, const std::string &mailboxid, bool is_pvt) const;
86-
http_status resp_autocfg(int) const;
86+
http_status resp_autocfg(int, const char *) const;
8787
http_status resp_dav(int) const;
8888
static tinyxml2::XMLElement *add_child(tinyxml2::XMLElement *, const char *, const char *);
8989
static tinyxml2::XMLElement *add_child(tinyxml2::XMLElement *, const char *, const std::string &);
@@ -312,14 +312,20 @@ http_status OxdiscoPlugin::proc(int ctx_id, const void *content, uint64_t len) t
312312
return http_status::none;
313313
auto uri = req->f_request_uri.c_str();
314314
if (auto z = umatch(uri, uri_wkmc11_xml); z != SIZE_MAX) {
315-
return resp_autocfg(ctx_id);
315+
if (uri[z] != '?')
316+
return resp_autocfg(ctx_id, auth_info.username);
317+
auto username = extract_qparam(&uri[45], "emailaddress");
318+
return resp_autocfg(ctx_id, username.c_str());
316319
} else if (auto z = umatch(uri, uri_wkcaldav); z != SIZE_MAX && uri[z] != '/') {
317320
/* Not using mod_rewrite: Silent rewrite disallowed by RFC */
318321
return resp_dav(ctx_id);
319322
} else if (auto z = umatch(uri, uri_wkcarddav); z != SIZE_MAX && uri[z] != '/') {
320323
return resp_dav(ctx_id);
321324
} else if (auto z = umatch(uri, uri_mc11_xml); z != SIZE_MAX) {
322-
return resp_autocfg(ctx_id);
325+
if (uri[z] != '?')
326+
return resp_autocfg(ctx_id, auth_info.username);
327+
auto username = extract_qparam(&uri[45], "emailaddress");
328+
return resp_autocfg(ctx_id, username.c_str());
323329
} else if (umatch(uri, uri_autod_json) != SIZE_MAX) {
324330
return resp_json(ctx_id, uri);
325331
} else if (umatch(uri, uri_autod_xml) == SIZE_MAX) {
@@ -958,10 +964,10 @@ http_status OxdiscoPlugin::resp_json(int ctx_id, const char *get_request_uri) co
958964
* https://datatracker.ietf.org/doc/html/draft-ietf-mailmaint-autoconfig-00
959965
*
960966
* config-v1.1.xml MUST be available without authorization. This also means we
961-
* should not output anything that is dependent on the username, as that would
962-
* allow unauthenticated clients to see the existence of a user account.
967+
* should not output anything that is dependent on the username, but there is
968+
* only so much that is optional.
963969
*/
964-
http_status OxdiscoPlugin::resp_autocfg(int ctx_id) const
970+
http_status OxdiscoPlugin::resp_autocfg(int ctx_id, const char *email) const
965971
{
966972
tinyxml2::XMLDocument respdoc;
967973
auto decl = respdoc.NewDeclaration();
@@ -971,14 +977,29 @@ http_status OxdiscoPlugin::resp_autocfg(int ctx_id) const
971977
resproot->SetAttribute("version", "1.1");
972978
respdoc.InsertEndChild(resproot);
973979

974-
auto t_host_id = host_id.c_str();
980+
auto domain = strchr(email, '@');
981+
if (domain == nullptr)
982+
return http_status::not_found;
983+
++domain;
984+
bool is_private = strncasecmp(email, public_folder_email, 19) != 0;
985+
std::pair<std::string, std::string> homesrv_buf;
986+
if (mysql_adaptor_get_homeserver(is_private ? email : domain,
987+
is_private, homesrv_buf) != 0) {
988+
mlog(LV_ERR, "oxdisco: no homeserver for \"%s\", does that user even exist?!",
989+
is_private ? email : domain);
990+
return http_status::not_found;
991+
}
992+
const char *t_host_id = homesrv_buf.second.c_str();
993+
if (*t_host_id == '\0')
994+
t_host_id = host_id.c_str();
995+
975996
auto resp_prov = add_child(resproot, "emailProvider");
976-
resp_prov->SetAttribute("id", t_host_id);
997+
resp_prov->SetAttribute("id", domain);
977998

978999
// TODO get all domains?
979-
add_child(resp_prov, "domain", t_host_id);
980-
add_child(resp_prov, "displayName", "Gromox Mail");
981-
add_child(resp_prov, "displayShortName", "Gromox");
1000+
add_child(resp_prov, "domain", domain);
1001+
add_child(resp_prov, "displayName", "Gromox Mail ("s + domain + ")");
1002+
add_child(resp_prov, "displayShortName", "Gromox/"s + domain);
9821003

9831004
/*
9841005
* <https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat> is not
@@ -1034,9 +1055,9 @@ http_status OxdiscoPlugin::resp_autocfg(int ctx_id) const
10341055
add_child(srv, "socketType", "SSL");
10351056
add_child(srv, "authentication", "password-cleartext");
10361057
add_child(srv, "username", "%EMAILADDRESS%");
1037-
add_child(srv, "owaURL", "https://"s + host_id + "/web/");
1038-
add_child(srv, "ewsURL", fmt::format(ews_base_url, host_id, exchange_asmx));
1039-
add_child(srv, "easURL", fmt::format(msas_base_url, host_id));
1058+
add_child(srv, "owaURL", "https://"s + t_host_id + "/web/");
1059+
add_child(srv, "ewsURL", fmt::format(ews_base_url, t_host_id, exchange_asmx));
1060+
add_child(srv, "easURL", fmt::format(msas_base_url, t_host_id));
10401061

10411062
/* Bug in TB: no outgoing server may be something else than SMTP. */
10421063
srv = add_child(resp_prov, "outgoingServer");

0 commit comments

Comments
 (0)