|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
contain.c
Abstract:
Container manipulators for the IIS cryptographic package.
The following routines are exported by this module:
IISCryptoGetStandardContainer IISCryptoGetStandardContainer2 IISCryptoGetContainerByName IISCryptoDeleteContainer IISCryptoCloseContainer
Author:
Keith Moore (keithmo) 02-Dec-1996
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// Private constants.
//
//
// Private types.
//
//
// Private globals.
//
//
// Private prototypes.
//
HRESULT IcpGetContainerHelper( OUT HCRYPTPROV * phProv, IN LPCTSTR pszContainer, IN LPCTSTR pszProvider, IN DWORD dwProvType, IN DWORD dwAdditionalFlags, IN BOOL fApplyAcl );
//
// Public functions.
//
HRESULT WINAPI IISCryptoGetStandardContainer( OUT HCRYPTPROV * phProv, IN DWORD dwAdditionalFlags )
/*++
Routine Description:
This routine attempts to open the crypto key container. If the container does not yet exist, this routine will attempt to create it.
Arguments:
phProv - Receives the provider handle if successful.
dwAdditionalFlags - Any additional flags that should be passed to the CryptAcquireContext() API. This is typically used by server processes that pass in the CRYPT_MACHINE_KEYSET flag.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
//
// Sanity check.
//
DBG_ASSERT( IcpGlobals.Initialized ); DBG_ASSERT( phProv != NULL ); DBG_ASSERT( ( dwAdditionalFlags & CRYPT_NEWKEYSET ) == 0 ); DBG_ASSERT( ( dwAdditionalFlags & CRYPT_DELETEKEYSET ) == 0 );
//
// Let IcpGetContainerHelper() do the dirty work.
//
result = IcpGetContainerHelper( phProv, IC_CONTAINER, IC_PROVIDER, IC_PROVTYPE, dwAdditionalFlags, ( dwAdditionalFlags & CRYPT_MACHINE_KEYSET ) != 0 );
return result;
} // IISCryptoGetStandardContainer
HRESULT WINAPI IISCryptoGetStandardContainer2( OUT HCRYPTPROV * phProv )
/*++
Routine Description:
This routine attempts to open the crypto key container. If the container does not yet exist, this routine will attempt to create it.
Arguments:
phProv - Receives the provider handle if successful.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
//
// Sanity check.
//
DBG_ASSERT( IcpGlobals.Initialized ); DBG_ASSERT( phProv != NULL );
//
// Let IcpGetContainerHelper() do the dirty work.
//
result = IcpGetContainerHelper( phProv, NULL, NULL, IC_PROVTYPE, CRYPT_VERIFYCONTEXT, FALSE );
return result;
} // IISCryptoGetStandardContainer2
HRESULT WINAPI IISCryptoGetContainerByName( OUT HCRYPTPROV * phProv, IN LPTSTR pszContainerName, IN DWORD dwAdditionalFlags, IN BOOL fApplyAcl )
/*++
Routine Description:
This routine attempts to open a specific named crypto key container. If the container does not yet exist, this routine will attempt to create it and (optionally) apply an ACL to the container.
Arguments:
phProv - Receives the provider handle if successful.
pszContainerName - The name of the container to open/create. NULL means temporary container
dwAdditionalFlags - Any additional flags that should be passed to the CryptAcquireContext() API. This is typically used by server processes that pass in the CRYPT_MACHINE_KEYSET flag.
fApplyAcl - If TRUE, then an ACL is applied to the container.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result;
//
// Sanity check.
//
DBG_ASSERT( IcpGlobals.Initialized ); DBG_ASSERT( phProv != NULL ); DBG_ASSERT( ( dwAdditionalFlags & CRYPT_NEWKEYSET ) == 0 ); DBG_ASSERT( ( dwAdditionalFlags & CRYPT_DELETEKEYSET ) == 0 );
//
// Let IcpGetContainerHelper() do the dirty work.
//
result = IcpGetContainerHelper( phProv, pszContainerName, IC_PROVIDER, IC_PROVTYPE, dwAdditionalFlags, fApplyAcl );
return result;
} // IISCryptoGetContainerByName
HRESULT WINAPI IISCryptoDeleteStandardContainer( IN DWORD dwAdditionalFlags )
/*++
Routine Description:
This routine deletes the standard crypto key container.
Arguments:
dwAdditionalFlags - Any additional flags that should be passed to the CryptAcquireContext() API. This is typically used by server processes that pass in the CRYPT_MACHINE_KEYSET flag.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result = NO_ERROR; BOOL status; HCRYPTPROV cryptProv;
//
// Sanity check.
//
DBG_ASSERT( IcpGlobals.Initialized ); DBG_ASSERT( ( dwAdditionalFlags & CRYPT_NEWKEYSET ) == 0 ); DBG_ASSERT( ( dwAdditionalFlags & CRYPT_DELETEKEYSET ) == 0 );
//
// Short-circuit if cryptography is disabled.
//
if( !IcpGlobals.EnableCryptography ) { return NO_ERROR; }
//
// Delete the container.
//
status = CryptAcquireContext( &cryptProv, IC_CONTAINER, IC_PROVIDER, IC_PROVTYPE, CRYPT_DELETEKEYSET | dwAdditionalFlags );
if( !status ) { result = IcpGetLastError(); }
return result;
} // IISCryptoDeleteStandardContainer
HRESULT WINAPI IISCryptoDeleteContainerByName( IN LPTSTR pszContainerName, IN DWORD dwAdditionalFlags )
/*++
Routine Description:
This routine deletes the specified crypto key container.
Arguments:
pszContainerName - The name of the container to delete.
dwAdditionalFlags - Any additional flags that should be passed to the CryptAcquireContext() API. This is typically used by server processes that pass in the CRYPT_MACHINE_KEYSET flag.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result = NO_ERROR; BOOL status; HCRYPTPROV cryptProv;
//
// Sanity check.
//
DBG_ASSERT( IcpGlobals.Initialized ); DBG_ASSERT( ( dwAdditionalFlags & CRYPT_NEWKEYSET ) == 0 ); DBG_ASSERT( ( dwAdditionalFlags & CRYPT_DELETEKEYSET ) == 0 );
//
// Short-circuit if cryptography is disabled.
//
if( !IcpGlobals.EnableCryptography ) { return NO_ERROR; }
//
// Delete the container.
//
status = CryptAcquireContext( &cryptProv, pszContainerName, IC_PROVIDER, IC_PROVTYPE, CRYPT_DELETEKEYSET | dwAdditionalFlags );
if( !status ) { result = IcpGetLastError(); }
return result;
} // IISCryptoDeleteContainerByName
HRESULT WINAPI IISCryptoCloseContainer( IN HCRYPTPROV hProv )
/*++
Routine Description:
This routine closes the container associated with the specified provider handle.
Arguments:
hProv - A handle to a crypto service provider.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
BOOL status;
//
// Sanity check.
//
DBG_ASSERT( IcpGlobals.Initialized ); DBG_ASSERT( hProv != CRYPT_NULL );
//
// Short-circuit if cryptography is disabled.
//
if( !IcpGlobals.EnableCryptography ) { if( hProv == DUMMY_HPROV ) { return NO_ERROR; } else { return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER ); } }
//
// Close the provider.
//
status = CryptReleaseContext( hProv, 0 );
if( status ) {
UpdateContainersClosed(); return NO_ERROR;
}
return IcpGetLastError();
} // IISCryptoCloseContainer
//
// Private functions.
//
HRESULT IcpGetContainerHelper( OUT HCRYPTPROV * phProv, IN LPCTSTR pszContainer, IN LPCTSTR pszProvider, IN DWORD dwProvType, IN DWORD dwAdditionalFlags, IN BOOL fApplyAcl )
/*++
Routine Description:
This is a helper routine for IISCryptoGetContainer. It tries to open/create the specified container in the specified provider.
Arguments:
phProv - Receives the provider handle if successful.
pszContainer - The key container name.
pszProvider - The provider name.
dwProvType - The type of provider to acquire.
dwAdditionalFlags - Any additional flags that should be passed to the CryptAcquireContext() API. This is typically used by server processes that pass in the CRYPT_MACHINE_KEYSET flag.
fApplyAcl - If TRUE, then an ACL is applied to the container.
Return Value:
HRESULT - Completion status, 0 if successful, !0 otherwise.
--*/
{
HRESULT result = NO_ERROR; HCRYPTPROV hProv; BOOL status; PSID systemSid; PSID adminSid; PACL dacl; DWORD daclSize; SECURITY_DESCRIPTOR securityDescriptor; SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY; BOOL isNt = FALSE; OSVERSIONINFO osInfo;
// Sanity check.
//
DBG_ASSERT( IcpGlobals.Initialized ); DBG_ASSERT( phProv != NULL ); DBG_ASSERT( ( dwAdditionalFlags & CRYPT_NEWKEYSET ) == 0 ); DBG_ASSERT( ( dwAdditionalFlags & CRYPT_DELETEKEYSET ) == 0 );
//
// Short-circuit if cryptography is disabled.
//
if( !IcpGlobals.EnableCryptography ) { *phProv = DUMMY_HPROV; return NO_ERROR; }
//
// Setup our locals so we know how to cleanup on exit.
//
hProv = CRYPT_NULL; systemSid = NULL; adminSid = NULL; dacl = NULL;
//
// Grab the lock protecting the container code. This is always
// necessary to prevent race conditions between this code and
// the code below that creates the container & adds a security
// descriptor.
//
IcpAcquireGlobalLock();
//
// Try to open an existing container.
//
if ( pszContainer == NULL ) { //
// if container is NULL it means that temporary (ephemeral)
// keys will be used
// CRYPT_VERIFYCONTEXT must be used in this case
// keys used for DCOM traffic encryption will be using
// NULL containers
//
status = CryptAcquireContext( &hProv, pszContainer, pszProvider, dwProvType, CRYPT_VERIFYCONTEXT ); if( !status ) { result = IcpGetLastError(); DBGPRINTF(( DBG_CONTEXT,"IcpGetContainerHelper. CryptAcquireContext(advapi32.dll) with CRYPT_VERIFYCONTEXT failed err=0x%x\n",result)); DBGPRINTF(( DBG_CONTEXT,"args for CryptAcquireContext(%p,%p,%p,%d,%d)\n",&hProv,pszContainer,pszProvider,dwProvType, CRYPT_VERIFYCONTEXT));
goto fatal; } else { goto success; } }
status = CryptAcquireContext( &hProv, pszContainer, pszProvider, dwProvType, 0 | dwAdditionalFlags );
if( !status ) { result = IcpGetLastError(); }
if( SUCCEEDED(result) ) {
DBG_ASSERT( hProv != CRYPT_NULL ); *phProv = hProv;
IcpReleaseGlobalLock();
UpdateContainersOpened(); return NO_ERROR;
}
//
// Could not open the container. If the failure was anything
// other than NTE_BAD_KEYSET, then we're toast.
//
if( result != NTE_BAD_KEYSET ) { DBGPRINTF(( DBG_CONTEXT,"IcpGetContainerHelper. CryptAcquireContext(advapi32.dll) failed err=0x%x.toast.\n",result)); DBGPRINTF(( DBG_CONTEXT,"args for CryptAcquireContext(%p,%p,%p,%d,%d)\n",&hProv,pszContainer,pszProvider,dwProvType,CRYPT_NEWKEYSET | dwAdditionalFlags)); hProv = CRYPT_NULL; goto fatal; }
if(result == NTE_BAD_KEYSET) { DBGPRINTF(( DBG_CONTEXT,"CryptAcquireContext(%p,%p,%p,%d,%d) returned NTE_BAD_KEYSET, so lets create a keyset now...\n",&hProv,pszContainer,pszProvider,dwProvType,0 | dwAdditionalFlags)); }
//
// OK, CryptAcquireContext() failed with NTE_BAD_KEYSET, meaning
// that the container does not yet exist, so create it now.
//
status = CryptAcquireContext( &hProv, pszContainer, pszProvider, dwProvType, CRYPT_NEWKEYSET | dwAdditionalFlags );
if( status ) { result = NO_ERROR; } else { result = IcpGetLastError(); }
if( FAILED(result) ) { DBGPRINTF(( DBG_CONTEXT,"IcpGetContainerHelper. CryptAcquireContext(advapi32.dll) failed err=0x%x.\n",result)); DBGPRINTF(( DBG_CONTEXT,"args for CryptAcquireContext(%p,%p,%p,%d,%d)\n",&hProv,pszContainer,pszProvider,dwProvType,CRYPT_NEWKEYSET | dwAdditionalFlags)); hProv = CRYPT_NULL; goto fatal; }
//
// We've created the container. If requested, then we must create
// a security descriptor for the container. This security descriptor
// allows full access to the the container by the local system and
// the local administrators group. Other login contexts may not
// access the container.
//
// Of course, we only need to do this under NT...
//
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if ( GetVersionEx( &osInfo ) ) { isNt = (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); }
if( fApplyAcl && isNt ) {
//
// Initialize the security descriptor.
//
status = InitializeSecurityDescriptor( &securityDescriptor, SECURITY_DESCRIPTOR_REVISION );
if( !status ) { result = IcpGetLastError(); goto fatal; }
//
// Create the SIDs for the local system and admin group.
//
status = AllocateAndInitializeSid( &ntAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &systemSid );
if( !status ) { result = IcpGetLastError(); goto fatal; }
status= AllocateAndInitializeSid( &ntAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &adminSid );
if( !status ) { result = IcpGetLastError(); goto fatal; }
//
// Create the DACL containing an access-allowed ACE
// for the local system and admin SIDs.
//
daclSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(adminSid) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(systemSid) - sizeof(DWORD);
dacl = (PACL)IcpAllocMemory( daclSize );
if( dacl == NULL ) { result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); goto fatal; }
status = InitializeAcl( dacl, daclSize, ACL_REVISION );
if( !status ) { result = IcpGetLastError(); goto fatal; }
status = AddAccessAllowedAce( dacl, ACL_REVISION, KEY_ALL_ACCESS, systemSid );
if( !status ) { result = IcpGetLastError(); goto fatal; }
status = AddAccessAllowedAce( dacl, ACL_REVISION, KEY_ALL_ACCESS, adminSid );
if( !status ) { result = IcpGetLastError(); goto fatal; }
//
// Set the DACL into the security descriptor.
//
status = SetSecurityDescriptorDacl( &securityDescriptor, TRUE, dacl, FALSE );
if( !status ) { result = IcpGetLastError(); goto fatal; }
//
// And (finally!) set the security descriptor on the
// container.
//
status = CryptSetProvParam( hProv, PP_KEYSET_SEC_DESCR, (BYTE *)&securityDescriptor, DACL_SECURITY_INFORMATION );
if( !status ) { result = IcpGetLastError(); goto fatal; }
}
success: //
// Success!
//
DBG_ASSERT( hProv != CRYPT_NULL ); *phProv = hProv;
UpdateContainersOpened(); result = NO_ERROR;
fatal:
if( dacl != NULL ) { IcpFreeMemory( dacl ); }
if( adminSid != NULL ) { FreeSid( adminSid ); }
if( systemSid != NULL ) { FreeSid( systemSid ); }
if( hProv != CRYPT_NULL && FAILED(result) ) { DBG_REQUIRE( CryptReleaseContext( hProv, 0 ) ); }
IcpReleaseGlobalLock(); return result;
} // IcpGetContainerHelper
|