/*++ Copyright (c) 1996 Microsoft Corporation Module Name: object.c Abstract: Routines to manage an 'object' which currently can only be a registry key, value name, value, handle and root handle. Author: Jim Schmidt (jimschm) 14-Feb-1997 Revision History: marcw 09-Mar-1999 Don't create empty keys that didn't exist in Win9x Registry. --*/ #include "pch.h" #include "mergep.h" extern POOLHANDLE g_TempPool; extern DWORD g_ProgressBarCounter; BOOL AllocObjectVal (IN OUT PDATAOBJECT SrcObPtr, IN PBYTE Value, IN DWORD Size, IN DWORD AllocSize); VOID FreeObjectVal (IN OUT PDATAOBJECT SrcObPtr); #define NON_ROOT_KEY(Key) ((Key) && ((UINT)(Key) < 0x7fffff00)) #ifdef DEBUG static TCHAR g_DebugEncoding[MAX_ENCODED_RULE]; PCTSTR DebugEncoder ( PVOID ObPtr ) { CreateObjectString ((CPDATAOBJECT) ObPtr, g_DebugEncoding); return g_DebugEncoding; } #endif PKEYPROPS pCreateKeyPropsFromString ( PCTSTR KeyString, BOOL Win95Flag ) { PKEYPROPS RegKey; RegKey = (PKEYPROPS) PoolMemGetAlignedMemory ( g_TempPool, sizeof (KEYPROPS) + SizeOfString (KeyString) ); StringCopy (RegKey->KeyString, KeyString); RegKey->UseCount = 1; RegKey->OpenCount = 0; RegKey->OpenKey = NULL; RegKey->Win95 = Win95Flag; return RegKey; } VOID pFreeKeyProps ( PKEYPROPS RegKey ) { RegKey->UseCount--; if (!RegKey->UseCount) { // Close the key if it is open if (NON_ROOT_KEY (RegKey->OpenKey)) { if (RegKey->Win95) { CloseRegKey95 (RegKey->OpenKey); } else { CloseRegKey (RegKey->OpenKey); } } // Free the KEYPROPS memory PoolMemReleaseMemory (g_TempPool, RegKey); } } VOID pIncKeyPropUse ( PKEYPROPS RegKey ) { RegKey->UseCount++; if (RegKey->OpenKey) { RegKey->OpenCount++; } } PKEYPROPS pCreateDuplicateKeyProps ( PKEYPROPS RegKey, BOOL Win95Flag ) { PKEYPROPS NewRegKey; NewRegKey = pCreateKeyPropsFromString (RegKey->KeyString, Win95Flag); pFreeKeyProps (RegKey); return NewRegKey; } HKEY pGetWinNTKey ( HKEY Key ) { if (Key == HKEY_ROOT) { return g_hKeyRootNT; } return Key; } HKEY pGetWin95Key ( HKEY Key ) { if (Key == HKEY_ROOT) { return g_hKeyRoot95; } return Key; } VOID FixUpUserSpecifiedObject ( PTSTR Object ) { PTSTR p; // Look for a space-open bracket pair p = _tcsrchr (Object, TEXT('[')); if (p) { p = _tcsdec2 (Object, p); if (p && _tcsnextc (p) == TEXT(' ')) { // Found: turn space into wack _settchar (p, TEXT('\\')); } } } VOID CreateObjectString ( IN CPDATAOBJECT InObPtr, OUT PTSTR Object ) { PTSTR p; *Object = 0; // Add HKR if (InObPtr->RootItem) { StringCopy (Object, GetRootStringFromOffset (InObPtr->RootItem)); } // If no root, start with a wack when key is not relative else if (!(InObPtr->ObjectType & OT_REGISTRY_RELATIVE)) { if (InObPtr->KeyPtr) { StringCopy (Object, TEXT("\\")); } } // Add key if (InObPtr->KeyPtr) { if (*Object) { AppendWack (Object); } EncodeRuleChars (GetEndOfString (Object), InObPtr->KeyPtr->KeyString); } // Add tree if (InObPtr->ObjectType & OT_TREE) { if (*Object) { AppendWack (Object); StringCat (Object, TEXT("*")); } } // Add value name if (InObPtr->ValueName) { if (*Object) { AppendWack (Object); } p = _tcsappend (Object, TEXT("[")); EncodeRuleChars (p, InObPtr->ValueName); StringCat (Object, TEXT("]")); } // Final product: HKR\Reg\Key\Path\*\[Root] } BOOL GetRegistryKeyStrFromObject ( IN CPDATAOBJECT InObPtr, OUT PTSTR RegKey ) { *RegKey = 0; // Add HKR if (InObPtr->RootItem) { StringCopy (RegKey, GetRootStringFromOffset (InObPtr->RootItem)); } else { return FALSE; } // Add key if (InObPtr->KeyPtr) { EncodeRuleChars (AppendWack (RegKey), InObPtr->KeyPtr->KeyString); } else { return FALSE; } // Final product: HKR\Reg\Key\Path return TRUE; } BOOL TrackedCreateObjectStruct ( IN PCTSTR Object, OUT PDATAOBJECT OutObPtr, IN BOOL Win95Flag /* , */ ALLOCATION_TRACKING_DEF ) { PCTSTR EndOfKey = NULL; PCTSTR EndOfSpace; PCTSTR ValueName; PCTSTR ObjectStart; TCHAR DecodeBuf[MAX_ENCODED_RULE]; DWORD Length; DWORD RelativeFlag = 0; BOOL TreeFlag = FALSE; CHARTYPE ch = 0; // // Init // ObjectStart = SkipSpace (Object); ZeroMemory (OutObPtr, sizeof (DATAOBJECT)); if (!(*ObjectStart)) { DEBUGMSG ((DBG_WARNING, "CreateObjectStruct: Empty object")); return TRUE; } if (Win95Flag) { OutObPtr->ObjectType |= OT_WIN95; } // // Root // OutObPtr->RootItem = GetOffsetOfRootString (ObjectStart, &Length); if (OutObPtr->RootItem) { ObjectStart += Length; OutObPtr->ObjectType |= OT_REGISTRY; // If we have HKR\*, make ObjectStart point to \* if (_tcsnextc (ObjectStart) == TEXT('*')) { ObjectStart = _tcsdec2 (Object, ObjectStart); MYASSERT (ObjectStart); } } // If no root, starting with a wack means 'relative to the current root' else if (*ObjectStart == TEXT('\\')) { ObjectStart = _tcsinc (ObjectStart); } // If no root and key does not start with a wack, means 'relative to current key' else if (*ObjectStart != TEXT('[')) { RelativeFlag = OT_REGISTRY_RELATIVE; } // // Key // if (*ObjectStart) { // Extract key, but not tree or valuename syntax for (EndOfKey = ObjectStart ; *EndOfKey ; EndOfKey = _tcsinc (EndOfKey)) { ch = (CHARTYPE)_tcsnextc (EndOfKey); if (ch == TEXT('[') || ch == TEXT('*')) { // // EndOfKey points to start of value name or tree identifier // // Make it point to optional space before value, or // make it point to wack before asterisk of the tree identifier EndOfKey = _tcsdec2 (ObjectStart, EndOfKey); // Verify that tree identifier points to wack-asterisk, otherwise // return a syntax error if (ch == TEXT('*')) { if (!EndOfKey || _tcsnextc (EndOfKey) != TEXT('\\')) { DEBUGMSG ((DBG_WARNING, "CreateObjectStruct: %s is not a valid object", Object)); return FALSE; } // Put EndOfKey on last character of the key // (one char before \* tree identifer) EndOfKey = _tcsdec2 (ObjectStart, EndOfKey); } break; } } if (EndOfKey) { // EndOfKey points to the last character of the key, or the // nul terminating the key. We need to trim trailing space. EndOfSpace = SkipSpaceR (ObjectStart, EndOfKey); // If EndOfSpace points to a wack, back it up one char (a key // that does not have a tree identifier can end in a wack) if (ch != TEXT('*')) { if (_tcsnextc (EndOfSpace) == TEXT('\\')) { EndOfSpace = _tcsdec2 (ObjectStart, EndOfSpace); } } // Now make EndOfSpace point to the character after the end if (EndOfSpace) { // always the case when we have a valid key EndOfSpace = _tcsinc (EndOfSpace); } // Now make EndOfKey point to the first character after the key // (which is either a nul, \*, \[valuename] or [valuename]) if (*EndOfKey) { EndOfKey = _tcsinc (EndOfKey); } } else { // no key found EndOfSpace = NULL; EndOfKey = ObjectStart; } // Decode key if it actually exists if (ObjectStart < EndOfSpace) { DecodeRuleCharsAB (DecodeBuf, ObjectStart, EndOfSpace); SetRegistryKey (OutObPtr, DecodeBuf); OutObPtr->ObjectType |= RelativeFlag; } else { // if HKR\*, set an empty key if (_tcsnextc (ObjectStart) != '[' && ch == TEXT('*')) { SetRegistryKey (OutObPtr, TEXT("")); } } // // Tree identifier exists // if (ch == TEXT('*')) { OutObPtr->ObjectType |= OT_TREE; // EndOfKey points to \*, so move it past the identifier EndOfKey = _tcsinc (EndOfKey); EndOfKey = _tcsinc (EndOfKey); // If we are at a wack, skip past it. if (_tcsnextc (EndOfKey) == TEXT('\\')) { EndOfKey = _tcsinc (EndOfKey); } } if (EndOfKey) { ObjectStart = EndOfKey; } } // // Value name // if (*ObjectStart) { // // ObjectStart may point to optional space // ObjectStart = SkipSpace (ObjectStart); // // ObjectStart now points to nul, [valuename] or syntax error // if (_tcsnextc (ObjectStart) == TEXT('[')) { // Skip past optional spaces following bracket ValueName = SkipSpace (_tcsinc (ObjectStart)); // Locate end of [valuename] EndOfKey = ValueName; while (TRUE) { if (!(*EndOfKey)) { DEBUGMSG ((DBG_WARNING, "CreateObjectStruct: Value name is incomplete in %s", Object)); return FALSE; } ch = (CHARTYPE)_tcsnextc (EndOfKey); if (ch == TEXT(']')) { // move to first space character before closing bracket, // or leave it at the bracket if no space exists EndOfKey = _tcsdec2 (ValueName, EndOfKey); if (EndOfKey) { EndOfKey = SkipSpaceR (ValueName, EndOfKey); if (EndOfKey) { EndOfKey = _tcsinc (EndOfKey); } } else { EndOfKey = ValueName; } break; } EndOfKey = _tcsinc (EndOfKey); } // Now decode ValueName, which may be empty DecodeRuleCharsAB (DecodeBuf, ValueName, EndOfKey); SetRegistryValueName (OutObPtr, DecodeBuf); // Make ObjectStart point to nul ObjectStart = SkipSpace (_tcsinc (EndOfKey)); } if (*ObjectStart) { DEBUGMSG ((DBG_WARNING, "CreateObjectStruct: %s does not have a valid value name", Object)); return FALSE; } } // // The next line is normally disabled, and is enabled only when // tracking is needed. // //DebugRegisterAllocation (MERGE_OBJECT, OutObPtr, File, Line); return TRUE; } BOOL CombineObjectStructs ( IN OUT PDATAOBJECT DestObPtr, IN CPDATAOBJECT SrcObPtr ) { if (!SrcObPtr->ObjectType) { DEBUGMSG ((DBG_WARNING, "CombineObjectStructs: Source is empty")); return TRUE; } // The values and handles are no longer valid FreeObjectVal (DestObPtr); CloseObject (DestObPtr); // Registry object merging if (DestObPtr->ObjectType & OT_REGISTRY || !DestObPtr->ObjectType) { if (SrcObPtr->ObjectType & OT_REGISTRY) { // // Verify objects are compatible // if ((SrcObPtr->ObjectType & OT_TREE) && (DestObPtr->ValueName) ) { DEBUGMSG ((DBG_WHOOPS, "Cannot combine registry tree with valuename structs")); return FALSE; } if ((DestObPtr->ObjectType & OT_TREE) && (SrcObPtr->ValueName) ) { DEBUGMSG ((DBG_WHOOPS, "Cannot combine registry tree with valuename structs")); return FALSE; } // // Make dest ob the same platform as src ob // SetPlatformType (DestObPtr, IsWin95Object (SrcObPtr)); // // Copy source's value name, key, type and root to dest // (if they exist) // if (SrcObPtr->ValueName) { SetRegistryValueName (DestObPtr, SrcObPtr->ValueName); } if (SrcObPtr->KeyPtr) { if ((SrcObPtr->ObjectType & OT_REGISTRY_RELATIVE) && (DestObPtr->KeyPtr) ) { TCHAR CompleteKeyName[MAX_ENCODED_RULE]; PTSTR p; // Src is only specifying a key name. Peel off // last key name of dest and replace it with // src. StringCopy (CompleteKeyName, DestObPtr->KeyPtr->KeyString); p = _tcsrchr (CompleteKeyName, TEXT('\\')); if (!p) { p = CompleteKeyName; } else { p = _tcsinc (p); } StringCopy (p, SrcObPtr->KeyPtr->KeyString); SetRegistryKey (DestObPtr, CompleteKeyName); } else { SetRegistryKey (DestObPtr, SrcObPtr->KeyPtr->KeyString); } } if (SrcObPtr->ObjectType & OT_REGISTRY_TYPE) { SetRegistryType (DestObPtr, SrcObPtr->Type); } if (SrcObPtr->RootItem) { DestObPtr->RootItem = SrcObPtr->RootItem; } return TRUE; } else { DEBUGMSG ((DBG_WHOOPS, "Cannot combine registry struct with other type of struct")); } } // Other type of object merging not supported DEBUGMSG ((DBG_WHOOPS, "Cannot combine unsupported or garbage objects")); return FALSE; } BOOL TrackedDuplicateObjectStruct ( OUT PDATAOBJECT DestObPtr, IN CPDATAOBJECT SrcObPtr /* , */ ALLOCATION_TRACKING_DEF ) { ZeroMemory (DestObPtr, sizeof (DATAOBJECT)); // // Create an object that has the same settings as the source, // but duplicate all strings. // if (SrcObPtr->ObjectType & OT_REGISTRY) { DestObPtr->ObjectType |= OT_REGISTRY; } if (SrcObPtr->KeyPtr) { DestObPtr->KeyPtr = SrcObPtr->KeyPtr; pIncKeyPropUse (DestObPtr->KeyPtr); } if (SrcObPtr->ValueName) { if (!SetRegistryValueName (DestObPtr, SrcObPtr->ValueName)) { LOG ((LOG_ERROR, "Error merging the registry (1)")); return FALSE; } } if (SrcObPtr->ObjectType & OT_VALUE) { if (!AllocObjectVal ( DestObPtr, SrcObPtr->Value.Buffer, SrcObPtr->Value.Size, SrcObPtr->Value.AllocatedSize )) { LOG ((LOG_ERROR, "Error merging the registry (2)")); return FALSE; } } if (SrcObPtr->ObjectType & OT_REGISTRY_TYPE) { SetRegistryType (DestObPtr, SrcObPtr->Type); } DestObPtr->RootItem = SrcObPtr->RootItem; #define DUP_OBJECT_FLAGS (OT_TREE|OT_WIN95|OT_REGISTRY_RELATIVE) if (SrcObPtr->ObjectType & DUP_OBJECT_FLAGS) { DestObPtr->ObjectType |= (SrcObPtr->ObjectType & DUP_OBJECT_FLAGS); } if (SrcObPtr->ObjectType & OT_REGISTRY_ENUM_KEY) { DestObPtr->KeyEnum = SrcObPtr->KeyEnum; DestObPtr->ObjectType |= OT_REGISTRY_ENUM_KEY; } if (SrcObPtr->ObjectType & OT_REGISTRY_ENUM_VALUENAME) { DestObPtr->ValNameEnum = SrcObPtr->ValNameEnum; DestObPtr->ObjectType |= OT_REGISTRY_ENUM_VALUENAME; } if (SrcObPtr->ObjectType & OT_REGISTRY_CLASS) { if (!SetRegistryClass (DestObPtr, SrcObPtr->Class.Buffer, SrcObPtr->Class.Size)) { LOG ((LOG_ERROR, "Error merging the registry (3)")); return FALSE; } } // // The next line is normally disabled, and is enabled only when // tracking is needed. // //DebugRegisterAllocation (MERGE_OBJECT, DestObPtr, File, Line); return TRUE; } BOOL AllocObjectVal ( IN OUT PDATAOBJECT SrcObPtr, IN PBYTE Value, OPTIONAL IN DWORD Size, IN DWORD AllocatedSize ) { SrcObPtr->Value.Buffer = PoolMemGetAlignedMemory (g_TempPool, AllocatedSize); if (!SrcObPtr->Value.Buffer) { DEBUGMSG ((DBG_WARNING, "AllocObjectVal failed to alloc memory")); return FALSE; } SrcObPtr->Value.AllocatedSize = AllocatedSize; SrcObPtr->Value.Size = Size; if (Value) { CopyMemory (SrcObPtr->Value.Buffer, Value, AllocatedSize); } SrcObPtr->ObjectType |= OT_VALUE; return TRUE; } VOID FreeObjectVal ( IN OUT PDATAOBJECT SrcObPtr ) { if (SrcObPtr->ObjectType & OT_VALUE) { PoolMemReleaseMemory (g_TempPool, SrcObPtr->Value.Buffer); SrcObPtr->Value.Buffer = NULL; SrcObPtr->ObjectType &= ~OT_VALUE; } } VOID CloseObject ( IN OUT PDATAOBJECT SrcObPtr ) { if (!(SrcObPtr->ObjectType & OT_OPEN)) { return; } MYASSERT (IsRegistryKeyOpen (SrcObPtr)); SrcObPtr->KeyPtr->OpenCount -= 1; if (!SrcObPtr->KeyPtr->OpenCount) { if (NON_ROOT_KEY (SrcObPtr->KeyPtr->OpenKey)) { if (IsWin95Object (SrcObPtr)) { CloseRegKey95 (SrcObPtr->KeyPtr->OpenKey); } else { CloseRegKey (SrcObPtr->KeyPtr->OpenKey); } } SrcObPtr->KeyPtr->OpenKey = NULL; } SrcObPtr->ObjectType &= ~OT_OPEN; } VOID FreeObjectStruct ( IN OUT PDATAOBJECT SrcObPtr ) { PushError(); // // The next line is normally disabled, and is enabled only when // tracking is needed. // //DebugUnregisterAllocation (MERGE_OBJECT, SrcObPtr); FreeObjectVal (SrcObPtr); if (SrcObPtr->KeyPtr) { pFreeKeyProps (SrcObPtr->KeyPtr); } if (SrcObPtr->ParentKeyPtr) { pFreeKeyProps (SrcObPtr->ParentKeyPtr); } if (SrcObPtr->ValueName) { PoolMemReleaseMemory (g_TempPool, (PVOID) SrcObPtr->ValueName); } if (SrcObPtr->ObjectType & OT_REGISTRY_CLASS) { PoolMemReleaseMemory (g_TempPool, (PVOID) SrcObPtr->Class.Buffer); } ZeroMemory (SrcObPtr, sizeof (DATAOBJECT)); PopError(); } BOOL CreateObject ( IN OUT PDATAOBJECT SrcObPtr ) { DWORD rc; DWORD DontCare; PTSTR ClassPtr; if (SrcObPtr->ObjectType & OT_OPEN) { return TRUE; } if (SrcObPtr->KeyPtr) { if (SrcObPtr->KeyPtr->OpenKey) { SrcObPtr->ObjectType |= OT_OPEN; SrcObPtr->KeyPtr->OpenCount++; return TRUE; } if (IsWin95Object (SrcObPtr)) { DEBUGMSG ((DBG_WHOOPS, "Cannot create Win95 registry objects (%s)", SrcObPtr->KeyPtr->KeyString)); return FALSE; } if (!SrcObPtr->KeyPtr->KeyString[0]) { // This is the root of a hive return OpenObject (SrcObPtr); } if (SrcObPtr->ObjectType & OT_REGISTRY_CLASS) { ClassPtr = (PTSTR) SrcObPtr->Class.Buffer; } else { ClassPtr = TEXT(""); } if (SrcObPtr->ParentKeyPtr && SrcObPtr->ParentKeyPtr->OpenKey && SrcObPtr->ChildKey) { rc = TrackedRegCreateKeyEx ( SrcObPtr->ParentKeyPtr->OpenKey, SrcObPtr->ChildKey, 0, ClassPtr, 0, KEY_ALL_ACCESS, NULL, &SrcObPtr->KeyPtr->OpenKey, &DontCare ); } else { rc = TrackedRegCreateKeyEx ( pGetWinNTKey (GetRootKeyFromOffset (SrcObPtr->RootItem)), SrcObPtr->KeyPtr->KeyString, 0, ClassPtr, 0, KEY_ALL_ACCESS, NULL, &SrcObPtr->KeyPtr->OpenKey, &DontCare ); } if (rc == ERROR_INVALID_PARAMETER) { // // Attempt was made to create a key directly under HKLM. There is no // backing storage, so the RegCreateKeyEx call failed with this error. // We handle it gracefully... // DEBUGMSG ((DBG_WARNING, "CreateObject: Not possible to create %s on NT", SrcObPtr->KeyPtr->KeyString)); SetLastError (ERROR_SUCCESS); return FALSE; } if (rc == ERROR_ACCESS_DENIED) { // // Attempt was made to create a key that has a strong ACL. We'll // just assume success in this case. // LOG (( LOG_INFORMATION, "Can't create %s because access was denied", SrcObPtr->KeyPtr->KeyString )); SetLastError (ERROR_SUCCESS); return FALSE; } if (rc != ERROR_SUCCESS) { SetLastError (rc); LOG ((LOG_ERROR, "Failed to create a registry key (%s)", SrcObPtr->KeyPtr->KeyString)); return FALSE; } SrcObPtr->KeyPtr->OpenCount = 1; SrcObPtr->ObjectType |= OT_OPEN; } return TRUE; } BOOL OpenObject ( IN OUT PDATAOBJECT SrcObPtr ) { DWORD rc = ERROR_SUCCESS; HKEY Parent; #if CLASS_FIELD_ENABLED TCHAR ClassBuf[MAX_CLASS_SIZE]; DWORD ClassBufSize = MAX_CLASS_SIZE; #endif if (SrcObPtr->ObjectType & OT_OPEN) { return TRUE; } if (SrcObPtr->KeyPtr) { if (SrcObPtr->KeyPtr->OpenKey) { SrcObPtr->ObjectType |= OT_OPEN; SrcObPtr->KeyPtr->OpenCount++; return TRUE; } if (IsWin95Object (SrcObPtr)) { if (SrcObPtr->ParentKeyPtr && SrcObPtr->ParentKeyPtr->OpenKey && SrcObPtr->ChildKey) { rc = TrackedRegOpenKeyEx95 ( SrcObPtr->ParentKeyPtr->OpenKey, SrcObPtr->ChildKey, 0, KEY_READ, &SrcObPtr->KeyPtr->OpenKey ); } else { Parent = pGetWin95Key (GetRootKeyFromOffset (SrcObPtr->RootItem)); if (*SrcObPtr->KeyPtr->KeyString || NON_ROOT_KEY (Parent)) { rc = TrackedRegOpenKeyEx95 ( Parent, SrcObPtr->KeyPtr->KeyString, 0, KEY_READ, &SrcObPtr->KeyPtr->OpenKey ); } else { SrcObPtr->KeyPtr->OpenKey = Parent; } } } else { if (SrcObPtr->ParentKeyPtr && SrcObPtr->ParentKeyPtr->OpenKey && SrcObPtr->ChildKey) { rc = TrackedRegOpenKeyEx ( SrcObPtr->ParentKeyPtr->OpenKey, SrcObPtr->ChildKey, 0, KEY_ALL_ACCESS, &SrcObPtr->KeyPtr->OpenKey ); } else { Parent = pGetWinNTKey (GetRootKeyFromOffset (SrcObPtr->RootItem)); if (*SrcObPtr->KeyPtr->KeyString || NON_ROOT_KEY (Parent)) { rc = TrackedRegOpenKeyEx ( Parent, SrcObPtr->KeyPtr->KeyString, 0, KEY_ALL_ACCESS, &SrcObPtr->KeyPtr->OpenKey ); } else { SrcObPtr->KeyPtr->OpenKey = Parent; } } } if (rc != ERROR_SUCCESS) { SetLastError (rc); return FALSE; } SrcObPtr->ObjectType |= OT_OPEN; SrcObPtr->KeyPtr->OpenCount = 1; #if CLASS_FIELD_ENABLED // Get the key's class if (IsWin95Object (SrcObPtr)) { rc = Win95RegQueryInfoKey (pGetWin95Key (SrcObPtr->RootKey), ClassBuf, &ClassBufSize, NULL, // reserved NULL, // sub key count NULL, // max sub key len NULL, // max class len NULL, // values NULL, // max value name len NULL, // max value len NULL, // security desc NULL // last write time ); } else { rc = WinNTRegQueryInfoKey (pGetWin95Key (SrcObPtr->RootKey), ClassBuf, &ClassBufSize, NULL, // reserved NULL, // sub key count NULL, // max sub key len NULL, // max class len NULL, // values NULL, // max value name len NULL, // max value len NULL, // security desc NULL // last write time ); } if (rc == ERROR_SUCCESS) { DEBUGMSG ((DBG_VERBOSE, "Class size is %u for %s\\%s", ClassBufSize, GetRootStringFromOffset (SrcObPtr->RootItem), SrcObPtr->KeyPtr->KeyString)); SetRegistryClass (SrcObPtr, ClassBuf, ClassBufSize); } #endif } return TRUE; } VOID pFixRegSzTermination ( IN OUT PDATAOBJECT SrcObPtr ) { BOOL addNul = FALSE; PTSTR end; PBYTE oldBuf; UINT oldSize; if (SrcObPtr->Type == REG_SZ || SrcObPtr->Type == REG_EXPAND_SZ) { if (SrcObPtr->Value.Size & 1) { // // Force type to REG_NONE because we assume all REG_SZ // and REG_EXPAND_SZ values are truncated. // SrcObPtr->Type = REG_NONE; DEBUGMSG (( DBG_WARNING, "Truncation occurred because of odd string size for %s", DebugEncoder (SrcObPtr) )); } else { // // Check if we need to append a nul. // addNul = FALSE; oldBuf = SrcObPtr->Value.Buffer; oldSize = SrcObPtr->Value.Size; if (oldSize < sizeof (TCHAR)) { addNul = TRUE; } else { end = (PTSTR) (oldBuf + oldSize - sizeof (TCHAR)); addNul = (*end != 0); } if (addNul) { if (AllocObjectVal (SrcObPtr, NULL, oldSize, oldSize + sizeof (TCHAR))) { CopyMemory (SrcObPtr->Value.Buffer, oldBuf, oldSize); end = (PTSTR) (SrcObPtr->Value.Buffer + oldSize); *end = 0; PoolMemReleaseMemory (g_TempPool, oldBuf); } else { SrcObPtr->Type = REG_NONE; } } } } } BOOL ReadObject ( IN OUT PDATAOBJECT SrcObPtr ) { return ReadObjectEx (SrcObPtr, FALSE); } BOOL ReadObjectEx ( IN OUT PDATAOBJECT SrcObPtr, IN BOOL QueryOnly ) { DWORD rc; DWORD ReqSize; // Skip if value has already been read if (SrcObPtr->ObjectType & OT_VALUE) { return TRUE; } // If registry key and valuename, query Win95 registry if (IsObjectRegistryKeyAndVal (SrcObPtr)) { // Open key if necessary if (!OpenObject (SrcObPtr)) { DEBUGMSG ((DBG_VERBOSE, "ReadObject failed because OpenObject failed")); return FALSE; } // Get the value size if (IsWin95Object (SrcObPtr)) { ReqSize = 0; // Temporary fix for win95reg rc = Win95RegQueryValueEx (SrcObPtr->KeyPtr->OpenKey, SrcObPtr->ValueName, NULL, &SrcObPtr->Type, NULL, &ReqSize); } else { rc = WinNTRegQueryValueEx ( SrcObPtr->KeyPtr->OpenKey, SrcObPtr->ValueName, NULL, &SrcObPtr->Type, NULL, &ReqSize ); if (rc == ERROR_ACCESS_DENIED) { LOG (( LOG_INFORMATION, "Access denied for query of %s in %s", SrcObPtr->ValueName, SrcObPtr->KeyPtr->KeyString )); ReqSize = 1; SrcObPtr->Type = REG_NONE; } } if (rc != ERROR_SUCCESS) { DEBUGMSG_IF ((rc != ERROR_FILE_NOT_FOUND, DBG_WARNING, "ReadObject failed for %s (type: %x)", DebugEncoder (SrcObPtr), SrcObPtr->ObjectType)); DEBUGMSG_IF (( !QueryOnly && rc == ERROR_FILE_NOT_FOUND, DBG_WARNING, "Object %s not found", DebugEncoder (SrcObPtr) )); SetLastError (rc); return FALSE; } // Query only is used to see if the object exists if (QueryOnly) { return TRUE; } // Allocate a buffer for the value if (!AllocObjectVal (SrcObPtr, NULL, ReqSize, ReqSize)) { return FALSE; } // Get the the value if (IsWin95Object (SrcObPtr)) { rc = Win95RegQueryValueEx (SrcObPtr->KeyPtr->OpenKey, SrcObPtr->ValueName, NULL, &SrcObPtr->Type, SrcObPtr->Value.Buffer, &ReqSize); } else { rc = WinNTRegQueryValueEx ( SrcObPtr->KeyPtr->OpenKey, SrcObPtr->ValueName, NULL, &SrcObPtr->Type, SrcObPtr->Value.Buffer, &ReqSize ); if (rc == ERROR_ACCESS_DENIED) { SrcObPtr->Type = REG_NONE; SrcObPtr->Value.Size = 0; rc = ERROR_SUCCESS; } } if (rc != ERROR_SUCCESS) { FreeObjectVal (SrcObPtr); SetLastError (rc); LOG ((LOG_ERROR, "Failed to read from the registry")); return FALSE; } // The SrcObPtr->Type field is accurate SrcObPtr->ObjectType |= OT_REGISTRY_TYPE; // Fix REG_SZ or REG_EXPAND_SZ pFixRegSzTermination (SrcObPtr); // // If necessary, convert the data // return FilterObject (SrcObPtr); } DEBUGMSG ((DBG_WHOOPS, "Read Object: Object type (%Xh) is not supported", SrcObPtr->ObjectType)); return FALSE; } BOOL WriteObject ( IN CPDATAOBJECT DestObPtr ) { DWORD rc; // If registry key, make sure it exists if ((DestObPtr->KeyPtr) && !IsWin95Object (DestObPtr) ) { // Create or open key if necessary if (!CreateObject (DestObPtr)) { DEBUGMSG ((DBG_WARNING, "WriteObject: CreateObject failed for %s", DestObPtr->KeyPtr->KeyString)); return FALSE; } // If no value name and no value, skip if (!(DestObPtr->ObjectType & OT_VALUE) && !(DestObPtr->ValueName)) { return TRUE; } // If no type, specify it as REG_NONE if (!IsRegistryTypeSpecified (DestObPtr)) { SetRegistryType (DestObPtr, REG_NONE); } // Write the value if (*DestObPtr->ValueName || NON_ROOT_KEY (DestObPtr->KeyPtr->OpenKey)) { rc = WinNTRegSetValueEx ( DestObPtr->KeyPtr->OpenKey, DestObPtr->ValueName, 0, DestObPtr->Type, DestObPtr->Value.Buffer, DestObPtr->Value.Size ); if (rc == ERROR_ACCESS_DENIED) { // // If access is denied, log & assume success // LOG (( LOG_INFORMATION, "Access denied; can't write registry value (%s [%s])", DestObPtr->KeyPtr->KeyString, DestObPtr->ValueName )); rc = ERROR_SUCCESS; } } else { rc = ERROR_SUCCESS; } if (rc != ERROR_SUCCESS) { SetLastError (rc); LOG ((LOG_ERROR, "Failed to set a registry value (%s [%s])", DestObPtr->KeyPtr->KeyString, DestObPtr->ValueName)); return FALSE; } return TRUE; } DEBUGMSG ((DBG_WHOOPS, "Write Object: Object type (%Xh) is not supported", DestObPtr->ObjectType)); return FALSE; } FILTERRETURN CopySingleObject ( IN OUT PDATAOBJECT SrcObPtr, IN OUT PDATAOBJECT DestObPtr, IN FILTERFUNCTION FilterFn, OPTIONAL IN PVOID FilterArg OPTIONAL ) { FILTERRETURN fr = FILTER_RETURN_FAIL; DATAOBJECT TempOb; if (!ReadObject (SrcObPtr)) { if (GetLastError() == ERROR_FILE_NOT_FOUND) { fr = FILTER_RETURN_CONTINUE; } else { DEBUGMSG ((DBG_ERROR, "CopySingleObject: Cannot read object %s", DebugEncoder (SrcObPtr))); } return fr; } if (FilterFn) { fr = FilterFn (SrcObPtr, DestObPtr, FILTER_VALUE_COPY, FilterArg); if (fr != FILTER_RETURN_CONTINUE) { // handled means skip copy but don't stop enum if (fr == FILTER_RETURN_HANDLED) { fr = FILTER_RETURN_CONTINUE; } // Debug version tells us when a filter failed DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "CopySingleObject failed because filter function FILTER_VALUE_COPY failed")); return fr; } } // // Temporarily transfer SrcOb's value, value type and to DestOb // CopyMemory (&TempOb, DestObPtr, sizeof (DATAOBJECT)); DestObPtr->ObjectType |= SrcObPtr->ObjectType & (OT_VALUE|OT_REGISTRY_TYPE|OT_REGISTRY_CLASS); DestObPtr->Value.Buffer = SrcObPtr->Value.Buffer; DestObPtr->Value.Size = SrcObPtr->Value.Size; DestObPtr->Class.Buffer = SrcObPtr->Class.Buffer; DestObPtr->Class.Size = SrcObPtr->Class.Size; DestObPtr->Type = SrcObPtr->Type; // // Write the dest ob // if (WriteObject (DestObPtr)) { fr = FILTER_RETURN_CONTINUE; } else { DEBUGMSG ((DBG_ERROR, "CopySingleObject: Cannot write object %s", DebugEncoder (DestObPtr))); } // // Restore the dest ob // CopyMemory (DestObPtr, &TempOb, sizeof (DATAOBJECT)); return fr; } FILTERRETURN NextSubObjectEnum ( IN PDATAOBJECT RootSrcObPtr, IN PDATAOBJECT RootDestObPtr, OPTIONAL OUT PDATAOBJECT SubSrcObPtr, OUT PDATAOBJECT SubDestObPtr, IN FILTERFUNCTION FilterFn, OPTIONAL IN PVOID FilterArg OPTIONAL ) { DWORD rc; FILTERRETURN fr = FILTER_RETURN_FAIL; PTSTR NewKey; TCHAR KeyNameBuf[MAX_REGISTRY_KEY]; DWORD KeyNameBufSize; TCHAR ClassBuf[MAX_CLASS_SIZE]; DWORD ClassBufSize; FILETIME DontCare; BOOL CreatedSubOb = FALSE; if (IsObjectRegistryKeyOnly (RootSrcObPtr)) { do { MYASSERT (RootSrcObPtr->KeyPtr->OpenKey); KeyNameBufSize = MAX_REGISTRY_KEY; ClassBufSize = MAX_CLASS_SIZE; fr = FILTER_RETURN_FAIL; // // Enumerate the next sub object // if (IsWin95Object (RootSrcObPtr)) { rc = Win95RegEnumKey ( RootSrcObPtr->KeyPtr->OpenKey, RootSrcObPtr->KeyEnum, KeyNameBuf, KeyNameBufSize ); ClassBufSize = 0; } else { rc = WinNTRegEnumKeyEx ( RootSrcObPtr->KeyPtr->OpenKey, RootSrcObPtr->KeyEnum, KeyNameBuf, &KeyNameBufSize, NULL, // reserved ClassBuf, &ClassBufSize, &DontCare // last write time ); if (rc == ERROR_ACCESS_DENIED) { LOG (( LOG_INFORMATION, "Access denied for enumeration of %s", RootSrcObPtr->KeyPtr->KeyString )); rc = ERROR_NO_MORE_ITEMS; } } if (rc != ERROR_SUCCESS) { SetLastError (rc); if (rc == ERROR_NO_MORE_ITEMS) { fr = FILTER_RETURN_DONE; } return fr; } // // Create sub source object // CreatedSubOb = TRUE; ZeroMemory (SubSrcObPtr, sizeof (DATAOBJECT)); SubSrcObPtr->ObjectType = RootSrcObPtr->ObjectType & (OT_WIN95|OT_TREE); SubSrcObPtr->RootItem = RootSrcObPtr->RootItem; SubSrcObPtr->ParentKeyPtr = RootSrcObPtr->KeyPtr; pIncKeyPropUse (SubSrcObPtr->ParentKeyPtr); MYASSERT (KeyNameBuf && *KeyNameBuf); NewKey = JoinPaths (RootSrcObPtr->KeyPtr->KeyString, KeyNameBuf); SetRegistryKey (SubSrcObPtr, NewKey); FreePathString (NewKey); SubSrcObPtr->ChildKey = _tcsrchr (SubSrcObPtr->KeyPtr->KeyString, TEXT('\\')); if (SubSrcObPtr->ChildKey) { SubSrcObPtr->ChildKey = _tcsinc (SubSrcObPtr->ChildKey); } else { SubSrcObPtr->ChildKey = SubSrcObPtr->KeyPtr->KeyString; } #if CLASS_FIELD_ENABLED SetRegistryClass (SubSrcObPtr, ClassBuf, ClassBufSize); #endif // // Create sub dest object // ZeroMemory (SubDestObPtr, sizeof (DATAOBJECT)); if (RootDestObPtr) { SubDestObPtr->ObjectType = RootDestObPtr->ObjectType & OT_TREE; SubDestObPtr->RootItem = RootDestObPtr->RootItem; SubDestObPtr->ParentKeyPtr = RootDestObPtr->KeyPtr; pIncKeyPropUse (SubDestObPtr->ParentKeyPtr); // let's convert KeyNameBuf if it's a path and the path changed ConvertWin9xCmdLine (KeyNameBuf, DEBUGENCODER(SubDestObPtr), NULL); NewKey = JoinPaths (RootDestObPtr->KeyPtr->KeyString, KeyNameBuf); SetRegistryKey (SubDestObPtr, NewKey); FreePathString (NewKey); SubDestObPtr->ChildKey = _tcsrchr (SubDestObPtr->KeyPtr->KeyString, TEXT('\\')); if (SubDestObPtr->ChildKey) { SubDestObPtr->ChildKey = _tcsinc (SubDestObPtr->ChildKey); } else { SubDestObPtr->ChildKey = SubDestObPtr->KeyPtr->KeyString; } #if CLASS_FIELD_ENABLED SetRegistryClass (SubDestObPtr, ClassBuf, ClassBufSize); #endif } if (FilterFn) { fr = FilterFn ( SubSrcObPtr, RootDestObPtr ? SubDestObPtr : NULL, FILTER_KEY_ENUM, FilterArg ); if (fr == FILTER_RETURN_DELETED) { CreatedSubOb = FALSE; FreeObjectStruct (SubSrcObPtr); FreeObjectStruct (SubDestObPtr); } // Debug version tells us when a filter fails DEBUGMSG_IF (( fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "NextSubObjectEnum failed because filter function FILTER_KEY_ENUM failed" )); } else { fr = FILTER_RETURN_CONTINUE; } } while (fr == FILTER_RETURN_DELETED); RootSrcObPtr->KeyEnum += 1; } if (fr != FILTER_RETURN_CONTINUE && fr != FILTER_RETURN_HANDLED) { if (CreatedSubOb) { FreeObjectStruct (SubSrcObPtr); FreeObjectStruct (SubDestObPtr); } } return fr; } BOOL BeginSubObjectEnum ( IN PDATAOBJECT RootSrcObPtr, IN PDATAOBJECT RootDestObPtr, OPTIONAL OUT PDATAOBJECT SubSrcObPtr, OUT PDATAOBJECT SubDestObPtr, IN FILTERFUNCTION FilterFn, OPTIONAL IN PVOID FilterArg OPTIONAL ) { if (IsObjectRegistryKeyOnly (RootSrcObPtr)) { // Open key if necessary if (!OpenObject (RootSrcObPtr)) { if (GetLastError() == ERROR_FILE_NOT_FOUND) { return FILTER_RETURN_DONE; } DEBUGMSG ((DBG_WARNING, "BeginSubObjectEnum: Can't open %s", DebugEncoder (RootSrcObPtr))); return FILTER_RETURN_FAIL; } RootSrcObPtr->KeyEnum = 0; return NextSubObjectEnum (RootSrcObPtr, RootDestObPtr, SubSrcObPtr, SubDestObPtr, FilterFn, FilterArg); } // Other object types do not have sub objects DEBUGMSG ((DBG_WARNING, "BeginSubObjectEnum: Trying to enumerate unknown object")); return FILTER_RETURN_FAIL; } FILTERRETURN NextValueNameEnum ( IN PDATAOBJECT RootSrcObPtr, IN PDATAOBJECT RootDestObPtr, OPTIONAL OUT PDATAOBJECT ValSrcObPtr, OUT PDATAOBJECT ValDestObPtr, IN FILTERFUNCTION FilterFn, OPTIONAL IN PVOID FilterArg OPTIONAL ) { DWORD rc; FILTERRETURN fr = FILTER_RETURN_FAIL; TCHAR ValNameBuf[MAX_REGISTRY_VALUE_NAME]; DWORD ValNameBufSize = MAX_REGISTRY_VALUE_NAME; BOOL CreatedValOb = FALSE; if (IsObjectRegistryKeyOnly (RootSrcObPtr)) { MYASSERT (IsRegistryKeyOpen (RootSrcObPtr)); if (IsWin95Object (RootSrcObPtr)) { rc = Win95RegEnumValue ( RootSrcObPtr->KeyPtr->OpenKey, RootSrcObPtr->ValNameEnum, ValNameBuf, &ValNameBufSize, NULL, // reserved NULL, // type ptr NULL, // value data ptr NULL // value data size ptr ); } else { rc = WinNTRegEnumValue ( RootSrcObPtr->KeyPtr->OpenKey, RootSrcObPtr->ValNameEnum, ValNameBuf, &ValNameBufSize, NULL, // reserved NULL, // type ptr NULL, // value data ptr NULL // value data size ptr ); if (rc == ERROR_ACCESS_DENIED) { LOG (( LOG_INFORMATION, "Access denied for enumeration of values in %s", RootSrcObPtr->KeyPtr->KeyString )); rc = ERROR_NO_MORE_ITEMS; } } if (rc != ERROR_SUCCESS) { SetLastError (rc); if (rc == ERROR_NO_MORE_ITEMS) { fr = FILTER_RETURN_DONE; } else { LOG ((LOG_ERROR, "Failed to enumerate a registry value")); } return fr; } // // Create src value object // CreatedValOb = TRUE; ZeroMemory (ValSrcObPtr, sizeof (DATAOBJECT)); ValSrcObPtr->ObjectType = RootSrcObPtr->ObjectType & OT_WIN95; // (OT_WIN95|OT_TREE) removed ValSrcObPtr->RootItem = RootSrcObPtr->RootItem; ValSrcObPtr->ParentKeyPtr = RootSrcObPtr->KeyPtr; pIncKeyPropUse (ValSrcObPtr->ParentKeyPtr); ValSrcObPtr->KeyPtr = RootSrcObPtr->KeyPtr; pIncKeyPropUse (ValSrcObPtr->KeyPtr); if (rc == ERROR_SUCCESS) { SetRegistryValueName (ValSrcObPtr, ValNameBuf); } else { SetRegistryValueName (ValSrcObPtr, TEXT("")); } // // Create dest value object // CreatedValOb = TRUE; ZeroMemory (ValDestObPtr, sizeof (DATAOBJECT)); if (RootDestObPtr) { ValDestObPtr->RootItem = RootDestObPtr->RootItem; ValDestObPtr->ParentKeyPtr = RootDestObPtr->KeyPtr; pIncKeyPropUse (ValDestObPtr->ParentKeyPtr); ValDestObPtr->KeyPtr = RootDestObPtr->KeyPtr; pIncKeyPropUse (ValDestObPtr->KeyPtr); // let's convert ValNameBuf if it's a path and the path changed ConvertWin9xCmdLine (ValNameBuf, DEBUGENCODER(ValDestObPtr), NULL); if (rc == ERROR_SUCCESS) { SetRegistryValueName (ValDestObPtr, ValNameBuf); } else { SetRegistryValueName (ValDestObPtr, TEXT("")); } } if (FilterFn) { fr = FilterFn ( ValSrcObPtr, RootDestObPtr ? ValDestObPtr : NULL, FILTER_VALUENAME_ENUM, FilterArg ); // Debug version tells us when a filter fails DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "NextValueNameEnum failed because filter function FILTER_VALUENAME_ENUM failed")); } else { fr = FILTER_RETURN_CONTINUE; } RootSrcObPtr->ValNameEnum += 1; } if (fr != FILTER_RETURN_CONTINUE && fr != FILTER_RETURN_HANDLED) { if (CreatedValOb) { FreeObjectStruct (ValSrcObPtr); FreeObjectStruct (ValDestObPtr); } } return fr; } FILTERRETURN BeginValueNameEnum ( IN PDATAOBJECT RootSrcObPtr, IN PDATAOBJECT RootDestObPtr, OPTIONAL OUT PDATAOBJECT ValSrcObPtr, OUT PDATAOBJECT ValDestObPtr, IN FILTERFUNCTION FilterFn, OPTIONAL IN PVOID FilterArg OPTIONAL ) { if (IsObjectRegistryKeyOnly (RootSrcObPtr)) { // Open key if necessary if (!OpenObject (RootSrcObPtr)) { if (GetLastError() == ERROR_FILE_NOT_FOUND) { return FILTER_RETURN_DONE; } DEBUGMSG ((DBG_WARNING, "BeginValueNameEnum: Can't open %s", DebugEncoder (RootSrcObPtr))); return FILTER_RETURN_FAIL; } RootSrcObPtr->ValNameEnum = 0; return NextValueNameEnum (RootSrcObPtr, RootDestObPtr, ValSrcObPtr, ValDestObPtr, FilterFn, FilterArg); } // Other object types do not have sub objects DEBUGMSG ((DBG_WARNING, "BeginValueNameEnum: Trying to enumerate unknown object")); return FILTER_RETURN_FAIL; } FILTERRETURN CopyObject ( IN PDATAOBJECT SrcObPtr, IN CPDATAOBJECT DestObPtr, OPTIONAL IN FILTERFUNCTION FilterFn, OPTIONAL IN PVOID FilterArg OPTIONAL ) { DATAOBJECT ChildOb, ChildDestOb; FILTERRETURN fr = FILTER_RETURN_FAIL; BOOL suppressKey = FALSE; // // Progress bar update // g_ProgressBarCounter++; if (g_ProgressBarCounter >= REGMERGE_TICK_THRESHOLD) { g_ProgressBarCounter = 0; TickProgressBar (); } // // Tree copy // if (SrcObPtr->ObjectType & OT_TREE) { if (DestObPtr) { #ifdef DEBUG // // Verify destination does not specify value but does specify key // if (!IsObjectRegistryKeyOnly (DestObPtr)) { DEBUGMSG (( DBG_WHOOPS, "CopyObject: Destination invalid for copy %s tree", DebugEncoder (SrcObPtr) )); return FILTER_RETURN_FAIL; } #endif // The source object cannot specify a registry value either MYASSERT (!(SrcObPtr->ValueName)); #ifndef VAR_PROGRESS_BAR // // Progress bar update // g_ProgressBarCounter++; if (g_ProgressBarCounter >= REGMERGE_TICK_THRESHOLD) { g_ProgressBarCounter = 0; TickProgressBarDelta (1); } #endif // // Ask the filter if it wants to create the key unconditionally // if (FilterFn) { // // suppressKey should never be set if filterFn exists. // MYASSERT (!suppressKey) fr = FilterFn (SrcObPtr, DestObPtr, FILTER_CREATE_KEY, FilterArg); if (fr == FILTER_RETURN_FAIL || fr == FILTER_RETURN_DONE) { // The done at the key create does not really mean end the whole copy! if (fr == FILTER_RETURN_DONE) { fr = FILTER_RETURN_CONTINUE; } return fr; } } else { // // Check to see if the win9x object actually exists. If not, // we'll pass on FILTER_RETURN_DONE. We don't want to get // empty keys created on nt where no keys existed on win9x. // if (!OpenObject (SrcObPtr)) { suppressKey = TRUE; fr = FILTER_RETURN_HANDLED; } else { fr = FILTER_RETURN_CONTINUE; } } if (fr == FILTER_RETURN_CONTINUE) { if (!CreateObject (DestObPtr)) { if (GetLastError() == ERROR_SUCCESS) { // // CreateObject failed but because the last error was // ERROR_SUCCESS, we skip this registry node and continue // processing as if the error didn't occur. // return FILTER_RETURN_CONTINUE; } else { DEBUGMSG ((DBG_WARNING, "CopyObject: CreateObject failed to create %s", DebugEncoder (DestObPtr) )); return FILTER_RETURN_FAIL; } } } } // // Copy all values (call CopyObject recursively) // SrcObPtr->ObjectType &= ~(OT_TREE); if (FilterFn) { // // suppress key should never be set if there is a FilterFn. // MYASSERT (!suppressKey) fr = FilterFn (SrcObPtr, DestObPtr, FILTER_PROCESS_VALUES, FilterArg); // Debug version tells us that the filter failed DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "CopyObject failed because filter function FILTER_PROCESS_VALUES failed")); if (fr == FILTER_RETURN_FAIL || fr == FILTER_RETURN_DONE) { DEBUGMSG ((DBG_VERBOSE, "CopyObject is exiting")); SrcObPtr->ObjectType |= OT_TREE; return fr; } } else { fr = suppressKey ? FILTER_RETURN_HANDLED : FILTER_RETURN_CONTINUE; } // // Skip copy of key's values if FilterFn returned FILTER_RETURN_HANDLED // if (fr == FILTER_RETURN_CONTINUE) { fr = CopyObject (SrcObPtr, DestObPtr, FilterFn, FilterArg); SrcObPtr->ObjectType |= OT_TREE; if (fr != FILTER_RETURN_CONTINUE) { return fr; } } else { SrcObPtr->ObjectType |= OT_TREE; } // // Enumerate all child objects and process them recursively // fr = BeginSubObjectEnum ( SrcObPtr, DestObPtr, &ChildOb, &ChildDestOb, FilterFn, FilterArg ); while (fr == FILTER_RETURN_CONTINUE || fr == FILTER_RETURN_HANDLED) { if (fr == FILTER_RETURN_CONTINUE) { fr = CopyObject ( &ChildOb, DestObPtr ? &ChildDestOb : NULL, FilterFn, FilterArg ); } else { fr = FILTER_RETURN_CONTINUE; } FreeObjectStruct (&ChildOb); FreeObjectStruct (&ChildDestOb); if (fr != FILTER_RETURN_CONTINUE) { return fr; } fr = NextSubObjectEnum ( SrcObPtr, DestObPtr, &ChildOb, &ChildDestOb, FilterFn, FilterArg ); } // The end of enum does not really mean end the copy! if (fr == FILTER_RETURN_DONE) { fr = FILTER_RETURN_CONTINUE; } DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "CopyObject: Filter in subob enum failed")); } // // Copy all values of a key // else if (IsObjectRegistryKeyOnly (SrcObPtr)) { #ifdef DEBUG if (DestObPtr) { // // Verify destination does not specify value but does specify key // if (!IsObjectRegistryKeyOnly (DestObPtr)) { DEBUGMSG (( DBG_WHOOPS, "CopyObject: Destination (%s) invalid for copy values in %s", DebugEncoder (DestObPtr), DebugEncoder (SrcObPtr) )); return fr; } } #endif // // Enumerate all values in the key // fr = BeginValueNameEnum ( SrcObPtr, DestObPtr, &ChildOb, &ChildDestOb, FilterFn, FilterArg ); if (fr == FILTER_RETURN_DONE) { // // No values in this key. Make sure DestObPtr is created. // if (DestObPtr && !suppressKey) { if (!CreateObject (DestObPtr)) { DEBUGMSG ((DBG_WARNING, "CopyObject: Could not create %s (type %x)", DebugEncoder (DestObPtr), DestObPtr->ObjectType)); } } } else { // // For each value, call CopySingleObject // while (fr == FILTER_RETURN_CONTINUE || fr == FILTER_RETURN_HANDLED) { if (fr == FILTER_RETURN_CONTINUE && DestObPtr) { fr = CopySingleObject (&ChildOb, &ChildDestOb, FilterFn, FilterArg); } else { fr = FILTER_RETURN_CONTINUE; } FreeObjectStruct (&ChildOb); FreeObjectStruct (&ChildDestOb); if (fr != FILTER_RETURN_CONTINUE) { DEBUGMSG ((DBG_VERBOSE, "CopyObject failed because CopySingleObject failed")); return fr; } fr = NextValueNameEnum ( SrcObPtr, DestObPtr, &ChildOb, &ChildDestOb, FilterFn, FilterArg ); } } // The end of enum does not really mean end the copy! if (fr == FILTER_RETURN_DONE) { fr = FILTER_RETURN_CONTINUE; } DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "CopyObject: Filter in val enum failed")); } // // One value copy // else if (IsObjectRegistryKeyAndVal (SrcObPtr)) { #ifdef DEBUG if (DestObPtr) { // // BUGBUG -- what is this used for? // if (!(DestObPtr->ValueName)) { if (!SetRegistryValueName (DestObPtr, SrcObPtr->ValueName)) { DEBUGMSG ((DBG_VERBOSE, "CopyObject failed because SetRegistryValueName failed")); return fr; } } } #endif if (DestObPtr) { fr = CopySingleObject (SrcObPtr, DestObPtr, FilterFn, FilterArg); } DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "CopyObject: Filter in CopySingleObject failed")); } // // Other object coping not supported // else { DEBUGMSG (( DBG_WHOOPS, "CopyObject: Don't know how to copy object %s", DebugEncoder (SrcObPtr) )); } return fr; } VOID FreeRegistryKey ( PDATAOBJECT p ) { if (p->KeyPtr && (p->ObjectType & OT_REGISTRY)) { pFreeKeyProps (p->KeyPtr); p->KeyPtr = NULL; } } VOID FreeRegistryParentKey ( PDATAOBJECT p ) { if (p->ParentKeyPtr && (p->ObjectType & OT_REGISTRY)) { pFreeKeyProps (p->ParentKeyPtr); p->ParentKeyPtr = NULL; } } BOOL SetRegistryKey ( PDATAOBJECT p, PCTSTR Key ) { FreeRegistryKey (p); p->KeyPtr = pCreateKeyPropsFromString (Key, IsWin95Object (p)); if (!p->KeyPtr) { DEBUGMSG ((DBG_WARNING, "SetRegistryKey failed to create KEYPROPS struct")); return FALSE; } p->ObjectType |= OT_REGISTRY; return TRUE; } VOID FreeRegistryValueName ( PDATAOBJECT p ) { if (p->ValueName && p->ObjectType & OT_REGISTRY) { PoolMemReleaseMemory (g_TempPool, (PVOID) p->ValueName); p->ValueName = NULL; } } BOOL SetRegistryValueName ( PDATAOBJECT p, PCTSTR ValueName ) { FreeRegistryValueName (p); p->ValueName = PoolMemDuplicateString (g_TempPool, ValueName); if (!p->ValueName) { DEBUGMSG ((DBG_WARNING, "SetRegistryValueName failed to duplicate string")); return FALSE; } p->ObjectType |= OT_REGISTRY; return TRUE; } BOOL SetRegistryClass ( PDATAOBJECT p, PBYTE Class, DWORD ClassSize ) { FreeRegistryClass (p); p->Class.Buffer = PoolMemGetAlignedMemory (g_TempPool, ClassSize); if (p->Class.Buffer) { p->ObjectType |= OT_REGISTRY_CLASS|OT_REGISTRY; p->Class.Size = ClassSize; if (ClassSize) { CopyMemory (p->Class.Buffer, Class, ClassSize); } } else { p->ObjectType &= ~OT_REGISTRY_CLASS; DEBUGMSG ((DBG_WARNING, "SetRegistryClass failed to duplicate string")); return FALSE; } return TRUE; } VOID FreeRegistryClass ( PDATAOBJECT p ) { if (p->ObjectType & OT_REGISTRY_CLASS) { PoolMemReleaseMemory (g_TempPool, (PVOID) p->Class.Buffer); p->ObjectType &= ~OT_REGISTRY_CLASS; } } VOID SetRegistryType ( PDATAOBJECT p, DWORD Type ) { p->Type = Type; p->ObjectType |= OT_REGISTRY_TYPE|OT_REGISTRY; } BOOL SetPlatformType ( PDATAOBJECT p, BOOL Win95Type ) { if (Win95Type != IsWin95Object (p)) { // // We need to close the other platform valid handle. Otherwise // all subsequent operations will fail because we will try to // use an valid handle for a wrong platform. // CloseObject (p); // key type is changing to be the opposite platform, // so we have to create a duplicate key struct // (except for the platform being different) if (p->KeyPtr) { p->KeyPtr = pCreateDuplicateKeyProps (p->KeyPtr, Win95Type); if (!p->KeyPtr) { return FALSE; } } if (Win95Type) { p->ObjectType |= OT_WIN95; } else { p->ObjectType &= ~OT_WIN95; } FreeRegistryParentKey (p); } return TRUE; } BOOL ReadWin95ObjectString ( PCTSTR ObjectStr, PDATAOBJECT ObPtr ) { LONG rc = ERROR_INVALID_NAME; BOOL b = FALSE; if (!CreateObjectStruct (ObjectStr, ObPtr, WIN95OBJECT)) { rc = GetLastError(); DEBUGMSG ((DBG_ERROR, "Read Win95 Object String: %s is invalid", ObjectStr)); goto c0; } if (!ReadObject (ObPtr)) { rc = GetLastError(); if (rc == ERROR_FILE_NOT_FOUND || rc == ERROR_BADKEY) { rc = ERROR_SUCCESS; DEBUGMSG ((DBG_WARNING, "ReadWin95ObjectString: %s does not exist", ObjectStr)); } FreeObjectStruct (ObPtr); } else { b = TRUE; } c0: if (!b) { SetLastError (rc); } return b; } BOOL WriteWinNTObjectString ( PCTSTR ObjectStr, CPDATAOBJECT SrcObPtr ) { DATAOBJECT DestOb, TempOb; BOOL b = FALSE; // // 1. Create TempOb from destination object string // 2. Copy SrcObPtr to DestOb // 3. Override DestOb with any setting in TempOb // if (!CreateObjectStruct (ObjectStr, &TempOb, WINNTOBJECT)) { DEBUGMSG ((DBG_ERROR, "WriteWinNTObjectString: %s struct cannot be created", ObjectStr)); goto c0; } if (!DuplicateObjectStruct (&DestOb, SrcObPtr)) { goto c1; } if (!CombineObjectStructs (&DestOb, &TempOb)) { goto c2; } MYASSERT (!(DestOb.ObjectType & OT_VALUE)); MYASSERT (SrcObPtr->ObjectType & OT_VALUE); if (SrcObPtr->ObjectType & OT_REGISTRY_TYPE) { DestOb.ObjectType |= OT_REGISTRY_TYPE; DestOb.Type = SrcObPtr->Type; } ReplaceValue (&DestOb, SrcObPtr->Value.Buffer, SrcObPtr->Value.Size); if (!WriteObject (&DestOb)) { DEBUGMSG ((DBG_ERROR, "WriteWinNTObjectString: %s cannot be written", ObjectStr)); goto c2; } b = TRUE; c2: FreeObjectStruct (&DestOb); c1: FreeObjectStruct (&TempOb); c0: return b; } BOOL ReplaceValue ( PDATAOBJECT ObPtr, PBYTE NewValue, DWORD Size ) { FreeObjectVal (ObPtr); if (!AllocObjectVal (ObPtr, NewValue, Size, Size)) { return FALSE; } // Fix REG_SZ or REG_EXPAND_SZ pFixRegSzTermination (ObPtr); return TRUE; } BOOL GetDwordFromObject ( CPDATAOBJECT ObPtr, PDWORD DwordPtr OPTIONAL ) { DWORD d; if (DwordPtr) { *DwordPtr = 0; } if (!(ObPtr->ObjectType & OT_VALUE)) { if (!ReadObject (ObPtr)) { return FALSE; } } if (!(ObPtr->ObjectType & OT_REGISTRY_TYPE)) { return FALSE; } if (ObPtr->Type == REG_SZ) { d = _tcstoul ((PCTSTR) ObPtr->Value.Buffer, NULL, 10); } else if ( ObPtr->Type == REG_BINARY || ObPtr->Type == REG_NONE || ObPtr->Type == REG_DWORD ) { if (ObPtr->Value.Size != sizeof (DWORD)) { DEBUGMSG ((DBG_NAUSEA, "GetDwordFromObject: Value size is %u", ObPtr->Value.Size)); return FALSE; } d = *((PDWORD) ObPtr->Value.Buffer); } else { return FALSE; } if (DwordPtr) { *DwordPtr = d; } return TRUE; } PCTSTR GetStringFromObject ( CPDATAOBJECT ObPtr ) { PTSTR result; PTSTR resultPtr; UINT i; if (!(ObPtr->ObjectType & OT_VALUE)) { if (!ReadObject (ObPtr)) { return NULL; } } if (!(ObPtr->ObjectType & OT_REGISTRY_TYPE)) { return NULL; } if (ObPtr->Type == REG_SZ) { result = AllocPathString (ObPtr->Value.Size); _tcssafecpy (result, (PCTSTR) ObPtr->Value.Buffer, ObPtr->Value.Size / sizeof (TCHAR)); } else if (ObPtr->Type == REG_DWORD) { result = AllocPathString (11); wsprintf (result, TEXT("%lu"), *((PDWORD) ObPtr->Value.Buffer)); } else if (ObPtr->Type == REG_BINARY) { result = AllocPathString (ObPtr->Value.Size?(ObPtr->Value.Size * 3):1); resultPtr = result; *resultPtr = 0; for (i = 0; i < ObPtr->Value.Size; i++) { wsprintf (resultPtr, TEXT("%02X"), ObPtr->Value.Buffer[i]); resultPtr = GetEndOfString (resultPtr); if (i < ObPtr->Value.Size - 1) { _tcscat (resultPtr, TEXT(" ")); resultPtr = GetEndOfString (resultPtr); } } } else { return NULL; } return result; } FILTERRETURN pDeleteDataObjectFilter ( IN CPDATAOBJECT SrcObjectPtr, IN CPDATAOBJECT UnusedObPtr, OPTIONAL IN FILTERTYPE FilterType, IN PVOID UnusedArg OPTIONAL ) { if (FilterType == FILTER_KEY_ENUM) { DeleteDataObject (SrcObjectPtr); return FILTER_RETURN_DELETED; } return FILTER_RETURN_HANDLED; } BOOL DeleteDataObject ( IN PDATAOBJECT ObjectPtr ) { FILTERRETURN fr; DWORD rc; ObjectPtr->ObjectType |= OT_TREE; fr = CopyObject (ObjectPtr, NULL, pDeleteDataObjectFilter, NULL); if (fr != FILTER_RETURN_FAIL) { // // Perform deletion // if (ObjectPtr->KeyPtr) { CloseObject (ObjectPtr); if (IsWin95Object (ObjectPtr)) { DEBUGMSG ((DBG_WHOOPS, "CreateObject: Cannot delete a Win95 object (%s)", DebugEncoder (ObjectPtr))); return FALSE; } if (ObjectPtr->ParentKeyPtr && ObjectPtr->ParentKeyPtr->OpenKey && ObjectPtr->ChildKey) { rc = WinNTRegDeleteKey ( ObjectPtr->ParentKeyPtr->OpenKey, ObjectPtr->ChildKey ); if (rc == ERROR_ACCESS_DENIED) { LOG (( LOG_INFORMATION, "Access denied trying to delete %s in %s", ObjectPtr->ChildKey, ObjectPtr->ParentKeyPtr->KeyString )); rc = ERROR_SUCCESS; } } else { rc = WinNTRegDeleteKey ( pGetWinNTKey (GetRootKeyFromOffset (ObjectPtr->RootItem)), ObjectPtr->KeyPtr->KeyString ); if (rc == ERROR_ACCESS_DENIED) { LOG (( LOG_INFORMATION, "Access denied trying to delete %s", ObjectPtr->KeyPtr->KeyString )); rc = ERROR_SUCCESS; } } if (rc != ERROR_SUCCESS) { SetLastError (rc); LOG ((LOG_ERROR, "Failed to delete registry key")); return FALSE; } } } return fr != FILTER_RETURN_FAIL; } BOOL RenameDataObject ( IN CPDATAOBJECT SrcObPtr, IN CPDATAOBJECT DestObPtr ) { FILTERRETURN fr; // // Copy source to destination // fr = CopyObject (SrcObPtr, DestObPtr, NULL, NULL); if (fr == FILTER_RETURN_FAIL) { DEBUGMSG ((DBG_ERROR, "Rename Object: Could not copy source to destination")); return FALSE; } // // Delete source // if (!DeleteDataObject (SrcObPtr)) { DEBUGMSG ((DBG_ERROR, "Rename Object: Could not delete destination")); return FALSE; } return TRUE; } BOOL DeleteDataObjectValue( IN CPDATAOBJECT ObPtr ) { HKEY hKey; BOOL bResult; HKEY Parent; LONG rc; if(!ObPtr || !IsObjectRegistryKeyAndVal(ObPtr)){ MYASSERT(FALSE); return FALSE; } Parent = pGetWinNTKey (GetRootKeyFromOffset (ObPtr->RootItem)); if(NON_ROOT_KEY (Parent)){ MYASSERT(FALSE); return FALSE; } if(ERROR_SUCCESS != TrackedRegOpenKeyEx(Parent, ObPtr->KeyPtr->KeyString, 0, KEY_ALL_ACCESS, &hKey)){ MYASSERT(FALSE); return FALSE; } rc = WinNTRegDeleteValue(hKey, ObPtr->ValueName); bResult = (rc == ERROR_SUCCESS); if (rc == ERROR_ACCESS_DENIED) { LOG (( LOG_INFORMATION, "Access denied trying to delete %s in %s", ObPtr->KeyPtr->KeyString, ObPtr->ValueName )); bResult = TRUE; } CloseRegKey(hKey); return bResult; }