19namespace openmsx::sspiutils {
21SspiPackageBase::SspiPackageBase(StreamWrapper& userStream,
const SEC_WCHAR* securityPackage)
23 , cbMaxTokenSize(GetPackageMaxTokenSize(securityPackage))
25 memset(&hCreds, 0,
sizeof(hCreds));
26 memset(&hContext, 0,
sizeof(hContext));
28 if (!cbMaxTokenSize) {
29 throw MSXException(
"GetPackageMaxTokenSize failed");
33SspiPackageBase::~SspiPackageBase()
35 DeleteSecurityContext(&hContext);
36 FreeCredentialsHandle(&hCreds);
39void InitTokenContextBuffer(PSecBufferDesc pSecBufferDesc, PSecBuffer pSecBuffer)
41 pSecBuffer->BufferType = SECBUFFER_TOKEN;
42 pSecBuffer->cbBuffer = 0;
43 pSecBuffer->pvBuffer =
nullptr;
45 pSecBufferDesc->ulVersion = SECBUFFER_VERSION;
46 pSecBufferDesc->cBuffers = 1;
47 pSecBufferDesc->pBuffers = pSecBuffer;
50void ClearContextBuffers(PSecBufferDesc pSecBufferDesc)
52 for (
auto i :
xrange(pSecBufferDesc->cBuffers)) {
53 FreeContextBuffer(pSecBufferDesc->pBuffers[i].pvBuffer);
54 pSecBufferDesc->pBuffers[i].cbBuffer = 0;
55 pSecBufferDesc->pBuffers[i].pvBuffer =
nullptr;
59void DebugPrintSecurityStatus(
const char* context, SECURITY_STATUS ss)
66 std::cerr <<
context <<
": SEC_E_OK\n";
68 case SEC_I_CONTINUE_NEEDED:
69 std::cerr <<
context <<
": SEC_I_CONTINUE_NEEDED\n";
71 case SEC_E_INVALID_TOKEN:
72 std::cerr <<
context <<
": SEC_E_INVALID_TOKEN\n";
74 case SEC_E_BUFFER_TOO_SMALL:
75 std::cerr <<
context <<
": SEC_E_BUFFER_TOO_SMALL\n";
77 case SEC_E_INVALID_HANDLE:
78 std::cerr <<
context <<
": SEC_E_INVALID_HANDLE\n";
80 case SEC_E_WRONG_PRINCIPAL:
81 std::cerr <<
context <<
": SEC_E_WRONG_PRINCIPAL\n";
84 std::cerr <<
context <<
": " << ss <<
'\n';
90void DebugPrintSecurityBool(
const char* context, BOOL ret)
96 std::cerr <<
context <<
": true\n";
98 std::cerr <<
context <<
": false - " << GetLastError() <<
'\n';
103void DebugPrintSecurityPackageName(PCtxtHandle phContext)
107 SecPkgContext_PackageInfoA package;
108 SECURITY_STATUS ss = QueryContextAttributesA(phContext, SECPKG_ATTR_PACKAGE_INFO, &package);
109 if (ss == SEC_E_OK) {
110 std::cerr <<
"Using " << package.PackageInfo->Name <<
" package\n";
115void DebugPrintSecurityPrincipalName(PCtxtHandle phContext)
119 SecPkgContext_NamesA name;
120 SECURITY_STATUS ss = QueryContextAttributesA(phContext, SECPKG_ATTR_NAMES, &name);
121 if (ss == SEC_E_OK) {
122 std::cerr <<
"Client principal " << name.sUserName <<
'\n';
127void DebugPrintSecurityDescriptor(PSECURITY_DESCRIPTOR psd)
132 BOOL ret = ConvertSecurityDescriptorToStringSecurityDescriptorA(
135 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
136 DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
140 std::cerr <<
"SecurityDescriptor: " << sddl <<
'\n';
148static PTOKEN_USER GetProcessToken()
150 PTOKEN_USER pToken =
nullptr;
152 HANDLE hProcessToken;
153 BOOL ret = OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hProcessToken);
154 DebugPrintSecurityBool(
"OpenProcessToken", ret);
157 ret = GetTokenInformation(hProcessToken, TokenUser,
nullptr, 0, &cbToken);
158 assert(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && cbToken);
160 pToken =
static_cast<TOKEN_USER*
>(LocalAlloc(LMEM_ZEROINIT, cbToken));
162 ret = GetTokenInformation(hProcessToken, TokenUser, pToken, cbToken, &cbToken);
163 DebugPrintSecurityBool(
"GetTokenInformation", ret);
169 CloseHandle(hProcessToken);
176PSECURITY_DESCRIPTOR CreateCurrentUserSecurityDescriptor()
178 PSECURITY_DESCRIPTOR psd =
nullptr;
179 PTOKEN_USER pToken = GetProcessToken();
181 PSID pUserSid = pToken->User.Sid;
182 const DWORD cbEachAce =
sizeof(ACCESS_ALLOWED_ACE) -
sizeof(DWORD);
183 const DWORD cbACL =
sizeof(ACL) + cbEachAce + GetLengthSid(pUserSid);
187 BYTE* buffer =
static_cast<BYTE*
>(LocalAlloc(LMEM_ZEROINIT, SECURITY_DESCRIPTOR_MIN_LENGTH + cbACL));
189 psd =
static_cast<PSECURITY_DESCRIPTOR
>(buffer);
190 PACL pacl =
reinterpret_cast<PACL
>(buffer + SECURITY_DESCRIPTOR_MIN_LENGTH);
191 PACCESS_ALLOWED_ACE pUserAce;
192 if (InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION) &&
193 InitializeAcl(pacl, cbACL, ACL_REVISION) &&
194 AddAccessAllowedAce(pacl, ACL_REVISION, ACCESS_ALL, pUserSid) &&
195 SetSecurityDescriptorDacl(psd, TRUE, pacl, FALSE) &&
197 GetAce(pacl, 0, std::bit_cast<void**>(&pUserAce)) &&
198 SetSecurityDescriptorGroup(psd, &pUserAce->SidStart, FALSE) &&
199 SetSecurityDescriptorOwner(psd, &pUserAce->SidStart, FALSE)) {
210 assert(IsValidSecurityDescriptor(psd));
211 DebugPrintSecurityDescriptor(psd);
216unsigned long GetPackageMaxTokenSize(
const SEC_WCHAR* package)
218 PSecPkgInfoW pkgInfo;
219 SECURITY_STATUS ss = QuerySecurityPackageInfoW(
const_cast<SEC_WCHAR*
>(package), &pkgInfo);
220 DebugPrintSecurityStatus(
"QuerySecurityPackageInfoW", ss);
221 if (ss != SEC_E_OK)
return 0;
223 unsigned long cbMaxToken = pkgInfo->cbMaxToken;
224 FreeContextBuffer(pkgInfo);
228static bool Send(StreamWrapper& stream,
void* buffer, uint32_t cb)
232 uint32_t ret = stream.Write(
static_cast<char*
>(buffer) + sent, cb - sent);
233 if (ret == STREAM_ERROR)
return false;
239bool SendChunk(StreamWrapper& stream,
void* buffer, uint32_t cb)
241 uint32_t nl = htonl(cb);
242 if (!Send(stream, &nl,
sizeof(nl))) {
245 return Send(stream, buffer, cb);
248static bool Recv(StreamWrapper& stream,
void* buffer, uint32_t cb)
252 uint32_t ret = stream.Read(
static_cast<char*
>(buffer) + recvd, cb - recvd);
253 if (ret == STREAM_ERROR)
return false;
259static bool RecvChunkSize(StreamWrapper& stream, uint32_t* pcb)
262 bool ret = Recv(stream, &cb,
sizeof(cb));
269bool RecvChunk(StreamWrapper& stream, std::vector<char>& buffer, uint32_t cbMaxSize)
272 if (!RecvChunkSize(stream, &cb) || cb > cbMaxSize) {
276 if (!Recv(stream, &buffer[0], cb)) {
std::optional< Context > context
constexpr auto xrange(T e)