Skip to content

Commit

Permalink
oxdisco: more detailed secondary store access validation
Browse files Browse the repository at this point in the history
If the entry from the MySQL scndstore_hints table is missing,
the request would be inadvertently rejected even if opening
the mailbox did succeed.
  • Loading branch information
jengelh committed Aug 8, 2023
1 parent 31a7a00 commit 6c7f971
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 4 deletions.
2 changes: 1 addition & 1 deletion doc/autodiscover.4gx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ When OL opens a non-default store (store of another user) or a public store, it
may also make an AutoDiscover inquiry for the extra store. This setting
controls whether the server-side AutoDiscover module should perform a
permission check on non-default stores and possibly reject returning connection
details. (Inquiry Public stores are always permitted.)
details. (Inquiry of public stores are always permitted.)
.br
Default: \fIyes\fP
.TP
Expand Down
2 changes: 2 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Enhancements:
* exmdb_local: persistent (on-disk) last-autoreply time tracking
* imap: allow large literals with APPEND
* imap: add RFC 7888 support
* oxdisco: allow AutoDiscover information retrieval from secondary
mailboxes even if the scndstore_hints table does not have an entry.

Fixes:

Expand Down
51 changes: 48 additions & 3 deletions exch/oxdisco.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <libHX/ctype_helper.h>
#include <libHX/string.h>
#include <gromox/config_file.hpp>
#include <gromox/element_data.hpp> /* MESSAGE_CONTENT alias */
#include <gromox/fileio.h>
#include <gromox/hpm_common.h>
#include <gromox/mapi_types.hpp>
Expand Down Expand Up @@ -51,8 +52,18 @@ class OxdiscoPlugin {
decltype(mysql_adaptor_get_domain_ids) *get_domain_ids;
decltype(mysql_adaptor_scndstore_hints) *scndstore_hints;
decltype(mysql_adaptor_get_homeserver) *get_homeserver;
decltype(mysql_adaptor_meta) *meta;
} mysql; // mysql adaptor function pointers

struct _exmdb {
_exmdb();
#define EXMIDL(n, p) EXMIDL_RETTYPE (*n) p;
#define IDLOUT
#include <gromox/exmdb_idef.hpp>
#undef EXMIDL
#undef IDLOUT
} exmdb;

private:
std::string x500_org_name = "Gromox default";
uint server_id; // Hash of the name of the mail server
Expand Down Expand Up @@ -103,7 +114,7 @@ static constexpr char
server_base_dn[] = "/o={}/ou=Exchange Administrative Group "
"(FYDIBOHF23SPDLT)/cn=Configuration/cn=Servers/cn={}@{}",
public_folder[] = "Public Folder",
public_folder_email[] = "public.folder.root@",
public_folder_email[] = "public.folder.root@", /* EXC: PUBS@thedomain */
bad_address_code[] = "501",
bad_address_msg[] = "Bad Address",
invalid_request_code[] = "600",
Expand Down Expand Up @@ -244,6 +255,11 @@ static std::string extract_qparam(const char *qstr, const char *srkey)
return ret;
}

/**
* Is it ok to give out metadata, such as their PR_DISPLAY_NAME?
* If @actor has _any_ kind of permission (or a scndstore hint entry),
* then allow it.
*/
BOOL OxdiscoPlugin::access_ok(int ctx_id, const char *target, const char *actor)
{
if (m_validate_scndrequest == 0 || strcasecmp(target, actor) == 0 ||
Expand All @@ -260,7 +276,20 @@ BOOL OxdiscoPlugin::access_ok(int ctx_id, const char *target, const char *actor)
if (std::any_of(hints.begin(), hints.end(),
[&](const sql_user &u) { return strcasecmp(u.username.c_str(), target) == 0; }))
return true;
/* authuser has no scndstore matching email */
sql_meta_result mres;
err = mysql.meta(target, WANTPRIV_METAONLY, mres);
if (err != 0) {
mlog(LV_ERR, "oxdisco: cannot retrieve usermeta for %s", strerror(err));
return die(ctx_id, server_error_code, server_error_msg);
}
uint32_t perm = 0;
if (!exmdb.get_mbox_perm(mres.maildir.c_str(), actor, &perm)) {
mlog(LV_ERR, "oxdisco: cannot access mailbox of %s to test for permissions", target);
return die(ctx_id, server_error_code, server_error_msg);
}
fprintf(stderr, "oxdisco: perm=%u\n", perm);
if (perm != 0)
return true;
return die(ctx_id, bad_address_code, (bad_address_msg +
" (403 Permission Denied)"s).c_str());
}
Expand Down Expand Up @@ -1067,15 +1096,31 @@ OxdiscoPlugin::_mysql::_mysql()
{
#define getService(f) \
if (query_service2(# f, f) == nullptr) \
throw std::runtime_error("[ews]: failed to get the \""# f"\" service")
throw std::runtime_error("oxdisco: failed to get the \""# f"\" service")
getService(get_user_displayname);
getService(get_user_ids);
getService(get_domain_ids);
getService(scndstore_hints);
getService(get_homeserver);
query_service2("mysql_auth_meta", meta);
if (meta == nullptr)
throw std::runtime_error("oxdisco: failed to get the \"meta\" symbol");
#undef getService
}

OxdiscoPlugin::_exmdb::_exmdb()
{
#define EXMIDL(n, p) do { \
query_service2("exmdb_client_" #n, n); \
if ((n) == nullptr) \
throw std::runtime_error("oxdisco: failed to get the \"exmdb_client_"# n"\" service\n"); \
} while (false);
#define IDLOUT
#include <gromox/exmdb_idef.hpp>
#undef EXMIDL
#undef IDLOUT
}

///////////////////////////////////////////////////////////////////////////////
//Plugin management

Expand Down

0 comments on commit 6c7f971

Please sign in to comment.