572 lines
16 KiB
C++
572 lines
16 KiB
C++
|
#include "stdafx.h"
|
||
|
#include "KeyObjs.h"
|
||
|
|
||
|
#include "CmnKey.h"
|
||
|
#include "W3Key.h"
|
||
|
#include "W3Serv.h"
|
||
|
|
||
|
#include "resource.h"
|
||
|
|
||
|
#include "kmlsa.h"
|
||
|
|
||
|
// the service image index
|
||
|
extern int g_iServiceImage;
|
||
|
extern HINSTANCE g_hInstance;
|
||
|
|
||
|
//--------------------------------------------------------
|
||
|
CW3KeyService::CW3KeyService():
|
||
|
m_pszwMachineName( NULL )
|
||
|
{
|
||
|
// set the icon id
|
||
|
m_iImage = (WORD)g_iServiceImage;
|
||
|
|
||
|
// load the service name
|
||
|
m_szItemName.LoadString( IDS_SERV_NAME );
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------
|
||
|
CW3KeyService::~CW3KeyService()
|
||
|
{
|
||
|
// if the machine name has been cached, release it
|
||
|
if ( m_pszwMachineName )
|
||
|
{
|
||
|
delete m_pszwMachineName;
|
||
|
m_pszwMachineName = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------
|
||
|
void CW3KeyService::LoadKeys( CMachine* pMachine )
|
||
|
{
|
||
|
// specify the resources to use
|
||
|
HINSTANCE hOldRes = AfxGetResourceHandle();
|
||
|
AfxSetResourceHandle( g_hInstance );
|
||
|
|
||
|
HANDLE hPolicy;
|
||
|
DWORD err;
|
||
|
|
||
|
// since we use the machine name several times, set it up only once
|
||
|
if ( !m_pszwMachineName )
|
||
|
{
|
||
|
// get the normal name
|
||
|
CString szName;
|
||
|
pMachine->GetMachineName( szName );
|
||
|
|
||
|
// allocate the cache for the machine name
|
||
|
m_pszwMachineName = new WCHAR[MAX_PATH];
|
||
|
if ( !m_pszwMachineName ) goto cleanup;
|
||
|
|
||
|
// unicodize the name
|
||
|
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, szName, -1, m_pszwMachineName, MAX_PATH );
|
||
|
}
|
||
|
|
||
|
// attempt to open an LSA policy on the target machine
|
||
|
hPolicy = HOpenLSAPolicy( m_pszwMachineName, &err );
|
||
|
// if we did not open a policy, fail
|
||
|
if ( !hPolicy ) goto cleanup;
|
||
|
|
||
|
// load the keys that were previously saved by key manager
|
||
|
FRestoreNormalKeys( hPolicy );
|
||
|
|
||
|
// load any keys that were created by keyset - not keymanager
|
||
|
FLoadKeySetKeys( hPolicy );
|
||
|
|
||
|
// close the policy
|
||
|
FCloseLSAPolicy( hPolicy, &err );
|
||
|
|
||
|
// restore the resources
|
||
|
cleanup:
|
||
|
AfxSetResourceHandle( hOldRes );
|
||
|
}
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
CW3Key* CW3KeyService::PGetDefaultKey( void )
|
||
|
{
|
||
|
// get the first key
|
||
|
CW3Key* pKey = GetFirstW3Key();
|
||
|
|
||
|
// loop through the keys, looking for the default
|
||
|
while( pKey )
|
||
|
{
|
||
|
// test the key
|
||
|
if ( pKey->FIsDefault() )
|
||
|
return pKey;
|
||
|
|
||
|
// get the next key
|
||
|
pKey = GetNextW3Key( pKey );
|
||
|
}
|
||
|
|
||
|
// we did not find the default key, return NULL
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
// the plan to commit the machine takes place in several steps
|
||
|
// First we write out the current keys to the secrets.
|
||
|
// The keys are written out using a structured naming sequense.
|
||
|
// namely, Key1, Key2, Key3, etc...
|
||
|
// After writing out all the keys, any keys that are still in the
|
||
|
// secrets but are not current keys (i.e. they were deleted) are
|
||
|
// removed from the secrets.
|
||
|
// Next, we build the mapping between the keys and the servers. This part
|
||
|
// is basically what KeySet did.
|
||
|
BOOL CW3KeyService::FCommitChangesNow( void )
|
||
|
{
|
||
|
HANDLE hPolicy;
|
||
|
DWORD err;
|
||
|
|
||
|
// if there is nothing to do, then do nothing
|
||
|
if ( !m_fDirty )
|
||
|
return TRUE;
|
||
|
|
||
|
// this can take a few seconds, so set the hourglass cursor
|
||
|
CWaitCursor waitcursor;
|
||
|
|
||
|
// open a policy to the target machine
|
||
|
hPolicy = HOpenLSAPolicy( m_pszwMachineName, &err );
|
||
|
// make sure it worked
|
||
|
if( !hPolicy )
|
||
|
{
|
||
|
WriteSecretMessageBox();
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// commit the changes here
|
||
|
if ( !DeleteAllW3Keys(hPolicy) )
|
||
|
{
|
||
|
FCloseLSAPolicy( hPolicy, &err );
|
||
|
WriteSecretMessageBox();
|
||
|
// even though we failed to delete all the old keys, write out the new
|
||
|
// ones anyway.
|
||
|
}
|
||
|
|
||
|
// commit the changes here
|
||
|
if ( !FWriteOutKeys(hPolicy) )
|
||
|
{
|
||
|
FCloseLSAPolicy( hPolicy, &err );
|
||
|
WriteSecretMessageBox();
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// record the new current number of keys in the registry
|
||
|
// now if all the keys are deleted, the right number of
|
||
|
// resources will be purged from the registry
|
||
|
m_nNumKeysRead = GetChildCount();
|
||
|
|
||
|
// close the policy
|
||
|
FCloseLSAPolicy( hPolicy, &err );
|
||
|
|
||
|
// clear the dirty flag
|
||
|
SetDirty( FALSE );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
void CW3KeyService::WriteSecretMessageBox( void )
|
||
|
{
|
||
|
CString szMessage;
|
||
|
|
||
|
// get the message string
|
||
|
szMessage.LoadString( IDS_COMMIT_ERROR );
|
||
|
|
||
|
// tack on the name of the server
|
||
|
szMessage += m_szItemName;
|
||
|
|
||
|
// tack on some punctuation
|
||
|
szMessage += _T(".");
|
||
|
|
||
|
AfxMessageBox( szMessage );
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
// looks for keys that were installed by keyset, not key manager. These
|
||
|
// keys only exist directly in w3 server form and are unnamed.
|
||
|
BOOL CW3KeyService::FLoadKeySetKeys( HANDLE hPolicy )
|
||
|
{
|
||
|
PLSA_UNICODE_STRING pLSAData;
|
||
|
DWORD err;
|
||
|
BOOL fFoundKeySetKeys = FALSE;
|
||
|
|
||
|
// get the W3 server links data from the secrets database
|
||
|
pLSAData = FRetrieveLSASecret( hPolicy, KEYSET_LIST, &err );
|
||
|
|
||
|
// if we get lucky, there won't be any keys to test
|
||
|
if ( !pLSAData ) return TRUE;
|
||
|
|
||
|
// allocate the name buffer
|
||
|
PWCHAR pWName = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) );
|
||
|
ASSERT( pWName );
|
||
|
if ( !pWName )
|
||
|
{
|
||
|
AfxThrowMemoryException();
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// No such luck. Now we have to walk the list and delete all those secrets
|
||
|
WCHAR* pszAddress = (WCHAR*)(pLSAData->Buffer);
|
||
|
WCHAR* pchKeys;
|
||
|
|
||
|
// loop the items in the list, deleting the associated items
|
||
|
while( pchKeys = wcschr(pszAddress, L',') )
|
||
|
{
|
||
|
// ignore empty segments
|
||
|
if ( *pszAddress != L',' )
|
||
|
{
|
||
|
*pchKeys = L'\0';
|
||
|
|
||
|
// put the wide name into a cstring
|
||
|
CString szTestAddress = pszAddress;
|
||
|
|
||
|
// see if we need to check for the default key
|
||
|
BOOL fCheckForDefault = (wcscmp(pszAddress, KEYSET_DEFAULT) == 0);
|
||
|
|
||
|
// search the keys, looking for the one that matches this
|
||
|
CW3Key* pKey = GetFirstW3Key();
|
||
|
while( pKey )
|
||
|
{
|
||
|
// if it is the default key, check for that
|
||
|
if ( fCheckForDefault )
|
||
|
{
|
||
|
if ( pKey->FIsDefault() )
|
||
|
{
|
||
|
// this is a keyman key
|
||
|
goto incrementKeyList;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// otherwise, check the actual ip address
|
||
|
if ( pKey->m_szIPAddress == szTestAddress )
|
||
|
{
|
||
|
// this is a keyman key
|
||
|
goto incrementKeyList;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get the next key
|
||
|
pKey = GetNextW3Key( pKey );
|
||
|
}
|
||
|
|
||
|
// if we get here, then we have found a keyset key
|
||
|
fFoundKeySetKeys = TRUE;
|
||
|
|
||
|
// create a new key
|
||
|
pKey = new CW3Key;
|
||
|
|
||
|
// initialize it from the wide address of the key
|
||
|
if ( pKey->FInitKey( hPolicy, pszAddress ) )
|
||
|
{
|
||
|
// add the key to the service
|
||
|
pKey->FAddToTree( this );
|
||
|
|
||
|
// mark the machine object as dirty
|
||
|
SetDirty( TRUE );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
incrementKeyList:
|
||
|
// increment the pointers
|
||
|
pchKeys++;
|
||
|
pszAddress = pchKeys;
|
||
|
}
|
||
|
|
||
|
// free the buffer for the names
|
||
|
GlobalFree( (HANDLE)pWName );
|
||
|
|
||
|
// delete the list key itself
|
||
|
// free the list key itself
|
||
|
if ( pLSAData )
|
||
|
DisposeLSAData( pLSAData );
|
||
|
|
||
|
// if we found any keyset keys, tell the user what to expect
|
||
|
if ( fFoundKeySetKeys )
|
||
|
AfxMessageBox( IDS_FOUND_KEYSET_KEYS, MB_OK|MB_ICONINFORMATION );
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
// similar to the routine "DeleteAll" in the KeySet utility
|
||
|
|
||
|
BOOL CW3KeyService::DeleteAllW3Keys( HANDLE hPolicy )
|
||
|
{
|
||
|
DWORD err;
|
||
|
PLSA_UNICODE_STRING pLSAData;
|
||
|
|
||
|
// get the secret list of keys
|
||
|
pLSAData = FRetrieveLSASecret( hPolicy, KEYSET_LIST, &err );
|
||
|
|
||
|
// if we get lucky, there won't be any keys to get rid of
|
||
|
if ( !pLSAData ) return TRUE;
|
||
|
|
||
|
// allocate the name buffer
|
||
|
PWCHAR pWName = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) );
|
||
|
ASSERT( pWName );
|
||
|
if ( !pWName )
|
||
|
{
|
||
|
AfxThrowMemoryException();
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// No such luck. Now we have to walk the list and delete all those secrets
|
||
|
WCHAR* pszAddress = (WCHAR*)(pLSAData->Buffer);
|
||
|
WCHAR* pchKeys;
|
||
|
|
||
|
// loop the items in the list, deleting the associated items
|
||
|
while( pchKeys = wcschr(pszAddress, L',') )
|
||
|
{
|
||
|
// ignore empty segments
|
||
|
if ( *pszAddress != L',' )
|
||
|
{
|
||
|
*pchKeys = L'\0';
|
||
|
|
||
|
// Nuke the secrets, one at a time
|
||
|
swprintf( pWName, KEYSET_PUB_KEY, pszAddress );
|
||
|
FStoreLSASecret( hPolicy, pWName, NULL, 0, &err );
|
||
|
|
||
|
swprintf( pWName, KEYSET_PRIV_KEY, pszAddress );
|
||
|
FStoreLSASecret( hPolicy, pWName, NULL, 0, &err );
|
||
|
|
||
|
swprintf( pWName, KEYSET_PASSWORD, pszAddress );
|
||
|
FStoreLSASecret( hPolicy, pWName, NULL, 0, &err );
|
||
|
}
|
||
|
|
||
|
// increment the pointers
|
||
|
pchKeys++;
|
||
|
pszAddress = pchKeys;
|
||
|
}
|
||
|
|
||
|
// delete the list key itself
|
||
|
FStoreLSASecret( hPolicy, KEYSET_LIST, NULL, 0, &err );
|
||
|
|
||
|
// free the buffer for the names
|
||
|
GlobalFree( (HANDLE)pWName );
|
||
|
|
||
|
// free the info we originally retrieved from the secret
|
||
|
if ( pLSAData )
|
||
|
DisposeLSAData( pLSAData );
|
||
|
|
||
|
// return success
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
// utiltiy to append data to an existing handle, thus growing it
|
||
|
BOOL CW3KeyService::FExpandoHandle( HANDLE* ph, PVOID pData, DWORD cbData )
|
||
|
{
|
||
|
HANDLE hNew;
|
||
|
HANDLE hOld = *ph;
|
||
|
|
||
|
ASSERT( ph && *ph && pData && cbData );
|
||
|
if ( !ph || !*ph ) return FALSE;
|
||
|
if ( !pData || !cbData ) return TRUE;
|
||
|
|
||
|
// calculate the new size of the handle
|
||
|
SIZE_T cbSizeOld = GlobalSize( *ph );
|
||
|
SIZE_T cbSizeNew = cbSizeOld + cbData;
|
||
|
|
||
|
// allocate a new handle at the new size
|
||
|
hNew = GlobalAlloc( GHND, cbSizeNew );
|
||
|
// if it didn't work, throw
|
||
|
if ( !hNew )
|
||
|
{
|
||
|
AfxThrowMemoryException();
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// lock down the handles and copy over the existing data
|
||
|
PCHAR pNew = (PCHAR)GlobalLock( hNew );
|
||
|
|
||
|
// only copy over the old data if there is some
|
||
|
if ( cbSizeOld > 0 )
|
||
|
{
|
||
|
PCHAR pOld = (PCHAR)GlobalLock( hOld );
|
||
|
CopyMemory( pNew, pOld, cbSizeOld );
|
||
|
GlobalUnlock( hOld );
|
||
|
}
|
||
|
|
||
|
// advance the new pointer and copy in the new data
|
||
|
pNew += cbSizeOld;
|
||
|
CopyMemory( pNew, pData, cbData );
|
||
|
|
||
|
// unlock the new handle
|
||
|
GlobalUnlock( hNew );
|
||
|
|
||
|
// it did work, so set the handle
|
||
|
*ph = hNew;
|
||
|
|
||
|
// finally, dispose of the old handle
|
||
|
GlobalFree( hOld );
|
||
|
|
||
|
// return success
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
BOOL CW3KeyService::FWriteOutKeys( HANDLE hPolicy )
|
||
|
{
|
||
|
WORD iKey;
|
||
|
DWORD err;
|
||
|
HANDLE hList = GlobalAlloc( GHND, 0 );
|
||
|
LONG cch;
|
||
|
BOOL fSomethingInList = FALSE;
|
||
|
|
||
|
ASSERT( hPolicy );
|
||
|
ASSERT( hList );
|
||
|
if ( !hList )
|
||
|
AfxThrowMemoryException();
|
||
|
|
||
|
// get the buffer for the wide name
|
||
|
PWCHAR pWName = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) );
|
||
|
|
||
|
|
||
|
// for each key in the machine, write its data out to the secrets
|
||
|
iKey = 0;
|
||
|
CW3Key* pKey = GetFirstW3Key();
|
||
|
while( pKey )
|
||
|
{
|
||
|
// tell the key to store itself
|
||
|
if ( !pKey->WriteKey(hPolicy, iKey, pWName) )
|
||
|
return FALSE;
|
||
|
|
||
|
// if this key has a link, add it to the w3 links list
|
||
|
cch = wcslen( pWName );
|
||
|
if ( cch )
|
||
|
{
|
||
|
wcscat( pWName, L"," );
|
||
|
cch++;
|
||
|
FExpandoHandle( &hList, pWName, cch * sizeof(WCHAR) ); // terminates later
|
||
|
fSomethingInList = TRUE;
|
||
|
}
|
||
|
|
||
|
// get the next key
|
||
|
pKey = GetNextW3Key( pKey );
|
||
|
iKey++;
|
||
|
}
|
||
|
|
||
|
// save the contents of the list as a secret
|
||
|
if ( fSomethingInList )
|
||
|
{
|
||
|
WORD word = 0;
|
||
|
// terminate the list of named keys
|
||
|
FExpandoHandle( &hList, &word, sizeof(WORD) );
|
||
|
|
||
|
ASSERT( GlobalSize(hList) < 0xFFFF );
|
||
|
PVOID p = GlobalLock(hList);
|
||
|
FStoreLSASecret( hPolicy, KEYSET_LIST, p, (WORD)GlobalSize(hList), &err );
|
||
|
GlobalUnlock(hList);
|
||
|
}
|
||
|
|
||
|
// free the handle for the list
|
||
|
GlobalFree( hList );
|
||
|
hList = NULL;
|
||
|
|
||
|
// once we get here we have already written out all our keys. However, the case could exist where
|
||
|
// we now have fewer keys than we started with. This means that there are keys in the secrets database
|
||
|
// that are no longer needed. If this is the case, get rid of them
|
||
|
WORD numKeys = GetChildCount();
|
||
|
if ( numKeys < m_nNumKeysRead )
|
||
|
{
|
||
|
PCHAR pName = (PCHAR)GlobalAlloc( GPTR, MAX_PATH+1 );
|
||
|
|
||
|
// make sure we got the name buffers
|
||
|
ASSERT( pName && pWName );
|
||
|
if ( pName && pWName )
|
||
|
for ( iKey = numKeys; iKey < m_nNumKeysRead; iKey++ )
|
||
|
{
|
||
|
// prepare the name of the secret. - Base name plus the number+1
|
||
|
sprintf( pName, "%s%d", KEY_NAME_BASE, iKey+1 );
|
||
|
// unicodize the name
|
||
|
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pName, -1, pWName, MAX_PATH+1 );
|
||
|
|
||
|
// remove the secret
|
||
|
FStoreLSASecret( hPolicy, pWName, NULL, 0, &err );
|
||
|
}
|
||
|
|
||
|
// free the string buffers
|
||
|
GlobalFree( (HANDLE)pName );
|
||
|
}
|
||
|
|
||
|
// free the string buffers
|
||
|
GlobalFree( (HANDLE)pWName );
|
||
|
|
||
|
// return success
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------
|
||
|
BOOL CW3KeyService::FRestoreNormalKeys( HANDLE hPolicy )
|
||
|
{
|
||
|
DWORD iKey = 0;
|
||
|
PCHAR pName = (PCHAR)GlobalAlloc( GPTR, MAX_PATH+1 );
|
||
|
PWCHAR pWName = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) );
|
||
|
|
||
|
PLSA_UNICODE_STRING pLSAData;
|
||
|
DWORD err;
|
||
|
|
||
|
// make sure we got the name buffers
|
||
|
ASSERT( pName && pWName );
|
||
|
if ( !pName || !pWName ) return FALSE;
|
||
|
|
||
|
// clear the number of keys read (we haven't read any yet!)
|
||
|
m_nNumKeysRead = 0;
|
||
|
|
||
|
// load keys until we have loaded them all
|
||
|
while(TRUE)
|
||
|
{
|
||
|
// increment the key counter
|
||
|
iKey++;
|
||
|
|
||
|
// build the key secret name
|
||
|
sprintf( pName, "%s%d", KEY_NAME_BASE, iKey );
|
||
|
// unicodize the name
|
||
|
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pName, -1, pWName, MAX_PATH+1 );
|
||
|
|
||
|
// get the secret
|
||
|
pLSAData = FRetrieveLSASecret( hPolicy, pWName, &err );
|
||
|
|
||
|
// if we didn't get anything, leave the loop
|
||
|
if ( !pLSAData )
|
||
|
break;
|
||
|
|
||
|
// there is a key here, so count it
|
||
|
m_nNumKeysRead++;
|
||
|
|
||
|
// ah, but we did get something. Make a new key and add it to the key list
|
||
|
CW3Key* pKey = new CW3Key;
|
||
|
if ( pKey->FInitKey(pLSAData->Buffer, pLSAData->Length) )
|
||
|
{
|
||
|
pKey->FAddToTree( this );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// failed to init key
|
||
|
delete pKey;
|
||
|
}
|
||
|
|
||
|
// dispose of the lsa buffer now that we have loaded from it
|
||
|
if ( pLSAData )
|
||
|
DisposeLSAData( pLSAData );
|
||
|
pLSAData = NULL;
|
||
|
}
|
||
|
|
||
|
// free the buffers
|
||
|
GlobalFree( (HANDLE)pName );
|
||
|
GlobalFree( (HANDLE)pWName );
|
||
|
if ( pLSAData )
|
||
|
DisposeLSAData( pLSAData );
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------
|
||
|
void DisposeLSAData( PVOID pData )
|
||
|
{
|
||
|
PLSA_UNICODE_STRING pDataLSA = (PLSA_UNICODE_STRING)pData;
|
||
|
if ( !pDataLSA || !pDataLSA->Buffer ) return;
|
||
|
GlobalFree(pDataLSA);
|
||
|
}
|