windows-nt/Source/XPSP1/NT/inetsrv/iis/ui/itools/w3key/w3serv.cpp
2020-09-26 16:20:57 +08:00

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);
}