Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1655 lines
37 KiB

/*++
Copyright (c) 1999-2000 Microsoft Corporation
Module Name:
HelpTab.cpp
Abstract:
Implementation of __HelpEntry structure and CHelpSessionTable.
Author:
HueiWang 06/29/2000
--*/
#include "stdafx.h"
#include <time.h>
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <tchar.h>
#include "helptab.h"
#include "policy.h"
#include "remotedesktoputils.h"
#include "helper.h"
//
//
// __HelpEntry strucutre implementation
//
//
HRESULT
__HelpEntry::LoadEntryValues(
IN HKEY hKey
)
/*++
Routine Description:
Load help session entry from registry key.
Parameters:
hKey : Handle to registry key containing help entry values.
Returns:
S_OK or error code.
--*/
{
DWORD dwStatus;
MYASSERT( NULL != hKey );
if( NULL != hKey )
{
dwStatus = m_EntryStatus.DBLoadValue( hKey );
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
if( REGVALUE_HELPSESSION_ENTRY_DELETED == m_EntryStatus )
{
// entry already been deleted, no reason to continue loading
dwStatus = ERROR_FILE_NOT_FOUND;
goto CLEANUPANDEXIT;
}
dwStatus = m_SessionId.DBLoadValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
if( m_SessionId->Length() == 0 )
{
// Help Session ID must exist, no default value.
dwStatus = ERROR_INVALID_DATA;
goto CLEANUPANDEXIT;
}
dwStatus = m_EnableResolver.DBLoadValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_SessResolverBlob.DBLoadValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_UserSID.DBLoadValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_CreationTime.DBLoadValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_ExpirationTime.DBLoadValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_SessionRdsSetting.DBLoadValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_EntryStatus.DBLoadValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_CreationTime.DBLoadValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_IpAddress.DBLoadValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_ICSPort.DBLoadValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_SessionCreateBlob.DBLoadValue(hKey);
}
else
{
dwStatus = E_UNEXPECTED;
}
CLEANUPANDEXIT:
return HRESULT_FROM_WIN32(dwStatus);
}
HRESULT
__HelpEntry::UpdateEntryValues(
IN HKEY hKey
)
/*++
Routine Description:
Update/store help entry value to registry.
Parameters:
hKey : Handle to registry to save help entry value.
Returns:
S_OK or error code.
--*/
{
DWORD dwStatus;
MYASSERT( NULL != hKey );
if( NULL == hKey )
{
dwStatus = E_UNEXPECTED;
goto CLEANUPANDEXIT;
}
if( REGVALUE_HELPSESSION_ENTRY_DELETED == m_EntryStatus )
{
// entry already deleted, error out
dwStatus = ERROR_FILE_NOT_FOUND;
goto CLEANUPANDEXIT;
}
// New entry value, entry status in registry is set
// to delete so when we failed to completely writting
// all value to registry, we can still assume it is
// deleted.
if( REGVALUE_HELPSESSION_ENTRY_NEW != m_EntryStatus )
{
// Mark entry dirty.
m_EntryStatus = REGVALUE_HELPSESSION_ENTRY_DIRTY;
dwStatus = m_EntryStatus.DBUpdateValue( hKey );
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
}
dwStatus = m_SessionId.DBUpdateValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_EnableResolver.DBUpdateValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_SessResolverBlob.DBUpdateValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_UserSID.DBUpdateValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_CreationTime.DBUpdateValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_ExpirationTime.DBUpdateValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_SessionRdsSetting.DBUpdateValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_IpAddress.DBUpdateValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_ICSPort.DBUpdateValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
dwStatus = m_SessionCreateBlob.DBUpdateValue(hKey);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
// Mark entry normal
m_EntryStatus = REGVALUE_HELPSESSION_ENTRY_NORMAL;
dwStatus = m_EntryStatus.DBUpdateValue( hKey );
CLEANUPANDEXIT:
return HRESULT_FROM_WIN32(dwStatus);
}
HRESULT
__HelpEntry::BackupEntry()
/*++
Routine Description:
Backup help entry, backup is stored under
<Help Entry Registry>\\Backup registry key.
Parameters:
None.
Returns:
S_OK or error code.
--*/
{
HKEY hKey = NULL;
DWORD dwStatus;
MYASSERT( NULL != m_hEntryKey );
if( NULL != m_hEntryKey )
{
//
// Delete current backup
(void)DeleteEntryBackup();
//
// Create a backup registry key
dwStatus = RegCreateKeyEx(
m_hEntryKey,
REGKEY_HELPENTRYBACKUP,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL
);
if( ERROR_SUCCESS != dwStatus )
{
MYASSERT(FALSE);
}
else
{
dwStatus = UpdateEntryValues( hKey );
}
}
else
{
dwStatus = E_UNEXPECTED;
}
if( NULL != hKey )
{
RegCloseKey( hKey );
}
return HRESULT_FROM_WIN32(dwStatus);
}
HRESULT
__HelpEntry::RestoreEntryFromBackup()
/*++
Routine Description:
Restore help entry from backup, backup is stored under
<Help Entry Registry>\\Backup registry key.
Parameters:
None.
Returns:
S_OK or error code.
--*/
{
DWORD dwStatus;
HKEY hBackupKey = NULL;
MYASSERT( NULL != m_hEntryKey );
if( NULL != m_hEntryKey )
{
//
// check if backup registry exists.
dwStatus = RegOpenKeyEx(
m_hEntryKey,
REGKEY_HELPENTRYBACKUP,
0,
KEY_ALL_ACCESS,
&hBackupKey
);
if( ERROR_SUCCESS == dwStatus )
{
HELPENTRY backup( m_pHelpSessionTable, hBackupKey, ENTRY_VALID_PERIOD );
// load backup values
dwStatus = backup.LoadEntryValues( hBackupKey );
if( ERROR_SUCCESS == dwStatus )
{
if( (DWORD)backup.m_EntryStatus == REGVALUE_HELPSESSION_ENTRY_NORMAL )
{
*this = backup;
}
else
{
(void)DeleteEntryBackup();
dwStatus = ERROR_FILE_NOT_FOUND;
}
}
// HELPSESSION destructor will close registry key
}
if( ERROR_SUCCESS == dwStatus )
{
//
// update all values.
dwStatus = UpdateEntryValues( m_hEntryKey );
if( ERROR_SUCCESS == dwStatus )
{
//
// Already restore entry, delete backup copy
(void)DeleteEntryBackup();
}
}
}
else
{
dwStatus = E_UNEXPECTED;
}
return HRESULT_FROM_WIN32( dwStatus );
}
HRESULT
__HelpEntry::DeleteEntryBackup()
/*++
Routine Description:
Delete help entry backup from registry.
Parameters:
None.
Returns:
always S_OK
--*/
{
DWORD dwStatus;
dwStatus = RegDelKey(
m_hEntryKey,
REGKEY_HELPENTRYBACKUP
);
return HRESULT_FROM_WIN32(dwStatus);
}
BOOL
__HelpEntry::IsEntryExpired()
{
FILETIME ft;
ULARGE_INTEGER ul1, ul2;
GetSystemTimeAsFileTime(&ft);
ul1.LowPart = ft.dwLowDateTime;
ul1.HighPart = ft.dwHighDateTime;
ft = (FILETIME)m_ExpirationTime;
ul2.LowPart = ft.dwLowDateTime;
ul2.HighPart = ft.dwHighDateTime;
#if DBG
if( ul1.QuadPart >= ul2.QuadPart )
{
DebugPrintf(
_TEXT("Help Entry %s has expired ...\n"),
(LPCTSTR)(CComBSTR)m_SessionId
);
}
#endif
return (ul1.QuadPart >= ul2.QuadPart);
}
////////////////////////////////////////////////////////////////////////////////
//
// CHelpSessionTable implementation
//
CHelpSessionTable::CHelpSessionTable() :
m_hHelpSessionTableKey(NULL), m_NumHelp(0)
{
HKEY hKey = NULL;
DWORD dwStatus;
DWORD dwSize;
DWORD dwType;
//
// Load entry valid period setting from registry
//
dwStatus = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
RDS_MACHINEPOLICY_SUBTREE,
0,
KEY_READ,
&hKey
);
if( ERROR_SUCCESS == dwStatus )
{
dwSize = sizeof(DWORD);
dwStatus = RegQueryValueEx(
hKey,
RDS_HELPENTRY_VALID_PERIOD,
NULL,
&dwType,
(PBYTE) &m_dwEntryValidPeriod,
&dwSize
);
if( REG_DWORD != dwType )
{
dwStatus = ERROR_FILE_NOT_FOUND;
}
RegCloseKey(hKey);
}
if(ERROR_SUCCESS != dwStatus )
{
// pick default value
m_dwEntryValidPeriod = ENTRY_VALID_PERIOD;
}
}
HRESULT
CHelpSessionTable::RestoreHelpSessionTable(
IN HKEY hKey,
IN LPTSTR pszKeyName,
IN HANDLE userData
)
/*++
Routine Description:
Restore help session table. This routine is callback from RegEnumSubKeys().
Parameters:
hKey : Handle to registry.
pszKeyName : registry sub-key name containing one help session entry
userData : User defined data.
Returns:
S_OK or error code.
--*/
{
HRESULT hRes;
if( NULL == userData )
{
hRes = E_UNEXPECTED;
MYASSERT(FALSE);
}
else
{
CHelpSessionTable* pTable = (CHelpSessionTable *) userData;
hRes = pTable->RestoreHelpSessionEntry( hKey, pszKeyName );
if( SUCCEEDED(hRes) )
{
pTable->m_NumHelp++;
}
hRes = S_OK;
}
return hRes;
}
BOOL
CHelpSessionTable::IsEntryExpired(
IN PHELPENTRY pEntry
)
/*++
Routine Description:
Determine if a help entry has expired.
Paramters:
pEntry : Pointer to help entry.
Returns:
TRUE if entry has expired, FALSE otherwise.
--*/
{
MYASSERT( NULL != pEntry );
return (NULL != pEntry) ? pEntry->IsEntryExpired() : TRUE;
}
HRESULT
CHelpSessionTable::RestoreHelpSessionEntry(
IN HKEY hKey,
IN LPTSTR pszKeyName
)
/*++
Routine Description:
Restore a single help session entry.
Parameters:
hKey : Handle to help session table.
pszKeyName : Registry sub-key name containing help entry.
Returns:
S_OK or error code.
--*/
{
HKEY hEntryKey = NULL;
DWORD dwStatus;
DWORD dwDuplicate = REG_CREATED_NEW_KEY;
LONG entryStatus;
BOOL bDeleteEntry = FALSE;
//
// Open the registry key for session entry
dwStatus = RegOpenKeyEx(
hKey,
pszKeyName,
0,
KEY_ALL_ACCESS,
&hEntryKey
);
if( ERROR_SUCCESS == dwStatus )
{
HELPENTRY helpEntry( *this, hEntryKey, m_dwEntryValidPeriod );
// load help entry
dwStatus = helpEntry.Refresh();
if( dwStatus != ERROR_SUCCESS || helpEntry.m_SessionId->Length() == 0 ||
REGVALUE_HELPSESSION_ENTRY_DELETEONSTARTUP == helpEntry.m_EntryStatus )
{
// Session ID must not be NULL.
bDeleteEntry = TRUE;
}
else
{
if( REGVALUE_HELPSESSION_ENTRY_DELETED != helpEntry.m_EntryStatus )
{
if( TRUE != IsEntryExpired( &helpEntry ) )
{
if( REGVALUE_HELPSESSION_ENTRY_DIRTY == helpEntry.m_EntryStatus )
{
// Entry is partially updated, try to restore from backup,
// is failed restoring, treat as bad entry.
if( FAILED(helpEntry.RestoreEntryFromBackup()) )
{
bDeleteEntry = TRUE;
}
}
}
else
{
LPTSTR eventString[2];
BSTR pszNoviceDomain = NULL;
BSTR pszNoviceName = NULL;
HRESULT hr;
//
// Log the event indicate that ticket was deleted, non-critical
// since we can still continue to run.
//
hr = ConvertSidToAccountName( (CComBSTR)helpEntry.m_UserSID, &pszNoviceDomain, &pszNoviceName );
if( SUCCEEDED(hr) )
{
eventString[0] = pszNoviceDomain;
eventString[1] = pszNoviceName;
LogRemoteAssistanceEventString(
EVENTLOG_INFORMATION_TYPE,
SESSMGR_I_REMOTEASSISTANCE_DELETEDTICKET,
2,
eventString
);
DebugPrintf(
_TEXT("Help Entry has expired %s\n"),
(CComBSTR)helpEntry.m_SessionId
);
}
if( pszNoviceDomain )
{
SysFreeString( pszNoviceDomain );
}
if( pszNoviceName )
{
SysFreeString( pszNoviceName );
}
}
}
else
{
bDeleteEntry = TRUE;
}
}
}
if( TRUE == bDeleteEntry )
{
dwStatus = RegDelKey( hKey, pszKeyName );
//
// Ignore error
//
DebugPrintf(
_TEXT("RegDelKey on entry %s returns %d\n"),
pszKeyName,
dwStatus
);
dwStatus = ERROR_FILE_NOT_FOUND;
}
return HRESULT_FROM_WIN32( dwStatus );
}
HRESULT
CHelpSessionTable::LoadHelpEntry(
IN HKEY hKey,
IN LPTSTR pszKeyName,
OUT PHELPENTRY* ppHelpSession
)
/*++
Routine description:
Load a help entry from registry.
Parameters:
hKey : registry handle to help session table.
pszKeyName : registry sub-key name (Help session ID).
ppHelpSession : Pointer to PHELPENTRY to receive loaded help
entry.
Returns:
S_OK or error code.
--*/
{
PHELPENTRY pSess;
HRESULT hRes;
HKEY hEntryKey = NULL;
DWORD dwStatus;
MYASSERT( NULL != hKey );
if( NULL != hKey )
{
// open the registry containing help entry
dwStatus = RegOpenKeyEx(
hKey,
pszKeyName,
0,
KEY_ALL_ACCESS,
&hEntryKey
);
if( ERROR_SUCCESS == dwStatus )
{
pSess = new HELPENTRY( *this, hEntryKey, m_dwEntryValidPeriod );
if( NULL == pSess )
{
hRes = E_OUTOFMEMORY;
}
else
{
// load help entry, Refresh() will failed if
// session ID is NULL or emptry string
hRes = pSess->Refresh();
if( SUCCEEDED(hRes) )
{
if( (DWORD)pSess->m_EntryStatus == REGVALUE_HELPSESSION_ENTRY_NORMAL )
{
*ppHelpSession = pSess;
}
else
{
dwStatus = ERROR_FILE_NOT_FOUND;
}
}
if( FAILED(hRes) )
{
pSess->Release();
}
}
}
else
{
hRes = HRESULT_FROM_WIN32( dwStatus );
}
}
else
{
hRes = E_UNEXPECTED;
}
return hRes;
}
HRESULT
CHelpSessionTable::OpenSessionTable(
IN LPCTSTR pszFileName // reserverd.
)
/*++
Routine Description:
Open help session table, routine enumerate all help entry (registry sub-key),
and restore/delete help entry if necessary.
Parameters:
pszFileName : reserved parameter, must be NULL.
Returns:
S_OK or error code.
--*/
{
DWORD dwStatus;
HRESULT hr;
CCriticalSectionLocker l(m_TableLock);
//
// Go thru all sub-key containing help entry and restore or delete
// help entry if necessary.
dwStatus = RegEnumSubKeys(
HKEY_LOCAL_MACHINE,
REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
RestoreHelpSessionTable,
(HANDLE)this
);
if( ERROR_SUCCESS != dwStatus )
{
if( NULL != m_hHelpSessionTableKey )
{
// Make sure registry key is not opened.
RegCloseKey(m_hHelpSessionTableKey);
m_hHelpSessionTableKey = NULL;
}
// If table is bad, delete and re-create again
dwStatus = RegDelKey(
HKEY_LOCAL_MACHINE,
REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE
);
if( ERROR_SUCCESS != dwStatus && ERROR_FILE_NOT_FOUND != dwStatus )
{
// Critical error
MYASSERT(FALSE);
goto CLEANUPANDEXIT;
}
hr = CreatePendingHelpTable();
dwStatus = HRESULT_CODE(hr);
if( ERROR_SUCCESS != dwStatus )
{
// we need registry key be ACLed.
MYASSERT(FALSE);
goto CLEANUPANDEXIT;
}
}
dwStatus = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
0,
KEY_ALL_ACCESS,
&m_hHelpSessionTableKey
);
if( ERROR_SUCCESS != dwStatus )
{
MYASSERT(FALSE);
goto CLEANUPANDEXIT;
}
else
{
m_bstrFileName = pszFileName;
}
CLEANUPANDEXIT:
return HRESULT_FROM_WIN32(dwStatus);
}
HRESULT
CHelpSessionTable::CloseSessionTable()
/*++
Routine Description:
Close help session table.
Parameters:
None.
Returns:
S_OK or error code.
--*/
{
// no help is opened.
CCriticalSectionLocker l(m_TableLock);
//
// release all cached help entries
for( HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.begin();
it != m_HelpEntryCache.end();
it++
)
{
if( ((*it).second)->m_RefCount > 1 )
{
MYASSERT(FALSE);
}
((*it).second)->Release();
}
m_HelpEntryCache.erase_all();
MYASSERT( m_HelpEntryCache.size() == 0 );
if( NULL != m_hHelpSessionTableKey )
{
RegCloseKey( m_hHelpSessionTableKey );
m_hHelpSessionTableKey = NULL;
}
return S_OK;
}
HRESULT
CHelpSessionTable::DeleteSessionTable()
/*++
Routine description:
Delete entire help session table.
Parameters:
None.
Returns:
S_OK or error code.
--*/
{
HRESULT hRes;
DWORD dwStatus;
CCriticalSectionLocker l(m_TableLock);
hRes = CloseSessionTable();
if( SUCCEEDED(hRes) )
{
// Recursively delete registry key and its sub-keys.
dwStatus = RegDelKey(
HKEY_LOCAL_MACHINE,
REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE
);
if( ERROR_SUCCESS == dwStatus )
{
hRes = OpenSessionTable( m_bstrFileName );
}
else
{
hRes = HRESULT_FROM_WIN32( dwStatus );
}
}
return hRes;
}
HRESULT
CHelpSessionTable::MemEntryToStorageEntry(
IN PHELPENTRY pEntry
)
/*++
Routine Description:
Conver an in-memory help entry to persist help entry.
Parameters:
pEntry : Pointer to HELPENTRY to be converted.
Returns:
S_OK or error code.
--*/
{
HRESULT hRes;
CCriticalSectionLocker l(m_TableLock);
if( NULL != pEntry )
{
//
// Check to see if this is in-memory entry
//
if( FALSE == pEntry->IsInMemoryHelpEntry() )
{
hRes = E_INVALIDARG;
}
else
{
DWORD dwStatus;
HKEY hKey;
//
// Create a help entry here
//
dwStatus = RegCreateKeyEx(
m_hHelpSessionTableKey,
(LPCTSTR)(CComBSTR)pEntry->m_SessionId,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL
);
if( ERROR_SUCCESS == dwStatus )
{
hRes = pEntry->UpdateEntryValues(hKey);
if( SUCCEEDED(hRes) )
{
pEntry->ConvertHelpEntry( hKey );
try {
m_HelpEntryCache[(CComBSTR)pEntry->m_SessionId] = pEntry;
}
catch(CMAPException e) {
hRes = HRESULT_FROM_WIN32( e.m_ErrorCode );
}
catch(...) {
hRes = E_UNEXPECTED;
throw;
}
}
}
else
{
hRes = HRESULT_FROM_WIN32( dwStatus );
MYASSERT(FALSE);
}
}
}
else
{
MYASSERT(FALSE);
hRes = E_UNEXPECTED;
}
return hRes;
}
HRESULT
CHelpSessionTable::CreateInMemoryHelpEntry(
IN const CComBSTR& bstrHelpSession,
OUT PHELPENTRY* ppHelpEntry
)
/*++
Routine Description:
Create an in-memory help entry, this help entry is not
persisted into registry until MemEntryToStorageEntry() is called.
Paramters:
bstrHelpSession : Help Session ID.
ppHelpEntry : Newly created HELPENTRY.
Returns:
S_OK or error code.
--*/
{
HRESULT hRes = S_OK;
CCriticalSectionLocker l(m_TableLock);
MYASSERT( NULL != m_hHelpSessionTableKey );
if( NULL != m_hHelpSessionTableKey )
{
DWORD dwStatus;
HKEY hKey;
DWORD dwDeposition;
DWORD dwEntryStatus;
// Create a key here so we can tell if this is a duplicate
dwStatus = RegCreateKeyEx(
m_hHelpSessionTableKey,
bstrHelpSession,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwDeposition
);
if( ERROR_SUCCESS == dwStatus )
{
if( REG_OPENED_EXISTING_KEY == dwDeposition )
{
hRes = HRESULT_FROM_WIN32( ERROR_FILE_EXISTS );
}
else
{
//
// Mark entry status to be deleted so if we abnormally
// terminated, this entry will be deleted on startup
//
dwEntryStatus = REGVALUE_HELPSESSION_ENTRY_DELETED;
dwStatus = RegSetValueEx(
hKey,
COLUMNNAME_KEYSTATUS,
0,
REG_DWORD,
(LPBYTE)&dwEntryStatus,
sizeof(dwEntryStatus)
);
if( ERROR_SUCCESS == dwStatus )
{
PHELPENTRY pSess;
// Create a in-memory entry
pSess = new HELPENTRY( *this, NULL, m_dwEntryValidPeriod );
if( NULL != pSess )
{
pSess->m_SessionId = bstrHelpSession;
*ppHelpEntry = pSess;
//
// In memory help entry should also be counted
// since we still write out help session ID to
// registry which on delete, will do m_NumHelp--.
//
m_NumHelp++;
}
else
{
hRes = E_OUTOFMEMORY;
}
}
}
RegCloseKey(hKey);
}
if(ERROR_SUCCESS != dwStatus )
{
hRes = HRESULT_FROM_WIN32( dwStatus );
}
}
else
{
hRes = E_UNEXPECTED;
}
return hRes;
}
HRESULT
CHelpSessionTable::OpenHelpEntry(
IN const CComBSTR& bstrHelpSession,
OUT PHELPENTRY* ppHelpEntry
)
/*++
Routine Description:
Open an existing help entry.
Parameters:
bstrHelpSession : ID of help entry to be opened.
ppHelpEntry : Pointer to PHELPENTY to receive loaded
help entry.
Returns:
S_OK or error code.
--*/
{
CCriticalSectionLocker l(m_TableLock);
HRESULT hRes = S_OK;
DebugPrintf(
_TEXT("OpenHelpEntry() %s\n"),
bstrHelpSession
);
MYASSERT( bstrHelpSession.Length() > 0 );
// check if entry already exists in cache
HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.find( bstrHelpSession );
if( it != m_HelpEntryCache.end() )
{
*ppHelpEntry = (*it).second;
//
// More reference to same object.
//
(*ppHelpEntry)->AddRef();
// timing, it is possible to have many-to-one mapping,
// helpmgr delete from its internal cache but has not
// release the help entry.
}
else
{
hRes = LoadHelpEntry(
m_hHelpSessionTableKey,
(LPTSTR)bstrHelpSession,
ppHelpEntry
);
DebugPrintf(
_TEXT("LoadHelpEntry() on %s returns 0x%08x\n"),
bstrHelpSession,
hRes
);
if( SUCCEEDED(hRes) )
{
try {
m_HelpEntryCache[ bstrHelpSession ] = *ppHelpEntry;
}
catch( CMAPException e ) {
hRes = HRESULT_FROM_WIN32( e.m_ErrorCode );
}
catch( ... ) {
hRes = E_UNEXPECTED;
throw;
}
}
}
return hRes;
}
HRESULT
CHelpSessionTable::DeleteHelpEntry(
IN const CComBSTR& bstrHelpSession
)
/*++
Routine Description:
Delete a help entry.
Parameters:
bstrHelpSession : ID of help session entry to be deleted.
Returns:
S_OK or error code.
--*/
{
HRESULT hRes = S_OK;
CCriticalSectionLocker l(m_TableLock);
DebugPrintf(
_TEXT("DeleteHelpEntry() %s\n"),
bstrHelpSession
);
// check if entry already exists in cache
HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.find( bstrHelpSession );
if( it != m_HelpEntryCache.end() )
{
// mark entry deleted in registry
hRes = ((*it).second)->DeleteEntry();
MYASSERT( SUCCEEDED(hRes) );
// release this entry ref. count.
((*it).second)->Release();
// remove from our cache
m_HelpEntryCache.erase( it );
}
else
{
//
// unsolicited help will not be in our cache.
//
hRes = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
{
DWORD dwStatus;
dwStatus = RegDelKey( m_hHelpSessionTableKey, bstrHelpSession );
if( ERROR_SUCCESS == dwStatus )
{
m_NumHelp--;
}
}
return hRes;
}
CHelpSessionTable::~CHelpSessionTable()
{
CloseSessionTable();
return;
}
HRESULT
CHelpSessionTable::EnumHelpEntry(
IN EnumHelpEntryCallback pFunc,
IN HANDLE userData
)
/*++
Routine Description:
Enumerate all help entries.
Parameters:
pFunc : Call back function.
userData : User defined data.
Returns:
S_OK or error code.
--*/
{
EnumHelpEntryParm parm;
HRESULT hRes = S_OK;
DWORD dwStatus;
CCriticalSectionLocker l(m_TableLock);
if( NULL == pFunc )
{
hRes = E_POINTER;
}
else
{
try {
parm.userData = userData;
parm.pCallback = pFunc;
parm.pTable = this;
dwStatus = RegEnumSubKeys(
HKEY_LOCAL_MACHINE,
REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
EnumOpenHelpEntry,
(HANDLE) &parm
);
if( ERROR_SUCCESS != dwStatus )
{
hRes = HRESULT_FROM_WIN32( dwStatus );
}
}
catch(...) {
hRes = E_UNEXPECTED;
}
}
return hRes;
}
HRESULT
CHelpSessionTable::ReleaseHelpEntry(
IN CComBSTR& bstrHelpSessionId
)
/*++
Routine Description:
Release/unload a help entry from cached, this help
entry is not deleted.
Paramters:
bstrHelpSessionId : ID of help entry to be unloaded from memory.
Returns:
S_OK or error code
--*/
{
CCriticalSectionLocker l(m_TableLock);
HRESULT hRes = S_OK;
HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.find( bstrHelpSessionId );
if( it != m_HelpEntryCache.end() )
{
(*it).second->Release();
m_HelpEntryCache.erase( it );
}
else
{
hRes = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
}
return hRes;
}
HRESULT
CHelpSessionTable::EnumOpenHelpEntry(
IN HKEY hKey,
IN LPTSTR pszKeyName,
IN HANDLE userData
)
/*++
Routine Description:
Call back funtion for EnumHelpEntry() and RegEnumSubKeys().
Parameters:
hKey : Registry key handle to help session table.
pszKeyName : help entry id (registry sub-key name).
userData : User defined data.
Returns:
S_OK or error code.
--*/
{
HRESULT hRes = S_OK;
PEnumHelpEntryParm pParm = (PEnumHelpEntryParm)userData;
if( NULL == pParm )
{
hRes = E_UNEXPECTED;
}
else
{
hRes = pParm->pCallback( CComBSTR(pszKeyName), pParm->userData );
}
return hRes;
}
HRESULT
CHelpSessionTable::CreatePendingHelpTable()
/*++
Routine to create pending help table registry key, if registry key already exist,
set the DACL to system context only.
--*/
{
PACL pAcl=NULL;
DWORD dwStatus = ERROR_SUCCESS;
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
DWORD cbAcl = 0;
PSID pSidSystem = NULL;
HKEY hKey = NULL;
pSecurityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, sizeof(SECURITY_DESCRIPTOR));
if( NULL == pSecurityDescriptor )
{
dwStatus = GetLastError();
goto CLEANUPANDEXIT;
}
//
// Initialize the security descriptor.
//
if (!InitializeSecurityDescriptor(
pSecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION
))
{
dwStatus = GetLastError();
goto CLEANUPANDEXIT;
}
dwStatus = CreateSystemSid( &pSidSystem );
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
cbAcl = GetLengthSid( pSidSystem ) + sizeof(ACL) + (2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
pAcl = (PACL) LocalAlloc( LPTR, cbAcl );
if( NULL == pAcl )
{
dwStatus = GetLastError();
goto CLEANUPANDEXIT;
}
//
// Initialize the ACL.
//
if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION))
{
dwStatus = GetLastError();
goto CLEANUPANDEXIT;
}
//
if (!AddAccessAllowedAce(pAcl,
ACL_REVISION,
GENERIC_READ | GENERIC_WRITE | GENERIC_ALL,
pSidSystem
))
{
dwStatus = GetLastError();
goto CLEANUPANDEXIT;
}
if (!SetSecurityDescriptorDacl(pSecurityDescriptor,
TRUE, pAcl, FALSE))
{
dwStatus = GetLastError();
goto CLEANUPANDEXIT;
}
//
// Create/open the pending table registry key
//
dwStatus = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL
);
if( ERROR_SUCCESS != dwStatus )
{
goto CLEANUPANDEXIT;
}
//
// Set table (registry) DACL
//
dwStatus = RegSetKeySecurity(
hKey,
DACL_SECURITY_INFORMATION,
pSecurityDescriptor
);
CLEANUPANDEXIT:
if( NULL != hKey )
{
RegCloseKey(hKey);
}
if( pAcl != NULL )
{
LocalFree(pAcl);
}
if( pSecurityDescriptor != NULL )
{
LocalFree( pSecurityDescriptor );
}
if( pSidSystem != NULL )
{
FreeSid( pSidSystem );
}
return HRESULT_FROM_WIN32(dwStatus);
}