diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index 35545c6e5..30b6ebb62 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -767,6 +767,17 @@ owned by rdpRdp */ FREERDP_API SECURITY_STATUS freerdp_nla_QueryContextAttributes(rdpContext* context, DWORD ulAttr, PVOID pBuffer); + /** Calls FreeContextbuffer on the SSPI context associated with the NLA part of the RDP context + * + * \param context the RDP context + * \param pBuffer an opaque pointer to free + * \returns a SECURITY_STATUS indicating if the operation completed successfully + * \since version 3.22.0 + * + * Supported buffers are ones retrieved from SECPKG_ATTR_PACKAGE_INFO. + */ + FREERDP_API SECURITY_STATUS freerdp_nla_FreeContextBuffer(rdpContext* context, PVOID pBuffer); + FREERDP_API void clearChannelError(rdpContext* context); FREERDP_API HANDLE getChannelErrorEventHandle(rdpContext* context); FREERDP_API UINT getChannelError(const rdpContext* context); diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 696bb8666..02d8d33aa 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -1349,6 +1349,20 @@ SECURITY_STATUS freerdp_nla_QueryContextAttributes(rdpContext* context, DWORD ul return nla_QueryContextAttributes(nla, ulAttr, pBuffer); } +SECURITY_STATUS freerdp_nla_FreeContextBuffer(rdpContext* context, PVOID pBuffer) +{ + WINPR_ASSERT(context); + WINPR_ASSERT(context->rdp); + + rdpNla* nla = context->rdp->nla; + if (!nla) + nla = transport_get_nla(context->rdp->transport); + + WINPR_ASSERT(nla); + + return nla_FreeContextBuffer(nla, pBuffer); +} + HANDLE getChannelErrorEventHandle(rdpContext* context) { WINPR_ASSERT(context); diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index 95e71bc4d..f768f88b0 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -2455,3 +2455,14 @@ SECURITY_STATUS nla_QueryContextAttributes(rdpNla* nla, DWORD ulAttr, PVOID pBuf return table->QueryContextAttributes(&context, ulAttr, pBuffer); } + +SECURITY_STATUS nla_FreeContextBuffer(rdpNla* nla, PVOID pBuffer) +{ + WINPR_ASSERT(nla); + + SecurityFunctionTable* table = NULL; + CtxtHandle context = { 0 }; + credssp_auth_tableAndContext(nla->auth, &table, &context); + + return table->FreeContextBuffer(pBuffer); +} diff --git a/libfreerdp/core/nla.h b/libfreerdp/core/nla.h index cfd758d29..e5a4541ba 100644 --- a/libfreerdp/core/nla.h +++ b/libfreerdp/core/nla.h @@ -78,5 +78,6 @@ FREERDP_LOCAL void nla_set_early_user_auth(rdpNla* nla, BOOL earlyUserAuth); FREERDP_LOCAL BOOL nla_encrypt(rdpNla* nla, const SecBuffer* inBuffer, SecBuffer* outBuffer); FREERDP_LOCAL BOOL nla_decrypt(rdpNla* nla, const SecBuffer* inBuffer, SecBuffer* outBuffer); FREERDP_LOCAL SECURITY_STATUS nla_QueryContextAttributes(rdpNla* nla, DWORD ulAttr, PVOID pBuffer); +FREERDP_LOCAL SECURITY_STATUS nla_FreeContextBuffer(rdpNla* nla, PVOID pBuffer); #endif /* FREERDP_LIB_CORE_NLA_H */ diff --git a/winpr/libwinpr/sspi/Kerberos/kerberos.c b/winpr/libwinpr/sspi/Kerberos/kerberos.c index f05746827..c61e14c9a 100644 --- a/winpr/libwinpr/sspi/Kerberos/kerberos.c +++ b/winpr/libwinpr/sspi/Kerberos/kerberos.c @@ -1781,6 +1781,33 @@ fail: return krb5_error_to_SECURITY_STATUS(rv); } +static SECURITY_STATUS kerberos_ATTR_PACKAGE_INFO(KRB_CONTEXT* context, + KRB_CREDENTIALS* credentials, + SecPkgContext_PackageInfo* PackageInfo) +{ + size_t size = sizeof(SecPkgInfoA); + SecPkgInfoA* pPackageInfo = + (SecPkgInfoA*)sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size); + + if (!pPackageInfo) + return SEC_E_INSUFFICIENT_MEMORY; + + pPackageInfo->fCapabilities = KERBEROS_SecPkgInfoA.fCapabilities; + pPackageInfo->wVersion = KERBEROS_SecPkgInfoA.wVersion; + pPackageInfo->wRPCID = KERBEROS_SecPkgInfoA.wRPCID; + pPackageInfo->cbMaxToken = KERBEROS_SecPkgInfoA.cbMaxToken; + pPackageInfo->Name = _strdup(KERBEROS_SecPkgInfoA.Name); + pPackageInfo->Comment = _strdup(KERBEROS_SecPkgInfoA.Comment); + + if (!pPackageInfo->Name || !pPackageInfo->Comment) + { + sspi_ContextBufferFree(pPackageInfo); + return SEC_E_INSUFFICIENT_MEMORY; + } + PackageInfo->PackageInfo = pPackageInfo; + return SEC_E_OK; +} + static SECURITY_STATUS kerberos_ATTR_TICKET_LOGON(KRB_CONTEXT* context, KRB_CREDENTIALS* credentials, KERB_TICKET_LOGON* ticketLogon) @@ -1883,6 +1910,10 @@ static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesA(PCtxtHandle ph return kerberos_ATTR_AUTH_IDENTITY(context, credentials, (SecPkgContext_AuthIdentity*)pBuffer); + case SECPKG_ATTR_PACKAGE_INFO: + return kerberos_ATTR_PACKAGE_INFO(context, credentials, + (SecPkgContext_PackageInfo*)pBuffer); + case SECPKG_CRED_ATTR_TICKET_LOGON: return kerberos_ATTR_TICKET_LOGON(context, credentials, (KERB_TICKET_LOGON*)pBuffer); diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c index 8ae7323aa..c406fc7ab 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm.c @@ -897,6 +897,31 @@ static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phCont { return ntlm_computeMicValue(context, (SecBuffer*)pBuffer); } + else if (ulAttribute == SECPKG_ATTR_PACKAGE_INFO) + { + SecPkgContext_PackageInfo* PackageInfo = (SecPkgContext_PackageInfo*)pBuffer; + size_t size = sizeof(SecPkgInfoA); + SecPkgInfoA* pPackageInfo = + (SecPkgInfoA*)sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size); + + if (!pPackageInfo) + return SEC_E_INSUFFICIENT_MEMORY; + + pPackageInfo->fCapabilities = NTLM_SecPkgInfoA.fCapabilities; + pPackageInfo->wVersion = NTLM_SecPkgInfoA.wVersion; + pPackageInfo->wRPCID = NTLM_SecPkgInfoA.wRPCID; + pPackageInfo->cbMaxToken = NTLM_SecPkgInfoA.cbMaxToken; + pPackageInfo->Name = _strdup(NTLM_SecPkgInfoA.Name); + pPackageInfo->Comment = _strdup(NTLM_SecPkgInfoA.Comment); + + if (!pPackageInfo->Name || !pPackageInfo->Comment) + { + sspi_ContextBufferFree(pPackageInfo); + return SEC_E_INSUFFICIENT_MEMORY; + } + PackageInfo->PackageInfo = pPackageInfo; + return SEC_E_OK; + } WLog_ERR(TAG, "TODO: Implement ulAttribute=0x%08" PRIx32, ulAttribute); return SEC_E_UNSUPPORTED_FUNCTION; diff --git a/winpr/libwinpr/sspi/sspi_winpr.c b/winpr/libwinpr/sspi/sspi_winpr.c index 99e321ded..5d5268ecc 100644 --- a/winpr/libwinpr/sspi/sspi_winpr.c +++ b/winpr/libwinpr/sspi/sspi_winpr.c @@ -147,7 +147,7 @@ static void sspi_ContextBufferAllocTableFree(void) ContextBufferAllocTable.entries = NULL; } -static void* sspi_ContextBufferAlloc(UINT32 allocatorIndex, size_t size) +void* sspi_ContextBufferAlloc(UINT32 allocatorIndex, size_t size) { void* contextBuffer = NULL; @@ -1050,7 +1050,7 @@ static const SecurityFunctionTableW* sspi_GetSecurityFunctionTableWByNameA(const static void FreeContextBuffer_EnumerateSecurityPackages(void* contextBuffer); static void FreeContextBuffer_QuerySecurityPackageInfo(void* contextBuffer); -static void sspi_ContextBufferFree(void* contextBuffer) +void sspi_ContextBufferFree(void* contextBuffer) { UINT32 allocatorIndex = 0; diff --git a/winpr/libwinpr/sspi/sspi_winpr.h b/winpr/libwinpr/sspi/sspi_winpr.h index 2f7b55afb..490da03f6 100644 --- a/winpr/libwinpr/sspi/sspi_winpr.h +++ b/winpr/libwinpr/sspi/sspi_winpr.h @@ -25,4 +25,7 @@ SecurityFunctionTableW* SEC_ENTRY winpr_InitSecurityInterfaceW(void); SecurityFunctionTableA* SEC_ENTRY winpr_InitSecurityInterfaceA(void); +void* sspi_ContextBufferAlloc(UINT32 allocatorIndex, size_t size); +void sspi_ContextBufferFree(void* contextBuffer); + #endif /* WINPR_SSPI_WINPR_H */