1
// $Id: SspiUtils.cpp 9438 2009-03-29 22:45:53Z mfeingol $
6
#include "MSXException.h"
11
// NOTE: This file MUST be kept in sync between the openmsx and openmsx-debugger projects
17
SspiPackageBase::SspiPackageBase(StreamWrapper& userStream, wchar_t* securityPackage)
19
, cbMaxTokenSize(GetPackageMaxTokenSize(securityPackage))
21
memset(&hCreds, 0, sizeof(hCreds));
22
memset(&hContext, 0, sizeof(hContext));
24
if (!cbMaxTokenSize) {
25
throw MSXException("GetPackageMaxTokenSize failed");
29
SspiPackageBase::~SspiPackageBase()
31
DeleteSecurityContext(&hContext);
32
FreeCredentialsHandle(&hCreds);
35
void InitTokenContextBuffer(PSecBufferDesc pSecBufferDesc, PSecBuffer pSecBuffer)
37
pSecBuffer->BufferType = SECBUFFER_TOKEN;
38
pSecBuffer->cbBuffer = 0;
39
pSecBuffer->pvBuffer = NULL;
41
pSecBufferDesc->ulVersion = SECBUFFER_VERSION;
42
pSecBufferDesc->cBuffers = 1;
43
pSecBufferDesc->pBuffers = pSecBuffer;
46
void ClearContextBuffers(PSecBufferDesc pSecBufferDesc)
48
for (ULONG i = 0; i < pSecBufferDesc->cBuffers; i ++)
50
FreeContextBuffer(pSecBufferDesc->pBuffers[i].pvBuffer);
51
pSecBufferDesc->pBuffers[i].cbBuffer = 0;
52
pSecBufferDesc->pBuffers[i].pvBuffer = NULL;
56
void DebugPrintSecurityStatus(const char* context, SECURITY_STATUS ss)
64
PRT_DEBUG(context << ": SEC_E_OK");
66
case SEC_I_CONTINUE_NEEDED:
67
PRT_DEBUG(context << ": SEC_I_CONTINUE_NEEDED");
69
case SEC_E_INVALID_TOKEN:
70
PRT_DEBUG(context << ": SEC_E_INVALID_TOKEN");
72
case SEC_E_BUFFER_TOO_SMALL:
73
PRT_DEBUG(context << ": SEC_E_BUFFER_TOO_SMALL");
75
case SEC_E_INVALID_HANDLE:
76
PRT_DEBUG(context << ": SEC_E_INVALID_HANDLE");
78
case SEC_E_WRONG_PRINCIPAL:
79
PRT_DEBUG(context << ": SEC_E_WRONG_PRINCIPAL");
82
PRT_DEBUG(context << ": " << ss);
88
void DebugPrintSecurityBool(const char* context, BOOL ret)
94
PRT_DEBUG(context << ": true");
96
PRT_DEBUG(context << ": false - " << GetLastError());
101
void DebugPrintSecurityPackageName(PCtxtHandle phContext)
105
SecPkgContext_PackageInfoA package;
106
SECURITY_STATUS ss = QueryContextAttributesA(phContext, SECPKG_ATTR_PACKAGE_INFO, &package);
107
if (ss == SEC_E_OK) {
108
PRT_DEBUG("Using " << package.PackageInfo->Name << " package");
113
void DebugPrintSecurityPrincipalName(PCtxtHandle phContext)
117
SecPkgContext_NamesA name;
118
SECURITY_STATUS ss = QueryContextAttributesA(phContext, SECPKG_ATTR_NAMES, &name);
119
if (ss == SEC_E_OK) {
120
PRT_DEBUG("Client principal " << name.sUserName);
125
void DebugPrintSecurityDescriptor(PSECURITY_DESCRIPTOR psd)
130
BOOL ret = ConvertSecurityDescriptorToStringSecurityDescriptorA(
133
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
134
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
138
PRT_DEBUG("SecurityDescriptor: " << sddl);
144
// If successful, caller must free the results with LocalFree()
145
// If unsuccessful, returns null
146
PTOKEN_USER GetProcessToken()
148
PTOKEN_USER pToken = NULL;
150
HANDLE hProcessToken;
151
BOOL ret = OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hProcessToken);
152
DebugPrintSecurityBool("OpenProcessToken", ret);
156
ret = GetTokenInformation(hProcessToken, TokenUser, NULL, 0, &cbToken);
157
assert(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && cbToken);
159
pToken = (TOKEN_USER*)LocalAlloc(LMEM_ZEROINIT, cbToken);
161
ret = GetTokenInformation(hProcessToken, TokenUser, pToken, cbToken, &cbToken);
162
DebugPrintSecurityBool("GetTokenInformation", ret);
169
CloseHandle(hProcessToken);
175
// If successful, caller must free the results with LocalFree()
176
// If unsuccessful, returns null
177
PSECURITY_DESCRIPTOR CreateCurrentUserSecurityDescriptor()
179
PSECURITY_DESCRIPTOR psd = NULL;
180
PTOKEN_USER pToken = GetProcessToken();
182
PSID pUserSid = pToken->User.Sid;
183
const DWORD cbEachAce = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD);
184
const DWORD cbACL = sizeof(ACL) + cbEachAce + GetLengthSid(pUserSid);
186
// Allocate the SD and the ACL in one allocation, so we only have one buffer to manage
187
// The SD structure ends with a pointer, so the start of the ACL will be well aligned
188
BYTE* buffer = (BYTE*)LocalAlloc(LMEM_ZEROINIT, SECURITY_DESCRIPTOR_MIN_LENGTH + cbACL);
190
psd = (PSECURITY_DESCRIPTOR)buffer;
191
PACL pacl = (PACL)(buffer + SECURITY_DESCRIPTOR_MIN_LENGTH);
192
PACCESS_ALLOWED_ACE pUserAce;
193
if (InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION) &&
194
InitializeAcl(pacl, cbACL, ACL_REVISION) &&
195
AddAccessAllowedAce(pacl, ACL_REVISION, ACCESS_ALL, pUserSid) &&
196
SetSecurityDescriptorDacl(psd, TRUE, pacl, FALSE) &&
197
// Need to set the Group and Owner on the SD in order to use it with AccessCheck()
198
GetAce(pacl, 0, (void**)&pUserAce) &&
199
SetSecurityDescriptorGroup(psd, &pUserAce->SidStart, FALSE) &&
200
SetSecurityDescriptorOwner(psd, &pUserAce->SidStart, FALSE))
214
assert(IsValidSecurityDescriptor(psd));
215
DebugPrintSecurityDescriptor(psd);
221
unsigned long GetPackageMaxTokenSize(wchar_t* package)
223
PSecPkgInfoW pkgInfo;
224
SECURITY_STATUS ss = QuerySecurityPackageInfoW(package, &pkgInfo);
225
DebugPrintSecurityStatus("QuerySecurityPackageInfoW", ss);
226
if (ss != SEC_E_OK) {
230
unsigned long cbMaxToken = pkgInfo->cbMaxToken;
231
FreeContextBuffer(pkgInfo);
235
bool Send(StreamWrapper& stream, void* buffer, uint32 cb)
240
uint32 ret = stream.Write((char*)buffer + sent, cb - sent);
241
if (ret == STREAM_ERROR) {
249
bool SendChunk(StreamWrapper& stream, void* buffer, uint32 cb)
251
uint32 nl = htonl(cb);
252
if (!Send(stream, &nl, sizeof(nl))) {
255
return Send(stream, buffer, cb);
258
bool Recv(StreamWrapper& stream, void* buffer, uint32 cb)
262
uint32 ret = stream.Read((char*)buffer + recvd, cb - recvd);
263
if (ret == STREAM_ERROR) {
272
bool RecvChunkSize(StreamWrapper& stream, uint32* pcb)
275
bool ret = Recv(stream, &cb, sizeof(cb));
282
bool RecvChunk(StreamWrapper& stream, std::vector<char>& buffer, uint32 cbMaxSize)
285
if (!RecvChunkSize(stream, &cb) || cb > cbMaxSize) {
289
if (!Recv(stream, &buffer[0], cb)) {
295
} // namespace sspiutils
296
} // namespace openmsx