2025-04-27 07:49:33 -04:00

720 lines
20 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows NT Security
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: scheme.cpp
//
// Contents: Generic Scheme Provider Utility Functions
//
// History: 18-Aug-97 kirtd Created
//
//----------------------------------------------------------------------------
#include <global.hxx>
#ifndef STABLE_CACHE_ENTRY
#define STABLE_CACHE_ENTRY NORMAL_CACHE_ENTRY
#endif
#if defined( DeleteUrlCacheEntry ) && ! defined(__CRYPTNET_DEMAND_H__)
#undef DeleteUrlCacheEntry
extern "C" {
BOOL WINAPI
DeleteUrlCacheEntry(
IN LPCSTR lpszUrlName
);
}
#endif
//+---------------------------------------------------------------------------
//
// Function: SchemeCacheCryptBlobArray
//
// Synopsis: cache the crypt blob array under the given URL
//
//----------------------------------------------------------------------------
BOOL WINAPI
SchemeCacheCryptBlobArray (
IN LPCSTR pszUrl,
IN DWORD dwRetrievalFlags,
IN PCRYPT_BLOB_ARRAY pcba,
IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
)
{
BOOL fResult;
CCryptBlobArray cba( pcba, 0 );
LPBYTE pb = NULL;
ULONG cb;
CHAR pszFile[MAX_PATH+1];
HANDLE hFile = INVALID_HANDLE_VALUE;
ULONG cbWritten = 0;
DWORD LastError = 0;
BOOL fCacheEntryCreated = FALSE;
fResult = cba.GetArrayInSingleBufferEncodedForm(
(PCRYPT_BLOB_ARRAY *)&pb,
&cb
);
if ( fResult == TRUE )
{
fResult = CreateUrlCacheEntryA(
pszUrl,
cb,
0,
pszFile,
0
);
}
if ( fResult == TRUE )
{
fCacheEntryCreated = TRUE;
hFile = CreateFileA(
pszFile,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL
);
}
if ( hFile != INVALID_HANDLE_VALUE )
{
fResult = WriteFile( hFile, pb, cb, &cbWritten, NULL );
if ( fResult == TRUE )
{
if ( cbWritten != cb )
{
LastError = (DWORD) E_FAIL;
fResult = FALSE;
}
}
else
{
LastError = GetLastError();
}
CloseHandle( hFile );
}
else
{
fResult = FALSE;
}
if ( fResult == TRUE )
{
FILETIME ft = { 0, 0 };
SCHEME_CACHE_ENTRY_HEADER sceh;
DWORD CacheEntryType;
memset( &sceh, 0, sizeof( SCHEME_CACHE_ENTRY_HEADER ) );
sceh.cbSize = sizeof( SCHEME_CACHE_ENTRY_HEADER );
sceh.MagicNumber = SCHEME_CACHE_ENTRY_MAGIC;
sceh.OriginalBase = (DWORD_PTR)pb;
CacheEntryType = STABLE_CACHE_ENTRY;
if ( dwRetrievalFlags & CRYPT_STICKY_CACHE_RETRIEVAL )
{
CacheEntryType |= STICKY_CACHE_ENTRY;
}
fResult = CommitUrlCacheEntryA(
pszUrl,
pszFile,
ft,
ft,
CacheEntryType,
(LPBYTE)&sceh,
sizeof( SCHEME_CACHE_ENTRY_HEADER ),
NULL,
0
);
}
if ( fResult == TRUE )
{
fResult = SchemeRetrieveCachedAuxInfo (
pszUrl,
dwRetrievalFlags & ~CRYPT_STICKY_CACHE_RETRIEVAL,
pAuxInfo
);
}
if ( LastError == 0 )
{
LastError = GetLastError();
}
if ( pb != NULL )
{
CryptMemFree( pb );
}
if ( fResult == FALSE )
{
if ( hFile != INVALID_HANDLE_VALUE )
{
DeleteFileA( pszFile );
}
if ( fCacheEntryCreated == TRUE )
{
DeleteUrlCacheEntry( pszUrl );
}
}
SetLastError( LastError );
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Function: SchemeRetrieveCachedCryptBlobArray
//
// Synopsis: retrieve cached blob array bits
//
//----------------------------------------------------------------------------
BOOL WINAPI
SchemeRetrieveCachedCryptBlobArray (
IN LPCSTR pszUrl,
IN DWORD dwRetrievalFlags,
OUT PCRYPT_BLOB_ARRAY pcba,
OUT PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject,
OUT LPVOID* ppvFreeContext,
IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
)
{
BOOL fResult;
DWORD cb = 0;
LPINTERNET_CACHE_ENTRY_INFOA pCacheEntry = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD dwSize = 0;
LPBYTE pb = NULL;
DWORD LastError = 0;
DWORD dwRead;
PCRYPT_BLOB_ARRAY pCachedArray = NULL;
PSCHEME_CACHE_ENTRY_HEADER psceh = NULL;
fResult = GetUrlCacheEntryInfoA( pszUrl, pCacheEntry, &cb );
if ( ( fResult == FALSE ) &&
( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) )
{
pCacheEntry = (LPINTERNET_CACHE_ENTRY_INFOA)new BYTE [cb];
if ( pCacheEntry != NULL )
{
fResult = GetUrlCacheEntryInfoA( pszUrl, pCacheEntry, &cb );
}
else
{
SetLastError( (DWORD) E_OUTOFMEMORY );
return( FALSE );
}
}
if ( fResult == TRUE )
{
psceh = (PSCHEME_CACHE_ENTRY_HEADER)pCacheEntry->lpHeaderInfo;
if ( ( psceh->cbSize != sizeof( SCHEME_CACHE_ENTRY_HEADER ) ) ||
( psceh->MagicNumber != SCHEME_CACHE_ENTRY_MAGIC ) )
{
delete (LPBYTE)pCacheEntry;
SetLastError( (DWORD) E_INVALIDARG );
return( FALSE );
}
if ( pAuxInfo &&
offsetof(CRYPT_RETRIEVE_AUX_INFO, pLastSyncTime) <
pAuxInfo->cbSize &&
pAuxInfo->pLastSyncTime )
{
*pAuxInfo->pLastSyncTime = pCacheEntry->LastSyncTime;
}
}
if ( fResult == TRUE )
{
hFile = CreateFileA(
pCacheEntry->lpszLocalFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
}
if ( hFile != INVALID_HANDLE_VALUE )
{
dwSize = GetFileSize( hFile, NULL );
pb = new BYTE [dwSize];
if ( pb != NULL )
{
fResult = ReadFile( hFile, pb, dwSize, &dwRead, NULL );
if ( fResult == TRUE )
{
if ( dwRead != dwSize )
{
LastError = (DWORD) E_FAIL;
fResult = FALSE;
}
}
else
{
LastError = GetLastError();
}
}
else
{
LastError = (DWORD) E_OUTOFMEMORY;
fResult = FALSE;
}
CloseHandle( hFile );
}
else
{
fResult = FALSE;
}
if ( fResult == TRUE )
{
DWORD dwFieldControl = CACHE_ENTRY_ACCTIME_FC;
GetSystemTimeAsFileTime( &pCacheEntry->LastAccessTime );
if ( dwRetrievalFlags & CRYPT_STICKY_CACHE_RETRIEVAL )
{
if ( 0 == (pCacheEntry->CacheEntryType & STICKY_CACHE_ENTRY) )
{
pCacheEntry->CacheEntryType |= STICKY_CACHE_ENTRY;
dwFieldControl |= CACHE_ENTRY_ATTRIBUTE_FC;
}
}
SetUrlCacheEntryInfoA( pszUrl, pCacheEntry, dwFieldControl );
fResult = SchemeFixupCachedBits(
dwSize,
pb,
&pCachedArray
);
}
if ( fResult == TRUE )
{
pcba->cBlob = pCachedArray->cBlob;
pcba->rgBlob = pCachedArray->rgBlob;
*ppfnFreeObject = SchemeFreeEncodedCryptBlobArray;
*ppvFreeContext = (LPVOID)pCachedArray;
}
else
{
if ( LastError != 0 )
{
SetLastError( LastError );
}
delete pb;
}
delete (LPBYTE)pCacheEntry;
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Function: SchemeFixupCachedBits
//
// Synopsis: fixup cached crypt blob array bits which have been stored in
// single buffer encoded form
//
//----------------------------------------------------------------------------
BOOL WINAPI
SchemeFixupCachedBits (
IN ULONG cb,
IN LPBYTE pb,
OUT PCRYPT_BLOB_ARRAY* ppcba
)
{
ULONG cCount;
PCRYPT_BLOB_ARRAY pcba = (PCRYPT_BLOB_ARRAY)pb;
DWORD_PTR OriginalBase;
OriginalBase = (DWORD_PTR)( (LPBYTE)pcba->rgBlob - sizeof( CRYPT_BLOB_ARRAY ) );
pcba->rgBlob = (PCRYPT_DATA_BLOB)( pb + sizeof( CRYPT_BLOB_ARRAY ) );
for ( cCount = 0; cCount < pcba->cBlob; cCount++ )
{
pcba->rgBlob[cCount].pbData =
( pb + ( pcba->rgBlob[cCount].pbData - (LPBYTE)OriginalBase ) );
if ( (DWORD)( pcba->rgBlob[ cCount ].pbData - pb ) > cb )
{
SetLastError( (DWORD) CRYPT_E_UNEXPECTED_ENCODING );
return( FALSE );
}
}
*ppcba = pcba;
return( TRUE );
}
//+---------------------------------------------------------------------------
//
// Function: SchemeDeleteUrlCacheEntry
//
// Synopsis: delete URL cache entry
//
//----------------------------------------------------------------------------
BOOL WINAPI
SchemeDeleteUrlCacheEntry (
IN LPCWSTR pwszUrl
)
{
CHAR pszUrl[ INTERNET_MAX_PATH_LENGTH + 1 ];
if ( WideCharToMultiByte(
CP_ACP,
0,
pwszUrl,
-1,
pszUrl,
INTERNET_MAX_PATH_LENGTH,
NULL,
NULL
) == 0 )
{
return( FALSE );
}
return( DeleteUrlCacheEntry( pszUrl ) );
}
//+---------------------------------------------------------------------------
//
// Function: SchemeFreeEncodedCryptBlobArray
//
// Synopsis: free encoded crypt blob array
//
//----------------------------------------------------------------------------
VOID WINAPI
SchemeFreeEncodedCryptBlobArray (
IN LPCSTR pszObjectOid,
IN PCRYPT_BLOB_ARRAY pcba,
IN LPVOID pvFreeContext
)
{
delete (LPBYTE)pvFreeContext;
}
//+---------------------------------------------------------------------------
//
// Function: SchemeGetPasswordCredentialsA
//
// Synopsis: get password credentials from crypt credentials
//
//----------------------------------------------------------------------------
BOOL WINAPI
SchemeGetPasswordCredentialsA (
IN PCRYPT_CREDENTIALS pCredentials,
OUT PCRYPT_PASSWORD_CREDENTIALSA pPasswordCredentials,
OUT BOOL* pfFreeCredentials
)
{
DWORD cwUsername;
DWORD cwPassword;
PCRYPT_PASSWORD_CREDENTIALSA pPassCredA;
PCRYPT_PASSWORD_CREDENTIALSW pPassCredW;
LPSTR pszUsername;
LPSTR pszPassword;
if ( pPasswordCredentials->cbSize != sizeof( CRYPT_PASSWORD_CREDENTIALS ) )
{
SetLastError( (DWORD) E_INVALIDARG );
return( FALSE );
}
if ( pCredentials == NULL )
{
pPasswordCredentials->pszUsername = NULL;
pPasswordCredentials->pszPassword = NULL;
*pfFreeCredentials = FALSE;
return( TRUE );
}
if ( pCredentials->pszCredentialsOid ==
CREDENTIAL_OID_PASSWORD_CREDENTIALS_A )
{
pPassCredA = (PCRYPT_PASSWORD_CREDENTIALSA)pCredentials->pvCredentials;
*pPasswordCredentials = *pPassCredA;
*pfFreeCredentials = FALSE;
return( TRUE );
}
if ( pCredentials->pszCredentialsOid !=
CREDENTIAL_OID_PASSWORD_CREDENTIALS_W )
{
SetLastError( (DWORD) E_INVALIDARG );
return( FALSE );
}
pPassCredW = (PCRYPT_PASSWORD_CREDENTIALSW)pCredentials->pvCredentials;
cwUsername = wcslen( pPassCredW->pszUsername ) + 1;
cwPassword = wcslen( pPassCredW->pszPassword ) + 1;
pszUsername = new CHAR [ cwUsername ];
pszPassword = new CHAR [ cwPassword ];
if ( ( pszUsername == NULL ) || ( pszPassword == NULL ) )
{
delete pszUsername;
delete pszPassword;
SetLastError( (DWORD) E_OUTOFMEMORY );
return( FALSE );
}
*pfFreeCredentials = TRUE;
WideCharToMultiByte(
CP_ACP,
0,
pPassCredW->pszUsername,
cwUsername,
pszUsername,
cwUsername,
NULL,
NULL
);
WideCharToMultiByte(
CP_ACP,
0,
pPassCredW->pszPassword,
cwPassword,
pszPassword,
cwPassword,
NULL,
NULL
);
pPasswordCredentials->pszUsername = pszUsername;
pPasswordCredentials->pszPassword = pszPassword;
return( TRUE );
}
//+---------------------------------------------------------------------------
//
// Function: SchemeFreePasswordCredentialsA
//
// Synopsis: free password credentials
//
//----------------------------------------------------------------------------
VOID WINAPI
SchemeFreePasswordCredentialsA (
IN PCRYPT_PASSWORD_CREDENTIALSA pPasswordCredentials
)
{
delete pPasswordCredentials->pszUsername;
delete pPasswordCredentials->pszPassword;
}
//+---------------------------------------------------------------------------
//
// Function: SchemeGetAuthIdentityFromPasswordCredentialsA
//
// Synopsis: converts a CRYPT_PASSWORD_CREDENTIALSA to a
// SEC_WINNT_AUTH_IDENTITY_A
//
//----------------------------------------------------------------------------
VOID WINAPI
SchemeGetAuthIdentityFromPasswordCredentialsA (
IN PCRYPT_PASSWORD_CREDENTIALSA pPasswordCredentials,
OUT PSEC_WINNT_AUTH_IDENTITY_A pAuthIdentity,
OUT LPSTR* ppDomainRestorePos
)
{
DWORD cDomain = 0;
*ppDomainRestorePos = NULL;
if ( pPasswordCredentials->pszUsername == NULL )
{
pAuthIdentity->User = NULL;
pAuthIdentity->UserLength = 0;
pAuthIdentity->Domain = NULL;
pAuthIdentity->DomainLength = 0;
pAuthIdentity->Password = NULL;
pAuthIdentity->PasswordLength = 0;
pAuthIdentity->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
return;
}
while ( ( pPasswordCredentials->pszUsername[cDomain] != '\0' ) &&
( pPasswordCredentials->pszUsername[cDomain] != '\\' ) )
{
cDomain += 1;
}
if ( cDomain != (DWORD)strlen( pPasswordCredentials->pszUsername ) )
{
pAuthIdentity->Domain = (UCHAR *)pPasswordCredentials->pszUsername;
pAuthIdentity->DomainLength = cDomain - 1;
pAuthIdentity->User = (UCHAR *)&pPasswordCredentials->pszUsername[
cDomain+1
];
pAuthIdentity->UserLength = strlen( (LPCSTR)pAuthIdentity->User );
*ppDomainRestorePos = &pPasswordCredentials->pszUsername[cDomain];
**ppDomainRestorePos = '\0';
}
else
{
pAuthIdentity->Domain = NULL;
pAuthIdentity->DomainLength = 0;
pAuthIdentity->User = (UCHAR *)pPasswordCredentials->pszUsername;
pAuthIdentity->UserLength = cDomain;
}
pAuthIdentity->Password = (UCHAR *)pPasswordCredentials->pszPassword;
pAuthIdentity->PasswordLength = strlen( (LPCSTR)pAuthIdentity->Password );
pAuthIdentity->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
}
//+---------------------------------------------------------------------------
//
// Function: SchemeRestorePasswordCredentialsFromAuthIdentityA
//
// Synopsis: restore the backslash to the domain username pair
//
//----------------------------------------------------------------------------
VOID WINAPI
SchemeRestorePasswordCredentialsFromAuthIdentityA (
IN PCRYPT_PASSWORD_CREDENTIALSA pPasswordCredentials,
IN PSEC_WINNT_AUTH_IDENTITY_A pAuthIdentity,
IN LPSTR pDomainRestorePos
)
{
if ( pDomainRestorePos != NULL )
{
*pDomainRestorePos = '\\';
}
}
//+---------------------------------------------------------------------------
//
// Function: SchemeRetrieveCachedAuxInfo
//
// Synopsis: get the LastSyncTime from the Url cache entry info and update
// the retrieval AuxInfo. If CRYPT_STICKY_CACHE_RETRIEVAL is
// set, mark the Url cache entry as being sticky.
//
//----------------------------------------------------------------------------
BOOL WINAPI
SchemeRetrieveCachedAuxInfo (
IN LPCSTR pszUrl,
IN DWORD dwRetrievalFlags,
IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
)
{
BOOL fResult = TRUE;
BOOL fGetLastSyncTime = FALSE;
DWORD cb = 0;
LPINTERNET_CACHE_ENTRY_INFOA pCacheEntry = NULL;
if ( pAuxInfo &&
offsetof(CRYPT_RETRIEVE_AUX_INFO, pLastSyncTime) <
pAuxInfo->cbSize &&
pAuxInfo->pLastSyncTime )
{
fGetLastSyncTime = TRUE;
}
if ( !fGetLastSyncTime &&
0 == (dwRetrievalFlags & CRYPT_STICKY_CACHE_RETRIEVAL) )
{
return( TRUE );
}
fResult = GetUrlCacheEntryInfoA( pszUrl, pCacheEntry, &cb );
if ( ( fResult == FALSE ) &&
( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) )
{
pCacheEntry = (LPINTERNET_CACHE_ENTRY_INFOA)new BYTE [cb];
if ( pCacheEntry != NULL )
{
fResult = GetUrlCacheEntryInfoA( pszUrl, pCacheEntry, &cb );
}
else
{
SetLastError( (DWORD) E_OUTOFMEMORY );
return( FALSE );
}
}
if ( fResult == TRUE )
{
if ( fGetLastSyncTime )
{
*pAuxInfo->pLastSyncTime = pCacheEntry->LastSyncTime;
}
if ( dwRetrievalFlags & CRYPT_STICKY_CACHE_RETRIEVAL )
{
if ( 0 == (pCacheEntry->CacheEntryType & STICKY_CACHE_ENTRY) )
{
pCacheEntry->CacheEntryType |= STICKY_CACHE_ENTRY;
fResult = SetUrlCacheEntryInfoA( pszUrl, pCacheEntry,
CACHE_ENTRY_ATTRIBUTE_FC );
}
}
}
delete (LPBYTE)pCacheEntry;
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Function: SchemeRetrieveUncachedAuxInfo
//
// Synopsis: update the LastSyncTime in the retrieval AuxInfo with the
// current time.
//
//----------------------------------------------------------------------------
BOOL WINAPI
SchemeRetrieveUncachedAuxInfo (
IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
)
{
if ( pAuxInfo &&
offsetof(CRYPT_RETRIEVE_AUX_INFO, pLastSyncTime) <
pAuxInfo->cbSize &&
pAuxInfo->pLastSyncTime )
{
GetSystemTimeAsFileTime( pAuxInfo->pLastSyncTime );
}
return( TRUE );
}