mirror of https://github.com/tongzx/nt5src
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.
669 lines
18 KiB
669 lines
18 KiB
// This class is to help setup retrieve the old-style LSA keys and convert them
|
|
// into the new MetaData keys.
|
|
// created by BoydM 4/2/97
|
|
|
|
#include "stdafx.h"
|
|
#include "LSAKeys.h"
|
|
|
|
#ifndef _CHICAGO_
|
|
|
|
// it is assumed that #include "ntlsa.h" is included in stdafx.h
|
|
|
|
#define KEYSET_LIST L"W3_KEY_LIST"
|
|
#define KEYSET_PUB_KEY L"W3_PUBLIC_KEY_%s"
|
|
#define KEYSET_PRIV_KEY L"W3_PRIVATE_KEY_%s"
|
|
#define KEYSET_PASSWORD L"W3_KEY_PASSWORD_%s"
|
|
#define KEYSET_DEFAULT L"Default"
|
|
|
|
#define KEY_NAME_BASE "W3_KEYMAN_KEY_"
|
|
#define KEY_LINKS_SECRET_W L"W3_KEYMAN_LINKS"
|
|
#define KEYMAN_LINK_DEFAULT "DEFAULT"
|
|
#define KEY_VERSION 0x102 // version we are converting from
|
|
|
|
#define MDNAME_INCOMPLETE "incomplete"
|
|
#define MDNAME_DISABLED "disabled"
|
|
#define MDNAME_DEFAULT "default"
|
|
#define MDNAME_PORT ":443" // use the default SSL port
|
|
|
|
//----------------------------------------------------------------------
|
|
// construction
|
|
CLSAKeys::CLSAKeys():
|
|
m_cbPublic(0),
|
|
m_pPublic(NULL),
|
|
m_cbPrivate(0),
|
|
m_pPrivate(NULL),
|
|
m_cbPassword(0),
|
|
m_pPassword(NULL),
|
|
m_cbRequest(0),
|
|
m_pRequest(NULL),
|
|
m_hPolicy(NULL)
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
CLSAKeys::~CLSAKeys()
|
|
{
|
|
DWORD err;
|
|
|
|
// clear out the last loaded key
|
|
UnloadKey();
|
|
|
|
// if it is opehn, close the LSA policy
|
|
if ( m_hPolicy )
|
|
FCloseLSAPolicy( m_hPolicy, &err );
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// clean up the currently loaded key
|
|
void CLSAKeys::UnloadKey()
|
|
{
|
|
// unload the public key
|
|
if ( m_cbPublic && m_pPublic )
|
|
{
|
|
GlobalFree( m_pPublic );
|
|
m_cbPublic = 0;
|
|
m_pPublic = NULL;
|
|
}
|
|
|
|
// unload the private key
|
|
if ( m_cbPrivate && m_pPrivate )
|
|
{
|
|
GlobalFree( m_pPrivate );
|
|
m_cbPrivate = 0;
|
|
m_pPrivate = NULL;
|
|
}
|
|
|
|
// unload the password
|
|
if ( m_cbPassword && m_pPassword )
|
|
{
|
|
GlobalFree( m_pPassword );
|
|
m_cbPassword = 0;
|
|
m_pPassword = NULL;
|
|
}
|
|
|
|
// unload the key request
|
|
if ( m_cbRequest && m_pRequest )
|
|
{
|
|
GlobalFree( m_pRequest );
|
|
m_cbRequest = 0;
|
|
m_pRequest = NULL;
|
|
}
|
|
|
|
// empty the strings too
|
|
m_szFriendlyName[0] = 0;
|
|
m_szMetaName[0] = 0;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// DeleteAllLSAKeys deletes ALL remenents of the LSA keys in the Metabase.
|
|
// (not including, of course anything written out there in the future as part
|
|
// of some backup scheme when uninstalling). Call this only AFTER ALL the keys
|
|
// have been converted to the metabase. They will no longer be there after
|
|
// this routine is used.
|
|
// NOTE: this also blows away any really-old KeySet keys because they look
|
|
// like the KeyMan keys. And we have to kill both the keyset keys and the
|
|
// generic storage used by the server.
|
|
DWORD CLSAKeys::DeleteAllLSAKeys()
|
|
{
|
|
DWORD err;
|
|
|
|
// first, delete the KeyManager type keys.
|
|
err = DeleteKMKeys();
|
|
if ( err != KEYLSA_SUCCESS )
|
|
return err;
|
|
|
|
// second, delete the keyset style keys. - this also removes the ones
|
|
// that the server uses and any keyset keys.
|
|
return DeleteServerKeys();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
DWORD CLSAKeys::DeleteKMKeys()
|
|
{
|
|
PCHAR pName = (PCHAR)GlobalAlloc( GPTR, MAX_PATH+1 );
|
|
PWCHAR pWName = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) );
|
|
PLSA_UNICODE_STRING pLSAData;
|
|
DWORD err;
|
|
|
|
if ( !pName || !pWName )
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
// reset the index so we get the first key
|
|
m_iKey = 0;
|
|
|
|
// loop through the keys, deleting each in turn
|
|
while( TRUE )
|
|
{
|
|
// increment the index
|
|
m_iKey++;
|
|
|
|
// build the key secret name
|
|
sprintf( pName, "%s%d", KEY_NAME_BASE, m_iKey );
|
|
// unicodize the name
|
|
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pName, -1, pWName, MAX_PATH+1 );
|
|
|
|
// get the secret
|
|
pLSAData = FRetrieveLSASecret( m_hPolicy, pWName, &err );
|
|
// if we don't get the secret, exit
|
|
if ( !pLSAData )
|
|
{
|
|
break;
|
|
}
|
|
|
|
// The secret is there. Clean up first
|
|
DisposeLSAData( pLSAData );
|
|
|
|
// now delete the secret
|
|
FStoreLSASecret( m_hPolicy, pWName, NULL, 0, &err );
|
|
};
|
|
|
|
return KEYLSA_SUCCESS;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
DWORD CLSAKeys::DeleteServerKeys()
|
|
{
|
|
DWORD err;
|
|
PLSA_UNICODE_STRING pLSAData;
|
|
|
|
// get the secret list of keys
|
|
pLSAData = FRetrieveLSASecret( m_hPolicy, KEYSET_LIST, &err );
|
|
|
|
// if we get lucky, there won't be any keys to get rid of
|
|
if ( !pLSAData )
|
|
return KEYLSA_SUCCESS;
|
|
|
|
// allocate the name buffer
|
|
PWCHAR pWName = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) );
|
|
ASSERT( pWName );
|
|
if ( !pWName )
|
|
{
|
|
return 0xFFFFFFFF;
|
|
}
|
|
|
|
// 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( m_hPolicy, pWName, NULL, 0, &err );
|
|
|
|
swprintf( pWName, KEYSET_PRIV_KEY, pszAddress );
|
|
FStoreLSASecret( m_hPolicy, pWName, NULL, 0, &err );
|
|
|
|
swprintf( pWName, KEYSET_PASSWORD, pszAddress );
|
|
FStoreLSASecret( m_hPolicy, pWName, NULL, 0, &err );
|
|
}
|
|
|
|
// increment the pointers
|
|
pchKeys++;
|
|
pszAddress = pchKeys;
|
|
}
|
|
|
|
// delete the list key itself
|
|
FStoreLSASecret( m_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 KEYLSA_SUCCESS;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// loading the keys
|
|
// LoadFirstKey loads the first key on the specified target machine. Until
|
|
// this method is called, the data values in the object are meaningless
|
|
// this method works by preparing the list of keys to load. Then it calls
|
|
// LoadNextKey to start the process
|
|
// Unfortunately, the whole process of saving keys in the LSA registry was a bit
|
|
// of a mess because they all had to be on the same level.
|
|
DWORD CLSAKeys::LoadFirstKey( PWCHAR pszwTargetMachine )
|
|
{
|
|
DWORD err;
|
|
|
|
// open the policy on the target machine being administered
|
|
m_hPolicy = HOpenLSAPolicy( pszwTargetMachine, &err );
|
|
if ( !m_hPolicy ) return KEYLSA_UNABLE_TO_OPEN_POLICY;
|
|
|
|
// tell it to load the first key. The first key's index is actually 1,
|
|
// but LoadNextKey impliess that it is ++LoadNextKey, so start it at 0
|
|
m_iKey = 0;
|
|
|
|
// load that first key and return the response
|
|
return LoadNextKey();
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// LoadNextKey loads the next key on the target machine specified in LoadFirstKey
|
|
// LoadNextKey automatically cleans up the memory used by the previous key.
|
|
DWORD CLSAKeys::LoadNextKey()
|
|
{
|
|
// the very first thing we do is - get rid of any previously loaded key
|
|
UnloadKey();
|
|
|
|
PCHAR pName = (PCHAR)GlobalAlloc( GPTR, MAX_PATH+1 );
|
|
PWCHAR pWName = (PWCHAR)GlobalAlloc( GPTR, (MAX_PATH+1) * sizeof(WCHAR) );
|
|
PLSA_UNICODE_STRING pLSAData = NULL;
|
|
DWORD err = 0xFFFFFFFF;
|
|
|
|
PUCHAR pSrc;
|
|
WORD cbSrc;
|
|
DWORD dword, version, i;
|
|
DWORD cbChar;
|
|
PUCHAR p;
|
|
|
|
CHAR szIPAddress[256];
|
|
BOOL fDefault;
|
|
|
|
if ( !pName || !pWName )
|
|
return err;
|
|
|
|
// increment the index so we get the next key
|
|
m_iKey++;
|
|
|
|
// build the key secret name
|
|
sprintf( pName, "%s%d", KEY_NAME_BASE, m_iKey );
|
|
// unicodize the name
|
|
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pName, -1, pWName, MAX_PATH+1 );
|
|
|
|
// get the secret
|
|
pLSAData = FRetrieveLSASecret( m_hPolicy, pWName, &err );
|
|
// if we don't get the secret, exit with the error
|
|
if ( !pLSAData )
|
|
{
|
|
err = KEYLSA_NO_MORE_KEYS;
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
// we have the data from the secret. Now we parse it out into the components we desire
|
|
// this probably could have been done cleaner the first time - but now it doesn't matter
|
|
// anyway because the MetaBase takes care of storing all the individual pieces of info
|
|
// anyway. It should also be way faster too.
|
|
// This part of the routine is pretty much lifted out of CW3Key::InitializeFromPointer
|
|
// from the w3key.dll. The appropriate sections have been either commented out or changed.
|
|
|
|
pSrc = (PUCHAR)pLSAData->Buffer;
|
|
cbSrc = pLSAData->Length;
|
|
cbChar = sizeof(TCHAR);
|
|
p = pSrc;
|
|
|
|
//========================== start from CW3Key::InitializeFromPointer
|
|
|
|
ASSERT(pSrc && cbSrc);
|
|
|
|
// get the version of the data - just put it into dword for now
|
|
version = *((UNALIGNED DWORD*)p);
|
|
// check the version for validity
|
|
// if ( version > KEY_VERSION )
|
|
// {
|
|
// return FALSE;
|
|
// }
|
|
p += sizeof(DWORD);
|
|
|
|
// anything below version 0x101 is BAD. Do not accept it
|
|
if ( version < 0x101 )
|
|
{
|
|
err = KEYLSA_INVALID_VERSION;
|
|
goto cleanup;
|
|
}
|
|
|
|
// get the bits and the complete flag
|
|
// no longer used
|
|
p += sizeof(DWORD);
|
|
p += sizeof(BOOL);
|
|
ASSERT( p < (pSrc + cbSrc) );
|
|
|
|
// get the reserved dword - (acutally, just skip over it)
|
|
p += sizeof(DWORD);
|
|
|
|
// now the strings......
|
|
// for each string, first get the size of the string, then the data from the string
|
|
|
|
// get the reserved string - (actually, just skip over it)
|
|
dword = *((UNALIGNED DWORD*)p);
|
|
p += sizeof(DWORD);
|
|
p += dword;
|
|
|
|
// get the name
|
|
dword = *((UNALIGNED DWORD*)p);
|
|
p += sizeof(DWORD);
|
|
strcpy( m_szFriendlyName, (PCHAR)p );
|
|
p += dword;
|
|
ASSERT( p < (pSrc + cbSrc) );
|
|
|
|
// get the password
|
|
dword = *((UNALIGNED DWORD*)p);
|
|
p += sizeof(DWORD);
|
|
// if there is no password, don't worry, just skip it
|
|
if ( dword )
|
|
{
|
|
// make a new pointer for it
|
|
m_cbPassword = dword;
|
|
m_pPassword = (PVOID)GlobalAlloc( GPTR, m_cbPassword );
|
|
if ( !m_pPassword )
|
|
{
|
|
err = 0xFFFFFFFF;
|
|
goto cleanup;
|
|
}
|
|
// put in the private key
|
|
CopyMemory( m_pPassword, p, m_cbPassword );
|
|
|
|
p += dword;
|
|
ASSERT( p < (pSrc + cbSrc) );
|
|
}
|
|
|
|
// get the organization
|
|
// no longer used - skip the DN info
|
|
for ( i = 0; i < 6; i++ )
|
|
{
|
|
dword = *((UNALIGNED DWORD*)p);
|
|
p += sizeof(DWORD);
|
|
p += dword;
|
|
ASSERT( p < (pSrc + cbSrc) );
|
|
}
|
|
|
|
// get the ip addres it is attached to
|
|
dword = *((UNALIGNED DWORD*)p);
|
|
p += sizeof(DWORD);
|
|
// szIPAddress = p;
|
|
strcpy( szIPAddress, (PCHAR)p );
|
|
p += dword;
|
|
ASSERT( p < (pSrc + cbSrc) );
|
|
|
|
// get the default flag
|
|
fDefault = *((UNALIGNED BOOL*)p);
|
|
p += sizeof(BOOL);
|
|
|
|
// now put get the number of bytes in the private key
|
|
m_cbPrivate = *((UNALIGNED DWORD*)p);
|
|
p += sizeof(DWORD);
|
|
ASSERT( p < (pSrc + cbSrc) );
|
|
|
|
// make a new pointer for it
|
|
m_pPrivate = (PVOID)GlobalAlloc( GPTR, m_cbPrivate );
|
|
if ( !m_pPrivate )
|
|
{
|
|
err = 0xFFFFFFFF;
|
|
goto cleanup;
|
|
}
|
|
|
|
// put in the private key
|
|
CopyMemory( m_pPrivate, p, m_cbPrivate );
|
|
p += m_cbPrivate;
|
|
ASSERT( p < (pSrc + cbSrc) );
|
|
|
|
|
|
// now put get the number of bytes in the certificate
|
|
m_cbPublic = *((UNALIGNED DWORD*)p);
|
|
p += sizeof(DWORD);
|
|
ASSERT( p < (pSrc + cbSrc) );
|
|
|
|
// only make a certificate pointer if m_cbCertificate is greater than zero
|
|
m_pPublic = NULL;
|
|
if ( m_cbPublic )
|
|
{
|
|
m_pPublic = (PVOID)GlobalAlloc( GPTR, m_cbPublic );
|
|
if ( !m_pPublic )
|
|
{
|
|
err = 0xFFFFFFFF;
|
|
goto cleanup;
|
|
}
|
|
|
|
// put in the private key
|
|
CopyMemory( m_pPublic, p, m_cbPublic );
|
|
p += m_cbPublic;
|
|
if ( version >= KEY_VERSION ) {
|
|
ASSERT( p < (pSrc + cbSrc) );
|
|
} else {
|
|
ASSERT( p == (pSrc + cbSrc) );
|
|
}
|
|
}
|
|
|
|
// added near the end
|
|
if ( version >= KEY_VERSION )
|
|
{
|
|
// now put get the number of bytes in the certificte request
|
|
m_cbRequest = *((UNALIGNED DWORD*)p);
|
|
p += sizeof(DWORD);
|
|
ASSERT( p < (pSrc + cbSrc) );
|
|
|
|
// only make a certificate pointer if m_cbCertificate is greater than zero
|
|
m_pRequest = NULL;
|
|
if ( m_cbRequest )
|
|
{
|
|
m_pRequest = (PVOID)GlobalAlloc( GPTR, m_cbRequest );
|
|
if ( !m_pRequest )
|
|
{
|
|
err = 0xFFFFFFFF;
|
|
goto cleanup;
|
|
}
|
|
|
|
// put in the private key
|
|
CopyMemory( m_pRequest, p, m_cbRequest );
|
|
p += m_cbRequest;
|
|
ASSERT( p < (pSrc + cbSrc) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_cbRequest = 0;
|
|
m_pRequest = NULL;
|
|
}
|
|
//========================== end from CW3Key::InitializeFromPointer
|
|
|
|
// now we figure out the appropriate metabase name for this key
|
|
// this isn't too bad. If the targets a specific address, then the title
|
|
// is the in the form of {IP}:{PORT}. Since there were no ports in the old
|
|
// version, we will assume an appropriate default number. If it is the
|
|
// default key, then the name is "default". If it is a disabled key, then
|
|
// the name is "disabled". If it is an incomplete key, then the name is
|
|
// "incomplete". Of course, it takes a little logic to tell the difference
|
|
// between some of these.
|
|
|
|
// first, see if it is an incomplete key. - test for the public portion
|
|
if ( !m_pPublic )
|
|
{
|
|
// there may be multiple incomplete keys, so make sure they have unique names
|
|
// m_szMetaName.Format( _T("%s%d"), MDNAME_INCOMPLETE, m_iKey );
|
|
sprintf( m_szMetaName, "%s%d", MDNAME_INCOMPLETE, m_iKey );
|
|
}
|
|
// now test if it is the default key
|
|
else if ( fDefault )
|
|
{
|
|
// m_szMetaName = MDNAME_DEFAULT;
|
|
strcpy( m_szMetaName, MDNAME_DEFAULT );
|
|
}
|
|
// test for a disabled key
|
|
else if ( szIPAddress[0] == 0 )
|
|
{
|
|
// there may be multiple disabled keys, so make sure they have unique names
|
|
// m_szMetaName.Format( _T("%s%d"), MDNAME_DISABLED, m_iKey );
|
|
sprintf( m_szMetaName, "%s%d", MDNAME_DISABLED, m_iKey );
|
|
}
|
|
else
|
|
{
|
|
// it is a regular old IP targeted key
|
|
// m_szMetaName = szIPAddress;
|
|
// add on the default port specification
|
|
// m_szMetaName += MDNAME_PORT;
|
|
// sprintf( m_szMetaName, "%s%s", szIPAddress, MDNAME_PORT );
|
|
strcpy(m_szMetaName, szIPAddress);
|
|
}
|
|
|
|
// free the buffers
|
|
cleanup:
|
|
GlobalFree( (HANDLE)pName );
|
|
GlobalFree( (HANDLE)pWName );
|
|
if ( pLSAData )
|
|
DisposeLSAData( pLSAData );
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
//============================================= LSA Utility routines
|
|
|
|
//-------------------------------------------------------------
|
|
// pass in a NULL pszwServer name to open the local machine
|
|
HANDLE CLSAKeys::HOpenLSAPolicy( WCHAR *pszwServer, DWORD *pErr )
|
|
{
|
|
NTSTATUS ntStatus;
|
|
LSA_OBJECT_ATTRIBUTES objectAttributs;
|
|
LSA_HANDLE hPolicy;
|
|
|
|
LSA_UNICODE_STRING unicodeServer;
|
|
|
|
// prepare the object attributes
|
|
InitializeObjectAttributes( &objectAttributs, NULL, 0L, NULL, NULL );
|
|
|
|
// prepare the lsa_unicode name of the server
|
|
if ( pszwServer )
|
|
{
|
|
unicodeServer.Buffer = pszwServer;
|
|
unicodeServer.Length = wcslen(pszwServer) * sizeof(WCHAR);
|
|
unicodeServer.MaximumLength = unicodeServer.Length + sizeof(WCHAR);
|
|
}
|
|
|
|
|
|
// attempt to open the policy
|
|
ntStatus = LsaOpenPolicy( pszwServer ? &unicodeServer : NULL,
|
|
&objectAttributs, POLICY_ALL_ACCESS, &hPolicy );
|
|
|
|
// check for an error
|
|
if ( !NT_SUCCESS(ntStatus) )
|
|
{
|
|
*pErr = LsaNtStatusToWinError( ntStatus );
|
|
return NULL;
|
|
}
|
|
|
|
// success, so return the policy handle as a regular handle
|
|
*pErr = 0;
|
|
return hPolicy;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
BOOL CLSAKeys::FCloseLSAPolicy( HANDLE hPolicy, DWORD *pErr )
|
|
{
|
|
NTSTATUS ntStatus;
|
|
|
|
// close the policy
|
|
ntStatus = LsaClose( hPolicy );
|
|
|
|
// check for an error
|
|
if ( !NT_SUCCESS(ntStatus) )
|
|
{
|
|
*pErr = LsaNtStatusToWinError( ntStatus );
|
|
return FALSE;
|
|
}
|
|
|
|
// success, so return the policy handle as a regular handle
|
|
*pErr = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
// passing NULL in for pvData deletes the secret
|
|
BOOL CLSAKeys::FStoreLSASecret( HANDLE hPolicy, WCHAR* pszwSecretName, void* pvData, WORD cbData, DWORD *pErr )
|
|
{
|
|
LSA_UNICODE_STRING unicodeSecretName;
|
|
LSA_UNICODE_STRING unicodeData;
|
|
NTSTATUS ntStatus;
|
|
|
|
// make sure we have a policy and a secret name
|
|
if ( !hPolicy || !pszwSecretName )
|
|
{
|
|
*pErr = 1;
|
|
return FALSE;
|
|
}
|
|
|
|
// prepare the lsa_unicode name of the server
|
|
unicodeSecretName.Buffer = pszwSecretName;
|
|
unicodeSecretName.Length = wcslen(pszwSecretName) * sizeof(WCHAR);
|
|
unicodeSecretName.MaximumLength = unicodeSecretName.Length + sizeof(WCHAR);
|
|
|
|
// prepare the unicode data record
|
|
if ( pvData )
|
|
{
|
|
unicodeData.Buffer = (WCHAR*)pvData;
|
|
unicodeData.Length = cbData;
|
|
unicodeData.MaximumLength = cbData;
|
|
}
|
|
|
|
// it is now time to store the secret
|
|
ntStatus = LsaStorePrivateData( hPolicy, &unicodeSecretName, pvData ? &unicodeData : NULL );
|
|
|
|
// check for an error
|
|
if ( !NT_SUCCESS(ntStatus) )
|
|
{
|
|
*pErr = LsaNtStatusToWinError( ntStatus );
|
|
return FALSE;
|
|
}
|
|
|
|
// success, so return the policy handle as a regular handle
|
|
*pErr = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
// passing NULL in for pvData deletes the secret
|
|
PLSA_UNICODE_STRING CLSAKeys::FRetrieveLSASecret( HANDLE hPolicy, WCHAR* pszwSecretName, DWORD *pErr )
|
|
{
|
|
LSA_UNICODE_STRING unicodeSecretName;
|
|
LSA_UNICODE_STRING* pUnicodeData = NULL;
|
|
NTSTATUS ntStatus;
|
|
|
|
// make sure we have a policy and a secret name
|
|
if ( !hPolicy || !pszwSecretName )
|
|
{
|
|
*pErr = 1;
|
|
return FALSE;
|
|
}
|
|
|
|
// prepare the lsa_unicode name of the server
|
|
unicodeSecretName.Buffer = pszwSecretName;
|
|
unicodeSecretName.Length = wcslen(pszwSecretName) * sizeof(WCHAR);
|
|
unicodeSecretName.MaximumLength = unicodeSecretName.Length + sizeof(WCHAR);
|
|
|
|
// it is now time to store the secret
|
|
ntStatus = LsaRetrievePrivateData( hPolicy, &unicodeSecretName, &pUnicodeData );
|
|
|
|
// check for an error
|
|
if ( !NT_SUCCESS(ntStatus) )
|
|
{
|
|
*pErr = LsaNtStatusToWinError( ntStatus );
|
|
return NULL;
|
|
}
|
|
|
|
// success, so return the policy handle as a regular handle
|
|
*pErr = 0;
|
|
return pUnicodeData;
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
void CLSAKeys::DisposeLSAData( PVOID pData )
|
|
{
|
|
PLSA_UNICODE_STRING pDataLSA = (PLSA_UNICODE_STRING)pData;
|
|
if ( !pDataLSA || !pDataLSA->Buffer ) return;
|
|
GlobalFree(pDataLSA);
|
|
}
|
|
|
|
#endif //_CHICAGO_
|