Skip to content

storeAccess cannot revoke client-granted store owners, revoked user keeps full read/write access and stays listed #93

Description

@csiocc

Environment

  • admin-api reporting API 1.21.0, backend 1.21.2, DB schema 133 (includes d8557b3 and bb64403,
    verified by observed write mask 0x700)
  • gromox backend on the same appliance
  • Observed both through grommunio-admin-web and through direct REST calls

Summary

Since d8557b3 / bb64403 ("Fix permission bits for store owner"), the storeAccess endpoints
operate on STOREACCESS = FOLDEROWNER | FOLDERCONTACT | FOLDERVISIBLE (0x700). This works for
grants created through the API itself, but breaks down for store owners granted by the mailbox
owner through a client (grommunio-web / Outlook, "Owner" permission on the top of the store):

  1. DELETE /domains/{d}/users/{u}/storeAccess/{username} returns 200 "Success" but the revoked
    user keeps full read/write/delete access to the store root (rights 0x4FB remain).
  2. Because foldervisible is part of the remaining rights, GET storeAccess keeps listing the
    user. In admin-web this becomes an endless loop: remove the entry from "Additional store
    owners", save, reload, the entry is back. The grant cannot be removed from the admin side at
    all.
  3. GET storeAccess also over-reports in general: any of the three bits matches the filter, so a
    user holding a plain read-only grant (foldervisible + readany) on IPM_SUBTREE is listed as
    an "additional store owner" even though gromox derives store ownership from FOLDEROWNER only.

Steps to reproduce

Mailbox target@example.com (user ID {u}, domain ID {d}), grantee grantee@example.com.

  1. As target@example.com in grommunio-web: right-click the top-level store entry → share folder →
    add grantee@example.com with permission profile "Owner".
  2. Read the raw ACL row:
    GET /api/v1/system/exmdb/target@example.com/folders/9
    → member grantee@example.com with rights: 2043 (0x7FB). So far so good; the grant is also
    visible in GET storeAccess (this part is an improvement over the pre-bb64403 behaviour).
  3. Revoke via API:
    DELETE /api/v1/domains/{d}/users/{u}/storeAccess/grantee@example.com → 200 "Success"
  4. Read the ACL row again:
    → member still present with rights: 1275 (0x4FB = readany, create, editowned, deleteowned,
    editany, deleteany, createsubfolder, foldervisible)
  5. GET /api/v1/domains/{d}/users/{u}/storeAccess → grantee is still listed.
  6. Repeat the DELETE (or PUT with {"usernames": []}): both return success, the row stays at
    0x4FB. Removing the entry in admin-web ("Mailbox permissions" → remove chip → save → reload)
    shows the same loop.

Counter-check: a grant created via POST storeAccess (row = exactly 0x700) is revoked cleanly,
the member row is removed entirely. The problem only manifests when the row carries additional
working bits, which is exactly what every client-side "Owner" grant produces.

Analysis (source reading)

The DELETE handler does remove all of 0x700 (0x7FB → 0xFB). However, gromox normalizes every
written ACL row in permission_adjust (exch/exmdb/folder.cpp): a row containing frightsReadAny
gets frightsVisible added back ("0x1 => 0x401"). The result is 0x4FB. Since
getUserStoreAccess filters on member.rights & Permissions.STOREACCESS, the re-added
foldervisible keeps the user listed, and every further revoke is a net no-op:
remove 0x700 → normalization adds 0x400 back → row unchanged.

So each component behaves as designed, but the composition of admin-api delete mask, gromox
normalization, and the GET filter makes client-granted store owners irrevocable through the
storeAccess API.

Expected behaviour / suggestions

  • DELETE storeAccess should actually end store access, either by removing the member row on
    IPM_SUBTREE entirely, or by clearing all rights bits (like the
    DELETE /system/exmdb/{user}/folders/{fid}/permissions endpoint does), or at minimum by
    documenting that residual client-granted rights survive.
  • GET storeAccess should list actual store owners. Given that gromox maps FOLDEROWNER on
    IPM_SUBTREE to store ownership, filtering on member.rights & FOLDEROWNER would avoid both the
    loop display and listing read-only grantees as store owners.

Impact

An administrator who revokes an "additional store owner" gets a success response while the revoked
user retains full read/write access to the mailbox top level. The admin UI keeps showing the user
as store owner and offers no working way to remove them. This is security-relevant: the only
complete removal paths are the mailbox owner acting in a client, or the raw
/system/exmdb/.../folders/9/permissions endpoint.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions