mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
fix(windows): accept the owner Windows actually stamps on what we create
An elevated install created its own staging file and then refused it:
error: failed to stage install candidate: activation transaction I/O
failed: owner-not-current-user
We compared the object's owner against TokenUser. Windows stamps newly created
objects with TokenOwner, and for a member of the Administrators group that
defaults to BUILTIN\Administrators ("System objects: Default owner for objects
created by members of the Administrators group" — default on Server, common on
hardened clients). So on any elevated account the check rejected a file written
seconds earlier by the same process. Reported by @spam0115 (#1580); @gotspatel
hit the same wall from the other side (#1582) — a fresh install whose MCP server
exits during initialize, from `C:\Users\Administrator`.
The fix reads TokenOwner and accepts that SID too. This is stricter-or-equal,
never looser: TokenOwner is the ONE SID this process stamps on its own
creations, so the check still refuses anything a different account owns. It does
NOT accept "whatever an administrator owns" — that would be the loose version,
and the neighbouring activation_windows_owner_is_trusted already covers the
pre-existing-directory case where a broader rule is appropriate. On a
non-elevated account TokenOwner == TokenUser and nothing changes at all.
Windows-only code, so it is unverifiable on the macOS host: this needs the
Windows leg to compile and exercise, which is the next step before merge.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
1 parent
0c64de93a2
commit
4c793c4ded
1 file changed
+57
@@ -453,6 +453,52 @@ static bool activation_windows_owner_is_trusted(HANDLE handle) {
|
||||
return trusted;
|
||||
}
|
||||
|
||||
/* The SID Windows will stamp as OWNER on objects this process creates.
|
||||
*
|
||||
* That is TokenOwner, NOT TokenUser, and the two differ exactly when it matters:
|
||||
* for a member of the Administrators group the default owner is
|
||||
* BUILTIN\Administrators (the "System objects: Default owner for objects
|
||||
* created by members of the Administrators group" policy, default on Server and
|
||||
* common on hardened clients). So an elevated install created its staging file,
|
||||
* then refused it as "owner-not-current-user" — we rejected a file we had just
|
||||
* written ourselves (#1580), and the daemon path failed the same way, exiting
|
||||
* before it could say anything (#1582).
|
||||
*
|
||||
* Reading TokenOwner is STRICTER-or-equal, never looser: it is the one SID this
|
||||
* process stamps. On a non-elevated account TokenOwner == TokenUser and nothing
|
||||
* changes. It does not accept "anything an administrator owns" — only the exact
|
||||
* SID our own creations carry. */
|
||||
static bool activation_windows_token_owner(void **information_out, PSID *sid_out) {
|
||||
*information_out = NULL;
|
||||
*sid_out = NULL;
|
||||
HANDLE token = NULL;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
|
||||
return false;
|
||||
}
|
||||
DWORD needed = 0;
|
||||
(void)GetTokenInformation(token, TokenOwner, NULL, 0, &needed);
|
||||
if (needed == 0 || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
(void)CloseHandle(token);
|
||||
return false;
|
||||
}
|
||||
void *information = calloc(1, needed);
|
||||
bool ok =
|
||||
information && GetTokenInformation(token, TokenOwner, information, needed, &needed) != 0;
|
||||
(void)CloseHandle(token);
|
||||
if (!ok) {
|
||||
free(information);
|
||||
return false;
|
||||
}
|
||||
PSID sid = ((TOKEN_OWNER *)information)->Owner;
|
||||
if (!sid || !IsValidSid(sid)) {
|
||||
free(information);
|
||||
return false;
|
||||
}
|
||||
*information_out = information;
|
||||
*sid_out = sid;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool activation_windows_owner_is_current(HANDLE handle) {
|
||||
void *information = NULL;
|
||||
PSID user_sid = NULL;
|
||||
@@ -464,6 +510,17 @@ static bool activation_windows_owner_is_current(HANDLE handle) {
|
||||
DWORD result = GetSecurityInfo(handle, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, &owner, NULL,
|
||||
NULL, NULL, &descriptor);
|
||||
bool same = result == ERROR_SUCCESS && owner && IsValidSid(owner) && EqualSid(owner, user_sid);
|
||||
/* Not our user SID — but Windows may legitimately have stamped our token's
|
||||
* OWNER instead (Administrators, for an elevated account). Accept that and
|
||||
* only that; see activation_windows_token_owner. */
|
||||
if (!same && result == ERROR_SUCCESS && owner && IsValidSid(owner)) {
|
||||
void *owner_information = NULL;
|
||||
PSID token_owner = NULL;
|
||||
if (activation_windows_token_owner(&owner_information, &token_owner)) {
|
||||
same = EqualSid(owner, token_owner) != 0;
|
||||
free(owner_information);
|
||||
}
|
||||
}
|
||||
if (!same) {
|
||||
activation_note_refusal("owner-not-current-user", result);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user