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.
911 lines
28 KiB
911 lines
28 KiB
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
crypto.c
|
|
|
|
Abstract:
|
|
|
|
routines for encrypting/decrypting resource data blob. uses crypto API to
|
|
generate the key used to encrypt/decrypt the CO password. Key is stored as
|
|
a crypto checkpoint associated with the resource.
|
|
|
|
Author:
|
|
|
|
Charlie Wickham (charlwi) 14-Feb-2001
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#define UNICODE 1
|
|
#define _UNICODE 1
|
|
|
|
#include "clusres.h"
|
|
#include "clusrtl.h"
|
|
#include "netname.h"
|
|
|
|
#include <wincrypt.h>
|
|
#include <lm.h>
|
|
|
|
//
|
|
// defines
|
|
//
|
|
|
|
#define NN_GUID_STRING_BUFFER_LENGTH 37 // includes the terminating NULL
|
|
|
|
//
|
|
// header for encrypted data.
|
|
//
|
|
|
|
typedef struct _NETNAME_ENCRYPTED_DATA {
|
|
DWORD Version;
|
|
BYTE Data[0];
|
|
} NETNAME_ENCRYPTED_DATA, *PNETNAME_ENCRYPTED_DATA;
|
|
|
|
#define NETNAME_ENCRYPTED_DATA_VERSION 1
|
|
|
|
//
|
|
// Container name is the resource's GUID followed by this decoration
|
|
//
|
|
WCHAR KeyDecoration[] = L"-Netname Resource Data";
|
|
|
|
DWORD
|
|
BuildKeyName(
|
|
IN HRESOURCE ResourceHandle,
|
|
IN LPWSTR KeyName,
|
|
IN DWORD KeyNameChars
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
build the key name (resource GUID followed by decoration)
|
|
|
|
Arguments:
|
|
|
|
ResourceHandle - handle to the cluster resource (not the one given to us
|
|
by resmon)
|
|
|
|
KeyName - buffer to receive the constructed name
|
|
|
|
KeyNameChars - size, in characteres, of KeyName
|
|
|
|
Return Value:
|
|
|
|
success, otherwise Win32 error
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
DWORD bytesReturned;
|
|
DWORD charsReturned;
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
if ( KeyNameChars < ( NN_GUID_STRING_BUFFER_LENGTH + COUNT_OF( KeyDecoration ))) {
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
//
|
|
// get our GUID (ID) to uniquely identify this resource throughout renames
|
|
//
|
|
status = ClusterResourceControl(ResourceHandle,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_ID,
|
|
NULL,
|
|
0,
|
|
KeyName,
|
|
KeyNameChars * sizeof( WCHAR ),
|
|
&bytesReturned);
|
|
|
|
charsReturned = bytesReturned / sizeof( WCHAR );
|
|
|
|
if ( status == ERROR_SUCCESS ) {
|
|
if (( charsReturned + COUNT_OF( KeyDecoration )) <= KeyNameChars ) {
|
|
wcscat( KeyName, KeyDecoration );
|
|
} else {
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
} // BuildKeyName
|
|
|
|
DWORD
|
|
FindNNCryptoContainer(
|
|
IN PNETNAME_RESOURCE Resource,
|
|
OUT LPWSTR * ContainerName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
find our key name in the list of crypto checkpoints associated with this
|
|
resource.
|
|
|
|
Arguments:
|
|
|
|
Resource - pointer to resource context info
|
|
|
|
ContainerName - address of pointer that gets pointer to container name
|
|
|
|
Return Value:
|
|
|
|
success if it worked, otherwise Win32 error
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
DWORD bytesReturned;
|
|
LPWSTR checkpointInfo = NULL;
|
|
LPWSTR chkpt;
|
|
WCHAR keyName[ NN_GUID_STRING_BUFFER_LENGTH + COUNT_OF( KeyDecoration ) ];
|
|
|
|
RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
|
|
|
|
//
|
|
// get our GUID (ID) to uniquely identify this resource throughout renames
|
|
//
|
|
status = ClusterResourceControl(Resource->ClusterResourceHandle,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_CRYPTO_CHECKPOINTS,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&bytesReturned);
|
|
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't get size of crypto checkpoint info. status %1!u!.\n",
|
|
status);
|
|
|
|
return status;
|
|
}
|
|
|
|
if ( bytesReturned == 0 ) {
|
|
return ERROR_FILE_NOT_FOUND;
|
|
}
|
|
|
|
checkpointInfo = LocalAlloc( LMEM_FIXED, bytesReturned );
|
|
if ( checkpointInfo == NULL ) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't allocate memory for resource's crypto checkpoint info. status %1!u!.\n",
|
|
status);
|
|
return status;
|
|
}
|
|
|
|
status = ClusterResourceControl(Resource->ClusterResourceHandle,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_CRYPTO_CHECKPOINTS,
|
|
NULL,
|
|
0,
|
|
checkpointInfo,
|
|
bytesReturned,
|
|
&bytesReturned);
|
|
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't get crypto checkpoint info. status %1!u!.\n",
|
|
status);
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// build our key name and look for it by walking the list of checkpoints
|
|
//
|
|
status = BuildKeyName(Resource->ClusterResourceHandle, keyName, COUNT_OF( keyName ));
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't build key name for crypto checkpoint. status %1!u!.\n",
|
|
status);
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
chkpt = wcsstr( checkpointInfo, keyName );
|
|
if ( chkpt == NULL ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't find key name (%1!ws!) in list of crypto checkpoints.\n",
|
|
keyName);
|
|
|
|
status = ERROR_INVALID_DATA;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// find the beginning of the string or the buffer, get the size, and move
|
|
// our string to the beginning of the buffer (which is freed by the
|
|
// caller)
|
|
//
|
|
while ( chkpt != checkpointInfo && *chkpt != UNICODE_NULL ) {
|
|
--chkpt;
|
|
}
|
|
|
|
if ( chkpt != checkpointInfo ) {
|
|
DWORD stringBytes;
|
|
|
|
++chkpt;
|
|
stringBytes = (wcslen( chkpt ) + 1 ) * sizeof( WCHAR );
|
|
memmove( checkpointInfo, chkpt, stringBytes );
|
|
}
|
|
|
|
*ContainerName = checkpointInfo;
|
|
|
|
cleanup:
|
|
if ( status != ERROR_SUCCESS && checkpointInfo != NULL ) {
|
|
LocalFree( checkpointInfo );
|
|
*ContainerName = NULL;
|
|
}
|
|
|
|
return status;
|
|
} // FindNNCryptoContainer
|
|
|
|
|
|
//
|
|
// exported routines
|
|
//
|
|
|
|
DWORD
|
|
EncryptNNResourceData(
|
|
PNETNAME_RESOURCE Resource,
|
|
LPWSTR MachinePwd,
|
|
PBYTE * EncryptedInfo,
|
|
PDWORD EncryptedInfoLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
encrypt the password, set a pointer to the encrypted data and store it in
|
|
the registry.
|
|
|
|
Arguments:
|
|
|
|
ResourceHandle - for logging to the cluster log
|
|
|
|
MachinePwd - pointer to unicode string password
|
|
|
|
EncryptedInfo - address of a pointer that receives a pointer to the encrypted blob
|
|
|
|
EncryptedInfoLength - pointer to a DWORD that receives the length of the blob
|
|
|
|
Key - handle to netname parameters key where the data is stored
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS, otherwise Win32 error
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status;
|
|
DWORD encInfoLength;
|
|
DWORD encDataLength = 0;
|
|
BOOL success;
|
|
DWORD pwdLength = ( wcslen( MachinePwd ) + 1 ) * sizeof( WCHAR );
|
|
DWORD provNameLength = 0;
|
|
PCHAR provName = NULL;
|
|
DWORD provTypeLength;
|
|
WCHAR typeBuffer[ 256 ];
|
|
DWORD containerNameChars;
|
|
PWCHAR containerName = NULL;
|
|
WCHAR keyName[ NN_GUID_STRING_BUFFER_LENGTH + COUNT_OF( KeyDecoration ) ];
|
|
|
|
HCRYPTPROV cryptoProvider = 0;
|
|
HCRYPTKEY encryptKey = 0;
|
|
|
|
RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
|
|
|
|
NETNAME_ENCRYPTED_DATA keyGenBuffer; // temp header buffer to generate key
|
|
PNETNAME_ENCRYPTED_DATA encryptedInfo = NULL; // final data area
|
|
|
|
//
|
|
// there shouldn't be a checkpoint on the resource but just in case, let's
|
|
// cleanup what might be there.
|
|
//
|
|
RemoveNNCryptoCheckpoint( Resource );
|
|
|
|
//
|
|
// get our GUID (ID) to uniquely identify this resource throughout renames
|
|
//
|
|
status = BuildKeyName( Resource->ClusterResourceHandle, keyName, COUNT_OF( keyName ));
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't get resource ID to build crypto container name. status %1!u!.\n",
|
|
status);
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// get a handle to the full RSA provider
|
|
//
|
|
if ( !CryptAcquireContext(&cryptoProvider,
|
|
keyName,
|
|
MS_ENHANCED_PROV,
|
|
PROV_RSA_FULL,
|
|
CRYPT_MACHINE_KEYSET | CRYPT_SILENT))
|
|
{
|
|
status = GetLastError();
|
|
if ( status == NTE_BAD_KEYSET ) {
|
|
success = CryptAcquireContext(&cryptoProvider,
|
|
keyName,
|
|
MS_ENHANCED_PROV,
|
|
PROV_RSA_FULL,
|
|
CRYPT_MACHINE_KEYSET |
|
|
CRYPT_SILENT |
|
|
CRYPT_NEWKEYSET);
|
|
|
|
status = success ? ERROR_SUCCESS : GetLastError();
|
|
}
|
|
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't acquire crypto context for encrypt. status %1!u!.\n",
|
|
status);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// generate a 1024 bit, exportable exchange key pair
|
|
//
|
|
if ( !CryptGenKey(cryptoProvider,
|
|
AT_KEYEXCHANGE,
|
|
( 1024 << 16 ) | CRYPT_EXPORTABLE,
|
|
&encryptKey)) {
|
|
|
|
status = GetLastError();
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't generate exchange key for encryption. status %1!u!.\n",
|
|
status);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// find the size we need for the buffer to receive the encrypted data
|
|
//
|
|
encDataLength = pwdLength;
|
|
if ( CryptEncrypt(encryptKey,
|
|
0,
|
|
TRUE,
|
|
0,
|
|
NULL,
|
|
&encDataLength,
|
|
0))
|
|
{
|
|
//
|
|
// alloc a buffer large enough to hold the data and copy the password into it.
|
|
//
|
|
ASSERT( encDataLength >= pwdLength );
|
|
|
|
encInfoLength = sizeof( NETNAME_ENCRYPTED_DATA ) + encDataLength;
|
|
|
|
encryptedInfo = LocalAlloc( LMEM_FIXED, encInfoLength );
|
|
if ( encryptedInfo != NULL ) {
|
|
wcscpy( (PWCHAR)encryptedInfo->Data, MachinePwd );
|
|
|
|
if ( CryptEncrypt(encryptKey,
|
|
0,
|
|
TRUE,
|
|
0,
|
|
encryptedInfo->Data,
|
|
&pwdLength,
|
|
encDataLength))
|
|
{
|
|
encryptedInfo->Version = NETNAME_ENCRYPTED_DATA_VERSION;
|
|
|
|
status = ResUtilSetBinaryValue(Resource->ParametersKey,
|
|
PARAM_NAME__RESOURCE_DATA,
|
|
(const LPBYTE)encryptedInfo,
|
|
encInfoLength,
|
|
NULL,
|
|
NULL);
|
|
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't write %1!u! bytes of data to registry. status %2!u!.\n",
|
|
encInfoLength,
|
|
status);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else {
|
|
status = GetLastError();
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't encrypt %1!u! bytes. status %2!u!.\n",
|
|
pwdLength,
|
|
status);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't allocate %1!u! bytes for encrypted data. status %2!u!.\n",
|
|
encInfoLength,
|
|
status);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else {
|
|
status = GetLastError();
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't determine size of encrypted data buffer for %1!u! bytes of data. status %2!u!.\n",
|
|
pwdLength,
|
|
status);
|
|
goto cleanup;
|
|
}
|
|
|
|
*EncryptedInfoLength = encInfoLength;
|
|
*EncryptedInfo = (PBYTE)encryptedInfo;
|
|
|
|
//
|
|
// it all worked; build the key container string and add a crypto
|
|
// checkpoint to the resource. Note that provider name is always returned
|
|
// as an ANSI string.
|
|
//
|
|
typeBuffer[ COUNT_OF( typeBuffer ) - 1 ] = UNICODE_NULL;
|
|
_snwprintf( typeBuffer, COUNT_OF( typeBuffer ) - 1, L"%u", PROV_RSA_FULL );
|
|
|
|
if ( !CryptGetProvParam(cryptoProvider,
|
|
PP_NAME,
|
|
NULL,
|
|
&provNameLength,
|
|
0))
|
|
{
|
|
status = GetLastError();
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't get length of provider name. status %1!u!.\n",
|
|
status);
|
|
goto cleanup;
|
|
}
|
|
|
|
provName = LocalAlloc( LMEM_FIXED, provNameLength );
|
|
if ( provName == NULL ) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't allocate memory for provider name. status %1!u!.\n",
|
|
status);
|
|
goto cleanup;
|
|
}
|
|
|
|
if ( !CryptGetProvParam(cryptoProvider,
|
|
PP_NAME,
|
|
provName,
|
|
&provNameLength,
|
|
0))
|
|
{
|
|
status = GetLastError();
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't get provider name. status %1!u!.\n",
|
|
status);
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// add 2 for the slashes in the key name plus one for the trailing null
|
|
//
|
|
containerNameChars = wcslen( typeBuffer ) + provNameLength + wcslen( keyName ) + 3;
|
|
containerName = LocalAlloc( LMEM_FIXED, containerNameChars * sizeof( WCHAR ));
|
|
if ( containerName == NULL ) {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't allocate memory for checkpoint name. status %1!u!.\n",
|
|
status);
|
|
goto cleanup;
|
|
}
|
|
|
|
containerName[ containerNameChars - 1 ] = UNICODE_NULL;
|
|
containerNameChars = _snwprintf(containerName,
|
|
containerNameChars,
|
|
L"%ws%\\%hs\\%ws",
|
|
typeBuffer,
|
|
provName,
|
|
keyName );
|
|
|
|
status = ClusterResourceControl(Resource->ClusterResourceHandle,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_ADD_CRYPTO_CHECKPOINT,
|
|
(PVOID)containerName,
|
|
( containerNameChars + 1 ) * sizeof( WCHAR ),
|
|
NULL,
|
|
0,
|
|
NULL);
|
|
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't set crypto checkpoint. status %1!u!.\n",
|
|
status);
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if ( status != ERROR_SUCCESS && encryptedInfo != NULL ) {
|
|
LocalFree( encryptedInfo );
|
|
*EncryptedInfo = NULL;
|
|
}
|
|
|
|
if ( encryptKey != 0 ) {
|
|
if ( !CryptDestroyKey( encryptKey )) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_WARNING,
|
|
L"Couldn't destory encryption key. status %1!u!.\n",
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
if ( !CryptReleaseContext( cryptoProvider, 0 )) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_WARNING,
|
|
L"Can't release crypto context. status %1!u!.\n",
|
|
GetLastError());
|
|
}
|
|
|
|
if ( provName != NULL ) {
|
|
LocalFree( provName );
|
|
}
|
|
|
|
if ( containerName != NULL ) {
|
|
LocalFree( containerName );
|
|
}
|
|
|
|
return status;
|
|
} // EncryptNNResourceData
|
|
|
|
DWORD
|
|
DecryptNNResourceData(
|
|
PNETNAME_RESOURCE Resource,
|
|
PBYTE EncryptedInfo,
|
|
DWORD EncryptedInfoLength,
|
|
LPWSTR MachinePwd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reverse of encrypt routine - find our crypto checkpoint container and
|
|
decrypt random blob and hand back the password
|
|
|
|
Arguments:
|
|
|
|
resourceHandle - used to log into the cluster log
|
|
|
|
EncryptedInfo - pointer to encrypted info header and data
|
|
|
|
EncryptedInfoLength - # of bytes in EncryptedInfo
|
|
|
|
MachinePwd - pointer to buffer that receives the unicode password
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS, otherwise Win32 error
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD status = ERROR_SUCCESS;
|
|
DWORD encDataLength = EncryptedInfoLength - sizeof( NETNAME_ENCRYPTED_DATA );
|
|
DWORD pwdByteLength;
|
|
DWORD pwdBufferSize;
|
|
PWCHAR machinePwd = NULL;
|
|
PWCHAR containerName = NULL;
|
|
DWORD providerType;
|
|
PWCHAR providerName;
|
|
PWCHAR keyName;
|
|
PWCHAR p; // for scanning checkpointInfo
|
|
DWORD scanCount;
|
|
|
|
HCRYPTPROV cryptoProvider = 0;
|
|
HCRYPTKEY encryptKey = 0;
|
|
|
|
RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
|
|
|
|
PNETNAME_ENCRYPTED_DATA encryptedInfo = (PNETNAME_ENCRYPTED_DATA)EncryptedInfo;
|
|
|
|
//
|
|
// find our container name in this resource's list of crypto checkpoints
|
|
//
|
|
status = FindNNCryptoContainer( Resource, &containerName );
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't find resource's container in crypto checkpoint info. status %1!u!.\n",
|
|
status);
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// break returned data into component parts
|
|
//
|
|
scanCount = swscanf( containerName, L"%d", &providerType );
|
|
if ( scanCount == 0 || scanCount == EOF ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Improperly formatted crypto checkpoint info \"%1!ws!\"\n",
|
|
containerName);
|
|
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
|
|
p = containerName;
|
|
while ( *p != L'\\' && *p != UNICODE_NULL ) ++p; // find backslash
|
|
if ( *p == UNICODE_NULL ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Improperly formatted crypto checkpoint info \"%1!ws!\"\n",
|
|
containerName);
|
|
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
|
|
++p; // skip over slash
|
|
providerName = p; // remember beginning of provider name
|
|
while ( *p != L'\\' && *p != UNICODE_NULL ) ++p; // find backslash
|
|
if ( *p == UNICODE_NULL ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Improperly formatted crypto checkpoint info \"%1!ws!\"\n",
|
|
containerName);
|
|
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
|
|
*p++ = UNICODE_NULL; // terminate provider name and skip over NULL
|
|
keyName = p; // remember container name
|
|
|
|
//
|
|
// get a handle to what was checkpointed
|
|
//
|
|
if ( !CryptAcquireContext(&cryptoProvider,
|
|
keyName,
|
|
providerName,
|
|
providerType,
|
|
CRYPT_MACHINE_KEYSET | CRYPT_SILENT))
|
|
{
|
|
status = GetLastError();
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't acquire crypto context for container %1!ws! with provider "
|
|
L"\"%2!u!\\%3!ws!\". status %4!u!.\n",
|
|
keyName,
|
|
providerType,
|
|
providerName,
|
|
status);
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// now get a handle to the exchange key
|
|
//
|
|
if ( ! CryptGetUserKey(cryptoProvider,
|
|
AT_KEYEXCHANGE,
|
|
&encryptKey))
|
|
{
|
|
status = GetLastError();
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't get size of crypto checkpoint info. status %1!u!.\n",
|
|
status);
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// CryptDecrypt writes the decrypted data back into the buffer that was
|
|
// holding the encrypted data. For this reason, allocate a new buffer that
|
|
// will eventually contain the password.
|
|
//
|
|
pwdByteLength = ( LM20_PWLEN + 1 ) * sizeof( WCHAR );
|
|
pwdBufferSize = ( pwdByteLength > encDataLength ? pwdByteLength : encDataLength );
|
|
|
|
machinePwd = LocalAlloc( LMEM_FIXED, pwdBufferSize );
|
|
if ( machinePwd != NULL ) {
|
|
RtlCopyMemory( machinePwd, encryptedInfo->Data, encDataLength );
|
|
|
|
if ( CryptDecrypt(encryptKey,
|
|
0,
|
|
TRUE,
|
|
0,
|
|
(PBYTE)machinePwd,
|
|
&encDataLength))
|
|
{
|
|
p = machinePwd;
|
|
|
|
ASSERT( pwdByteLength == encDataLength );
|
|
wcscpy( MachinePwd, machinePwd );
|
|
|
|
while ( *p != UNICODE_NULL ) {
|
|
*p++ = UNICODE_NULL;
|
|
}
|
|
}
|
|
else {
|
|
status = GetLastError();
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't decrypt %1!u! bytes of data. status %2!u!.\n",
|
|
encDataLength,
|
|
status);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else {
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Can't allocate %1!u! bytes for decrypt. status %2!u!.\n",
|
|
pwdBufferSize,
|
|
status);
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if ( machinePwd != NULL) {
|
|
LocalFree( machinePwd );
|
|
}
|
|
|
|
if ( encryptKey != 0 ) {
|
|
if ( !CryptDestroyKey( encryptKey )) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_WARNING,
|
|
L"Couldn't destory session key. status %1!u!.\n",
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
if ( cryptoProvider != 0 ) {
|
|
if ( !CryptReleaseContext( cryptoProvider, 0 )) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_WARNING,
|
|
L"Can't release crypto context. status %1!u!.\n",
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
if ( containerName != NULL ) {
|
|
LocalFree( containerName );
|
|
}
|
|
|
|
return status;
|
|
} // DecryptNNResourceData
|
|
|
|
VOID
|
|
RemoveNNCryptoCheckpoint(
|
|
PNETNAME_RESOURCE Resource
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove any crypto checkpoints associated with this resource. Delete the
|
|
crypto container.
|
|
|
|
Arguments:
|
|
|
|
Resource - pointer to resource context block
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PWCHAR containerName = NULL;
|
|
DWORD containerLength;
|
|
DWORD status;
|
|
WCHAR keyName[ NN_GUID_STRING_BUFFER_LENGTH + COUNT_OF( KeyDecoration ) ];
|
|
|
|
HCRYPTPROV cryptoProvider;
|
|
|
|
RESOURCE_HANDLE resourceHandle = Resource->ResourceHandle;
|
|
|
|
//
|
|
// find our container name in this resource's list of crypto checkpoints
|
|
//
|
|
status = FindNNCryptoContainer( Resource, &containerName );
|
|
if ( status != ERROR_SUCCESS ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// remove our container
|
|
//
|
|
containerLength = ( wcslen( containerName ) + 1 ) * sizeof( WCHAR );
|
|
status = ClusterResourceControl(Resource->ClusterResourceHandle,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_DELETE_CRYPTO_CHECKPOINT,
|
|
containerName,
|
|
containerLength,
|
|
NULL,
|
|
0,
|
|
NULL);
|
|
|
|
if ( status != ERROR_SUCCESS ) {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_WARNING,
|
|
L"Couldn't remove crypto checkpoint \"%1!ws!\". status %2!u!.\n",
|
|
containerName,
|
|
status);
|
|
}
|
|
|
|
//
|
|
// now delete the container; first, reconstruct the key name
|
|
//
|
|
status = BuildKeyName(Resource->ClusterResourceHandle, keyName, COUNT_OF( keyName ));
|
|
if ( status == ERROR_SUCCESS ) {
|
|
|
|
if ( CryptAcquireContext(&cryptoProvider,
|
|
keyName,
|
|
MS_ENHANCED_PROV,
|
|
PROV_RSA_FULL,
|
|
CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET))
|
|
{
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_INFORMATION,
|
|
L"Deleted crypto container \"%1!ws!\".\n",
|
|
keyName);
|
|
} else {
|
|
status = GetLastError();
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_ERROR,
|
|
L"Couldn't delete crypto container \"%1!ws!\". status %2!08X!.\n",
|
|
keyName,
|
|
status);
|
|
}
|
|
} else {
|
|
(NetNameLogEvent)(resourceHandle,
|
|
LOG_WARNING,
|
|
L"Couldn't build key container name to delete crypto container. status %1!u!.\n",
|
|
status);
|
|
}
|
|
|
|
if ( containerName != NULL ) {
|
|
LocalFree( containerName );
|
|
}
|
|
|
|
} // RemoveNNCryptoCheckpoint
|
|
|
|
|
|
/* end crypto.c */
|