Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1596 lines
35 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
base.cxx
Abstract:
This module implements the IIS_CRYPTO_BASE class.
Author:
Keith Moore (keithmo) 02-Dec-1996
Revision History:
--*/
#include "precomp.hxx"
#pragma hdrstop
//
// Private constants.
//
//
// Private types.
//
//
// Private globals.
//
//
// Private prototypes.
//
//
// Public functions.
//
IIS_CRYPTO_BASE::IIS_CRYPTO_BASE()
/*++
Routine Description:
IIS_CRYPTO_BASE class constructor. Just sets the member variables
to known values; does nothing that can actually fail. All of the
hard work is in the Initialize() method.
Arguments:
None.
Return Value:
None.
--*/
{
//
// Set the handles to known values so we know what to cleanup
// in the destructor.
//
m_hProv = CRYPT_NULL;
m_fCloseProv = FALSE;
m_hKeyExchangeKey = CRYPT_NULL;
m_hSignatureKey = CRYPT_NULL;
} // IIS_CRYPTO_BASE::IIS_CRYPTO_BASE
IIS_CRYPTO_BASE::~IIS_CRYPTO_BASE()
/*++
Routine Description:
IIS_CRYPTO_BASE class destructor. Performs any necessary cleanup.
Arguments:
None.
Return Value:
None.
--*/
{
//
// Close any open keys.
//
CLOSE_KEY( m_hSignatureKey );
CLOSE_KEY( m_hKeyExchangeKey );
//
// Close the container.
//
if( m_fCloseProv && m_hProv != CRYPT_NULL ) {
(VOID)::IISCryptoCloseContainer( m_hProv );
m_hProv = CRYPT_NULL;
}
} // IIS_CRYPTO_BASE::~IIS_CRYPTO_BASE
HRESULT
IIS_CRYPTO_BASE::GetCryptoContainerByName(
OUT HCRYPTPROV * phProv,
IN LPTSTR pszContainerName,
IN DWORD dwAdditionalFlags,
IN BOOL fApplyAcl
)
/*++
Routine Description:
Creates or opens the specified crypto container. This method plays
games to ensure the container can be opened regardless of the
current security impersonation context.
Arguments:
phProv - Receives the handle to the provider.
pszContainerName - The name of the container to open/create.
(NULL means temporary container)
dwAdditionalFlags - Flags to pass into IISCryptoGetStandardContainer().
fApplyAcl - If TRUE, then an ACL is applied to the container.
Return Value:
HRESULT - 0 if successful, !0 otherwise.
--*/
{
HRESULT result = NO_ERROR;
HANDLE token = NULL;
BOOL resetToken = FALSE;
//
// Sanity check.
//
DBG_ASSERT( phProv != NULL );
//
// If the caller is not already asking for CRYPT_MACHINE_KEYSET
// *and* the current process is running in the local system context,
// then forcibly set CRYPT_MACHINE_KEYSET and note that we need to
// apply an ACL to the container. This is to workaround an issue
// with the NT5 Protected Storage service that causes the client-side
// containers to fail after NT5 GUI Setup. Apparently, there is some
// as-yet unidentified interaction between creating the client-side
// container under NT5 GUI Setup (which runs in the Local System
// security context) and later attempts to create containers in
// lesser security contexts.
//
if( !( dwAdditionalFlags & CRYPT_MACHINE_KEYSET ) ) {
if( AmIRunningInTheLocalSystemContext() ) {
dwAdditionalFlags |= CRYPT_MACHINE_KEYSET;
fApplyAcl = TRUE;
}
}
//
// Step 1: Just try to open/create the container.
//
result = ::IISCryptoGetContainerByName(
phProv,
pszContainerName,
dwAdditionalFlags,
fApplyAcl
);
if( SUCCEEDED(result) ) {
goto complete;
}
//
// NTE_BAD_KEYSET is typically returned when the caller has
// insufficient privilege to access the key container registry
// tree. If we failed for any other reason, bail.
//
if( result != NTE_BAD_KEYSET ) {
goto complete;
}
//
// Step 2: If the caller didn't ask for CRYPT_MACHINE_KEYSET, then
// retry the operation with this flag set.
//
if( ( dwAdditionalFlags & CRYPT_MACHINE_KEYSET ) == 0 ) {
result = ::IISCryptoGetContainerByName(
phProv,
pszContainerName,
dwAdditionalFlags | CRYPT_MACHINE_KEYSET,
fApplyAcl
);
if( SUCCEEDED(result) ) {
goto complete;
}
}
//
// OK, now things get a bit complex.
//
// If the current thread has an impersonation token, then
// (temporarily) remove it and retry the container operation.
// This is mainly here so that ISAPI applications (like, say, ASP)
// can access the DCOM interface while impersonating a non-privileged
// security context.
//
// Note that, after we remove the impersonation token, we first try
// the operation with CRYPT_MACHINE_KEYSET ORed in. We do this on
// the assumption that, if the thread had an impersonation token,
// then we're probably running in the context of a server process.
// If this operation fails, we try again without forcing the flag.
//
result = GetThreadImpersonationToken( &token );
if( FAILED(result) ) {
goto complete;
}
if( token != NULL ) {
result = SetThreadImpersonationToken( NULL );
if( FAILED(result) ) {
goto complete;
}
resetToken = TRUE;
//
// Step 3: With the token removed, retry the operation with the
// CRYPT_MACHINE_KEYSET flag set if not already set.
//
if( ( dwAdditionalFlags & CRYPT_MACHINE_KEYSET ) == 0 ) {
result = ::IISCryptoGetContainerByName(
phProv,
pszContainerName,
dwAdditionalFlags | CRYPT_MACHINE_KEYSET,
fApplyAcl
);
if( SUCCEEDED(result) ) {
goto complete;
}
}
//
// Step 4: With the token removed, try to open/create the container.
//
result = ::IISCryptoGetContainerByName(
phProv,
pszContainerName,
dwAdditionalFlags,
fApplyAcl
);
if( SUCCEEDED(result) ) {
goto complete;
}
}
//
// If we made it this far, then the container cannot be opened.
//
result = NTE_BAD_KEYSET;
complete:
if( resetToken ) {
HRESULT result2;
DBG_ASSERT( token != NULL );
result2 = SetThreadImpersonationToken( token );
if( FAILED(result2) ) {
//
// This is really, really, really bad news. The current
// thread, which does not have an impersonation token
// (and is therefore running in the system context)
// cannot reset its impersonation token to the original
// value.
//
DBG_ASSERT( SUCCEEDED( result2 ) );
}
}
if( token != NULL ) {
DBG_REQUIRE( CloseHandle( token ) );
}
return result;
} // IIS_CRYPTO_BASE::GetCryptoContainerByName
HRESULT
IIS_CRYPTO_BASE::Initialize(
IN HCRYPTPROV hProv,
IN HCRYPTKEY hKeyExchangeKey,
IN HCRYPTKEY hSignatureKey,
IN BOOL fUseMachineKeyset
)
/*++
Routine Description:
Performs any complex initialization.
Arguments:
hProv - Optional pre-opened handle to a crypto provider. If this
is not present, then the standard container is opened. If this
is present, then it is used and it is the responsibility of the
caller to close the handle when no longer needed.
hKeyExchangeKey - Optional pre-opened handle to a key exchange key. If
this is not present, then the local key exchange key is used.
hSignatureKey - Optional pre-opened handle to a signature key. If this
is not present, then the local signature key is used.
fUseMachineKeyset - TRUE if the per-machine keyset container should
be used, as opposed to the per-user keyset container.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
//
// Sanity check.
//
DBG_ASSERT( m_hProv == CRYPT_NULL );
DBG_ASSERT( m_hKeyExchangeKey == CRYPT_NULL );
DBG_ASSERT( m_hSignatureKey == CRYPT_NULL );
IcpAcquireGlobalLock();
if( hProv == CRYPT_NULL ) {
//
// Open the container.
//
result = ::IISCryptoGetStandardContainer(
&m_hProv,
fUseMachineKeyset
? CRYPT_MACHINE_KEYSET
: 0
);
m_fCloseProv = TRUE;
} else {
m_hProv = hProv;
m_fCloseProv = FALSE;
result = NO_ERROR;
}
if( SUCCEEDED(result) ) {
if( hKeyExchangeKey == CRYPT_NULL ) {
//
// Get the key exchange key.
//
result = ::IISCryptoGetKeyExchangeKey(
&m_hKeyExchangeKey,
m_hProv
);
} else {
m_hKeyExchangeKey = hKeyExchangeKey;
}
}
if( SUCCEEDED(result) ) {
if( hSignatureKey == CRYPT_NULL ) {
//
// Get the signature key.
//
result = ::IISCryptoGetSignatureKey(
&m_hSignatureKey,
m_hProv
);
} else {
m_hSignatureKey = hSignatureKey;
}
}
IcpReleaseGlobalLock();
return result;
} // IIS_CRYPTO_BASE::Initialize
HRESULT
IIS_CRYPTO_BASE::Initialize2(
IN HCRYPTPROV hProv
)
/*++
Routine Description:
Performs any complex initialization.
Arguments:
hProv - Optional pre-opened handle to a crypto provider. If this
is not present, then the standard container is opened. If this
is present, then it is used and it is the responsibility of the
caller to close the handle when no longer needed.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
//
// Sanity check.
//
DBG_ASSERT( m_hProv == CRYPT_NULL );
DBG_ASSERT( m_hKeyExchangeKey == CRYPT_NULL );
DBG_ASSERT( m_hSignatureKey == CRYPT_NULL );
IcpAcquireGlobalLock();
if( hProv == CRYPT_NULL ) {
//
// Open the container.
//
result = ::IISCryptoGetStandardContainer2(
&m_hProv
);
m_fCloseProv = TRUE;
} else {
m_hProv = hProv;
m_fCloseProv = FALSE;
result = NO_ERROR;
}
IcpReleaseGlobalLock();
return result;
} // IIS_CRYPTO_BASE::Initialize2
HRESULT
IIS_CRYPTO_BASE::GetKeyExchangeKeyBlob(
OUT PIIS_CRYPTO_BLOB * ppKeyExchangeKeyBlob
)
/*++
Routine Description:
Exports the key exchange key as a public blob.
Arguments:
ppKeyExchangeKeyBlob - Receives a pointer to the key exchange key
public blob if successful.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
//
// Sanity check.
//
DBG_ASSERT( ValidateState() );
DBG_ASSERT( ppKeyExchangeKeyBlob != NULL );
//
// Let the IIS Crypto APIs do the dirty work.
//
result = ::IISCryptoExportPublicKeyBlob(
ppKeyExchangeKeyBlob,
m_hProv,
m_hKeyExchangeKey
);
return result;
} // IIS_CRYPTO_BASE::GetKeyExchangeKeyBlob
HRESULT
IIS_CRYPTO_BASE::GetSignatureKeyBlob(
OUT PIIS_CRYPTO_BLOB * ppSignatureKeyBlob
)
/*++
Routine Description:
Exports the signature key as a public blob.
Arguments:
ppSignatureKeyBlob - Receives a pointer to the signature key
public blob if successful.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
//
// Sanity check.
//
DBG_ASSERT( ValidateState() );
DBG_ASSERT( ppSignatureKeyBlob != NULL );
//
// Let the IIS Crypto APIs do the dirty work.
//
result = ::IISCryptoExportPublicKeyBlob(
ppSignatureKeyBlob,
m_hProv,
m_hSignatureKey
);
return result;
} // IIS_CRYPTO_BASE::GetSignatureKeyBlob
//
// Private functions.
//
#if DBG
BOOL
IIS_CRYPTO_BASE::ValidateState()
/*++
Routine Description:
This debug-only routine validates the current object state.
Arguments:
None.
Return Value:
BOOL - TRUE if state is valid, FALSE otherwise.
--*/
{
if( m_hProv != CRYPT_NULL &&
m_hKeyExchangeKey != CRYPT_NULL &&
m_hSignatureKey != CRYPT_NULL ) {
return TRUE;
}
return FALSE;
} // IIS_CRYPTO_BASE::ValidateState
BOOL
IIS_CRYPTO_BASE::ValidateState2()
/*++
Routine Description:
This debug-only routine validates the current object state.
Arguments:
None.
Return Value:
BOOL - TRUE if state is valid, FALSE otherwise.
--*/
{
if( m_hProv != CRYPT_NULL )
{
return TRUE;
}
return FALSE;
} // IIS_CRYPTO_BASE::ValidateState2
#endif // DBG
HRESULT
IIS_CRYPTO_BASE::SafeImportSessionKeyBlob(
OUT HCRYPTKEY * phSessionKey,
IN PIIS_CRYPTO_BLOB pSessionKeyBlob,
IN HCRYPTPROV hProv,
IN HCRYPTKEY hSignatureKey
)
/*++
Routine Description:
This routine takes the specified session key blob and creates the
corresponding session key, iff the encrypted session key can be
decrypted and the digital signature can be validated.
Arguments:
phSessionKey - Receives a pointer to the newly created session key
if successful.
pSessionKeyBlob - Pointer to a key blob created with
IISCryptoExportSessionKeyBlob().
hProv - A handle to a crypto service provider.
hSignatureKey - Handle to the encryption key to use when validating
the digital signature.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
HCRYPTKEY sessionKey = CRYPT_NULL;
HANDLE token = NULL;
//
// First, just call through to wrapper function. If it succeeds, cool.
//
result = ::IISCryptoImportSessionKeyBlob(
&sessionKey,
pSessionKeyBlob,
hProv,
hSignatureKey
);
if( FAILED(result) ) {
HRESULT result2;
//
// Bummer. If the current thread has an impersonation token, then
// temporarily remove it and retry the operation.
//
result2 = GetThreadImpersonationToken( &token );
if( SUCCEEDED(result2) && token != NULL ) {
result2 = SetThreadImpersonationToken( NULL );
if( SUCCEEDED(result2) ) {
result2 = ::IISCryptoImportSessionKeyBlob(
&sessionKey,
pSessionKeyBlob,
hProv,
hSignatureKey
);
if( SUCCEEDED(result2) ) {
result = result2;
}
//
// Restore the original impersonation token.
//
result2 = SetThreadImpersonationToken( token );
DBG_ASSERT( SUCCEEDED(result2) );
}
//
// Close the token handle.
//
DBG_REQUIRE( CloseHandle( token ) );
}
}
if( SUCCEEDED(result) ) {
DBG_ASSERT( sessionKey != NULL );
*phSessionKey = sessionKey;
}
return result;
} // IIS_CRYPTO_BASE::SafeImportSessionKeyBlob
HRESULT
IIS_CRYPTO_BASE::SafeImportSessionKeyBlob2(
OUT HCRYPTKEY * phSessionKey,
IN PIIS_CRYPTO_BLOB pSessionKeyBlob,
IN HCRYPTPROV hProv,
IN LPSTR pszPasswd
)
/*++
Routine Description:
This routine takes the specified session key blob and creates the
corresponding session key, iff the encrypted session key can be
decrypted.
Arguments:
phSessionKey - Receives a pointer to the newly created session key
if successful.
pSessionKeyBlob - Pointer to a key blob created with
IISCryptoExportSessionKeyBlob().
hProv - A handle to a crypto service provider.
pszPasswd - The password to use to encrypt the session key.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
HCRYPTKEY sessionKey = CRYPT_NULL;
HANDLE token = NULL;
//
// First, just call through to wrapper function. If it succeeds, cool.
//
result = ::IISCryptoImportSessionKeyBlob2(
&sessionKey,
pSessionKeyBlob,
hProv,
pszPasswd
);
if( FAILED(result) ) {
HRESULT result2;
//
// Bummer. If the current thread has an impersonation token, then
// temporarily remove it and retry the operation.
//
result2 = GetThreadImpersonationToken( &token );
if( SUCCEEDED(result2) && token != NULL ) {
result2 = SetThreadImpersonationToken( NULL );
if( SUCCEEDED(result2) ) {
result2 = ::IISCryptoImportSessionKeyBlob2(
&sessionKey,
pSessionKeyBlob,
hProv,
pszPasswd
);
if( SUCCEEDED(result2) ) {
result = result2;
}
//
// Restore the original impersonation token.
//
result2 = SetThreadImpersonationToken( token );
DBG_ASSERT( SUCCEEDED(result2) );
}
//
// Close the token handle.
//
DBG_REQUIRE( CloseHandle( token ) );
}
}
if( SUCCEEDED(result) ) {
DBG_ASSERT( sessionKey != NULL );
*phSessionKey = sessionKey;
}
return result;
} // IIS_CRYPTO_BASE::SafeImportSessionKeyBlob2
HRESULT
IIS_CRYPTO_BASE::SafeExportSessionKeyBlob(
OUT PIIS_CRYPTO_BLOB * ppSessionKeyBlob,
IN HCRYPTPROV hProv,
IN HCRYPTKEY hSessionKey,
IN HCRYPTKEY hKeyExchangeKey
)
/*++
Routine Description:
This routine exports a session key into a secure session key blob.
The blob contains the session key (encrypted with the specified
private key exchange key) and a digital signature (also encrypted).
Arguments:
ppSessionKeyBlob - Will receive a pointer to the newly created
session key blob if successful.
hProv - A handle to a crypto service provider.
hSessionKey - The key to export.
hKeyExchangeKey - The key to use when encrypting the session key.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
PIIS_CRYPTO_BLOB sessionKeyBlob = NULL;
HANDLE token = NULL;
//
// First, just call through to wrapper function. If it succeeds, cool.
//
result = ::IISCryptoExportSessionKeyBlob(
&sessionKeyBlob,
hProv,
hSessionKey,
hKeyExchangeKey
);
if( FAILED(result) ) {
HRESULT result2;
//
// Bummer. If the current thread has an impersonation token, then
// temporarily remove it and retry the operation.
//
result2 = GetThreadImpersonationToken( &token );
if( SUCCEEDED(result2) && token != NULL ) {
result2 = SetThreadImpersonationToken( NULL );
if( SUCCEEDED(result2) ) {
result2 = ::IISCryptoExportSessionKeyBlob(
&sessionKeyBlob,
hProv,
hSessionKey,
hKeyExchangeKey
);
if( SUCCEEDED(result2) ) {
result = result2;
}
//
// Restore the original impersonation token.
//
result2 = SetThreadImpersonationToken( token );
DBG_ASSERT( SUCCEEDED(result2) );
}
//
// Close the token handle.
//
DBG_REQUIRE( CloseHandle( token ) );
}
}
if( SUCCEEDED(result) ) {
DBG_ASSERT( sessionKeyBlob != NULL );
*ppSessionKeyBlob = sessionKeyBlob;
}
return result;
} // IIS_CRYPTO_BASE::SafeExportSessionKeyBlob
HRESULT
IIS_CRYPTO_BASE::SafeExportSessionKeyBlob2(
OUT PIIS_CRYPTO_BLOB * ppSessionKeyBlob,
IN HCRYPTPROV hProv,
IN HCRYPTKEY hSessionKey,
IN LPSTR pszPasswd
)
/*++
Routine Description:
This routine exports a session key into a secure session key blob.
The blob contains the session key (encrypted with the specified
password) and a digital signature (also encrypted).
Arguments:
ppSessionKeyBlob - Will receive a pointer to the newly created
session key blob if successful.
hProv - A handle to a crypto service provider.
hSessionKey - The key to export.
pszPasswd - The password to use to encrypt the session key.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
PIIS_CRYPTO_BLOB sessionKeyBlob = NULL;
HANDLE token = NULL;
//
// First, just call through to wrapper function. If it succeeds, cool.
//
result = ::IISCryptoExportSessionKeyBlob2(
&sessionKeyBlob,
hProv,
hSessionKey,
pszPasswd
);
if( FAILED(result) ) {
HRESULT result2;
//
// Bummer. If the current thread has an impersonation token, then
// temporarily remove it and retry the operation.
//
result2 = GetThreadImpersonationToken( &token );
if( SUCCEEDED(result2) && token != NULL ) {
result2 = SetThreadImpersonationToken( NULL );
if( SUCCEEDED(result2) ) {
result2 = ::IISCryptoExportSessionKeyBlob2(
&sessionKeyBlob,
hProv,
hSessionKey,
pszPasswd
);
if( SUCCEEDED(result2) ) {
result = result2;
}
//
// Restore the original impersonation token.
//
result2 = SetThreadImpersonationToken( token );
DBG_ASSERT( SUCCEEDED(result2) );
}
//
// Close the token handle.
//
DBG_REQUIRE( CloseHandle( token ) );
}
}
if( SUCCEEDED(result) ) {
DBG_ASSERT( sessionKeyBlob != NULL );
*ppSessionKeyBlob = sessionKeyBlob;
}
return result;
} // IIS_CRYPTO_BASE::SafeExportSessionKeyBlob
HRESULT
IIS_CRYPTO_BASE::SafeEncryptDataBlob(
OUT PIIS_CRYPTO_BLOB * ppDataBlob,
IN PVOID pBuffer,
IN DWORD dwBufferLength,
IN DWORD dwRegType,
IN HCRYPTPROV hProv,
IN HCRYPTKEY hSessionKey
)
/*++
Routine Description:
This routine encrypts a block of data, resulting in a data blob.
The data blob contains the encrypted data and a digital signature
validating the data.
Arguments:
ppDataBlob - Receives a pointer to the newly created data blob if
successful.
pBuffer - The buffer to encrypt.
dwBufferLength - The length of the buffer.
dwRegType - The REG_* type to associate with this data.
hProv - A handle to a crypto service provider.
hSessionKey - The key used to encrypt the data.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
PIIS_CRYPTO_BLOB dataBlob = NULL;
HANDLE token = NULL;
//
// First, just call through to wrapper function. If it succeeds, cool.
//
result = ::IISCryptoEncryptDataBlob(
&dataBlob,
pBuffer,
dwBufferLength,
dwRegType,
hProv,
hSessionKey
);
if( FAILED(result) ) {
HRESULT result2;
//
// Bummer. If the current thread has an impersonation token, then
// temporarily remove it and retry the operation.
//
result2 = GetThreadImpersonationToken( &token );
if( SUCCEEDED(result2) && token != NULL ) {
result2 = SetThreadImpersonationToken( NULL );
if( SUCCEEDED(result2) ) {
result2 = ::IISCryptoEncryptDataBlob(
&dataBlob,
pBuffer,
dwBufferLength,
dwRegType,
hProv,
hSessionKey
);
if( SUCCEEDED(result2) ) {
result = result2;
}
//
// Restore the original impersonation token.
//
result2 = SetThreadImpersonationToken( token );
DBG_ASSERT( SUCCEEDED(result2) );
}
//
// Close the token handle.
//
DBG_REQUIRE( CloseHandle( token ) );
}
}
if( SUCCEEDED(result) ) {
DBG_ASSERT( dataBlob != NULL );
*ppDataBlob = dataBlob;
}
return result;
} // IIS_CRYPTO_BASE::SafeEncryptDataBlob
HRESULT
IIS_CRYPTO_BASE::SafeEncryptDataBlob2(
OUT PIIS_CRYPTO_BLOB * ppDataBlob,
IN PVOID pBuffer,
IN DWORD dwBufferLength,
IN DWORD dwRegType,
IN HCRYPTPROV hProv,
IN HCRYPTKEY hSessionKey
)
/*++
Routine Description:
This routine encrypts a block of data, resulting in a data blob.
The data blob contains the encrypted data and a digital signature
validating the data.
Arguments:
ppDataBlob - Receives a pointer to the newly created data blob if
successful.
pBuffer - The buffer to encrypt.
dwBufferLength - The length of the buffer.
dwRegType - The REG_* type to associate with this data.
hProv - A handle to a crypto service provider.
hSessionKey - The key used to encrypt the data.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
PIIS_CRYPTO_BLOB dataBlob = NULL;
HANDLE token = NULL;
//
// First, just call through to wrapper function. If it succeeds, cool.
//
result = ::IISCryptoEncryptDataBlob2(
&dataBlob,
pBuffer,
dwBufferLength,
dwRegType,
hProv,
hSessionKey
);
if( FAILED(result) ) {
HRESULT result2;
//
// Bummer. If the current thread has an impersonation token, then
// temporarily remove it and retry the operation.
//
result2 = GetThreadImpersonationToken( &token );
if( SUCCEEDED(result2) && token != NULL ) {
result2 = SetThreadImpersonationToken( NULL );
if( SUCCEEDED(result2) ) {
result2 = ::IISCryptoEncryptDataBlob2(
&dataBlob,
pBuffer,
dwBufferLength,
dwRegType,
hProv,
hSessionKey
);
if( SUCCEEDED(result2) ) {
result = result2;
}
//
// Restore the original impersonation token.
//
result2 = SetThreadImpersonationToken( token );
DBG_ASSERT( SUCCEEDED(result2) );
}
//
// Close the token handle.
//
DBG_REQUIRE( CloseHandle( token ) );
}
}
if( SUCCEEDED(result) ) {
DBG_ASSERT( dataBlob != NULL );
*ppDataBlob = dataBlob;
}
return result;
} // IIS_CRYPTO_BASE::SafeEncryptDataBlob2
HRESULT
IIS_CRYPTO_BASE::GetThreadImpersonationToken(
OUT HANDLE * Token
)
/*++
Routine Description:
Gets the impersonation token for the current thread.
Arguments:
Token - Receives a handle to the impersonation token if successful.
If successful, it is the caller's responsibility to CloseHandle()
the token when no longer needed.
Return Value:
HRESULT - 0 if successful, !0 otherwise.
--*/
{
HRESULT result = NO_ERROR;
DBG_ASSERT( Token != NULL );
//
// Open the token.
//
if( !OpenThreadToken(
GetCurrentThread(),
TOKEN_ALL_ACCESS,
TRUE,
Token
) ) {
DWORD err = GetLastError();
//
// There are a couple of "expected" errors here:
//
// ERROR_NO_TOKEN - The thread has no impersonation token.
// ERROR_CALL_NOT_IMPLEMENTED - We're probably on Win9x.
// ERROR_NOT_SUPPORTED - Ditto.
//
// If OpenThreadToken() failed with any of the above error codes,
// then succeed the call, but return a NULL token handle.
//
if( err != ERROR_NO_TOKEN &&
err != ERROR_CALL_NOT_IMPLEMENTED &&
err != ERROR_NOT_SUPPORTED ) {
result = HRESULT_FROM_WIN32(err);
}
*Token = NULL;
}
return result;
} // IIS_CRYPTO_BASE::GetThreadImpersonationToken
HRESULT
IIS_CRYPTO_BASE::SetThreadImpersonationToken(
IN HANDLE Token
)
/*++
Routine Description:
Sets the impersonation token for the current thread.
Arguments:
Token - A handle to the impersonation token.
Return Value:
HRESULT - 0 if successful, !0 otherwise.
--*/
{
HRESULT result = NO_ERROR;
//
// Set it.
//
if( !SetThreadToken(
NULL,
Token
) ) {
DWORD err = GetLastError();
result = HRESULT_FROM_WIN32(err);
}
return result;
} // IIS_CRYPTO_BASE::SetThreadImpersonationToken
BOOL
IIS_CRYPTO_BASE::AmIRunningInTheLocalSystemContext(
VOID
)
/*++
Routine Description:
Determines if the current process is running in the local system
security context.
Arguments:
None.
Return Value:
BOOL - TRUE if we're running in the local system context, FALSE
otherwise.
--*/
{
BOOL result;
HANDLE token;
DWORD lengthRequired;
PTOKEN_USER tokenInfo;
PSID systemSid;
SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
//
// Setup local so we know how to cleanup on exit.
//
result = FALSE; // until proven otherwise...
token = NULL;
tokenInfo = NULL;
systemSid = NULL;
//
// Get a handle to the current process token.
//
if( !OpenProcessToken(
GetCurrentProcess(), // ProcessHandle
TOKEN_READ, // DesiredAccess
&token // TokenHandle
) ) {
goto cleanup;
}
//
// Determine the length of the token information, then allocate
// a buffer and read the info.
//
if( !GetTokenInformation(
token, // TokenHandle
TokenUser, // TokenInformationClass
NULL, // TokenInformation
0, // TokenInformationLength
&lengthRequired // ReturnLength
) ) {
goto cleanup;
}
tokenInfo = (PTOKEN_USER)new char[lengthRequired];
if( tokenInfo == NULL ) {
goto cleanup;
}
if( !GetTokenInformation(
token, // TokenHandle
TokenUser, // TokenInformationClass
tokenInfo, // TokenInformation
lengthRequired, // TokenInformationLength
&lengthRequired // ReturnLength
) ) {
goto cleanup;
}
//
// OK, we have the token. Now build the system SID so we can compare
// it with the one stored in the token.
//
if( !AllocateAndInitializeSid(
&ntAuthority, // pIdentifierAuthority
1, // nSubAuthorityCount
SECURITY_LOCAL_SYSTEM_RID, // nSubAuthority0
0, // nSubAuthority1
0, // nSubAuthority2
0, // nSubAuthority3
0, // nSubAuthority4
0, // nSubAuthority5
0, // nSubAuthority6
0, // nSubAuthority7
&systemSid // pSid
) ) {
goto cleanup;
}
//
// Now that we have the SID from the token and our hand-built
// local system SID, we can compare them.
//
result = EqualSid(
tokenInfo->User.Sid, // pSid1
systemSid // pSid2
);
cleanup:
if( systemSid != NULL ) {
FreeSid( systemSid );
}
if( tokenInfo != NULL ) {
delete[] tokenInfo;
}
if( token != NULL ) {
CloseHandle( token );
}
return result;
} // IIS_CRYPTO_BASE::AmIRunningInTheLocalSystemContext