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