2025-04-27 07:49:33 -04:00

333 lines
9.5 KiB
C++

/********************************************************************
Copyright (c) 1999 Microsoft Corporation
Module Name:
SecretsStore.cpp
Abstract:
File for Implementation of CPCHSecretsStore class, used to store secrets.
Revision History:
Davide Massarenti created 03/27/2000
********************************************************************/
#include "stdafx.h"
/////////////////////////////////////////////////////////////////////////////
static const WCHAR c_SecretsStore[] = HC_HELPSVC_STORE_USERS;
static const WCHAR c_SecretsKey [] = L"HelpService_PrivateData";
/////////////////////////////////////////////////////////////////////////////
CFG_BEGIN_FIELDS_MAP(CPCHSecretsStore::Inner_Pair)
CFG_ATTRIBUTE( L"Key", wstring, m_strKey ),
CFG_VALUE ( wstring, m_strValue),
CFG_END_FIELDS_MAP()
CFG_BEGIN_CHILD_MAP(CPCHSecretsStore::Inner_Pair)
CFG_END_CHILD_MAP()
DEFINE_CFG_OBJECT(CPCHSecretsStore::Inner_Pair,L"Pair")
DEFINE_CONFIG_METHODS__NOCHILD(CPCHSecretsStore::Inner_Pair)
bool CPCHSecretsStore::Inner_Pair::operator==( /*[in]*/ const MPC::wstring& strKey ) const
{
MPC::NocaseCompare cmp;
return cmp( m_strKey, strKey );
}
////////////////////
CFG_BEGIN_FIELDS_MAP(CPCHSecretsStore)
CFG_END_FIELDS_MAP()
CFG_BEGIN_CHILD_MAP(CPCHSecretsStore)
CFG_CHILD(CPCHSecretsStore::Inner_Pair)
CFG_END_CHILD_MAP()
DEFINE_CFG_OBJECT(CPCHSecretsStore,L"SecretsStore")
DEFINE_CONFIG_METHODS_CREATEINSTANCE_SECTION(CPCHSecretsStore,tag,defSubType)
if(tag == _cfg_table_tags[0])
{
defSubType = &(*(m_lst.insert( m_lst.end() )));
return S_OK;
}
DEFINE_CONFIG_METHODS_SAVENODE_SECTION(CPCHSecretsStore,xdn)
hr = MPC::Config::SaveList( m_lst, xdn );
DEFINE_CONFIG_METHODS_END(CPCHSecretsStore)
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
CPCHSecretsStore::CPCHSecretsStore()
{
m_fLoaded = false; // bool m_fLoaded;
m_fDirty = false; // bool m_fDirty;
m_strStore = c_SecretsStore; MPC::SubstituteEnvVariables( m_strStore ); // MPC::wstring m_strStore;
// List m_lst;
// CComBSTR m_bstrSecret;
}
////////////////////
CPCHSecretsStore* CPCHSecretsStore::s_GLOBAL( NULL );
HRESULT CPCHSecretsStore::InitializeSystem()
{
if(s_GLOBAL == NULL)
{
s_GLOBAL = new CPCHSecretsStore;
}
return s_GLOBAL ? S_OK : E_OUTOFMEMORY;
}
void CPCHSecretsStore::FinalizeSystem()
{
if(s_GLOBAL)
{
delete s_GLOBAL; s_GLOBAL = NULL;
}
}
////////////////////////////////////////////////////////////////////////////////
HRESULT CPCHSecretsStore::GetSecret()
{
__HCP_FUNC_ENTRY( "CPCHSecretsStore::GetSecret" );
HRESULT hr;
NTSTATUS ntRes;
LSA_OBJECT_ATTRIBUTES objectAttributes; ::ZeroMemory( &objectAttributes, sizeof(objectAttributes) );
LSA_UNICODE_STRING lsaKeyString;
LSA_UNICODE_STRING lsaPrivateDataWrite;
PLSA_UNICODE_STRING lsaPrivateDataRead = NULL;
HANDLE policyHandle = NULL;
if(m_bstrSecret.Length() == 0)
{
GUID guidNEW;
__MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateGuid( &guidNEW )); // Initialized to a new, random value.
ntRes = ::LsaOpenPolicy( NULL, &objectAttributes, POLICY_CREATE_SECRET | POLICY_GET_PRIVATE_INFORMATION, &policyHandle );
if(ntRes != STATUS_SUCCESS)
{
__MPC_SET_WIN32_ERROR_AND_EXIT(hr, ::LsaNtStatusToWinError( ntRes ));
}
CPCHSecurityDescriptorDirect::InitLsaString( lsaKeyString, c_SecretsKey );
ntRes = ::LsaRetrievePrivateData( policyHandle, &lsaKeyString, &lsaPrivateDataRead );
if(ntRes == STATUS_SUCCESS && lsaPrivateDataRead)
{
m_bstrSecret.Attach( ::SysAllocStringLen( lsaPrivateDataRead->Buffer, lsaPrivateDataRead->Length / sizeof(WCHAR) ) );
}
else if(ntRes == STATUS_OBJECT_NAME_NOT_FOUND)
{
CComBSTR bstrSecret( guidNEW );
CPCHSecurityDescriptorDirect::InitLsaString( lsaPrivateDataWrite, bstrSecret );
ntRes = ::LsaStorePrivateData( policyHandle, &lsaKeyString, &lsaPrivateDataWrite );
if(ntRes != STATUS_SUCCESS)
{
__MPC_SET_WIN32_ERROR_AND_EXIT(hr, ::LsaNtStatusToWinError( ntRes ));
}
m_bstrSecret = bstrSecret;
}
else
{
__MPC_SET_WIN32_ERROR_AND_EXIT(hr, ::LsaNtStatusToWinError( ntRes ));
}
}
hr = S_OK;
__MPC_FUNC_CLEANUP;
if(lsaPrivateDataRead) ::LsaFreeMemory( lsaPrivateDataRead );
if(policyHandle ) ::LsaClose ( policyHandle );
__MPC_FUNC_EXIT(hr);
}
HRESULT CPCHSecretsStore::SyncFile()
{
__HCP_FUNC_ENTRY( "CPCHSecretsStore::SyncFile" );
HRESULT hr;
CComPtr<MPC::EncryptedStream> streamEncrypted;
CComPtr<MPC::FileStream> streamPlain;
if(m_fLoaded == false)
{
__MPC_EXIT_IF_METHOD_FAILS(hr, GetSecret());
//
// Load the file, decrypting using the GUID stored in the secret data.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &streamEncrypted ));
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &streamPlain ));
if(SUCCEEDED(hr = streamPlain->InitForRead( m_strStore.c_str() )))
{
__MPC_EXIT_IF_METHOD_FAILS(hr, streamEncrypted->Init( streamPlain, m_bstrSecret ));
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::Config::LoadStream( this, streamEncrypted ));
}
streamEncrypted.Release();
streamPlain .Release();
m_fLoaded = true;
m_fDirty = false;
}
if(m_fDirty == true)
{
MPC::wstring strStoreNew( m_strStore ); strStoreNew += L".new";
CComPtr<IStream> stream;
__MPC_EXIT_IF_METHOD_FAILS(hr, GetSecret());
//
// Save to a temp file, encrypting using the GUID stored in the secret data.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &streamEncrypted ));
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &streamPlain ));
__MPC_EXIT_IF_METHOD_FAILS(hr, streamPlain->InitForWrite( strStoreNew.c_str() ));
__MPC_EXIT_IF_METHOD_FAILS(hr, streamEncrypted->Init( streamPlain, m_bstrSecret ));
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::Config::SaveStream( this, &stream ));
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::BaseStream::TransferData( stream, streamEncrypted ));
streamEncrypted.Release();
streamPlain .Release();
//
// Move the temp file to the real one.
//
::SetFileAttributesW( m_strStore.c_str(), FILE_ATTRIBUTE_NORMAL );
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::MoveFileExW( strStoreNew.c_str(), m_strStore.c_str(), MOVEFILE_REPLACE_EXISTING ));
m_fDirty = false;
}
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr);
}
/////////////////////////////////////////////////////////////////////////////
HRESULT CPCHSecretsStore::Write( /*[in]*/ const MPC::wstring& strKey ,
/*[in]*/ const MPC::wstring& strValue )
{
__HCP_FUNC_ENTRY( "CPCHSecretsStore::Write" );
HRESULT hr;
MPC::SmartLock<_ThreadModel> lock( this );
Iter it;
__MPC_EXIT_IF_METHOD_FAILS(hr, SyncFile());
it = std::find( m_lst.begin(), m_lst.end(), strKey );
if(it == m_lst.end())
{
it = m_lst.insert( m_lst.end() );
it->m_strKey = strKey;
}
it->m_strValue = strValue; m_fDirty = true;
__MPC_EXIT_IF_METHOD_FAILS(hr, SyncFile());
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT CPCHSecretsStore::Read( /*[in ]*/ const MPC::wstring& strKey ,
/*[out]*/ MPC::wstring& strValue )
{
__HCP_FUNC_ENTRY( "CPCHSecretsStore::Read" );
HRESULT hr;
MPC::SmartLock<_ThreadModel> lock( this );
IterConst it;
__MPC_EXIT_IF_METHOD_FAILS(hr, SyncFile());
it = std::find( m_lst.begin(), m_lst.end(), strKey );
if(it == m_lst.end())
{
__MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND);
}
strValue = it->m_strValue;
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT CPCHSecretsStore::Remove( /*[in]*/ const MPC::wstring& strKey )
{
__HCP_FUNC_ENTRY( "CPCHSecretsStore::Remove" );
HRESULT hr;
MPC::SmartLock<_ThreadModel> lock( this );
Iter it;
__MPC_EXIT_IF_METHOD_FAILS(hr, SyncFile());
it = std::find( m_lst.begin(), m_lst.end(), strKey );
if(it != m_lst.end())
{
m_lst.erase( it ); m_fDirty = true;
__MPC_EXIT_IF_METHOD_FAILS(hr, SyncFile());
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}