diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
commit | a9bcc81f821d7c66f623779fa5147e728eb3c388 (patch) | |
tree | 98676963bcdd537ae5908a067a8eb110b93486a6 /winpr/libwinpr/sspi/sspi_winpr.c | |
parent | Initial commit. (diff) | |
download | freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip |
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'winpr/libwinpr/sspi/sspi_winpr.c')
-rw-r--r-- | winpr/libwinpr/sspi/sspi_winpr.c | 2226 |
1 files changed, 2226 insertions, 0 deletions
diff --git a/winpr/libwinpr/sspi/sspi_winpr.c b/winpr/libwinpr/sspi/sspi_winpr.c new file mode 100644 index 0000000..1978650 --- /dev/null +++ b/winpr/libwinpr/sspi/sspi_winpr.c @@ -0,0 +1,2226 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Security Support Provider Interface (SSPI) + * + * Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * Copyright 2017 Dorian Ducournau <dorian.ducournau@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <winpr/config.h> +#include <winpr/assert.h> +#include <winpr/windows.h> + +#include <winpr/crt.h> +#include <winpr/sspi.h> +#include <winpr/ssl.h> +#include <winpr/print.h> + +#include "sspi.h" + +#include "sspi_winpr.h" + +#include "../log.h" +#define TAG WINPR_TAG("sspi") + +/* Authentication Functions: http://msdn.microsoft.com/en-us/library/windows/desktop/aa374731/ */ + +#include "NTLM/ntlm.h" +#include "NTLM/ntlm_export.h" +#include "CredSSP/credssp.h" +#include "Kerberos/kerberos.h" +#include "Negotiate/negotiate.h" +#include "Schannel/schannel.h" + +static const SecPkgInfoA* SecPkgInfoA_LIST[] = { &NTLM_SecPkgInfoA, &KERBEROS_SecPkgInfoA, + &NEGOTIATE_SecPkgInfoA, &CREDSSP_SecPkgInfoA, + &SCHANNEL_SecPkgInfoA }; + +static const SecPkgInfoW* SecPkgInfoW_LIST[] = { &NTLM_SecPkgInfoW, &KERBEROS_SecPkgInfoW, + &NEGOTIATE_SecPkgInfoW, &CREDSSP_SecPkgInfoW, + &SCHANNEL_SecPkgInfoW }; + +static SecurityFunctionTableA winpr_SecurityFunctionTableA; +static SecurityFunctionTableW winpr_SecurityFunctionTableW; + +typedef struct +{ + const SEC_CHAR* Name; + const SecurityFunctionTableA* SecurityFunctionTable; +} SecurityFunctionTableA_NAME; + +typedef struct +{ + const SEC_WCHAR* Name; + const SecurityFunctionTableW* SecurityFunctionTable; +} SecurityFunctionTableW_NAME; + +static const SecurityFunctionTableA_NAME SecurityFunctionTableA_NAME_LIST[] = { + { "NTLM", &NTLM_SecurityFunctionTableA }, + { "Kerberos", &KERBEROS_SecurityFunctionTableA }, + { "Negotiate", &NEGOTIATE_SecurityFunctionTableA }, + { "CREDSSP", &CREDSSP_SecurityFunctionTableA }, + { "Schannel", &SCHANNEL_SecurityFunctionTableA } +}; + +static WCHAR BUFFER_NAME_LIST_W[5][32] = { 0 }; + +static const SecurityFunctionTableW_NAME SecurityFunctionTableW_NAME_LIST[] = { + { BUFFER_NAME_LIST_W[0], &NTLM_SecurityFunctionTableW }, + { BUFFER_NAME_LIST_W[1], &KERBEROS_SecurityFunctionTableW }, + { BUFFER_NAME_LIST_W[2], &NEGOTIATE_SecurityFunctionTableW }, + { BUFFER_NAME_LIST_W[3], &CREDSSP_SecurityFunctionTableW }, + { BUFFER_NAME_LIST_W[4], &SCHANNEL_SecurityFunctionTableW } +}; + +#define SecHandle_LOWER_MAX 0xFFFFFFFF +#define SecHandle_UPPER_MAX 0xFFFFFFFE + +typedef struct +{ + void* contextBuffer; + UINT32 allocatorIndex; +} CONTEXT_BUFFER_ALLOC_ENTRY; + +typedef struct +{ + UINT32 cEntries; + UINT32 cMaxEntries; + CONTEXT_BUFFER_ALLOC_ENTRY* entries; +} CONTEXT_BUFFER_ALLOC_TABLE; + +static CONTEXT_BUFFER_ALLOC_TABLE ContextBufferAllocTable = { 0 }; + +static int sspi_ContextBufferAllocTableNew(void) +{ + size_t size = 0; + ContextBufferAllocTable.entries = NULL; + ContextBufferAllocTable.cEntries = 0; + ContextBufferAllocTable.cMaxEntries = 4; + size = sizeof(CONTEXT_BUFFER_ALLOC_ENTRY) * ContextBufferAllocTable.cMaxEntries; + ContextBufferAllocTable.entries = (CONTEXT_BUFFER_ALLOC_ENTRY*)calloc(1, size); + + if (!ContextBufferAllocTable.entries) + return -1; + + return 1; +} + +static int sspi_ContextBufferAllocTableGrow(void) +{ + size_t size = 0; + CONTEXT_BUFFER_ALLOC_ENTRY* entries = NULL; + ContextBufferAllocTable.cEntries = 0; + ContextBufferAllocTable.cMaxEntries *= 2; + size = sizeof(CONTEXT_BUFFER_ALLOC_ENTRY) * ContextBufferAllocTable.cMaxEntries; + + if (!size) + return -1; + + entries = (CONTEXT_BUFFER_ALLOC_ENTRY*)realloc(ContextBufferAllocTable.entries, size); + + if (!entries) + { + free(ContextBufferAllocTable.entries); + return -1; + } + + ContextBufferAllocTable.entries = entries; + ZeroMemory((void*)&ContextBufferAllocTable.entries[ContextBufferAllocTable.cMaxEntries / 2], + size / 2); + return 1; +} + +static void sspi_ContextBufferAllocTableFree(void) +{ + if (ContextBufferAllocTable.cEntries != 0) + WLog_ERR(TAG, "ContextBufferAllocTable.entries == %" PRIu32, + ContextBufferAllocTable.cEntries); + + ContextBufferAllocTable.cEntries = ContextBufferAllocTable.cMaxEntries = 0; + free(ContextBufferAllocTable.entries); + ContextBufferAllocTable.entries = NULL; +} + +static void* sspi_ContextBufferAlloc(UINT32 allocatorIndex, size_t size) +{ + void* contextBuffer = NULL; + + for (UINT32 index = 0; index < ContextBufferAllocTable.cMaxEntries; index++) + { + if (!ContextBufferAllocTable.entries[index].contextBuffer) + { + contextBuffer = calloc(1, size); + + if (!contextBuffer) + return NULL; + + ContextBufferAllocTable.cEntries++; + ContextBufferAllocTable.entries[index].contextBuffer = contextBuffer; + ContextBufferAllocTable.entries[index].allocatorIndex = allocatorIndex; + return ContextBufferAllocTable.entries[index].contextBuffer; + } + } + + /* no available entry was found, the table needs to be grown */ + + if (sspi_ContextBufferAllocTableGrow() < 0) + return NULL; + + /* the next call to sspi_ContextBufferAlloc() should now succeed */ + return sspi_ContextBufferAlloc(allocatorIndex, size); +} + +SSPI_CREDENTIALS* sspi_CredentialsNew(void) +{ + SSPI_CREDENTIALS* credentials = NULL; + credentials = (SSPI_CREDENTIALS*)calloc(1, sizeof(SSPI_CREDENTIALS)); + return credentials; +} + +void sspi_CredentialsFree(SSPI_CREDENTIALS* credentials) +{ + size_t userLength = 0; + size_t domainLength = 0; + size_t passwordLength = 0; + + if (!credentials) + return; + + if (credentials->ntlmSettings.samFile) + free(credentials->ntlmSettings.samFile); + + userLength = credentials->identity.UserLength; + domainLength = credentials->identity.DomainLength; + passwordLength = credentials->identity.PasswordLength; + + if (passwordLength > SSPI_CREDENTIALS_HASH_LENGTH_OFFSET) /* [pth] */ + passwordLength -= SSPI_CREDENTIALS_HASH_LENGTH_OFFSET; + + if (credentials->identity.Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) + { + userLength *= 2; + domainLength *= 2; + passwordLength *= 2; + } + + if (credentials->identity.User) + memset(credentials->identity.User, 0, userLength); + if (credentials->identity.Domain) + memset(credentials->identity.Domain, 0, domainLength); + if (credentials->identity.Password) + memset(credentials->identity.Password, 0, passwordLength); + free(credentials->identity.User); + free(credentials->identity.Domain); + free(credentials->identity.Password); + free(credentials); +} + +void* sspi_SecBufferAlloc(PSecBuffer SecBuffer, ULONG size) +{ + if (!SecBuffer) + return NULL; + + SecBuffer->pvBuffer = calloc(1, size); + + if (!SecBuffer->pvBuffer) + return NULL; + + SecBuffer->cbBuffer = size; + return SecBuffer->pvBuffer; +} + +void sspi_SecBufferFree(PSecBuffer SecBuffer) +{ + if (!SecBuffer) + return; + + if (SecBuffer->pvBuffer) + memset(SecBuffer->pvBuffer, 0, SecBuffer->cbBuffer); + + free(SecBuffer->pvBuffer); + SecBuffer->pvBuffer = NULL; + SecBuffer->cbBuffer = 0; +} + +SecHandle* sspi_SecureHandleAlloc(void) +{ + SecHandle* handle = (SecHandle*)calloc(1, sizeof(SecHandle)); + + if (!handle) + return NULL; + + SecInvalidateHandle(handle); + return handle; +} + +void* sspi_SecureHandleGetLowerPointer(SecHandle* handle) +{ + void* pointer = NULL; + + if (!handle || !SecIsValidHandle(handle) || !handle->dwLower) + return NULL; + + pointer = (void*)~((size_t)handle->dwLower); + return pointer; +} + +void sspi_SecureHandleInvalidate(SecHandle* handle) +{ + if (!handle) + return; + + handle->dwLower = 0; + handle->dwUpper = 0; +} + +void sspi_SecureHandleSetLowerPointer(SecHandle* handle, void* pointer) +{ + if (!handle) + return; + + handle->dwLower = (ULONG_PTR)(~((size_t)pointer)); +} + +void* sspi_SecureHandleGetUpperPointer(SecHandle* handle) +{ + void* pointer = NULL; + + if (!handle || !SecIsValidHandle(handle) || !handle->dwUpper) + return NULL; + + pointer = (void*)~((size_t)handle->dwUpper); + return pointer; +} + +void sspi_SecureHandleSetUpperPointer(SecHandle* handle, void* pointer) +{ + if (!handle) + return; + + handle->dwUpper = (ULONG_PTR)(~((size_t)pointer)); +} + +void sspi_SecureHandleFree(SecHandle* handle) +{ + free(handle); +} + +int sspi_SetAuthIdentityW(SEC_WINNT_AUTH_IDENTITY* identity, const WCHAR* user, const WCHAR* domain, + const WCHAR* password) +{ + return sspi_SetAuthIdentityWithLengthW(identity, user, user ? _wcslen(user) : 0, domain, + domain ? _wcslen(domain) : 0, password, + password ? _wcslen(password) : 0); +} + +static BOOL copy(WCHAR** dst, ULONG* dstLen, const WCHAR* what, size_t len) +{ + WINPR_ASSERT(dst); + WINPR_ASSERT(dstLen); + + *dst = NULL; + *dstLen = 0; + + *dst = calloc(sizeof(WCHAR), len + 1); + if (!*dst) + return FALSE; + memcpy(*dst, what, len * sizeof(WCHAR)); + *dstLen = len; + return TRUE; +} + +int sspi_SetAuthIdentityWithLengthW(SEC_WINNT_AUTH_IDENTITY* identity, const WCHAR* user, + size_t userLen, const WCHAR* domain, size_t domainLen, + const WCHAR* password, size_t passwordLen) +{ + WINPR_ASSERT(identity); + sspi_FreeAuthIdentity(identity); + identity->Flags &= ~SEC_WINNT_AUTH_IDENTITY_ANSI; + identity->Flags |= SEC_WINNT_AUTH_IDENTITY_UNICODE; + + if (!copy(&identity->User, &identity->UserLength, user, userLen)) + return -1; + + if (!copy(&identity->Domain, &identity->DomainLength, domain, domainLen)) + return -1; + + if (!copy(&identity->Password, &identity->PasswordLength, password, passwordLen)) + return -1; + + return 1; +} + +static void zfree(WCHAR* str, size_t len) +{ + if (str) + memset(str, 0, len * sizeof(WCHAR)); + free(str); +} + +int sspi_SetAuthIdentityA(SEC_WINNT_AUTH_IDENTITY* identity, const char* user, const char* domain, + const char* password) +{ + int rc = 0; + size_t unicodeUserLenW = 0; + size_t unicodeDomainLenW = 0; + size_t unicodePasswordLenW = 0; + LPWSTR unicodeUser = ConvertUtf8ToWCharAlloc(user, &unicodeUserLenW); + LPWSTR unicodeDomain = ConvertUtf8ToWCharAlloc(domain, &unicodeDomainLenW); + LPWSTR unicodePassword = ConvertUtf8ToWCharAlloc(password, &unicodePasswordLenW); + + rc = sspi_SetAuthIdentityWithLengthW(identity, unicodeUser, unicodeUserLenW, unicodeDomain, + unicodeDomainLenW, unicodePassword, unicodePasswordLenW); + + zfree(unicodeUser, unicodeUserLenW); + zfree(unicodeDomain, unicodeDomainLenW); + zfree(unicodePassword, unicodePasswordLenW); + return rc; +} + +UINT32 sspi_GetAuthIdentityVersion(const void* identity) +{ + UINT32 version = 0; + + if (!identity) + return 0; + + version = *((const UINT32*)identity); + + if ((version == SEC_WINNT_AUTH_IDENTITY_VERSION) || + (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2)) + { + return version; + } + + return 0; // SEC_WINNT_AUTH_IDENTITY (no version) +} + +UINT32 sspi_GetAuthIdentityFlags(const void* identity) +{ + UINT32 version = 0; + UINT32 flags = 0; + + if (!identity) + return 0; + + version = sspi_GetAuthIdentityVersion(identity); + + if (version == SEC_WINNT_AUTH_IDENTITY_VERSION) + { + flags = ((const SEC_WINNT_AUTH_IDENTITY_EX*)identity)->Flags; + } + else if (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2) + { + flags = ((const SEC_WINNT_AUTH_IDENTITY_EX2*)identity)->Flags; + } + else // SEC_WINNT_AUTH_IDENTITY + { + flags = ((const SEC_WINNT_AUTH_IDENTITY*)identity)->Flags; + } + + return flags; +} + +BOOL sspi_GetAuthIdentityUserDomainW(const void* identity, const WCHAR** pUser, UINT32* pUserLength, + const WCHAR** pDomain, UINT32* pDomainLength) +{ + UINT32 version = 0; + + if (!identity) + return FALSE; + + version = sspi_GetAuthIdentityVersion(identity); + + if (version == SEC_WINNT_AUTH_IDENTITY_VERSION) + { + const SEC_WINNT_AUTH_IDENTITY_EXW* id = (const SEC_WINNT_AUTH_IDENTITY_EXW*)identity; + *pUser = (const WCHAR*)id->User; + *pUserLength = id->UserLength; + *pDomain = (const WCHAR*)id->Domain; + *pDomainLength = id->DomainLength; + } + else if (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2) + { + const SEC_WINNT_AUTH_IDENTITY_EX2* id = (const SEC_WINNT_AUTH_IDENTITY_EX2*)identity; + UINT32 UserOffset = id->UserOffset; + UINT32 DomainOffset = id->DomainOffset; + *pUser = (const WCHAR*)&((const uint8_t*)identity)[UserOffset]; + *pUserLength = id->UserLength / 2; + *pDomain = (const WCHAR*)&((const uint8_t*)identity)[DomainOffset]; + *pDomainLength = id->DomainLength / 2; + } + else // SEC_WINNT_AUTH_IDENTITY + { + const SEC_WINNT_AUTH_IDENTITY_W* id = (const SEC_WINNT_AUTH_IDENTITY_W*)identity; + *pUser = (const WCHAR*)id->User; + *pUserLength = id->UserLength; + *pDomain = (const WCHAR*)id->Domain; + *pDomainLength = id->DomainLength; + } + + return TRUE; +} + +BOOL sspi_GetAuthIdentityUserDomainA(const void* identity, const char** pUser, UINT32* pUserLength, + const char** pDomain, UINT32* pDomainLength) +{ + UINT32 version = 0; + + if (!identity) + return FALSE; + + version = sspi_GetAuthIdentityVersion(identity); + + if (version == SEC_WINNT_AUTH_IDENTITY_VERSION) + { + const SEC_WINNT_AUTH_IDENTITY_EXA* id = (const SEC_WINNT_AUTH_IDENTITY_EXA*)identity; + *pUser = (const char*)id->User; + *pUserLength = id->UserLength; + *pDomain = (const char*)id->Domain; + *pDomainLength = id->DomainLength; + } + else if (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2) + { + const SEC_WINNT_AUTH_IDENTITY_EX2* id = (const SEC_WINNT_AUTH_IDENTITY_EX2*)identity; + UINT32 UserOffset = id->UserOffset; + UINT32 DomainOffset = id->DomainOffset; + *pUser = (const char*)&((const uint8_t*)identity)[UserOffset]; + *pUserLength = id->UserLength; + *pDomain = (const char*)&((const uint8_t*)identity)[DomainOffset]; + *pDomainLength = id->DomainLength; + } + else // SEC_WINNT_AUTH_IDENTITY + { + const SEC_WINNT_AUTH_IDENTITY_A* id = (const SEC_WINNT_AUTH_IDENTITY_A*)identity; + *pUser = (const char*)id->User; + *pUserLength = id->UserLength; + *pDomain = (const char*)id->Domain; + *pDomainLength = id->DomainLength; + } + + return TRUE; +} + +BOOL sspi_GetAuthIdentityPasswordW(const void* identity, const WCHAR** pPassword, + UINT32* pPasswordLength) +{ + UINT32 version = 0; + + if (!identity) + return FALSE; + + version = sspi_GetAuthIdentityVersion(identity); + + if (version == SEC_WINNT_AUTH_IDENTITY_VERSION) + { + const SEC_WINNT_AUTH_IDENTITY_EXW* id = (const SEC_WINNT_AUTH_IDENTITY_EXW*)identity; + *pPassword = (const WCHAR*)id->Password; + *pPasswordLength = id->PasswordLength; + } + else if (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2) + { + return FALSE; // TODO: packed credentials + } + else // SEC_WINNT_AUTH_IDENTITY + { + const SEC_WINNT_AUTH_IDENTITY_W* id = (const SEC_WINNT_AUTH_IDENTITY_W*)identity; + *pPassword = (const WCHAR*)id->Password; + *pPasswordLength = id->PasswordLength; + } + + return TRUE; +} + +BOOL sspi_GetAuthIdentityPasswordA(const void* identity, const char** pPassword, + UINT32* pPasswordLength) +{ + UINT32 version = 0; + + if (!identity) + return FALSE; + + version = sspi_GetAuthIdentityVersion(identity); + + if (version == SEC_WINNT_AUTH_IDENTITY_VERSION) + { + const SEC_WINNT_AUTH_IDENTITY_EXA* id = (const SEC_WINNT_AUTH_IDENTITY_EXA*)identity; + *pPassword = (const char*)id->Password; + *pPasswordLength = id->PasswordLength; + } + else if (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2) + { + return FALSE; // TODO: packed credentials + } + else // SEC_WINNT_AUTH_IDENTITY + { + const SEC_WINNT_AUTH_IDENTITY_A* id = (const SEC_WINNT_AUTH_IDENTITY_A*)identity; + *pPassword = (const char*)id->Password; + *pPasswordLength = id->PasswordLength; + } + + return TRUE; +} + +BOOL sspi_CopyAuthIdentityFieldsA(const SEC_WINNT_AUTH_IDENTITY_INFO* identity, char** pUser, + char** pDomain, char** pPassword) +{ + BOOL success = FALSE; + const char* UserA = NULL; + const char* DomainA = NULL; + const char* PasswordA = NULL; + const WCHAR* UserW = NULL; + const WCHAR* DomainW = NULL; + const WCHAR* PasswordW = NULL; + UINT32 UserLength = 0; + UINT32 DomainLength = 0; + UINT32 PasswordLength = 0; + + if (!identity || !pUser || !pDomain || !pPassword) + return FALSE; + + *pUser = *pDomain = *pPassword = NULL; + + UINT32 identityFlags = sspi_GetAuthIdentityFlags(identity); + + if (identityFlags & SEC_WINNT_AUTH_IDENTITY_ANSI) + { + if (!sspi_GetAuthIdentityUserDomainA(identity, &UserA, &UserLength, &DomainA, + &DomainLength)) + goto cleanup; + + if (!sspi_GetAuthIdentityPasswordA(identity, &PasswordA, &PasswordLength)) + goto cleanup; + + if (UserA && UserLength) + { + *pUser = _strdup(UserA); + + if (!(*pUser)) + goto cleanup; + } + + if (DomainA && DomainLength) + { + *pDomain = _strdup(DomainA); + + if (!(*pDomain)) + goto cleanup; + } + + if (PasswordA && PasswordLength) + { + *pPassword = _strdup(PasswordA); + + if (!(*pPassword)) + goto cleanup; + } + + success = TRUE; + } + else + { + if (!sspi_GetAuthIdentityUserDomainW(identity, &UserW, &UserLength, &DomainW, + &DomainLength)) + goto cleanup; + + if (!sspi_GetAuthIdentityPasswordW(identity, &PasswordW, &PasswordLength)) + goto cleanup; + + if (UserW && (UserLength > 0)) + { + *pUser = ConvertWCharNToUtf8Alloc(UserW, UserLength, NULL); + if (!(*pUser)) + goto cleanup; + } + + if (DomainW && (DomainLength > 0)) + { + *pDomain = ConvertWCharNToUtf8Alloc(DomainW, DomainLength, NULL); + if (!(*pDomain)) + goto cleanup; + } + + if (PasswordW && (PasswordLength > 0)) + { + *pPassword = ConvertWCharNToUtf8Alloc(PasswordW, PasswordLength, NULL); + if (!(*pPassword)) + goto cleanup; + } + + success = TRUE; + } + +cleanup: + return success; +} + +BOOL sspi_CopyAuthIdentityFieldsW(const SEC_WINNT_AUTH_IDENTITY_INFO* identity, WCHAR** pUser, + WCHAR** pDomain, WCHAR** pPassword) +{ + BOOL success = FALSE; + const char* UserA = NULL; + const char* DomainA = NULL; + const char* PasswordA = NULL; + const WCHAR* UserW = NULL; + const WCHAR* DomainW = NULL; + const WCHAR* PasswordW = NULL; + UINT32 UserLength = 0; + UINT32 DomainLength = 0; + UINT32 PasswordLength = 0; + + if (!identity || !pUser || !pDomain || !pPassword) + return FALSE; + + *pUser = *pDomain = *pPassword = NULL; + + UINT32 identityFlags = sspi_GetAuthIdentityFlags(identity); + + if (identityFlags & SEC_WINNT_AUTH_IDENTITY_ANSI) + { + if (!sspi_GetAuthIdentityUserDomainA(identity, &UserA, &UserLength, &DomainA, + &DomainLength)) + goto cleanup; + + if (!sspi_GetAuthIdentityPasswordA(identity, &PasswordA, &PasswordLength)) + goto cleanup; + + if (UserA && (UserLength > 0)) + { + WCHAR* ptr = ConvertUtf8NToWCharAlloc(UserA, UserLength, NULL); + *pUser = ptr; + + if (!ptr) + goto cleanup; + } + + if (DomainA && (DomainLength > 0)) + { + WCHAR* ptr = ConvertUtf8NToWCharAlloc(DomainA, DomainLength, NULL); + *pDomain = ptr; + if (!ptr) + goto cleanup; + } + + if (PasswordA && (PasswordLength > 0)) + { + WCHAR* ptr = ConvertUtf8NToWCharAlloc(PasswordA, PasswordLength, NULL); + + *pPassword = ptr; + if (!ptr) + goto cleanup; + } + + success = TRUE; + } + else + { + if (!sspi_GetAuthIdentityUserDomainW(identity, &UserW, &UserLength, &DomainW, + &DomainLength)) + goto cleanup; + + if (!sspi_GetAuthIdentityPasswordW(identity, &PasswordW, &PasswordLength)) + goto cleanup; + + if (UserW && UserLength) + { + *pUser = _wcsdup(UserW); + + if (!(*pUser)) + goto cleanup; + } + + if (DomainW && DomainLength) + { + *pDomain = _wcsdup(DomainW); + + if (!(*pDomain)) + goto cleanup; + } + + if (PasswordW && PasswordLength) + { + *pPassword = _wcsdup(PasswordW); + + if (!(*pPassword)) + goto cleanup; + } + + success = TRUE; + } + +cleanup: + return success; +} + +BOOL sspi_CopyAuthPackageListA(const SEC_WINNT_AUTH_IDENTITY_INFO* identity, char** pPackageList) +{ + UINT32 version = 0; + UINT32 identityFlags = 0; + char* PackageList = NULL; + const char* PackageListA = NULL; + const WCHAR* PackageListW = NULL; + UINT32 PackageListLength = 0; + UINT32 PackageListOffset = 0; + const void* pAuthData = (const void*)identity; + + if (!pAuthData) + return FALSE; + + version = sspi_GetAuthIdentityVersion(pAuthData); + identityFlags = sspi_GetAuthIdentityFlags(pAuthData); + + if (identityFlags & SEC_WINNT_AUTH_IDENTITY_ANSI) + { + if (version == SEC_WINNT_AUTH_IDENTITY_VERSION) + { + const SEC_WINNT_AUTH_IDENTITY_EXA* ad = (const SEC_WINNT_AUTH_IDENTITY_EXA*)pAuthData; + PackageListA = (const char*)ad->PackageList; + PackageListLength = ad->PackageListLength; + } + + if (PackageListA && PackageListLength) + { + PackageList = _strdup(PackageListA); + } + } + else + { + if (version == SEC_WINNT_AUTH_IDENTITY_VERSION) + { + const SEC_WINNT_AUTH_IDENTITY_EXW* ad = (const SEC_WINNT_AUTH_IDENTITY_EXW*)pAuthData; + PackageListW = (const WCHAR*)ad->PackageList; + PackageListLength = ad->PackageListLength; + } + else if (version == SEC_WINNT_AUTH_IDENTITY_VERSION_2) + { + const SEC_WINNT_AUTH_IDENTITY_EX2* ad = (const SEC_WINNT_AUTH_IDENTITY_EX2*)pAuthData; + PackageListOffset = ad->PackageListOffset; + PackageListW = (const WCHAR*)&((const uint8_t*)pAuthData)[PackageListOffset]; + PackageListLength = ad->PackageListLength / 2; + } + + if (PackageListW && (PackageListLength > 0)) + PackageList = ConvertWCharNToUtf8Alloc(PackageListW, PackageListLength, NULL); + } + + if (PackageList) + { + *pPackageList = PackageList; + return TRUE; + } + + return FALSE; +} + +int sspi_CopyAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, + const SEC_WINNT_AUTH_IDENTITY_INFO* srcIdentity) +{ + int status = 0; + UINT32 identityFlags = 0; + const char* UserA = NULL; + const char* DomainA = NULL; + const char* PasswordA = NULL; + const WCHAR* UserW = NULL; + const WCHAR* DomainW = NULL; + const WCHAR* PasswordW = NULL; + UINT32 UserLength = 0; + UINT32 DomainLength = 0; + UINT32 PasswordLength = 0; + + sspi_FreeAuthIdentity(identity); + + identityFlags = sspi_GetAuthIdentityFlags(srcIdentity); + + identity->Flags = identityFlags; + + if (identityFlags & SEC_WINNT_AUTH_IDENTITY_ANSI) + { + if (!sspi_GetAuthIdentityUserDomainA(srcIdentity, &UserA, &UserLength, &DomainA, + &DomainLength)) + { + return -1; + } + + if (!sspi_GetAuthIdentityPasswordA(srcIdentity, &PasswordA, &PasswordLength)) + { + return -1; + } + + status = sspi_SetAuthIdentity(identity, UserA, DomainA, PasswordA); + + if (status <= 0) + return -1; + + identity->Flags &= ~SEC_WINNT_AUTH_IDENTITY_ANSI; + identity->Flags |= SEC_WINNT_AUTH_IDENTITY_UNICODE; + return 1; + } + + identity->Flags |= SEC_WINNT_AUTH_IDENTITY_UNICODE; + + if (!sspi_GetAuthIdentityUserDomainW(srcIdentity, &UserW, &UserLength, &DomainW, &DomainLength)) + { + return -1; + } + + if (!sspi_GetAuthIdentityPasswordW(srcIdentity, &PasswordW, &PasswordLength)) + { + return -1; + } + + /* login/password authentication */ + identity->UserLength = UserLength; + + if (identity->UserLength > 0) + { + identity->User = (UINT16*)calloc((identity->UserLength + 1), sizeof(WCHAR)); + + if (!identity->User) + return -1; + + CopyMemory(identity->User, UserW, identity->UserLength * sizeof(WCHAR)); + identity->User[identity->UserLength] = 0; + } + + identity->DomainLength = DomainLength; + + if (identity->DomainLength > 0) + { + identity->Domain = (UINT16*)calloc((identity->DomainLength + 1), sizeof(WCHAR)); + + if (!identity->Domain) + return -1; + + CopyMemory(identity->Domain, DomainW, identity->DomainLength * sizeof(WCHAR)); + identity->Domain[identity->DomainLength] = 0; + } + + identity->PasswordLength = PasswordLength; + + if (identity->PasswordLength > SSPI_CREDENTIALS_HASH_LENGTH_OFFSET) + identity->PasswordLength -= SSPI_CREDENTIALS_HASH_LENGTH_OFFSET; + + if (PasswordW) + { + identity->Password = (UINT16*)calloc((identity->PasswordLength + 1), sizeof(WCHAR)); + + if (!identity->Password) + return -1; + + CopyMemory(identity->Password, PasswordW, identity->PasswordLength * sizeof(WCHAR)); + identity->Password[identity->PasswordLength] = 0; + } + + identity->PasswordLength = PasswordLength; + /* End of login/password authentication */ + return 1; +} + +PSecBuffer sspi_FindSecBuffer(PSecBufferDesc pMessage, ULONG BufferType) +{ + PSecBuffer pSecBuffer = NULL; + + for (UINT32 index = 0; index < pMessage->cBuffers; index++) + { + if (pMessage->pBuffers[index].BufferType == BufferType) + { + pSecBuffer = &pMessage->pBuffers[index]; + break; + } + } + + return pSecBuffer; +} + +static BOOL WINPR_init(void) +{ + + for (size_t x = 0; x < ARRAYSIZE(SecurityFunctionTableA_NAME_LIST); x++) + { + const SecurityFunctionTableA_NAME* const cur = &SecurityFunctionTableA_NAME_LIST[x]; + InitializeConstWCharFromUtf8(cur->Name, BUFFER_NAME_LIST_W[x], + ARRAYSIZE(BUFFER_NAME_LIST_W[x])); + } + return TRUE; +} + +static BOOL CALLBACK sspi_init(PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context) +{ + winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT); + sspi_ContextBufferAllocTableNew(); + if (!SCHANNEL_init()) + return FALSE; + if (!KERBEROS_init()) + return FALSE; + if (!NTLM_init()) + return FALSE; + if (!CREDSSP_init()) + return FALSE; + if (!NEGOTIATE_init()) + return FALSE; + return WINPR_init(); +} + +void sspi_GlobalInit(void) +{ + static INIT_ONCE once = INIT_ONCE_STATIC_INIT; + DWORD flags = 0; + InitOnceExecuteOnce(&once, sspi_init, &flags, NULL); +} + +void sspi_GlobalFinish(void) +{ + sspi_ContextBufferAllocTableFree(); +} + +static const SecurityFunctionTableA* sspi_GetSecurityFunctionTableAByNameA(const SEC_CHAR* Name) +{ + size_t cPackages = sizeof(SecPkgInfoA_LIST) / sizeof(*(SecPkgInfoA_LIST)); + + for (size_t index = 0; index < cPackages; index++) + { + if (strcmp(Name, SecurityFunctionTableA_NAME_LIST[index].Name) == 0) + { + return (const SecurityFunctionTableA*)SecurityFunctionTableA_NAME_LIST[index] + .SecurityFunctionTable; + } + } + + return NULL; +} + +static const SecurityFunctionTableW* sspi_GetSecurityFunctionTableWByNameW(const SEC_WCHAR* Name) +{ + size_t cPackages = sizeof(SecPkgInfoW_LIST) / sizeof(*(SecPkgInfoW_LIST)); + + for (size_t index = 0; index < cPackages; index++) + { + if (_wcscmp(Name, SecurityFunctionTableW_NAME_LIST[index].Name) == 0) + { + return (const SecurityFunctionTableW*)SecurityFunctionTableW_NAME_LIST[index] + .SecurityFunctionTable; + } + } + + return NULL; +} + +static const SecurityFunctionTableW* sspi_GetSecurityFunctionTableWByNameA(const SEC_CHAR* Name) +{ + SEC_WCHAR* NameW = NULL; + const SecurityFunctionTableW* table = NULL; + + if (!Name) + return NULL; + + NameW = ConvertUtf8ToWCharAlloc(Name, NULL); + + if (!NameW) + return NULL; + + table = sspi_GetSecurityFunctionTableWByNameW(NameW); + free(NameW); + return table; +} + +static void FreeContextBuffer_EnumerateSecurityPackages(void* contextBuffer); +static void FreeContextBuffer_QuerySecurityPackageInfo(void* contextBuffer); + +static void sspi_ContextBufferFree(void* contextBuffer) +{ + UINT32 allocatorIndex = 0; + + for (size_t index = 0; index < ContextBufferAllocTable.cMaxEntries; index++) + { + if (contextBuffer == ContextBufferAllocTable.entries[index].contextBuffer) + { + contextBuffer = ContextBufferAllocTable.entries[index].contextBuffer; + allocatorIndex = ContextBufferAllocTable.entries[index].allocatorIndex; + ContextBufferAllocTable.cEntries--; + ContextBufferAllocTable.entries[index].allocatorIndex = 0; + ContextBufferAllocTable.entries[index].contextBuffer = NULL; + + switch (allocatorIndex) + { + case EnumerateSecurityPackagesIndex: + FreeContextBuffer_EnumerateSecurityPackages(contextBuffer); + break; + + case QuerySecurityPackageInfoIndex: + FreeContextBuffer_QuerySecurityPackageInfo(contextBuffer); + break; + } + } + } +} + +/** + * Standard SSPI API + */ + +/* Package Management */ + +static SECURITY_STATUS SEC_ENTRY winpr_EnumerateSecurityPackagesW(ULONG* pcPackages, + PSecPkgInfoW* ppPackageInfo) +{ + size_t size = 0; + UINT32 cPackages = 0; + SecPkgInfoW* pPackageInfo = NULL; + cPackages = sizeof(SecPkgInfoW_LIST) / sizeof(*(SecPkgInfoW_LIST)); + size = sizeof(SecPkgInfoW) * cPackages; + pPackageInfo = (SecPkgInfoW*)sspi_ContextBufferAlloc(EnumerateSecurityPackagesIndex, size); + + if (!pPackageInfo) + return SEC_E_INSUFFICIENT_MEMORY; + + for (size_t index = 0; index < cPackages; index++) + { + pPackageInfo[index].fCapabilities = SecPkgInfoW_LIST[index]->fCapabilities; + pPackageInfo[index].wVersion = SecPkgInfoW_LIST[index]->wVersion; + pPackageInfo[index].wRPCID = SecPkgInfoW_LIST[index]->wRPCID; + pPackageInfo[index].cbMaxToken = SecPkgInfoW_LIST[index]->cbMaxToken; + pPackageInfo[index].Name = _wcsdup(SecPkgInfoW_LIST[index]->Name); + pPackageInfo[index].Comment = _wcsdup(SecPkgInfoW_LIST[index]->Comment); + } + + *(pcPackages) = cPackages; + *(ppPackageInfo) = pPackageInfo; + return SEC_E_OK; +} + +static SECURITY_STATUS SEC_ENTRY winpr_EnumerateSecurityPackagesA(ULONG* pcPackages, + PSecPkgInfoA* ppPackageInfo) +{ + size_t size = 0; + UINT32 cPackages = 0; + SecPkgInfoA* pPackageInfo = NULL; + cPackages = sizeof(SecPkgInfoA_LIST) / sizeof(*(SecPkgInfoA_LIST)); + size = sizeof(SecPkgInfoA) * cPackages; + pPackageInfo = (SecPkgInfoA*)sspi_ContextBufferAlloc(EnumerateSecurityPackagesIndex, size); + + if (!pPackageInfo) + return SEC_E_INSUFFICIENT_MEMORY; + + for (size_t index = 0; index < cPackages; index++) + { + pPackageInfo[index].fCapabilities = SecPkgInfoA_LIST[index]->fCapabilities; + pPackageInfo[index].wVersion = SecPkgInfoA_LIST[index]->wVersion; + pPackageInfo[index].wRPCID = SecPkgInfoA_LIST[index]->wRPCID; + pPackageInfo[index].cbMaxToken = SecPkgInfoA_LIST[index]->cbMaxToken; + pPackageInfo[index].Name = _strdup(SecPkgInfoA_LIST[index]->Name); + pPackageInfo[index].Comment = _strdup(SecPkgInfoA_LIST[index]->Comment); + + if (!pPackageInfo[index].Name || !pPackageInfo[index].Comment) + { + sspi_ContextBufferFree(pPackageInfo); + return SEC_E_INSUFFICIENT_MEMORY; + } + } + + *(pcPackages) = cPackages; + *(ppPackageInfo) = pPackageInfo; + return SEC_E_OK; +} + +static void FreeContextBuffer_EnumerateSecurityPackages(void* contextBuffer) +{ + UINT32 cPackages = 0; + SecPkgInfoA* pPackageInfo = (SecPkgInfoA*)contextBuffer; + cPackages = sizeof(SecPkgInfoA_LIST) / sizeof(*(SecPkgInfoA_LIST)); + + if (!pPackageInfo) + return; + + for (size_t index = 0; index < cPackages; index++) + { + free(pPackageInfo[index].Name); + free(pPackageInfo[index].Comment); + } + + free(pPackageInfo); +} + +SecurityFunctionTableW* SEC_ENTRY winpr_InitSecurityInterfaceW(void) +{ + return &winpr_SecurityFunctionTableW; +} + +SecurityFunctionTableA* SEC_ENTRY winpr_InitSecurityInterfaceA(void) +{ + return &winpr_SecurityFunctionTableA; +} + +static SECURITY_STATUS SEC_ENTRY winpr_QuerySecurityPackageInfoW(SEC_WCHAR* pszPackageName, + PSecPkgInfoW* ppPackageInfo) +{ + size_t size = 0; + SecPkgInfoW* pPackageInfo = NULL; + size_t cPackages = sizeof(SecPkgInfoW_LIST) / sizeof(*(SecPkgInfoW_LIST)); + + for (size_t index = 0; index < cPackages; index++) + { + if (_wcscmp(pszPackageName, SecPkgInfoW_LIST[index]->Name) == 0) + { + size = sizeof(SecPkgInfoW); + pPackageInfo = + (SecPkgInfoW*)sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size); + + if (!pPackageInfo) + return SEC_E_INSUFFICIENT_MEMORY; + + pPackageInfo->fCapabilities = SecPkgInfoW_LIST[index]->fCapabilities; + pPackageInfo->wVersion = SecPkgInfoW_LIST[index]->wVersion; + pPackageInfo->wRPCID = SecPkgInfoW_LIST[index]->wRPCID; + pPackageInfo->cbMaxToken = SecPkgInfoW_LIST[index]->cbMaxToken; + pPackageInfo->Name = _wcsdup(SecPkgInfoW_LIST[index]->Name); + pPackageInfo->Comment = _wcsdup(SecPkgInfoW_LIST[index]->Comment); + *(ppPackageInfo) = pPackageInfo; + return SEC_E_OK; + } + } + + *(ppPackageInfo) = NULL; + return SEC_E_SECPKG_NOT_FOUND; +} + +static SECURITY_STATUS SEC_ENTRY winpr_QuerySecurityPackageInfoA(SEC_CHAR* pszPackageName, + PSecPkgInfoA* ppPackageInfo) +{ + size_t size = 0; + SecPkgInfoA* pPackageInfo = NULL; + size_t cPackages = sizeof(SecPkgInfoA_LIST) / sizeof(*(SecPkgInfoA_LIST)); + + for (size_t index = 0; index < cPackages; index++) + { + if (strcmp(pszPackageName, SecPkgInfoA_LIST[index]->Name) == 0) + { + size = sizeof(SecPkgInfoA); + pPackageInfo = + (SecPkgInfoA*)sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size); + + if (!pPackageInfo) + return SEC_E_INSUFFICIENT_MEMORY; + + pPackageInfo->fCapabilities = SecPkgInfoA_LIST[index]->fCapabilities; + pPackageInfo->wVersion = SecPkgInfoA_LIST[index]->wVersion; + pPackageInfo->wRPCID = SecPkgInfoA_LIST[index]->wRPCID; + pPackageInfo->cbMaxToken = SecPkgInfoA_LIST[index]->cbMaxToken; + pPackageInfo->Name = _strdup(SecPkgInfoA_LIST[index]->Name); + pPackageInfo->Comment = _strdup(SecPkgInfoA_LIST[index]->Comment); + + if (!pPackageInfo->Name || !pPackageInfo->Comment) + { + sspi_ContextBufferFree(pPackageInfo); + return SEC_E_INSUFFICIENT_MEMORY; + } + + *(ppPackageInfo) = pPackageInfo; + return SEC_E_OK; + } + } + + *(ppPackageInfo) = NULL; + return SEC_E_SECPKG_NOT_FOUND; +} + +void FreeContextBuffer_QuerySecurityPackageInfo(void* contextBuffer) +{ + SecPkgInfo* pPackageInfo = (SecPkgInfo*)contextBuffer; + + if (!pPackageInfo) + return; + + free(pPackageInfo->Name); + free(pPackageInfo->Comment); + free(pPackageInfo); +} + +/* Credential Management */ + +static SECURITY_STATUS SEC_ENTRY winpr_AcquireCredentialsHandleW( + SEC_WCHAR* pszPrincipal, SEC_WCHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID, + void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential, + PTimeStamp ptsExpiry) +{ + SECURITY_STATUS status = 0; + const SecurityFunctionTableW* table = sspi_GetSecurityFunctionTableWByNameW(pszPackage); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->AcquireCredentialsHandleW) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->AcquireCredentialsHandleW(pszPrincipal, pszPackage, fCredentialUse, pvLogonID, + pAuthData, pGetKeyFn, pvGetKeyArgument, phCredential, + ptsExpiry); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "AcquireCredentialsHandleW status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_AcquireCredentialsHandleA( + SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID, + void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential, + PTimeStamp ptsExpiry) +{ + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByNameA(pszPackage); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->AcquireCredentialsHandleA) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->AcquireCredentialsHandleA(pszPrincipal, pszPackage, fCredentialUse, pvLogonID, + pAuthData, pGetKeyFn, pvGetKeyArgument, phCredential, + ptsExpiry); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "AcquireCredentialsHandleA status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_ExportSecurityContext(PCtxtHandle phContext, ULONG fFlags, + PSecBuffer pPackedContext, + HANDLE* pToken) +{ + SEC_CHAR* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableW* table = NULL; + Name = (SEC_CHAR*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableWByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->ExportSecurityContext) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->ExportSecurityContext(phContext, fFlags, pPackedContext, pToken); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "ExportSecurityContext status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_FreeCredentialsHandle(PCredHandle phCredential) +{ + char* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (char*)sspi_SecureHandleGetUpperPointer(phCredential); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->FreeCredentialsHandle) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->FreeCredentialsHandle(phCredential); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "FreeCredentialsHandle status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_ImportSecurityContextW(SEC_WCHAR* pszPackage, + PSecBuffer pPackedContext, + HANDLE pToken, PCtxtHandle phContext) +{ + SEC_CHAR* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableW* table = NULL; + Name = (SEC_CHAR*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableWByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->ImportSecurityContextW) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->ImportSecurityContextW(pszPackage, pPackedContext, pToken, phContext); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "ImportSecurityContextW status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_ImportSecurityContextA(SEC_CHAR* pszPackage, + PSecBuffer pPackedContext, + HANDLE pToken, PCtxtHandle phContext) +{ + char* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (char*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->ImportSecurityContextA) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->ImportSecurityContextA(pszPackage, pPackedContext, pToken, phContext); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "ImportSecurityContextA status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_QueryCredentialsAttributesW(PCredHandle phCredential, + ULONG ulAttribute, void* pBuffer) +{ + SEC_WCHAR* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableW* table = NULL; + Name = (SEC_WCHAR*)sspi_SecureHandleGetUpperPointer(phCredential); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableWByNameW(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->QueryCredentialsAttributesW) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "QueryCredentialsAttributesW status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_QueryCredentialsAttributesA(PCredHandle phCredential, + ULONG ulAttribute, void* pBuffer) +{ + char* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (char*)sspi_SecureHandleGetUpperPointer(phCredential); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->QueryCredentialsAttributesA) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->QueryCredentialsAttributesA(phCredential, ulAttribute, pBuffer); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "QueryCredentialsAttributesA status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_SetCredentialsAttributesW(PCredHandle phCredential, + ULONG ulAttribute, void* pBuffer, + ULONG cbBuffer) +{ + SEC_WCHAR* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableW* table = NULL; + Name = (SEC_WCHAR*)sspi_SecureHandleGetUpperPointer(phCredential); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableWByNameW(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->SetCredentialsAttributesW) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->SetCredentialsAttributesW(phCredential, ulAttribute, pBuffer, cbBuffer); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "SetCredentialsAttributesW status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_SetCredentialsAttributesA(PCredHandle phCredential, + ULONG ulAttribute, void* pBuffer, + ULONG cbBuffer) +{ + char* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (char*)sspi_SecureHandleGetUpperPointer(phCredential); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->SetCredentialsAttributesA) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->SetCredentialsAttributesA(phCredential, ulAttribute, pBuffer, cbBuffer); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "SetCredentialsAttributesA status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +/* Context Management */ + +static SECURITY_STATUS SEC_ENTRY +winpr_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, + ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, + PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp) +{ + char* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (char*)sspi_SecureHandleGetUpperPointer(phCredential); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->AcceptSecurityContext) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = + table->AcceptSecurityContext(phCredential, phContext, pInput, fContextReq, TargetDataRep, + phNewContext, pOutput, pfContextAttr, ptsTimeStamp); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "AcceptSecurityContext status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_ApplyControlToken(PCtxtHandle phContext, + PSecBufferDesc pInput) +{ + char* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (char*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->ApplyControlToken) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->ApplyControlToken(phContext, pInput); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "ApplyControlToken status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_CompleteAuthToken(PCtxtHandle phContext, + PSecBufferDesc pToken) +{ + char* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (char*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->CompleteAuthToken) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->CompleteAuthToken(phContext, pToken); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "CompleteAuthToken status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_DeleteSecurityContext(PCtxtHandle phContext) +{ + const char* Name = (char*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + const SecurityFunctionTableA* table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->DeleteSecurityContext) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + const UINT32 status = table->DeleteSecurityContext(phContext); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "DeleteSecurityContext status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_FreeContextBuffer(void* pvContextBuffer) +{ + if (!pvContextBuffer) + return SEC_E_INVALID_HANDLE; + + sspi_ContextBufferFree(pvContextBuffer); + return SEC_E_OK; +} + +static SECURITY_STATUS SEC_ENTRY winpr_ImpersonateSecurityContext(PCtxtHandle phContext) +{ + SEC_CHAR* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableW* table = NULL; + Name = (SEC_CHAR*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableWByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->ImpersonateSecurityContext) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->ImpersonateSecurityContext(phContext); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "ImpersonateSecurityContext status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_InitializeSecurityContextW( + PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR* pszTargetName, ULONG fContextReq, + ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2, + PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry) +{ + SEC_CHAR* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableW* table = NULL; + Name = (SEC_CHAR*)sspi_SecureHandleGetUpperPointer(phCredential); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableWByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->InitializeSecurityContextW) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->InitializeSecurityContextW(phCredential, phContext, pszTargetName, fContextReq, + Reserved1, TargetDataRep, pInput, Reserved2, + phNewContext, pOutput, pfContextAttr, ptsExpiry); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "InitializeSecurityContextW status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_InitializeSecurityContextA( + PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR* pszTargetName, ULONG fContextReq, + ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2, + PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry) +{ + SEC_CHAR* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (SEC_CHAR*)sspi_SecureHandleGetUpperPointer(phCredential); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->InitializeSecurityContextA) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->InitializeSecurityContextA(phCredential, phContext, pszTargetName, fContextReq, + Reserved1, TargetDataRep, pInput, Reserved2, + phNewContext, pOutput, pfContextAttr, ptsExpiry); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "InitializeSecurityContextA status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_QueryContextAttributesW(PCtxtHandle phContext, + ULONG ulAttribute, void* pBuffer) +{ + SEC_CHAR* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableW* table = NULL; + Name = (SEC_CHAR*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableWByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->QueryContextAttributesW) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->QueryContextAttributesW(phContext, ulAttribute, pBuffer); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "QueryContextAttributesW status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_QueryContextAttributesA(PCtxtHandle phContext, + ULONG ulAttribute, void* pBuffer) +{ + SEC_CHAR* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (SEC_CHAR*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->QueryContextAttributesA) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->QueryContextAttributesA(phContext, ulAttribute, pBuffer); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "QueryContextAttributesA status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_QuerySecurityContextToken(PCtxtHandle phContext, + HANDLE* phToken) +{ + SEC_CHAR* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableW* table = NULL; + Name = (SEC_CHAR*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableWByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->QuerySecurityContextToken) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->QuerySecurityContextToken(phContext, phToken); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "QuerySecurityContextToken status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_SetContextAttributesW(PCtxtHandle phContext, + ULONG ulAttribute, void* pBuffer, + ULONG cbBuffer) +{ + SEC_CHAR* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableW* table = NULL; + Name = (SEC_CHAR*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableWByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->SetContextAttributesW) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->SetContextAttributesW(phContext, ulAttribute, pBuffer, cbBuffer); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "SetContextAttributesW status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_SetContextAttributesA(PCtxtHandle phContext, + ULONG ulAttribute, void* pBuffer, + ULONG cbBuffer) +{ + char* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (char*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->SetContextAttributesA) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->SetContextAttributesA(phContext, ulAttribute, pBuffer, cbBuffer); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "SetContextAttributesA status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_RevertSecurityContext(PCtxtHandle phContext) +{ + SEC_CHAR* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableW* table = NULL; + Name = (SEC_CHAR*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableWByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->RevertSecurityContext) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->RevertSecurityContext(phContext); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "RevertSecurityContext status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +/* Message Support */ + +static SECURITY_STATUS SEC_ENTRY winpr_DecryptMessage(PCtxtHandle phContext, + PSecBufferDesc pMessage, ULONG MessageSeqNo, + PULONG pfQOP) +{ + char* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (char*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->DecryptMessage) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->DecryptMessage(phContext, pMessage, MessageSeqNo, pfQOP); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "DecryptMessage status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, + PSecBufferDesc pMessage, ULONG MessageSeqNo) +{ + char* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (char*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->EncryptMessage) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->EncryptMessage(phContext, fQOP, pMessage, MessageSeqNo); + + if (status != SEC_E_OK) + { + WLog_ERR(TAG, "EncryptMessage status %s [0x%08" PRIX32 "]", GetSecurityStatusString(status), + status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_MakeSignature(PCtxtHandle phContext, ULONG fQOP, + PSecBufferDesc pMessage, ULONG MessageSeqNo) +{ + char* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (char*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->MakeSignature) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->MakeSignature(phContext, fQOP, pMessage, MessageSeqNo); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "MakeSignature status %s [0x%08" PRIX32 "]", GetSecurityStatusString(status), + status); + } + + return status; +} + +static SECURITY_STATUS SEC_ENTRY winpr_VerifySignature(PCtxtHandle phContext, + PSecBufferDesc pMessage, ULONG MessageSeqNo, + PULONG pfQOP) +{ + char* Name = NULL; + SECURITY_STATUS status = 0; + const SecurityFunctionTableA* table = NULL; + Name = (char*)sspi_SecureHandleGetUpperPointer(phContext); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableAByNameA(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + if (!table->VerifySignature) + { + WLog_WARN(TAG, "Security module does not provide an implementation"); + return SEC_E_UNSUPPORTED_FUNCTION; + } + + status = table->VerifySignature(phContext, pMessage, MessageSeqNo, pfQOP); + + if (IsSecurityStatusError(status)) + { + WLog_WARN(TAG, "VerifySignature status %s [0x%08" PRIX32 "]", + GetSecurityStatusString(status), status); + } + + return status; +} + +static SecurityFunctionTableA winpr_SecurityFunctionTableA = { + 3, /* dwVersion */ + winpr_EnumerateSecurityPackagesA, /* EnumerateSecurityPackages */ + winpr_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */ + winpr_AcquireCredentialsHandleA, /* AcquireCredentialsHandle */ + winpr_FreeCredentialsHandle, /* FreeCredentialsHandle */ + NULL, /* Reserved2 */ + winpr_InitializeSecurityContextA, /* InitializeSecurityContext */ + winpr_AcceptSecurityContext, /* AcceptSecurityContext */ + winpr_CompleteAuthToken, /* CompleteAuthToken */ + winpr_DeleteSecurityContext, /* DeleteSecurityContext */ + winpr_ApplyControlToken, /* ApplyControlToken */ + winpr_QueryContextAttributesA, /* QueryContextAttributes */ + winpr_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ + winpr_RevertSecurityContext, /* RevertSecurityContext */ + winpr_MakeSignature, /* MakeSignature */ + winpr_VerifySignature, /* VerifySignature */ + winpr_FreeContextBuffer, /* FreeContextBuffer */ + winpr_QuerySecurityPackageInfoA, /* QuerySecurityPackageInfo */ + NULL, /* Reserved3 */ + NULL, /* Reserved4 */ + winpr_ExportSecurityContext, /* ExportSecurityContext */ + winpr_ImportSecurityContextA, /* ImportSecurityContext */ + NULL, /* AddCredentials */ + NULL, /* Reserved8 */ + winpr_QuerySecurityContextToken, /* QuerySecurityContextToken */ + winpr_EncryptMessage, /* EncryptMessage */ + winpr_DecryptMessage, /* DecryptMessage */ + winpr_SetContextAttributesA, /* SetContextAttributes */ + winpr_SetCredentialsAttributesA, /* SetCredentialsAttributes */ +}; + +static SecurityFunctionTableW winpr_SecurityFunctionTableW = { + 3, /* dwVersion */ + winpr_EnumerateSecurityPackagesW, /* EnumerateSecurityPackages */ + winpr_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */ + winpr_AcquireCredentialsHandleW, /* AcquireCredentialsHandle */ + winpr_FreeCredentialsHandle, /* FreeCredentialsHandle */ + NULL, /* Reserved2 */ + winpr_InitializeSecurityContextW, /* InitializeSecurityContext */ + winpr_AcceptSecurityContext, /* AcceptSecurityContext */ + winpr_CompleteAuthToken, /* CompleteAuthToken */ + winpr_DeleteSecurityContext, /* DeleteSecurityContext */ + winpr_ApplyControlToken, /* ApplyControlToken */ + winpr_QueryContextAttributesW, /* QueryContextAttributes */ + winpr_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ + winpr_RevertSecurityContext, /* RevertSecurityContext */ + winpr_MakeSignature, /* MakeSignature */ + winpr_VerifySignature, /* VerifySignature */ + winpr_FreeContextBuffer, /* FreeContextBuffer */ + winpr_QuerySecurityPackageInfoW, /* QuerySecurityPackageInfo */ + NULL, /* Reserved3 */ + NULL, /* Reserved4 */ + winpr_ExportSecurityContext, /* ExportSecurityContext */ + winpr_ImportSecurityContextW, /* ImportSecurityContext */ + NULL, /* AddCredentials */ + NULL, /* Reserved8 */ + winpr_QuerySecurityContextToken, /* QuerySecurityContextToken */ + winpr_EncryptMessage, /* EncryptMessage */ + winpr_DecryptMessage, /* DecryptMessage */ + winpr_SetContextAttributesW, /* SetContextAttributes */ + winpr_SetCredentialsAttributesW, /* SetCredentialsAttributes */ +}; |