|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996.
//
// registry.cxx
//
// Registry related routines
//
//--------------------------------------------------------------------------
#include "act.hxx"
#ifdef SERVER_HANDLER
BOOL gbDisableEmbeddingServerHandler = FALSE; #endif // SERVER_HANDLER
BOOL gbSAFERROTChecksEnabled = TRUE; BOOL gbSAFERAAAChecksEnabled = TRUE;
BOOL gbDynamicIPChangesEnabled = TRUE; // On in whistler; was off by default in W2K
DWORD gdwTimeoutPeriodForStaleMids = 10 * 60 * 1000; // ten minutes
//-------------------------------------------------------------------------
//
// ReadStringValue
//
// Returns the named value string under the specified open registry key.
//
// Returns :
//
// ERROR_SUCCESS, ERROR_FILE_NOT_FOUND, ERROR_BAD_FORMAT, ERROR_OUTOFMEMORY,
// ERROR_BAD_PATHNAME, or other more esoteric win32 error code.
//
//-------------------------------------------------------------------------
DWORD ReadStringValue( IN HKEY hKey, IN WCHAR * pwszValueName, OUT WCHAR ** ppwszString ) { DWORD Status; DWORD Type; DWORD StringSize; WCHAR * pwszScan; WCHAR * pwszSource; WCHAR wszString[64];
*ppwszString = 0;
StringSize = sizeof(wszString);
Status = RegQueryValueEx( hKey, pwszValueName, NULL, &Type, (BYTE *) wszString, &StringSize );
if ( (ERROR_SUCCESS == Status) && (Type != REG_SZ) && (Type != REG_MULTI_SZ) && (Type != REG_EXPAND_SZ) ) Status = ERROR_BAD_FORMAT;
if ( (Status != ERROR_SUCCESS) && (Status != ERROR_MORE_DATA) ) return Status;
// Allocate one extra WCHAR for an extra null at the end.
*ppwszString = (WCHAR *) PrivMemAlloc( StringSize + sizeof(WCHAR) );
if ( ! *ppwszString ) return ERROR_OUTOFMEMORY;
if ( ERROR_MORE_DATA == Status ) { Status = RegQueryValueEx( hKey, pwszValueName, NULL, &Type, (BYTE *) *ppwszString, &StringSize );
if ( Status != ERROR_SUCCESS ) { PrivMemFree( *ppwszString ); *ppwszString = 0; return Status; } } else { memcpy( *ppwszString, wszString, StringSize ); }
//
// Put an extra null at the end. This allows using identical logic for both
// REG_SZ and REG_MULTI_SZ values like RemoteServerNames instead of special
// casing it.
//
(*ppwszString)[StringSize/sizeof(WCHAR)] = 0;
//
// Don't bother with any of the following conversions for multi strings.
// They better be in the correct format.
//
if ( REG_MULTI_SZ == Type ) return Status;
pwszScan = pwszSource = *ppwszString;
//
// The original OLE sources had logic for stripping out a quoted
// value. I have no idea on the origin of this or if it is still
// important. It shouldn't hurt anything to keep it in to save
// us from some nasty compatability problem.
// - DKays, 8/96
//
if ( L'\"' == *pwszScan ) { pwszScan++;
// Copy everything between the quotes.
while ( *pwszScan && (*pwszScan != L'\"') ) *pwszSource++ = *pwszScan++;
*pwszSource = 0; }
//
// Leading and trailing whitespace would hose us for some values, like
// RemoteServerName or RunAs. These are stripped here. Once again, only
// good things can happen if we put this logic in.
//
pwszScan = *ppwszString;
while ( *pwszScan && ((L' ' == *pwszScan) || (L'\t' == *pwszScan)) ) pwszScan++;
if ( ! *pwszScan ) { PrivMemFree( *ppwszString ); *ppwszString = 0; return ERROR_BAD_PATHNAME; }
if ( *ppwszString < pwszScan ) lstrcpyW( *ppwszString, pwszScan );
pwszScan = *ppwszString + lstrlenW(*ppwszString);
while ( (pwszScan != *ppwszString) && ((L' ' == pwszScan[-1]) || (L'\t' == pwszScan[-1])) ) pwszScan--;
*pwszScan = 0;
//
// Finally, handle environment string expansion if necessary.
// Remember to add the extra trailing null again.
//
if ( REG_EXPAND_SZ == Type ) { WCHAR * pwszExpandedString; DWORD ExpandedStringSize;
pwszExpandedString = 0; StringSize /= sizeof(WCHAR);
for (;;) { PrivMemFree( pwszExpandedString ); pwszExpandedString = (WCHAR *) PrivMemAlloc( (StringSize + 1) * sizeof(WCHAR) );
if ( ! pwszExpandedString ) { Status = ERROR_OUTOFMEMORY; break; }
ExpandedStringSize = ExpandEnvironmentStrings( *ppwszString, pwszExpandedString, StringSize );
if ( ! ExpandedStringSize ) { Status = GetLastError(); break; }
if ( ExpandedStringSize > StringSize ) { StringSize = ExpandedStringSize; continue; }
Status = ERROR_SUCCESS; break; }
PrivMemFree( *ppwszString );
if ( ERROR_SUCCESS == Status ) { pwszExpandedString[lstrlenW(pwszExpandedString)+1] = 0; *ppwszString = pwszExpandedString; } else { PrivMemFree( pwszExpandedString ); *ppwszString = 0; } }
return Status; }
//-------------------------------------------------------------------------
//
// ReadStringKeyValue
//
// Reads the unnamed named value string for the specified subkey name
// under the given open registry key.
//
//-------------------------------------------------------------------------
DWORD ReadStringKeyValue( IN HKEY hKey, IN WCHAR * pwszKeyName, OUT WCHAR ** ppwszString ) { DWORD Status; HKEY hSubKey;
Status = RegOpenKeyEx( hKey, pwszKeyName, NULL, KEY_READ, &hSubKey );
if ( Status != ERROR_SUCCESS ) return Status;
Status = ReadStringValue( hSubKey, L"", ppwszString );
RegCloseKey( hSubKey );
return Status; }
//-------------------------------------------------------------------------
//
// ReadSecurityDescriptor
//
// Converts a security descriptor from self relative to absolute form.
// Stuffs in an owner and a group.
//
// Notes :
//
// REGDB_E_INVALIDVALUE is returned when there is something
// at the specified value, but it is not a security descriptor.
//
//-------------------------------------------------------------------------
DWORD ReadSecurityDescriptor( IN HKEY hKey, IN WCHAR * pwszValue, OUT CSecDescriptor ** ppCSecDescriptor )
{ PSID pGroupSid; PSID pOwnerSid; DWORD Size; DWORD Type; DWORD Status; DWORD Size2; SECURITY_DESCRIPTOR* pSD = NULL; CSecDescriptor* pCSecDescriptor = NULL;
// Find put how much memory to allocate for the security descriptor.
Size = 0; *ppCSecDescriptor = NULL;
Status = RegQueryValueEx( hKey, pwszValue, 0, &Type, 0, &Size ); Size2 = Size;
if ( Status != ERROR_SUCCESS ) return Status;
if ( Type != REG_BINARY || (Size < sizeof(SECURITY_DESCRIPTOR)) ) return ERROR_BAD_FORMAT;
//
// Allocate memory for the security descriptor plus the owner and
// group SIDs.
//
#ifdef _WIN64
{ DWORD deltaSize = sizeof( SECURITY_DESCRIPTOR ) - sizeof( SECURITY_DESCRIPTOR_RELATIVE ); ASSERT( deltaSize < sizeof( SECURITY_DESCRIPTOR ) ); deltaSize = (DWORD) OLE2INT_ROUND_UP( deltaSize, sizeof(PVOID) );
Size2 += deltaSize; } #endif // _WIN64
// Allocate sd buffer and wrapper class
pSD = (SECURITY_DESCRIPTOR *) PrivMemAlloc( Size2 ); if (!pSD) return ERROR_OUTOFMEMORY;
// Read the security descriptor.
Status = RegQueryValueEx( hKey, pwszValue, 0, &Type, (PBYTE) pSD, &Size );
if ( Status != ERROR_SUCCESS ) goto ReadSecurityDescriptorEnd;
if ( Type != REG_BINARY ) { Status = ERROR_BAD_FORMAT; goto ReadSecurityDescriptorEnd; }
//
// Fix up the security descriptor.
//
#ifdef _WIN64
if ( MakeAbsoluteSD2( pSD, &Size2 ) == FALSE ) { Status = ERROR_BAD_FORMAT; goto ReadSecurityDescriptorEnd; } #else // !_WIN64
pSD->Control &= ~SE_SELF_RELATIVE; pSD->Sacl = NULL;
if ( pSD->Dacl != NULL ) { if ( (Size < sizeof(ACL) + sizeof(SECURITY_DESCRIPTOR)) || ((ULONG) pSD->Dacl > Size - sizeof(ACL)) ) { Status = ERROR_BAD_FORMAT; goto ReadSecurityDescriptorEnd; }
pSD->Dacl = (ACL *) (((char *) pSD) + ((ULONG) pSD->Dacl));
if ( pSD->Dacl->AclSize + sizeof(SECURITY_DESCRIPTOR) > Size ) { Status = ERROR_BAD_FORMAT; goto ReadSecurityDescriptorEnd; } }
// Set up the owner and group SIDs.
if ( pSD->Group == 0 || ((ULONG)pSD->Group) + sizeof(SID) > Size || pSD->Owner == 0 || ((ULONG)pSD->Owner) + sizeof(SID) > Size ) { Status = ERROR_BAD_FORMAT; goto ReadSecurityDescriptorEnd; }
pSD->Group = (SID *) (((BYTE *) pSD) + (ULONG) (pSD)->Group); pSD->Owner = (SID *) (((BYTE *) pSD) + (ULONG) (pSD)->Owner);
#endif // !_WIN64
ReadSecurityDescriptorEnd:
if ( Status != ERROR_SUCCESS ) { if ( pSD ) PrivMemFree( pSD );
return Status; } // Allocate wrapper class for refcount semantics
pCSecDescriptor = new CSecDescriptor(pSD); if (!pCSecDescriptor) { PrivMemFree(pSD); return ERROR_OUTOFMEMORY; }
ASSERT( IsValidSecurityDescriptor( pCSecDescriptor->GetSD()) ); // New class has refcount of 1, owned by the caller
*ppCSecDescriptor = pCSecDescriptor;
return ERROR_SUCCESS; }
//-------------------------------------------------------------------------
//
// InitSCMRegistry
//
// Opens global registry keys and settings.
//
//-------------------------------------------------------------------------
HRESULT InitSCMRegistry() { HRESULT hr; LONG err; DWORD dwDisp;
ReadRemoteActivationKeys();
ReadRemoteBindingHandleCacheKeys(); ReadSAFERKeys();
ReadDynamicIPChangesKeys();
// Now read the actual values from the registry
// Check if Embedding Server Handler is enabled
#ifdef SERVER_HANDLER
HKEY hkeyOle; err = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\OLE\\DisableEmbeddingServerHandler", NULL, KEY_QUERY_VALUE, &hkeyOle );
if (err == ERROR_SUCCESS) { gbDisableEmbeddingServerHandler=TRUE; RegCloseKey(hkeyOle); } #endif // SERVER_HANDLER
return S_OK; }
//-------------------------------------------------------------------------
//
// ReadRemoteActivationKeys
//
//-------------------------------------------------------------------------
void ReadRemoteActivationKeys() { DWORD err; HKEY hOle;
// Read the DefaultLaunchPermission value (if present) from the registry
if ((err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\OLE", NULL, KEY_READ, &hOle)) == ERROR_SUCCESS) { DWORD dwStatus; CSecDescriptor* pSecDescriptor = NULL;
dwStatus = ReadSecurityDescriptor( hOle, L"DefaultLaunchPermission", &pSecDescriptor); if (dwStatus == ERROR_SUCCESS) { ASSERT(pSecDescriptor); SetDefaultLaunchPermissions(pSecDescriptor); pSecDescriptor->DecRefCount(); } else { // In case of a non-existent or malformed descriptor, reset
// current perms to NULL - this blocks everybody.
ASSERT(!pSecDescriptor); SetDefaultLaunchPermissions(NULL); }
RegCloseKey(hOle); } }
//-------------------------------------------------------------------------
//
// GetActivationFailureLoggingLevel
//
// Returns current activation failure logging level as specified
// by a certain key in the Registry.
//
// History:
//
// a-sergiv 6-17-99 Created
//
// Returns :
//
// 0 = Discretionary logging. Log by default, client can override
// 1 = Always log. Log all errors no matter what client specified
// 2 = Never log. Never log error no matter what client speciied
//
//-------------------------------------------------------------------------
DWORD GetActivationFailureLoggingLevel() { DWORD err; DWORD dwSize; DWORD dwType; HKEY hOle; DWORD dwLevel = 0;
if ((err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\OLE", NULL, KEY_READ, &hOle)) == ERROR_SUCCESS) { dwSize = sizeof(DWORD);
if ((err = RegQueryValueEx(hOle, L"ActivationFailureLoggingLevel", NULL, &dwType, (BYTE *) &dwLevel, &dwSize)) == ERROR_SUCCESS) { // Valid values are 0, 1 and 2. The variable is unsigned.
// Assume 0 if invalid value is specified.
if(dwLevel > 2) dwLevel = 0; } else { // Assume 0 if not specified
dwLevel = 0; }
RegCloseKey(hOle); }
return dwLevel; }
//
// ReadRegistryIntegerValue
//
// Tries to read a numeric value from the specified value under the key.
// Returns FALSE if it doesn't exist or is of the wrong type, TRUE
// otherwise.
//
BOOL ReadRegistryIntegerValue(HKEY hkey, WCHAR* pwszValue, DWORD* pdwValue) { BOOL bResult = FALSE; DWORD error; DWORD dwSize = sizeof(DWORD); DWORD dwType; DWORD dwValue;
error = RegQueryValueExW(hkey, pwszValue, NULL, &dwType, (BYTE*)&dwValue, &dwSize); if (error == ERROR_SUCCESS && dwType == REG_DWORD) { *pdwValue = dwValue; bResult = TRUE; } return bResult; }
//-------------------------------------------------------------------------
//
// ReadRemoteBindingHandleCacheKeys
//
// Reads optional values from the registry to control the behavior of the
// remote binding handle cache (gpRemoteMachineList).
//
//-------------------------------------------------------------------------
void ReadRemoteBindingHandleCacheKeys() { HKEY hOle; DWORD error;
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\OLE", NULL, KEY_READ, &hOle); if (error == ERROR_SUCCESS) { DWORD dwValue;
if (ReadRegistryIntegerValue(hOle, L"RemoteHandleCacheMaxSize", &dwValue)) { gdwRemoteBindingHandleCacheMaxSize = dwValue; }
if (ReadRegistryIntegerValue(hOle, L"RemoteHandleCacheMaxLifetime", &dwValue)) { gdwRemoteBindingHandleCacheMaxLifetime = dwValue; }
if (ReadRegistryIntegerValue(hOle, L"RemoteHandleCacheMaxIdleTimeout", &dwValue)) { gdwRemoteBindingHandleCacheIdleTimeout = dwValue; }
// This one not really a "binding handle cache" knob.
// CODEWORK: all of this registry knob reading code needs to be
// cleaned-up and rewritten.
if (ReadRegistryIntegerValue(hOle, L"StaleMidTimeout", &dwValue)) { gdwTimeoutPeriodForStaleMids = dwValue; } RegCloseKey(hOle); }
return; }
//-------------------------------------------------------------------------
//
// ReadSAFERKeys
//
// Reads optional values from the registry to control aspects of our
// SAFER windows support
//
//-------------------------------------------------------------------------
void ReadSAFERKeys() { HKEY hOle; DWORD error; DWORD dwType; DWORD dwSize; WCHAR wszYN[5];
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\OLE", NULL, KEY_READ, &hOle); if (error == ERROR_SUCCESS) { dwSize = sizeof(wszYN) / sizeof(WCHAR);
error = RegQueryValueEx(hOle, L"SRPRunningObjectChecks", NULL, &dwType, (BYTE*)wszYN, &dwSize); if (error == ERROR_SUCCESS && (wszYN[0] == L'n' || wszYN[0] == L'N')) { gbSAFERROTChecksEnabled = FALSE; }
dwSize = sizeof(wszYN) / sizeof(WCHAR);
error = RegQueryValueEx(hOle, L"SRPActivateAsActivatorChecks", NULL, &dwType, (BYTE*)wszYN, &dwSize); if (error == ERROR_SUCCESS && (wszYN[0] == L'n' || wszYN[0] == L'N')) { gbSAFERAAAChecksEnabled = FALSE; }
CloseHandle(hOle); } return; }
//-------------------------------------------------------------------------
//
// ReadDynamicIPChangesKeys
//
// Reads optional values from the registry to control aspects of our
// dynamic IP change support.
//
//-------------------------------------------------------------------------
void ReadDynamicIPChangesKeys() { HKEY hOle; DWORD error; DWORD dwType; DWORD dwSize; WCHAR wszYN[5];
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\OLE", NULL, KEY_READ, &hOle); if (error == ERROR_SUCCESS) { dwSize = sizeof(wszYN) / sizeof(WCHAR);
error = RegQueryValueEx(hOle, L"EnableSystemDynamicIPTracking", NULL, &dwType, (BYTE*)wszYN, &dwSize); // note: in w2k, this code turned the flag on only if the registry
// value was "y" or "Y". In whistler I have reversed these semantics.
if (error == ERROR_SUCCESS && (wszYN[0] == L'n' || wszYN[0] == L'N')) { gbDynamicIPChangesEnabled = FALSE; }
CloseHandle(hOle); } return; }
//-------------------------------------------------------------------------
//
// CRegistryWatcher::CRegistryWatcher
//
// Constructor for CRegistryWatcher.
//
// If allocation of the event fails, or opening the key fails, or registering
// for the notify fails, then Changed() always returns S_OK (yes, it changed).
// This doesn't affect correctness, only speed.
//
//-------------------------------------------------------------------------
CRegistryWatcher::CRegistryWatcher(HKEY hKeyRoot, const WCHAR *wszSubKey) { _fValid = FALSE;
_hEvent = CreateEvent(NULL, FALSE, TRUE, NULL); if (!_hEvent) return; LONG res = RegOpenKeyEx(hKeyRoot, wszSubKey, 0, KEY_NOTIFY, &_hWatchedKey); if (res != ERROR_SUCCESS) { Cleanup(); return; } _fValid = TRUE; }
//-------------------------------------------------------------------------
//
// CRegistryWatcher::CRegistryWatcher
//
// Determine if the registry key being watched has changed. Returns
// S_OK if it has changed, S_FALSE if not, and an error if something
// failed.
//
//-------------------------------------------------------------------------
HRESULT CRegistryWatcher::Changed() { if (!_fValid) return S_OK;
// _hEvent is auto-reset, so only one thread will re-register.
if (WAIT_OBJECT_0 == WaitForSingleObject(_hEvent, 0)) { LONG res = RegNotifyChangeKeyValue(_hWatchedKey, TRUE, REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET, _hEvent, TRUE); if (res != ERROR_SUCCESS) { // Could not re-register, so we can't watch the key anymore.
_fValid = FALSE; return HRESULT_FROM_WIN32(res); } else return S_OK; } else return S_FALSE; }
void CRegistryWatcher::Cleanup() { if (_hEvent) { CloseHandle(_hEvent); _hEvent = NULL; }
if (_hWatchedKey) { RegCloseKey(_hWatchedKey); _hWatchedKey = NULL; } }
|