windows-nt/Source/XPSP1/NT/ds/security/protocols/schannel/lsa/credapi.c

2800 lines
75 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: credapi.c
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 9-18-96 RichardW Created
//
//----------------------------------------------------------------------------
#include "sslp.h"
#include "mapper.h"
#include "rpc.h"
#include <sslwow64.h>
typedef struct _SCH_CRED_SECRET {
union {
SCH_CRED_SECRET_CAPI Capi;
SCH_CRED_SECRET_PRIVKEY PrivKey;
} u;
} SCH_CRED_SECRET, * PSCH_CRED_SECRET ;
extern CHAR CertTag[ 13 ];
//+-------------------------------------------------------------------------
//
// Function: CopyClientString
//
// Synopsis: copies a client string to local memory, including
// allocating space for it locally.
//
// Arguments:
// SourceString - Could be Ansi or Wchar in client process
// SourceLength - bytes
// DoUnicode - whether the string is Wchar
//
// Returns:
// DestinationString - Unicode String in Lsa Process
//
// Notes:
//
//--------------------------------------------------------------------------
HRESULT
CopyClientString(
IN PWSTR SourceString,
IN ULONG SourceLength,
IN BOOLEAN DoUnicode,
OUT PUNICODE_STRING DestinationString
)
{
NTSTATUS Status = STATUS_SUCCESS;
STRING TemporaryString;
ULONG SourceSize = 0;
ULONG CharacterSize = sizeof(CHAR);
//
// First initialize the string to zero, in case the source is a null
// string
//
DestinationString->Length = DestinationString->MaximumLength = 0;
DestinationString->Buffer = NULL;
TemporaryString.Buffer = NULL;
if (SourceString != NULL)
{
//
// If the length is zero, allocate one byte for a "\0" terminator
//
if (SourceLength == 0)
{
DestinationString->Buffer = (LPWSTR) LocalAlloc(LPTR, sizeof(WCHAR));
if (DestinationString->Buffer == NULL)
{
Status = SP_LOG_RESULT(STATUS_NO_MEMORY);
goto Cleanup;
}
DestinationString->MaximumLength = sizeof(WCHAR);
*DestinationString->Buffer = L'\0';
}
else
{
//
// Allocate a temporary buffer to hold the client string. We may
// then create a buffer for the unicode version. The length
// is the length in characters, so possible expand to hold unicode
// characters and a null terminator.
//
if (DoUnicode)
{
CharacterSize = sizeof(WCHAR);
}
SourceSize = (SourceLength + 1) * CharacterSize;
//
// insure no overflow aggainst UNICODE_STRING
//
if ( (SourceSize > 0xFFFF) ||
((SourceSize - CharacterSize) > 0xFFFF)
)
{
Status = SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
goto Cleanup;
}
TemporaryString.Buffer = (LPSTR) LocalAlloc(LPTR, SourceSize);
if (TemporaryString.Buffer == NULL)
{
Status = SP_LOG_RESULT(STATUS_NO_MEMORY);
goto Cleanup;
}
TemporaryString.Length = (USHORT) (SourceSize - CharacterSize);
TemporaryString.MaximumLength = (USHORT) SourceSize;
//
// Finally copy the string from the client
//
Status = LsaTable->CopyFromClientBuffer(
NULL,
SourceSize - CharacterSize,
TemporaryString.Buffer,
SourceString
);
if (!NT_SUCCESS(Status))
{
SP_LOG_RESULT(Status);
goto Cleanup;
}
//
// If we are doing unicode, finish up now
//
if (DoUnicode)
{
DestinationString->Buffer = (LPWSTR) TemporaryString.Buffer;
DestinationString->Length = (USHORT) (SourceSize - CharacterSize);
DestinationString->MaximumLength = (USHORT) SourceSize;
}
else
{
NTSTATUS Status1;
Status1 = RtlAnsiStringToUnicodeString(
DestinationString,
&TemporaryString,
TRUE
); // allocate destination
if (!NT_SUCCESS(Status1))
{
Status = SP_LOG_RESULT(STATUS_NO_MEMORY);
goto Cleanup;
}
}
}
}
Cleanup:
if (TemporaryString.Buffer != NULL)
{
//
// Free this if we failed and were doing unicode or if we weren't
// doing unicode
//
if ((DoUnicode && !NT_SUCCESS(Status)) || !DoUnicode)
{
LocalFree(TemporaryString.Buffer);
}
}
return(Status);
}
//+---------------------------------------------------------------------------
//
// Function: SpAcceptCredentials
//
// Synopsis: Accept Credentials - logon notification
//
// Arguments: [LogonType] --
// [UserName] --
// [PrimaryCred] --
// [SupplementalCreds] --
//
// History: 10-04-96 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
SECURITY_STATUS
SEC_ENTRY
SpAcceptCredentials(
IN SECURITY_LOGON_TYPE LogonType,
IN PUNICODE_STRING UserName,
IN PSECPKG_PRIMARY_CRED PrimaryCred,
IN PSECPKG_SUPPLEMENTAL_CRED SupplementalCreds)
{
return( SEC_E_OK );
}
//+---------------------------------------------------------------------------
//
// Function: SpMapSchPublic
//
// Synopsis: Maps a public key credential into LSA memory
//
// Arguments: [pRemotePubs] --
//
// History: 10-06-96 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PVOID
SpMapSchPublic(
PVOID pRemotePubs
)
{
SECURITY_STATUS Status ;
SCH_CRED_PUBLIC_CERTCHAIN Pub, * pPub ;
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof( SCH_CRED_PUBLIC_CERTCHAIN ),
&Pub,
pRemotePubs );
if ( !NT_SUCCESS( Status ) )
{
return( NULL );
}
// Reality check
if(Pub.cbCertChain > 0x00100000)
{
return( NULL );
}
pPub = SPExternalAlloc( sizeof( SCH_CRED_PUBLIC_CERTCHAIN ) +
Pub.cbCertChain );
if ( pPub )
{
pPub->dwType = Pub.dwType ;
pPub->cbCertChain = Pub.cbCertChain ;
pPub->pCertChain = (PUCHAR) ( pPub + 1 );
Status = LsaTable->CopyFromClientBuffer( NULL,
Pub.cbCertChain,
pPub->pCertChain,
Pub.pCertChain );
}
else
{
Status = SEC_E_INSUFFICIENT_MEMORY ;
}
if ( NT_SUCCESS( Status ) )
{
return( pPub );
}
if ( pPub )
{
SPExternalFree( pPub );
}
return( NULL );
}
#ifdef _WIN64
PVOID
SpWow64MapSchPublic(
SSLWOW64_PVOID pRemotePubs)
{
SECURITY_STATUS Status;
SSLWOW64_SCH_CRED_PUBLIC_CERTCHAIN Pub;
SCH_CRED_PUBLIC_CERTCHAIN * pPub;
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof( SSLWOW64_SCH_CRED_PUBLIC_CERTCHAIN ),
&Pub,
ULongToPtr(pRemotePubs));
if ( !NT_SUCCESS( Status ) )
{
return( NULL );
}
// Reality check
if(Pub.cbCertChain > 0x00100000)
{
return( NULL );
}
pPub = SPExternalAlloc( sizeof( SCH_CRED_PUBLIC_CERTCHAIN ) +
Pub.cbCertChain );
if ( pPub )
{
pPub->dwType = Pub.dwType ;
pPub->cbCertChain = Pub.cbCertChain ;
pPub->pCertChain = (PUCHAR) ( pPub + 1 );
Status = LsaTable->CopyFromClientBuffer( NULL,
Pub.cbCertChain,
pPub->pCertChain,
ULongToPtr(Pub.pCertChain));
}
else
{
Status = SEC_E_INSUFFICIENT_MEMORY ;
}
if ( NT_SUCCESS( Status ) )
{
return( pPub );
}
if ( pPub )
{
SPExternalFree( pPub );
}
return( NULL );
}
#endif // _WIN64
PVOID
SpMapSchCred(
PVOID pRemoteCred )
{
SCH_CRED_SECRET Cred ;
SECURITY_STATUS Status ;
DWORD Size ;
DWORD dwType;
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof( DWORD ),
&Cred,
pRemoteCred );
if ( !NT_SUCCESS( Status ) )
{
return( NULL );
}
dwType = Cred.u.Capi.dwType;
switch ( dwType )
{
case SCHANNEL_SECRET_TYPE_CAPI:
Size = sizeof( SCH_CRED_SECRET_CAPI );
break;
case SCHANNEL_SECRET_PRIVKEY:
Size = sizeof( SCH_CRED_SECRET_PRIVKEY );
break;
default:
DebugOut(( DEB_ERROR, "Caller specified an unknown cred type\n" ));
return( NULL );
}
if ( Size )
{
Status = LsaTable->CopyFromClientBuffer(NULL,
Size,
&Cred,
pRemoteCred );
}
else
{
Status = SEC_E_INVALID_HANDLE ;
}
if(dwType != Cred.u.Capi.dwType)
{
Status = SEC_E_INVALID_HANDLE ;
}
if ( !NT_SUCCESS( Status ) )
{
return( NULL );
}
if(Cred.u.Capi.dwType == SCHANNEL_SECRET_TYPE_CAPI)
{
SCH_CRED_SECRET_CAPI *pCapiCred;
pCapiCred = SPExternalAlloc( Size );
if ( !pCapiCred )
{
return( NULL );
}
pCapiCred->dwType = Cred.u.Capi.dwType;
pCapiCred->hProv = Cred.u.Capi.hProv;
return( pCapiCred );
}
if(Cred.u.Capi.dwType == SCHANNEL_SECRET_PRIVKEY)
{
UCHAR Password[ MAX_PATH + 1 ];
DWORD PasswordLen = 0;
SCH_CRED_SECRET_PRIVKEY *pCred;
//
// The password is the painful part. Since it is a string, we don't know
// how long it is. So, we have to take a stab at it:
//
Status = LsaTable->CopyFromClientBuffer( NULL,
MAX_PATH,
Password,
Cred.u.PrivKey.pszPassword );
if ( !NT_SUCCESS( Status ) )
{
return( NULL );
}
Password[ MAX_PATH ] = '\0';
PasswordLen = strlen( Password );
// Reality check private key length.
if(Cred.u.PrivKey.cbPrivateKey > 0x10000)
{
return( NULL );
}
Size = PasswordLen + 1 + Cred.u.PrivKey.cbPrivateKey +
sizeof( SCH_CRED_SECRET_PRIVKEY ) ;
pCred = SPExternalAlloc( Size );
if ( !pCred )
{
return( NULL );
}
pCred->dwType = Cred.u.PrivKey.dwType ;
pCred->cbPrivateKey = Cred.u.PrivKey.cbPrivateKey ;
pCred->pPrivateKey = (PBYTE) ( pCred + 1 );
pCred->pszPassword = (PBYTE) (pCred->pPrivateKey + pCred->cbPrivateKey );
RtlCopyMemory( pCred->pszPassword, Password, PasswordLen + 1 );
Status = LsaTable->CopyFromClientBuffer( NULL,
pCred->cbPrivateKey,
pCred->pPrivateKey,
Cred.u.PrivKey.pPrivateKey );
if ( !NT_SUCCESS( Status ) )
{
SPExternalFree( pCred );
return( NULL );
}
return( pCred );
}
return( NULL );
}
#ifdef _WIN64
PVOID
SpWow64MapSchCred(
SSLWOW64_PVOID pRemoteCred )
{
SSLWOW64_SCH_CRED_SECRET_PRIVKEY LocalCred;
SCH_CRED_SECRET_PRIVKEY *pCred;
UCHAR Password[MAX_PATH + 1];
DWORD PasswordLen = 0;
SECURITY_STATUS Status ;
DWORD dwType;
DWORD Size;
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof( DWORD ),
&dwType,
ULongToPtr(pRemoteCred));
if ( !NT_SUCCESS( Status ) )
{
return( NULL );
}
if(dwType != SCHANNEL_SECRET_PRIVKEY)
{
DebugOut(( DEB_ERROR, "Caller specified an unknown cred type\n" ));
return( NULL );
}
Status = LsaTable->CopyFromClientBuffer(NULL,
sizeof(SSLWOW64_SCH_CRED_SECRET_PRIVKEY),
&LocalCred,
ULongToPtr(pRemoteCred));
if ( !NT_SUCCESS( Status ) )
{
return( NULL );
}
//
// The password is the painful part. Since it is a string, we don't know
// how long it is. So, we have to take a stab at it:
//
Status = LsaTable->CopyFromClientBuffer( NULL,
MAX_PATH,
Password,
ULongToPtr(LocalCred.pszPassword));
if ( !NT_SUCCESS( Status ) )
{
return( NULL );
}
Password[ MAX_PATH ] = '\0';
PasswordLen = strlen( Password );
// Reality check private key length.
if(LocalCred.cbPrivateKey > 0x10000)
{
return( NULL );
}
Size = PasswordLen + 1 + LocalCred.cbPrivateKey +
sizeof( SCH_CRED_SECRET_PRIVKEY ) ;
pCred = SPExternalAlloc( Size );
if ( !pCred )
{
return( NULL );
}
pCred->dwType = SCHANNEL_SECRET_PRIVKEY;
pCred->cbPrivateKey = LocalCred.cbPrivateKey ;
pCred->pPrivateKey = (PBYTE) ( pCred + 1 );
pCred->pszPassword = (PBYTE) (pCred->pPrivateKey + pCred->cbPrivateKey );
RtlCopyMemory( pCred->pszPassword, Password, PasswordLen + 1 );
Status = LsaTable->CopyFromClientBuffer( NULL,
pCred->cbPrivateKey,
pCred->pPrivateKey,
ULongToPtr(LocalCred.pPrivateKey));
if ( !NT_SUCCESS( Status ) )
{
SPExternalFree( pCred );
return( NULL );
}
return( pCred );
}
#endif // _WIN64
VOID
SpFreeVersion2Certificate(
SCH_CRED * pCred
)
{
DWORD i;
for ( i = 0 ; i < pCred->cCreds ; i++ )
{
if ( pCred->paSecret[ i ] )
{
SPExternalFree( pCred->paSecret[ i ] );
}
if ( pCred->paPublic[ i ] )
{
SPExternalFree( pCred->paPublic[ i ] );
}
}
SPExternalFree( pCred );
}
VOID
SpFreeVersion3Certificate(
PLSA_SCHANNEL_CRED pSchannelCred)
{
DWORD i;
if(pSchannelCred->paSubCred)
{
for(i = 0; i < pSchannelCred->cSubCreds; i++)
{
PLSA_SCHANNEL_SUB_CRED pSubCred = pSchannelCred->paSubCred + i;
if(pSubCred->pCert)
{
CertFreeCertificateContext(pSubCred->pCert);
}
if(pSubCred->pszPin)
{
SPExternalFree(pSubCred->pszPin);
}
if(pSubCred->pPrivateKey)
{
SPExternalFree(pSubCred->pPrivateKey);
}
if(pSubCred->pszPassword)
{
SPExternalFree(pSubCred->pszPassword);
}
memset(pSubCred, 0, sizeof(LSA_SCHANNEL_SUB_CRED));
}
SPExternalFree((PVOID)pSchannelCred->paSubCred);
pSchannelCred->paSubCred = NULL;
}
if(pSchannelCred->hRootStore)
{
CertCloseStore(pSchannelCred->hRootStore, 0);
pSchannelCred->hRootStore = 0;
}
if(pSchannelCred->aphMappers)
{
for(i = 0; i < pSchannelCred->cMappers; i++)
{
if(pSchannelCred->aphMappers[i])
{
SPExternalFree(pSchannelCred->aphMappers[i]);
}
}
SPExternalFree(pSchannelCred->aphMappers);
pSchannelCred->aphMappers = 0;
}
if(pSchannelCred->palgSupportedAlgs)
{
SPExternalFree(pSchannelCred->palgSupportedAlgs);
pSchannelCred->palgSupportedAlgs = 0;
}
ZeroMemory(pSchannelCred, sizeof(SCHANNEL_CRED));
}
SECURITY_STATUS
SpMapProtoCredential(
SSL_CREDENTIAL_CERTIFICATE *pSslCert,
PSCH_CRED *ppSchCred)
{
SCH_CRED * pCred = NULL;
SCH_CRED_PUBLIC_CERTCHAIN * pPub = NULL;
SCH_CRED_SECRET_PRIVKEY * pPriv = NULL;
UCHAR Password[ MAX_PATH + 1 ];
DWORD PasswordLen = 0;
SECURITY_STATUS Status ;
DWORD Size;
#if DBG
DebugLog((DEB_TRACE, "SpMapProtoCredential\n"));
DBG_HEX_STRING(DEB_TRACE, (PBYTE)pSslCert, sizeof(SSL_CREDENTIAL_CERTIFICATE));
#endif
//
// Map over the certificate.
//
// Reality check
if(pSslCert->cbCertificate > 0x00100000)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto error;
}
pPub = SPExternalAlloc( sizeof( SCH_CRED_PUBLIC_CERTCHAIN ) +
pSslCert->cbCertificate );
if ( pPub == NULL)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto error;
}
pPub->dwType = SCH_CRED_X509_CERTCHAIN;
pPub->cbCertChain = pSslCert->cbCertificate;
pPub->pCertChain = (PUCHAR) ( pPub + 1 );
Status = LsaTable->CopyFromClientBuffer( NULL,
pSslCert->cbCertificate,
pPub->pCertChain,
pSslCert->pCertificate );
if ( !NT_SUCCESS( Status ) )
{
goto error;
}
//
// Map over the private key and password.
//
//
// The password is the painful part. Since it is a string, we don't know
// how long it is. So, we have to take a stab at it:
//
Status = LsaTable->CopyFromClientBuffer( NULL,
MAX_PATH,
Password,
pSslCert->pszPassword );
if ( !NT_SUCCESS( Status ) )
{
goto error;
}
Password[ MAX_PATH ] = '\0';
PasswordLen = strlen( Password );
// Reality check private key length.
if(pSslCert->cbPrivateKey > 0x100000)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto error;
}
Size = PasswordLen + 1 + pSslCert->cbPrivateKey +
sizeof( SCH_CRED_SECRET_PRIVKEY ) ;
pPriv = SPExternalAlloc( Size );
if(pPriv == NULL)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto error;
}
pPriv->dwType = SCHANNEL_SECRET_PRIVKEY;
pPriv->cbPrivateKey = pSslCert->cbPrivateKey ;
pPriv->pPrivateKey = (PBYTE) ( pPriv + 1 );
pPriv->pszPassword = (PBYTE) (pPriv->pPrivateKey + pPriv->cbPrivateKey );
RtlCopyMemory( pPriv->pszPassword, Password, PasswordLen + 1 );
Status = LsaTable->CopyFromClientBuffer( NULL,
pSslCert->cbPrivateKey,
pPriv->pPrivateKey,
pSslCert->pPrivateKey );
if ( !NT_SUCCESS( Status ) )
{
goto error;
}
//
// Allocate SCH_CRED structure.
//
pCred = SPExternalAlloc(sizeof(SCH_CRED) + 2 * sizeof(PVOID));
if(pCred == NULL)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto error;
}
pCred->dwVersion = SCH_CRED_VERSION ;
pCred->cCreds = 1 ;
pCred->paSecret = (PVOID) ( pCred + 1 );
pCred->paPublic = (PVOID) ( pCred->paSecret + 1 );
pCred->paSecret[0] = pPriv;
pCred->paPublic[0] = pPub;
*ppSchCred = pCred;
return SEC_E_OK;
error:
if(pCred) SPExternalFree(pCred);
if(pPub) SPExternalFree(pPub);
if(pPriv) SPExternalFree(pPriv);
return Status;
}
#ifdef _WIN64
SECURITY_STATUS
SpWow64MapProtoCredential(
SSLWOW64_CREDENTIAL_CERTIFICATE *pSslCert,
PSCH_CRED *ppSchCred)
{
SCH_CRED * pCred = NULL;
SCH_CRED_PUBLIC_CERTCHAIN * pPub = NULL;
SCH_CRED_SECRET_PRIVKEY * pPriv = NULL;
UCHAR Password[ MAX_PATH + 1 ];
DWORD PasswordLen = 0;
SECURITY_STATUS Status ;
DWORD Size;
#if DBG
DebugLog((DEB_TRACE, "SpWow64MapProtoCredential\n"));
DBG_HEX_STRING(DEB_TRACE, (PBYTE)pSslCert, sizeof(SSLWOW64_CREDENTIAL_CERTIFICATE));
#endif
//
// Map over the certificate.
//
// Reality check
if(pSslCert->cbCertificate > 0x00100000)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto error;
}
pPub = SPExternalAlloc( sizeof( SCH_CRED_PUBLIC_CERTCHAIN ) +
pSslCert->cbCertificate );
if ( pPub == NULL)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto error;
}
pPub->dwType = SCH_CRED_X509_CERTCHAIN;
pPub->cbCertChain = pSslCert->cbCertificate;
pPub->pCertChain = (PUCHAR) ( pPub + 1 );
Status = LsaTable->CopyFromClientBuffer( NULL,
pSslCert->cbCertificate,
pPub->pCertChain,
ULongToPtr(pSslCert->pCertificate));
if ( !NT_SUCCESS( Status ) )
{
goto error;
}
//
// Map over the private key and password.
//
//
// The password is the painful part. Since it is a string, we don't know
// how long it is. So, we have to take a stab at it:
//
Status = LsaTable->CopyFromClientBuffer( NULL,
MAX_PATH,
Password,
ULongToPtr(pSslCert->pszPassword));
if ( !NT_SUCCESS( Status ) )
{
goto error;
}
Password[ MAX_PATH ] = '\0';
PasswordLen = strlen( Password );
// Reality check private key length.
if(pSslCert->cbPrivateKey > 0x100000)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto error;
}
Size = PasswordLen + 1 + pSslCert->cbPrivateKey +
sizeof( SCH_CRED_SECRET_PRIVKEY ) ;
pPriv = SPExternalAlloc( Size );
if(pPriv == NULL)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto error;
}
pPriv->dwType = SCHANNEL_SECRET_PRIVKEY;
pPriv->cbPrivateKey = pSslCert->cbPrivateKey ;
pPriv->pPrivateKey = (PBYTE) ( pPriv + 1 );
pPriv->pszPassword = (PBYTE) (pPriv->pPrivateKey + pPriv->cbPrivateKey );
RtlCopyMemory( pPriv->pszPassword, Password, PasswordLen + 1 );
Status = LsaTable->CopyFromClientBuffer( NULL,
pSslCert->cbPrivateKey,
pPriv->pPrivateKey,
ULongToPtr(pSslCert->pPrivateKey));
if ( !NT_SUCCESS( Status ) )
{
goto error;
}
//
// Allocate SCH_CRED structure.
//
pCred = SPExternalAlloc(sizeof(SCH_CRED) + 2 * sizeof(PVOID));
if(pCred == NULL)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto error;
}
pCred->dwVersion = SCH_CRED_VERSION ;
pCred->cCreds = 1 ;
pCred->paSecret = (PVOID) ( pCred + 1 );
pCred->paPublic = (PVOID) ( pCred->paSecret + 1 );
pCred->paSecret[0] = pPriv;
pCred->paPublic[0] = pPub;
*ppSchCred = pCred;
return SEC_E_OK;
error:
if(pCred) SPExternalFree(pCred);
if(pPub) SPExternalFree(pPub);
if(pPriv) SPExternalFree(pPriv);
return Status;
}
#endif // _WIN64
SECURITY_STATUS
SpMapVersion2Certificate(
PVOID pvAuthData,
SCH_CRED * *ppCred
)
{
SECURITY_STATUS Status ;
SCH_CRED Cred;
PSCH_CRED pCred;
DWORD Size;
DWORD i;
BOOL Failed = FALSE ;
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof( SCH_CRED ),
&Cred,
pvAuthData );
if ( !NT_SUCCESS( Status ) )
{
return( Status );
}
#if DBG
DebugLog((DEB_TRACE, "SpMapVersion2Certificate: %d certificates in cred\n", Cred.cCreds));
DBG_HEX_STRING(DEB_TRACE, (PBYTE)&Cred, sizeof(SCH_CRED));
#endif
// Reality check credential count.
if(Cred.cCreds > 100)
{
return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
}
Size = sizeof( SCH_CRED ) + (2 * Cred.cCreds * sizeof( PVOID ) );
pCred = SPExternalAlloc( Size );
if(pCred == NULL)
{
return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
}
pCred->dwVersion = Cred.dwVersion ;
pCred->cCreds = Cred.cCreds ;
pCred->paSecret = (PVOID) ( pCred + 1 );
pCred->paPublic = (PVOID) ( pCred->paSecret + Cred.cCreds );
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof( PVOID ) * Cred.cCreds,
pCred->paSecret,
Cred.paSecret );
if ( NT_SUCCESS( Status ) )
{
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof( PVOID ) * Cred.cCreds,
pCred->paPublic,
Cred.paPublic );
}
if ( !NT_SUCCESS( Status ) )
{
SPExternalFree( pCred );
return( Status );
}
//
// Ok. We have pCred in local memory, with a chain of cert/private key
// stuff hanging off of it. We now have to map in each one. Happy, happy.
//
for ( i = 0 ; i < Cred.cCreds ; i++ )
{
pCred->paSecret[i] = SpMapSchCred( pCred->paSecret[i] );
if ( pCred->paSecret[i] == NULL )
{
Failed = TRUE ;
}
}
for ( i = 0 ; i < Cred.cCreds ; i++ )
{
pCred->paPublic[i] = SpMapSchPublic( pCred->paPublic[i] );
if ( pCred->paPublic[i] == NULL )
{
Failed = TRUE ;
}
}
if ( Failed )
{
SpFreeVersion2Certificate( pCred );
pCred = NULL ;
Status = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS) ;
}
*ppCred = pCred ;
return( Status );
}
#ifdef _WIN64
SECURITY_STATUS
SpWow64MapVersion2Certificate(
PVOID pvAuthData,
SCH_CRED * *ppCred
)
{
SECURITY_STATUS Status ;
SSLWOW64_SCH_CRED Cred;
PSCH_CRED pCred;
DWORD Size;
BOOL Failed = FALSE ;
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof( SSLWOW64_SCH_CRED ),
&Cred,
pvAuthData );
if ( !NT_SUCCESS( Status ) )
{
return( Status );
}
#if DBG
DebugLog((DEB_TRACE, "SpMapVersion2Certificate: %d certificates in cred\n", Cred.cCreds));
DBG_HEX_STRING(DEB_TRACE, (PBYTE)&Cred, sizeof(SCH_CRED));
#endif
if(Cred.cCreds > 100)
{
return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
}
if(Cred.cCreds > 1)
{
// Only support a single certificate, which is all that anyone
// ever uses anyway.
Cred.cCreds = 1;
}
Size = sizeof( SCH_CRED ) + (2 * Cred.cCreds * sizeof( PVOID ) );
pCred = SPExternalAlloc( Size );
if(pCred == NULL)
{
return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
}
pCred->dwVersion = Cred.dwVersion;
pCred->cCreds = Cred.cCreds;
if(pCred->cCreds > 0)
{
SSLWOW64_PVOID ClientSecret;
SSLWOW64_PVOID ClientPublic;
pCred->paSecret = (PVOID) ( pCred + 1 );
pCred->paPublic = (PVOID) ( pCred->paSecret + Cred.cCreds );
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof(SSLWOW64_PVOID),
&ClientSecret,
ULongToPtr(Cred.paSecret));
if ( NT_SUCCESS( Status ) )
{
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof(SSLWOW64_PVOID),
&ClientPublic,
ULongToPtr(Cred.paPublic));
}
if ( !NT_SUCCESS( Status ) )
{
SPExternalFree( pCred );
return( Status );
}
pCred->paSecret[0] = SpWow64MapSchCred(ClientSecret);
if ( pCred->paSecret[0] == NULL )
{
Failed = TRUE ;
}
pCred->paPublic[0] = SpWow64MapSchPublic(ClientPublic);
if ( pCred->paPublic[0] == NULL )
{
Failed = TRUE ;
}
}
if ( Failed )
{
SpFreeVersion2Certificate( pCred );
pCred = NULL ;
Status = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS) ;
}
*ppCred = pCred ;
return( Status );
}
#endif // _WIN64
// Selectively enable the unified protocol.
DWORD
EnableUnifiedProtocol(DWORD dwPackageType, DWORD dwProtocol)
{
DWORD cProts = 0;
// Disable unified.
dwProtocol &= ~SP_PROT_UNI;
if(dwPackageType & SP_PROT_UNI)
{
// Count enabled protocols.
if(dwProtocol & SP_PROT_PCT1) cProts++;
if(dwProtocol & SP_PROT_SSL2) cProts++;
if(dwProtocol & (SP_PROT_SSL3 | SP_PROT_TLS1)) cProts++;
// Enable unified if multiple protocols enabled.
if(cProts > 1)
{
if(dwPackageType & SP_PROT_CLIENTS)
{
dwProtocol |= SP_PROT_UNI_CLIENT;
}
else
{
dwProtocol |= SP_PROT_UNI_SERVER;
}
}
}
return dwProtocol;
}
SECURITY_STATUS
SpMapMapperList(
HMAPPER ** apMappers, // in
DWORD cMappers, // in
HMAPPER *** papMappers) // out
{
HMAPPER ** MapperList;
HMAPPER ** ClientMapperList;
DWORD cbMapperList;
SECURITY_STATUS scRet;
DWORD i;
if(cMappers == 0)
{
return SEC_E_OK;
}
// Allocate memory for mapper pointer list.
cbMapperList = cMappers * sizeof(PVOID);
MapperList = SPExternalAlloc(cbMapperList * 2);
if(MapperList == NULL)
{
return SEC_E_INSUFFICIENT_MEMORY;
}
ClientMapperList = MapperList + cMappers;
// Copy mapper list over from client memory.
scRet = LsaTable->CopyFromClientBuffer(
NULL,
cbMapperList,
ClientMapperList,
apMappers);
if(!NT_SUCCESS(scRet))
{
goto error;
}
// Make local copies of the mapper structures.
for(i = 0; i < cMappers; i++)
{
MapperList[i] = SPExternalAlloc(sizeof(HMAPPER));
if(MapperList[i] == NULL)
{
scRet = SEC_E_INSUFFICIENT_MEMORY;
goto error;
}
// Copy HMAPPER structure over from client memory.
scRet = LsaTable->CopyFromClientBuffer(
NULL,
sizeof(HMAPPER),
MapperList[i],
ClientMapperList[i]);
if(!NT_SUCCESS(scRet))
{
goto error;
}
// Save original application HMAPPER pointer.
MapperList[i]->m_Reserved1 = ClientMapperList[i];
}
*papMappers = MapperList;
return SEC_E_OK;
error:
for(i = 0; i < cMappers; i++)
{
if(MapperList[i])
{
SPExternalFree(MapperList[i]);
}
}
SPExternalFree(MapperList);
return scRet;
}
typedef struct _V3_SCHANNEL_CRED
{
DWORD dwVersion; // always SCHANNEL_CRED_VERSION
DWORD cCreds;
PCCERT_CONTEXT *paCred;
HCERTSTORE hRootStore;
DWORD cMappers;
struct _HMAPPER **aphMappers;
DWORD cSupportedAlgs;
ALG_ID * palgSupportedAlgs;
DWORD grbitEnabledProtocols;
DWORD dwMinimumCipherStrength;
DWORD dwMaximumCipherStrength;
DWORD dwSessionLifespan;
} V3_SCHANNEL_CRED;
//+---------------------------------------------------------------------------
//
// Function: SpMapVersion3Certificate
//
// Synopsis: Maps a version 3 schannel credential into LSA memory
//
// Arguments: [pvAuthData] -- pointer to cred in application process
// [pCred] -- pointer to cred in LSA process
//
// History: 09-23-97 jbanes Created
//
// Notes: The credential consists of the following structure. Note
// that all CryptoAPI 2.0 handles must be mapped over as well,
// via the callback mechanism.
//
// typedef struct _SCHANNEL_CRED
// {
// DWORD dwVersion;
// DWORD cCreds;
// PCCERT_CONTEXT *paCred;
// HCERTSTORE hRootStore;
//
// DWORD cMappers;
// struct _HMAPPER **aphMappers;
//
// DWORD cSupportedAlgs;
// ALG_ID *palgSupportedAlgs;
//
// DWORD grbitEnabledProtocols;
// DWORD dwMinimumCipherStrength;
// DWORD dwMaximumCipherStrength;
// DWORD dwSessionLifespan;
//
// } SCHANNEL_CRED, *PSCHANNEL_CRED;
//
//----------------------------------------------------------------------------
SECURITY_STATUS
SpMapVersion3Certificate(
PVOID pvAuthData, // in
DWORD dwVersion, // in
PLSA_SCHANNEL_CRED pCred) // out
{
PCERT_CONTEXT * pLocalCredList = NULL;
HCERTSTORE hStore = NULL;
CRYPT_DATA_BLOB Serialized;
CRYPT_DATA_BLOB DataBlob;
SCHANNEL_CRED LocalCred;
SecBuffer Input;
SecBuffer Output;
PBYTE pbBuffer;
DWORD cbBuffer;
DWORD cbData;
SECURITY_STATUS scRet;
DWORD Size;
DWORD iCred;
Output.pvBuffer = NULL;
//
// Copy over the SCHANNEL_CRED structure.
//
if(dwVersion == SCH_CRED_V3)
{
scRet = LsaTable->CopyFromClientBuffer(NULL,
sizeof(V3_SCHANNEL_CRED),
&LocalCred,
pvAuthData);
if(!NT_SUCCESS(scRet))
{
goto cleanup;
}
LocalCred.dwFlags = 0;
LocalCred.reserved = 0;
#if DBG
DebugLog((DEB_TRACE, "SpMapVersion3Certificate: %d certificates in cred\n", LocalCred.cCreds));
DBG_HEX_STRING(DEB_TRACE, (PBYTE)&LocalCred, sizeof(V3_SCHANNEL_CRED));
#endif
}
else
{
scRet = LsaTable->CopyFromClientBuffer(NULL,
sizeof(SCHANNEL_CRED),
&LocalCred,
pvAuthData);
if(!NT_SUCCESS(scRet))
{
goto cleanup;
}
#if DBG
DebugLog((DEB_TRACE, "SpMapVersion4Certificate: %d certificates in cred\n", LocalCred.cCreds));
DBG_HEX_STRING(DEB_TRACE, (PBYTE)&LocalCred, sizeof(SCHANNEL_CRED));
#endif
}
//
// DWORD dwVersion;
//
memset(pCred, 0, sizeof(LSA_SCHANNEL_CRED));
pCred->dwVersion = LocalCred.dwVersion;
//
// DWORD cCreds;
// PCCERT_CONTEXT *paCred;
//
if(LocalCred.cCreds && LocalCred.paCred)
{
Size = LocalCred.cCreds * sizeof(PVOID);
// Reality check credential count.
if(LocalCred.cCreds > 1000)
{
scRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
// Make local copy of application cred list.
pLocalCredList = SPExternalAlloc(Size);
if(pLocalCredList == NULL)
{
scRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
scRet = LsaTable->CopyFromClientBuffer(
NULL,
Size,
pLocalCredList,
(PCERT_CONTEXT *)LocalCred.paCred);
if(!NT_SUCCESS(scRet))
{
goto cleanup;
}
// Allocate memory for our cred list.
pCred->cSubCreds = LocalCred.cCreds;
pCred->paSubCred = SPExternalAlloc(pCred->cSubCreds * sizeof(LSA_SCHANNEL_SUB_CRED));
if(pCred->paSubCred == NULL)
{
scRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
// Create an in-memory certificate store.
hStore = CertOpenStore(CERT_STORE_PROV_MEMORY,
0, 0,
CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
0);
if(hStore == NULL)
{
SP_LOG_RESULT(GetLastError());
scRet = SEC_E_INSUFFICIENT_MEMORY;
goto cleanup;
}
// Copy over each certificate context.
for(iCred = 0; iCred < LocalCred.cCreds; iCred++)
{
PLSA_SCHANNEL_SUB_CRED pSubCred;
pSubCred = pCred->paSubCred + iCred;
Input.BufferType = SECBUFFER_DATA;
Input.cbBuffer = sizeof(PVOID);
Input.pvBuffer = (PVOID)&pLocalCredList[iCred];
scRet = PerformApplicationCallback(SCH_UPLOAD_CREDENTIAL_CALLBACK,
0, 0,
&Input,
&Output,
TRUE);
if(!NT_SUCCESS(scRet))
{
Output.pvBuffer = NULL;
goto cleanup;
}
pbBuffer = Output.pvBuffer;
cbBuffer = Output.cbBuffer;
if(pbBuffer == NULL ||
cbBuffer < sizeof(HCRYPTPROV) + sizeof(DWORD))
{
scRet = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
goto cleanup;
}
// Parse hProv.
pSubCred->hRemoteProv = *(HCRYPTPROV *)pbBuffer;
pbBuffer += sizeof(HCRYPTPROV);
cbBuffer -= sizeof(HCRYPTPROV);
// Parse certificate context length.
cbData = *(DWORD *)pbBuffer;
pbBuffer += sizeof(DWORD);
cbBuffer -= sizeof(DWORD);
// Parse certificate context.
if(cbBuffer < cbData)
{
scRet = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
goto cleanup;
}
if(!CertAddSerializedElementToStore(hStore,
pbBuffer,
cbData,
CERT_STORE_ADD_ALWAYS,
0,
CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
NULL,
&pSubCred->pCert))
{
scRet = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS);
goto cleanup;
}
// Free the output buffer.
SPExternalFree(Output.pvBuffer);
Output.pvBuffer = NULL;
}
}
//
// HCERTSTORE hRootStore;
//
if(LocalCred.hRootStore != NULL)
{
Input.BufferType = SECBUFFER_DATA;
Input.cbBuffer = sizeof(HCERTSTORE);
Input.pvBuffer = (PVOID)&LocalCred.hRootStore;
scRet = PerformApplicationCallback(SCH_UPLOAD_CERT_STORE_CALLBACK,
0, 0,
&Input,
&Output,
TRUE);
if(scRet != SEC_E_OK)
{
goto cleanup;
}
pbBuffer = Output.pvBuffer;
cbBuffer = Output.cbBuffer;
if(pbBuffer == NULL || cbBuffer < sizeof(DWORD))
{
scRet = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
goto cleanup;
}
// Parse certificate store.
Serialized.cbData = *(DWORD *)pbBuffer;
Serialized.pbData = pbBuffer + sizeof(DWORD);
if(cbBuffer - sizeof(DWORD) < Serialized.cbData)
{
scRet = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
goto cleanup;
}
pCred->hRootStore = CertOpenStore( CERT_STORE_PROV_SERIALIZED,
X509_ASN_ENCODING,
0, 0,
&Serialized);
if(pCred->hRootStore == NULL)
{
scRet = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS);
goto cleanup;
}
// Free the output buffer.
SPExternalFree(Output.pvBuffer);
Output.pvBuffer = NULL;
}
//
// DWORD cMappers;
// struct _HMAPPER **aphMappers;
//
if(LocalCred.cMappers && LocalCred.aphMappers)
{
// Reality check.
if(LocalCred.cMappers > 100)
{
scRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
}
pCred->cMappers = LocalCred.cMappers;
scRet = SpMapMapperList(LocalCred.aphMappers,
LocalCred.cMappers,
&pCred->aphMappers);
if(!NT_SUCCESS(scRet))
{
SP_LOG_RESULT(scRet);
goto cleanup;
}
}
//
// DWORD cSupportedAlgs;
// ALG_ID *palgSupportedAlgs;
//
if(LocalCred.cSupportedAlgs && LocalCred.palgSupportedAlgs)
{
// Reality check.
if(LocalCred.cSupportedAlgs > 1000)
{
scRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
Size = LocalCred.cSupportedAlgs * sizeof(ALG_ID);
pCred->cSupportedAlgs = LocalCred.cSupportedAlgs;
pCred->palgSupportedAlgs = SPExternalAlloc(Size);
if(pCred->palgSupportedAlgs == NULL)
{
scRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
scRet = LsaTable->CopyFromClientBuffer(NULL,
Size,
pCred->palgSupportedAlgs,
LocalCred.palgSupportedAlgs);
if(!NT_SUCCESS(scRet))
{
goto cleanup;
}
}
//
// DWORD grbitEnabledProtocols;
// DWORD dwMinimumCipherStrength;
// DWORD dwMaximumCipherStrength;
// DWORD dwSessionLifespan;
// DWORD dwFlags;
// DWORD reserved;
//
pCred->grbitEnabledProtocols = LocalCred.grbitEnabledProtocols;
pCred->dwMinimumCipherStrength = LocalCred.dwMinimumCipherStrength;
pCred->dwMaximumCipherStrength = LocalCred.dwMaximumCipherStrength;
pCred->dwSessionLifespan = LocalCred.dwSessionLifespan;
pCred->dwFlags = LocalCred.dwFlags;
pCred->reserved = LocalCred.reserved;
scRet = SEC_E_OK;
cleanup:
if(Output.pvBuffer)
{
SPExternalFree(Output.pvBuffer);
}
if(pLocalCredList)
{
SPExternalFree(pLocalCredList);
}
if(hStore)
{
CertCloseStore(hStore, 0);
}
if(!NT_SUCCESS(scRet))
{
SpFreeVersion3Certificate(pCred);
}
return scRet;
}
#ifdef _WIN64
SECURITY_STATUS
SpWow64MapVersion3Certificate(
PVOID pvAuthData, // in
DWORD dwVersion, // in
PLSA_SCHANNEL_CRED pCred) // out
{
SSLWOW64_PCCERT_CONTEXT *pLocalCredList = NULL;
HCERTSTORE hStore = NULL;
CRYPT_DATA_BLOB Serialized;
CRYPT_DATA_BLOB DataBlob;
SSLWOW64_SCHANNEL_CRED LocalCred;
SecBuffer Input;
SecBuffer Output;
PBYTE pbBuffer;
DWORD cbBuffer;
DWORD cbData;
SECURITY_STATUS scRet;
DWORD Size;
DWORD iCred;
Output.pvBuffer = NULL;
//
// Copy over the SCHANNEL_CRED structure.
//
if(dwVersion == SCH_CRED_V3)
{
scRet = LsaTable->CopyFromClientBuffer(NULL,
sizeof(SSLWOW64_SCHANNEL3_CRED),
&LocalCred,
pvAuthData);
if(!NT_SUCCESS(scRet))
{
goto cleanup;
}
LocalCred.dwFlags = 0;
LocalCred.reserved = 0;
#if DBG
DebugLog((DEB_TRACE, "SpMapVersion3Certificate: %d certificates in cred\n", LocalCred.cCreds));
DBG_HEX_STRING(DEB_TRACE, (PBYTE)&LocalCred, sizeof(SSLWOW64_SCHANNEL_CRED));
#endif
}
else
{
scRet = LsaTable->CopyFromClientBuffer(NULL,
sizeof(SSLWOW64_SCHANNEL_CRED),
&LocalCred,
pvAuthData);
if(!NT_SUCCESS(scRet))
{
goto cleanup;
}
#if DBG
DebugLog((DEB_TRACE, "SpMapVersion4Certificate: %d certificates in cred\n", LocalCred.cCreds));
DBG_HEX_STRING(DEB_TRACE, (PBYTE)&LocalCred, sizeof(SSLWOW64_SCHANNEL_CRED));
#endif
}
//
// DWORD dwVersion;
//
memset(pCred, 0, sizeof(LSA_SCHANNEL_CRED));
pCred->dwVersion = LocalCred.dwVersion;
//
// DWORD cCreds;
// PCCERT_CONTEXT *paCred;
//
if(LocalCred.cCreds && LocalCred.paCred)
{
Size = LocalCred.cCreds * sizeof(SSLWOW64_PCCERT_CONTEXT);
// Reality check credential count.
if(LocalCred.cCreds > 1000)
{
scRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
// Make local copy of application cred list.
pLocalCredList = SPExternalAlloc(Size);
if(pLocalCredList == NULL)
{
scRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
scRet = LsaTable->CopyFromClientBuffer(
NULL,
Size,
pLocalCredList,
ULongToPtr(LocalCred.paCred));
if(!NT_SUCCESS(scRet))
{
goto cleanup;
}
// Allocate memory for our cred list.
pCred->cSubCreds = LocalCred.cCreds;
pCred->paSubCred = SPExternalAlloc(pCred->cSubCreds * sizeof(LSA_SCHANNEL_SUB_CRED));
if(pCred->paSubCred == NULL)
{
scRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
// Create an in-memory certificate store.
hStore = CertOpenStore(CERT_STORE_PROV_MEMORY,
0, 0,
CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
0);
if(hStore == NULL)
{
SP_LOG_RESULT(GetLastError());
scRet = SEC_E_INSUFFICIENT_MEMORY;
goto cleanup;
}
// Copy over each certificate context.
for(iCred = 0; iCred < LocalCred.cCreds; iCred++)
{
PLSA_SCHANNEL_SUB_CRED pSubCred;
pSubCred = pCred->paSubCred + iCred;
Input.BufferType = SECBUFFER_DATA;
Input.cbBuffer = sizeof(SSLWOW64_PCCERT_CONTEXT);
Input.pvBuffer = (PVOID)&pLocalCredList[iCred];
scRet = PerformApplicationCallback(SCH_UPLOAD_CREDENTIAL_CALLBACK,
0, 0,
&Input,
&Output,
TRUE);
if(!NT_SUCCESS(scRet))
{
Output.pvBuffer = NULL;
goto cleanup;
}
pbBuffer = Output.pvBuffer;
cbBuffer = Output.cbBuffer;
if(pbBuffer == NULL ||
cbBuffer < sizeof(HCRYPTPROV) + sizeof(DWORD))
{
scRet = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
goto cleanup;
}
// Parse hProv.
pSubCred->hRemoteProv = *(SSLWOW64_HCRYPTPROV *)pbBuffer;
pbBuffer += sizeof(SSLWOW64_HCRYPTPROV);
cbBuffer -= sizeof(SSLWOW64_HCRYPTPROV);
// Parse certificate context length.
cbData = *(DWORD *)pbBuffer;
pbBuffer += sizeof(DWORD);
cbBuffer -= sizeof(DWORD);
// Parse certificate context.
if(cbBuffer < cbData)
{
scRet = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
goto cleanup;
}
if(!CertAddSerializedElementToStore(hStore,
pbBuffer,
cbData,
CERT_STORE_ADD_ALWAYS,
0,
CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
NULL,
&pSubCred->pCert))
{
SP_LOG_RESULT(GetLastError());
scRet = SEC_E_UNKNOWN_CREDENTIALS;
goto cleanup;
}
// Free the output buffer.
SPExternalFree(Output.pvBuffer);
Output.pvBuffer = NULL;
}
}
//
// HCERTSTORE hRootStore;
//
if(LocalCred.hRootStore)
{
Input.BufferType = SECBUFFER_DATA;
Input.cbBuffer = sizeof(SSLWOW64_HCERTSTORE);
Input.pvBuffer = (PVOID)&LocalCred.hRootStore;
scRet = PerformApplicationCallback(SCH_UPLOAD_CERT_STORE_CALLBACK,
0, 0,
&Input,
&Output,
TRUE);
if(scRet != SEC_E_OK)
{
goto cleanup;
}
pbBuffer = Output.pvBuffer;
cbBuffer = Output.cbBuffer;
if(pbBuffer == NULL || cbBuffer < sizeof(DWORD))
{
scRet = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
goto cleanup;
}
// Parse certificate store.
Serialized.cbData = *(DWORD *)pbBuffer;
Serialized.pbData = pbBuffer + sizeof(DWORD);
if(cbBuffer - sizeof(DWORD) < Serialized.cbData)
{
scRet = SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
goto cleanup;
}
pCred->hRootStore = CertOpenStore( CERT_STORE_PROV_SERIALIZED,
X509_ASN_ENCODING,
0, 0,
&Serialized);
if(pCred->hRootStore == NULL)
{
scRet = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS);
goto cleanup;
}
// Free the output buffer.
SPExternalFree(Output.pvBuffer);
Output.pvBuffer = NULL;
}
//
// DWORD cMappers;
// struct _HMAPPER **aphMappers;
//
if(LocalCred.cMappers && LocalCred.aphMappers)
{
// We don't support WOW64 application certificate mappers.
pCred->cMappers = 0;
pCred->aphMappers = NULL;
}
//
// DWORD cSupportedAlgs;
// ALG_ID *palgSupportedAlgs;
//
if(LocalCred.cSupportedAlgs && LocalCred.palgSupportedAlgs)
{
// Reality check.
if(LocalCred.cSupportedAlgs > 1000)
{
scRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
Size = LocalCred.cSupportedAlgs * sizeof(ALG_ID);
pCred->cSupportedAlgs = LocalCred.cSupportedAlgs;
pCred->palgSupportedAlgs = SPExternalAlloc(Size);
if(pCred->palgSupportedAlgs == NULL)
{
scRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
scRet = LsaTable->CopyFromClientBuffer(NULL,
Size,
pCred->palgSupportedAlgs,
ULongToPtr(LocalCred.palgSupportedAlgs));
if(!NT_SUCCESS(scRet))
{
goto cleanup;
}
}
//
// DWORD grbitEnabledProtocols;
// DWORD dwMinimumCipherStrength;
// DWORD dwMaximumCipherStrength;
// DWORD dwSessionLifespan;
// DWORD dwFlags;
// DWORD reserved;
//
pCred->grbitEnabledProtocols = LocalCred.grbitEnabledProtocols;
pCred->dwMinimumCipherStrength = LocalCred.dwMinimumCipherStrength;
pCred->dwMaximumCipherStrength = LocalCred.dwMaximumCipherStrength;
pCred->dwSessionLifespan = LocalCred.dwSessionLifespan;
pCred->dwFlags = LocalCred.dwFlags;
pCred->reserved = LocalCred.reserved;
scRet = SEC_E_OK;
cleanup:
if(Output.pvBuffer)
{
SPExternalFree(Output.pvBuffer);
}
if(pLocalCredList)
{
SPExternalFree(pLocalCredList);
}
if(hStore)
{
CertCloseStore(hStore, 0);
}
if(!NT_SUCCESS(scRet))
{
SpFreeVersion3Certificate(pCred);
}
return scRet;
}
#endif // _WIN64
SECURITY_STATUS
SpMapAuthIdentity(
PVOID pAuthData,
PLSA_SCHANNEL_CRED pSchannelCred)
{
PSEC_WINNT_AUTH_IDENTITY_EXW pAuthIdentity = NULL;
SEC_WINNT_AUTH_IDENTITY_EX32 AuthIdentity32 = {0};
BOOLEAN DoUnicode = TRUE;
UNICODE_STRING UserName;
UNICODE_STRING Password;
NTSTATUS Status;
CRED_MARSHAL_TYPE CredType;
PCERT_CREDENTIAL_INFO pCertInfo = NULL;
PCCERT_CONTEXT pCertContext = NULL;
HCERTSTORE hStore = 0;
CRYPT_HASH_BLOB HashBlob;
BOOL fImpersonating = FALSE;
SECPKG_CALL_INFO CallInfo;
BOOL fWow64Client = FALSE;
DebugLog((DEB_TRACE, "SpMapAuthIdentity\n"));
#ifdef _WIN64
if(!LsaTable->GetCallInfo(&CallInfo))
{
Status = STATUS_INTERNAL_ERROR;
return SP_LOG_RESULT(Status);
}
fWow64Client = (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT) != 0;
#endif
//
// Initialize.
//
RtlInitUnicodeString(
&UserName,
NULL);
RtlInitUnicodeString(
&Password,
NULL);
//
// Copy over the SEC_WINNT_AUTH_IDENTITY_EX structure from client memory.
//
pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY_EXW)SPExternalAlloc(sizeof(SEC_WINNT_AUTH_IDENTITY_EXW));
if(pAuthIdentity == NULL)
{
Status = SEC_E_INSUFFICIENT_MEMORY;
goto cleanup;
}
if(fWow64Client)
{
Status = LsaTable->CopyFromClientBuffer(
NULL,
sizeof(SEC_WINNT_AUTH_IDENTITY_EX32),
&AuthIdentity32,
pAuthData);
if (!NT_SUCCESS(Status))
{
SP_LOG_RESULT(Status);
goto cleanup;
}
pAuthIdentity->Version = AuthIdentity32.Version;
pAuthIdentity->Length = (AuthIdentity32.Length < sizeof(SEC_WINNT_AUTH_IDENTITY_EX) ?
sizeof(SEC_WINNT_AUTH_IDENTITY_EX) : AuthIdentity32.Length);
pAuthIdentity->UserLength = AuthIdentity32.UserLength;
pAuthIdentity->User = (PWSTR) UlongToPtr(AuthIdentity32.User);
pAuthIdentity->DomainLength = AuthIdentity32.DomainLength ;
pAuthIdentity->Domain = (PWSTR) UlongToPtr( AuthIdentity32.Domain );
pAuthIdentity->PasswordLength = AuthIdentity32.PasswordLength ;
pAuthIdentity->Password = (PWSTR) UlongToPtr( AuthIdentity32.Password );
pAuthIdentity->Flags = AuthIdentity32.Flags ;
pAuthIdentity->PackageListLength = AuthIdentity32.PackageListLength ;
pAuthIdentity->PackageList = (PWSTR) UlongToPtr( AuthIdentity32.PackageList );
}
else
{
Status = LsaTable->CopyFromClientBuffer(
NULL,
sizeof(SEC_WINNT_AUTH_IDENTITY_EXW),
pAuthIdentity,
pAuthData);
if (!NT_SUCCESS(Status))
{
SP_LOG_RESULT(Status);
goto cleanup;
}
}
if ((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
{
DoUnicode = FALSE;
}
//
// Copy over the user name and password.
//
if (pAuthIdentity->User != NULL)
{
Status = CopyClientString(
pAuthIdentity->User,
pAuthIdentity->UserLength,
DoUnicode,
&UserName);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status));
goto cleanup;
}
}
if (pAuthIdentity->Password != NULL)
{
Status = CopyClientString(
pAuthIdentity->Password,
pAuthIdentity->PasswordLength,
DoUnicode,
&Password);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status));
goto cleanup;
}
}
//
// Extract the certificate thumbprint.
//
if(!CredIsMarshaledCredentialW(UserName.Buffer))
{
Status = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS);
goto cleanup;
}
if(!CredUnmarshalCredentialW(UserName.Buffer,
&CredType,
&pCertInfo))
{
Status = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS);
goto cleanup;
}
if(CredType != CertCredential)
{
Status = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS);
goto cleanup;
}
//
// Look up the certificate in the MY certificate store.
//
fImpersonating = SslImpersonateClient();
hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
X509_ASN_ENCODING, 0,
CERT_SYSTEM_STORE_CURRENT_USER |
CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
L"MY");
if(!hStore)
{
SP_LOG_RESULT(GetLastError());
Status = SEC_E_NO_CREDENTIALS;
goto cleanup;
}
HashBlob.cbData = sizeof(pCertInfo->rgbHashOfCert);
HashBlob.pbData = pCertInfo->rgbHashOfCert;
pCertContext = CertFindCertificateInStore(hStore,
X509_ASN_ENCODING,
0,
CERT_FIND_HASH,
&HashBlob,
NULL);
if(pCertContext == NULL)
{
DebugLog((DEB_ERROR, "Certificate designated by authority info was not found in certificate store (0x%x).\n", GetLastError()));
Status = SEC_E_NO_CREDENTIALS;
goto cleanup;
}
//
// Build sub cred structure and attach it to the credential.
//
pSchannelCred->paSubCred = SPExternalAlloc(sizeof(LSA_SCHANNEL_SUB_CRED));
if(pSchannelCred->paSubCred == NULL)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
pSchannelCred->paSubCred[0].pCert = pCertContext;
pSchannelCred->paSubCred[0].pszPin = Password.Buffer;
Password.Buffer = NULL;
pSchannelCred->cSubCreds = 1;
Status = STATUS_SUCCESS;
cleanup:
if(pAuthIdentity)
{
SPExternalFree(pAuthIdentity);
}
if(UserName.Buffer)
{
LocalFree(UserName.Buffer);
}
if(Password.Buffer)
{
LocalFree(Password.Buffer);
}
if(pCertInfo)
{
CredFree(pCertInfo);
}
if(hStore)
{
CertCloseStore(hStore, 0);
}
if(fImpersonating)
{
RevertToSelf();
}
return Status;
}
//+---------------------------------------------------------------------------
//
// Function: SpCommonAcquireCredentialsHandle
//
// Synopsis: Common AcquireCredentialsHandle function.
//
// Arguments: [Type] -- Type expected (Unified v. specific)
// [pLogonID] --
// [pvAuthData] --
// [pvGetKeyFn] --
// [pvGetKeyArgument] --
// [pdwHandle] --
// [ptsExpiry] --
//
// History: 10-06-96 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
SECURITY_STATUS
SpCommonAcquireCredentialsHandle(
ULONG Type,
PLUID pLogonID,
PVOID pvAuthData,
PVOID pvGetKeyFn,
PVOID pvGetKeyArgument,
PLSA_SEC_HANDLE pdwHandle,
PTimeStamp ptsExpiry)
{
SP_STATUS pctRet;
PSPCredentialGroup pCredGroup;
LSA_SCHANNEL_CRED SchannelCred;
PSCH_CRED pSchCred;
SECURITY_STATUS Status;
SSL_CREDENTIAL_CERTIFICATE SslCert;
DWORD dwVersion;
SECPKG_CALL_INFO CallInfo;
BOOL fWow64Client = FALSE;
TRACE_ENTER( SpCommonAcquireCredentialsHandle );
if(!SchannelInit(FALSE))
{
return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
}
#ifdef _WIN64
if(!LsaTable->GetCallInfo(&CallInfo))
{
Status = STATUS_INTERNAL_ERROR;
return SP_LOG_RESULT(Status);
}
fWow64Client = (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT) != 0;
#endif
__try
{
// Default to null credential
memset(&SchannelCred, 0, sizeof(SchannelCred));
SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
if ( pvAuthData )
{
//
// Read in the first few bytes of data so we can see what's there.
//
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof( SSL_CREDENTIAL_CERTIFICATE ),
&SslCert,
pvAuthData );
if ( !NT_SUCCESS( Status ) )
{
return( Status );
}
dwVersion = SslCert.cbPrivateKey;
//
// Ok, see what kind of blob we got:
//
switch(dwVersion)
{
case SEC_WINNT_AUTH_IDENTITY_VERSION:
//
// The application passed in a SEC_WINNT_AUTH_IDENTITY_EXW
// structure.
//
Status = SpMapAuthIdentity(pvAuthData, &SchannelCred);
if(!NT_SUCCESS(Status))
{
return Status;
}
break;
case SCH_CRED_V3:
case SCHANNEL_CRED_VERSION:
//
// The application is using modern (version 3) credentials.
//
#ifdef _WIN64
if(fWow64Client)
{
Status = SpWow64MapVersion3Certificate(pvAuthData, dwVersion, &SchannelCred);
}
else
#endif
{
Status = SpMapVersion3Certificate(pvAuthData, dwVersion, &SchannelCred);
}
if(!NT_SUCCESS(Status))
{
return Status;
}
// Selectively enable the unified protocol.
SchannelCred.grbitEnabledProtocols = EnableUnifiedProtocol(
Type,
SchannelCred.grbitEnabledProtocols);
break;
case SCH_CRED_V1:
case SCH_CRED_V2:
//
// Okay, it's a V1 or V2 style request. Map it in, following
// its scary chains.
//
#ifdef _WIN64
if(fWow64Client)
{
Status = SpWow64MapVersion2Certificate(pvAuthData, &pSchCred);
}
else
#endif
{
Status = SpMapVersion2Certificate(pvAuthData, &pSchCred);
}
if(!NT_SUCCESS(Status))
{
return Status;
}
//
// Convert this version 2 credential to a version 3 credential.
//
Status = UpdateCredentialFormat(pSchCred, &SchannelCred);
SpFreeVersion2Certificate( pSchCred );
if(!NT_SUCCESS(Status))
{
return Status;
}
break;
default:
//
// A really old-style credential.
//
#ifdef _WIN64
if(fWow64Client)
{
Status = SpWow64MapProtoCredential((SSLWOW64_CREDENTIAL_CERTIFICATE *)&SslCert, &pSchCred);
}
else
#endif
{
Status = SpMapProtoCredential(&SslCert, &pSchCred);
}
if(!NT_SUCCESS(Status))
{
return Status;
}
//
// Convert this version 2 credential to a version 3 credential.
//
Status = UpdateCredentialFormat(pSchCred, &SchannelCred);
SpFreeVersion2Certificate( pSchCred );
if(!NT_SUCCESS(Status))
{
return Status;
}
break;
}
// Set the legacy flags if this is an old-style credential.
if(dwVersion != SCHANNEL_CRED_VERSION &&
dwVersion != SEC_WINNT_AUTH_IDENTITY_VERSION)
{
SchannelCred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION;
SchannelCred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS);
}
if(pvAuthData == NULL && (Type & SP_PROT_SERVERS))
{
//
// A server is creating credential without specifying any
// authentication data, so attempt to acquire a default
// machine credential.
//
Status = FindDefaultMachineCred(&pCredGroup, Type);
if(!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR, "Unable to create default server credential (0x%x)\n", Status));
return Status;
}
*pdwHandle = (LSA_SEC_HANDLE) pCredGroup;
return SEC_E_OK;
}
pctRet = SPCreateCredential( &pCredGroup,
Type,
&SchannelCred );
SpFreeVersion3Certificate( &SchannelCred );
if (PCT_ERR_OK == pctRet)
{
*pdwHandle = (LSA_SEC_HANDLE) pCredGroup;
return SEC_E_OK;
}
return PctTranslateError(pctRet);
}
SECURITY_STATUS
SEC_ENTRY
SpUniAcquireCredentialsHandle(
PSECURITY_STRING psPrincipal,
ULONG fCredentials,
PLUID pLogonID,
PVOID pvAuthData,
PVOID pvGetKeyFn,
PVOID pvGetKeyArgument,
PLSA_SEC_HANDLE pdwHandle,
PTimeStamp ptsExpiry)
{
DWORD Type;
DebugLog((DEB_TRACE, "SpUniAcquireCredentialsHandle(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
psPrincipal, fCredentials, pLogonID, pvAuthData,
pvGetKeyFn, pvGetKeyArgument, pdwHandle, ptsExpiry));
if ( fCredentials & SECPKG_CRED_INBOUND )
{
Type = SP_PROT_UNI_SERVER ;
}
else if ( fCredentials & SECPKG_CRED_OUTBOUND )
{
Type = SP_PROT_UNI_CLIENT ;
}
else
{
return SP_LOG_RESULT(SEC_E_NO_CREDENTIALS);
}
return( SpCommonAcquireCredentialsHandle( Type,
pLogonID,
pvAuthData,
pvGetKeyFn,
pvGetKeyArgument,
pdwHandle,
ptsExpiry ) );
}
SECURITY_STATUS
SEC_ENTRY
SpQueryCredentialsAttributes(
LSA_SEC_HANDLE dwCredHandle,
ULONG dwAttribute,
PVOID Buffer)
{
PSPCredentialGroup pCred;
ULONG Size;
PVOID pvClient = NULL;
DWORD cbClient;
SECURITY_STATUS Status;
SECPKG_CALL_INFO CallInfo;
BOOL fWow64Client = FALSE;
typedef struct _SecPkgCred_SupportedAlgsWow64
{
DWORD cSupportedAlgs;
SSLWOW64_PVOID palgSupportedAlgs;
} SecPkgCred_SupportedAlgsWow64, *PSecPkgCred_SupportedAlgsWow64;
union {
SecPkgCred_SupportedAlgs SupportedAlgs;
SecPkgCred_SupportedAlgsWow64 SupportedAlgsWow64;
SecPkgCred_CipherStrengths CipherStrengths;
SecPkgCred_SupportedProtocols SupportedProtocols;
} LocalBuffer;
pCred = (PSPCredentialGroup)dwCredHandle;
if(pCred == NULL)
{
return(SEC_E_INVALID_HANDLE);
}
#ifdef _WIN64
if(!LsaTable->GetCallInfo(&CallInfo))
{
Status = STATUS_INTERNAL_ERROR;
return SP_LOG_RESULT(Status);
}
fWow64Client = (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT) != 0;
#endif
__try
{
switch (dwAttribute)
{
case SECPKG_ATTR_SUPPORTED_ALGS:
DebugLog((DEB_TRACE, "QueryCredentialsAttributes(SECPKG_ATTR_SUPPORTED_ALGS)\n"));
if(fWow64Client)
{
Size = sizeof(SecPkgCred_SupportedAlgsWow64);
}
else
{
Size = sizeof(SecPkgCred_SupportedAlgs);
}
break;
case SECPKG_ATTR_CIPHER_STRENGTHS:
DebugLog((DEB_TRACE, "QueryCredentialsAttributes(SECPKG_ATTR_CIPHER_STRENGTHS)\n"));
Size = sizeof(SecPkgCred_CipherStrengths);
break;
case SECPKG_ATTR_SUPPORTED_PROTOCOLS:
DebugLog((DEB_TRACE, "QueryCredentialsAttributes(SECPKG_ATTR_SUPPORTED_PROTOCOLS)\n"));
Size = sizeof(SecPkgCred_SupportedProtocols);
break;
default:
DebugLog((DEB_WARN, "QueryCredentialsAttributes(unsupported function %d)\n", dwAttribute));
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
// Copy structure from client memory, just in case any of this
// stuff is in/out.
Status = LsaTable->CopyFromClientBuffer( NULL,
Size,
&LocalBuffer,
Buffer );
if(FAILED(Status))
{
return Status;
}
switch (dwAttribute)
{
case SECPKG_ATTR_SUPPORTED_ALGS:
{
cbClient = pCred->cSupportedAlgs * sizeof(ALG_ID);
// Allocate client memory for algorithm list.
Status = LsaTable->AllocateClientBuffer(NULL, cbClient, &pvClient);
if(FAILED(Status))
{
return Status;
}
if(fWow64Client)
{
LocalBuffer.SupportedAlgsWow64.cSupportedAlgs = pCred->cSupportedAlgs;
LocalBuffer.SupportedAlgsWow64.palgSupportedAlgs = PtrToUlong(pvClient);
}
else
{
LocalBuffer.SupportedAlgs.cSupportedAlgs = pCred->cSupportedAlgs;
LocalBuffer.SupportedAlgs.palgSupportedAlgs = pvClient;
}
// Copy algorithm list to client memory.
Status = LsaTable->CopyToClientBuffer(
NULL,
cbClient,
pvClient,
pCred->palgSupportedAlgs);
if(FAILED(Status))
{
LsaTable->FreeClientBuffer(NULL, pvClient);
return Status;
}
break;
}
case SECPKG_ATTR_CIPHER_STRENGTHS:
GetDisplayCipherSizes(pCred,
&LocalBuffer.CipherStrengths.dwMinimumCipherStrength,
&LocalBuffer.CipherStrengths.dwMaximumCipherStrength);
break;
case SECPKG_ATTR_SUPPORTED_PROTOCOLS:
LocalBuffer.SupportedProtocols.grbitProtocol = pCred->grbitEnabledProtocols;
break;
}
// Copy structure back to client memory.
Status = LsaTable->CopyToClientBuffer( NULL,
Size,
Buffer,
&LocalBuffer );
if(FAILED(Status))
{
if(pvClient) LsaTable->FreeClientBuffer(NULL, pvClient);
return Status;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
return SEC_E_OK;
}
SECURITY_STATUS
SEC_ENTRY
SpFreeCredentialsHandle(LSA_SEC_HANDLE dwHandle)
{
PSPCredentialGroup pCred;
SECPKG_CALL_INFO CallInfo;
DWORD Status;
DebugLog((DEB_TRACE, "SpFreeCredentialsHandle(0x%x)\n", dwHandle));
pCred = (PSPCredentialGroup) dwHandle ;
__try
{
if (pCred)
{
// Delete all mention of this credential from the cache.
SPCachePurgeCredential(pCred);
// Was this call made from the LSA cleanup code? In other
// words, did the application terminate without cleaning up
// properly? If so, then throw away all unreferenced zombies
// associated with that process.
if(LsaTable->GetCallInfo(&CallInfo))
{
if(CallInfo.Attributes & SECPKG_CALL_CLEANUP)
{
SPCachePurgeProcessId(pCred->ProcessId);
}
}
pCred->dwFlags |= CRED_FLAG_DELETED;
SPDereferenceCredential(pCred);
return(SEC_E_OK);
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
return SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
}