forked from microsoft/winget-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSecurity.cpp
More file actions
121 lines (102 loc) · 4.14 KB
/
Copy pathSecurity.cpp
File metadata and controls
121 lines (102 loc) · 4.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
#include "winget/Security.h"
#include "AppInstallerLogging.h"
#include "AppInstallerLanguageUtilities.h"
namespace AppInstaller::Security
{
namespace
{
bool IsSameAuthority(const SID_IDENTIFIER_AUTHORITY& a, const SID_IDENTIFIER_AUTHORITY& b)
{
for (size_t i = 0; i < ARRAYSIZE(a.Value); ++i)
{
if (a.Value[i] != b.Value[i])
{
return false;
}
}
return true;
}
// Helper to impersonate the COM or RPC caller.
struct ImpersonateCOMorRPCCaller
{
static ImpersonateCOMorRPCCaller BeginImpersonation()
{
return {};
}
~ImpersonateCOMorRPCCaller()
{
if (m_serverSecurity)
{
FAIL_FAST_IF_FAILED(m_serverSecurity->RevertToSelf());
}
else
{
FAIL_FAST_IF(RpcRevertToSelf() != RPC_S_OK);
}
}
private:
ImpersonateCOMorRPCCaller()
{
if (SUCCEEDED_LOG(CoGetCallContext(IID_IServerSecurity, m_serverSecurity.put_void())))
{
THROW_IF_FAILED(m_serverSecurity->ImpersonateClient());
}
else
{
RPC_STATUS status = RpcImpersonateClient(nullptr);
THROW_HR_IF(MAKE_HRESULT(SEVERITY_ERROR, FACILITY_RPC, status), status != RPC_S_OK);
}
}
wil::com_ptr<IServerSecurity> m_serverSecurity;
};
}
IntegrityLevel GetEffectiveIntegrityLevel()
{
auto currentIntegrityLevel = wil::get_token_information<TOKEN_MANDATORY_LABEL>();
PSID sid = currentIntegrityLevel->Label.Sid;
THROW_HR_IF(CO_E_INVALIDSID, !IsValidSid(sid));
auto identifierAuthority = GetSidIdentifierAuthority(sid);
THROW_HR_IF(E_UNEXPECTED, !IsSameAuthority(*identifierAuthority, SECURITY_MANDATORY_LABEL_AUTHORITY));
PUCHAR subAuthorityCount = GetSidSubAuthorityCount(sid);
THROW_HR_IF(E_UNEXPECTED, *subAuthorityCount != 1);
PDWORD subAuthority = GetSidSubAuthority(sid, 0);
switch (*subAuthority)
{
case SECURITY_MANDATORY_UNTRUSTED_RID: return IntegrityLevel::Untrusted;
case SECURITY_MANDATORY_LOW_RID: return IntegrityLevel::Low;
case SECURITY_MANDATORY_MEDIUM_RID: return IntegrityLevel::Medium;
case SECURITY_MANDATORY_HIGH_RID: return IntegrityLevel::High;
case SECURITY_MANDATORY_SYSTEM_RID: return IntegrityLevel::System;
case SECURITY_MANDATORY_PROTECTED_PROCESS_RID: return IntegrityLevel::ProtectedProcess;
}
THROW_HR(E_UNEXPECTED);
}
bool IsCOMCallerSameUserAndIntegrityLevel()
{
auto serverUser = wil::get_token_information<TOKEN_USER>();
IntegrityLevel serverIntegrityLevel = GetEffectiveIntegrityLevel();
auto impersonation = ImpersonateCOMorRPCCaller::BeginImpersonation();
auto callingUser = wil::get_token_information<TOKEN_USER>();
IntegrityLevel callingIntegrityLevel = GetEffectiveIntegrityLevel();
if (!EqualSid(serverUser->User.Sid, callingUser->User.Sid))
{
AICLI_LOG(Core, Crit, << "Attempt to access by another user: " << ToString(callingUser->User.Sid));
return false;
}
if (ToIntegral(callingIntegrityLevel) < ToIntegral(serverIntegrityLevel))
{
AICLI_LOG(Core, Crit, << "Attempt to access by a lower integrity process: " << callingIntegrityLevel << " < " << serverIntegrityLevel);
return false;
}
return true;
}
std::string ToString(PSID sid)
{
wil::unique_hlocal_ansistring result;
THROW_IF_WIN32_BOOL_FALSE(ConvertSidToStringSidA(sid, &result));
return result.get();
}
}