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.
 
 
 
 
 
 

847 lines
19 KiB

/*++
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