From 33ea79c7fe129c99a9f7117ffa22cca2aec067dd Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Wed, 9 May 2007 18:30:21 +0000 Subject: [PATCH] - Implement CmGetSystemControlValues and all related low-level Cm functionality required to select the proper control set and read all the kernel variables during Phase 0 initialization. We can now read time-zone data, version, suite, language IDs and other important kernel variables in the lowest-level boot phase. - New code uses cmlib from Filip Navara without any modification, and is fully compatible with reading Windows hives as well except XP's "Big value cells" (cells with > 2GB data) which aren't supported. - Create /config directory where the new Configuration Manager code lies. svn path=/trunk/; revision=26666 --- reactos/ntoskrnl/cm/newcm.c | 12 - reactos/ntoskrnl/config/cm.h | 968 +++++++++++++++++++++++++++++ reactos/ntoskrnl/config/cm_x.h | 143 +++++ reactos/ntoskrnl/config/cmboot.c | 127 ++++ reactos/ntoskrnl/config/cmcontrl.c | 262 ++++++++ reactos/ntoskrnl/config/cmdata.c | 718 +++++++++++++++++++++ reactos/ntoskrnl/config/cmindex.c | 646 +++++++++++++++++++ reactos/ntoskrnl/config/cmmapvw.c | 33 + reactos/ntoskrnl/config/cmname.c | 166 +++++ reactos/ntoskrnl/config/cmparse.c | 75 +++ reactos/ntoskrnl/config/cmsecach.c | 38 ++ reactos/ntoskrnl/config/cmvalue.c | 125 ++++ reactos/ntoskrnl/ntoskrnl.rbuild | 13 +- 13 files changed, 3312 insertions(+), 14 deletions(-) delete mode 100644 reactos/ntoskrnl/cm/newcm.c create mode 100644 reactos/ntoskrnl/config/cm.h create mode 100644 reactos/ntoskrnl/config/cm_x.h create mode 100644 reactos/ntoskrnl/config/cmboot.c create mode 100644 reactos/ntoskrnl/config/cmcontrl.c create mode 100644 reactos/ntoskrnl/config/cmdata.c create mode 100644 reactos/ntoskrnl/config/cmindex.c create mode 100644 reactos/ntoskrnl/config/cmmapvw.c create mode 100644 reactos/ntoskrnl/config/cmname.c create mode 100644 reactos/ntoskrnl/config/cmparse.c create mode 100644 reactos/ntoskrnl/config/cmsecach.c create mode 100644 reactos/ntoskrnl/config/cmvalue.c diff --git a/reactos/ntoskrnl/cm/newcm.c b/reactos/ntoskrnl/cm/newcm.c deleted file mode 100644 index 76ea69df9fb..00000000000 --- a/reactos/ntoskrnl/cm/newcm.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "ntoskrnl.h" -#include "cm.h" -#include "debug.h" - -VOID -NTAPI -CmGetSystemControlValues(IN PVOID SystemHiveData, - IN PCM_SYSTEM_CONTROL_VECTOR ControlVector) -{ - return; -} - diff --git a/reactos/ntoskrnl/config/cm.h b/reactos/ntoskrnl/config/cm.h new file mode 100644 index 00000000000..e1de9db4daf --- /dev/null +++ b/reactos/ntoskrnl/config/cm.h @@ -0,0 +1,968 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/cm/cm.h + * PURPOSE: Internal header for the Configuration Manager + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ +#define _CM_ +#include "cmlib.h" + +// +// Define this if you want debugging support +// +#define _CM_DEBUG_ 0x00 + +// +// These define the Debug Masks Supported +// +#define CM_HANDLE_DEBUG 0x01 +#define CM_NAMESPACE_DEBUG 0x02 +#define CM_SECURITY_DEBUG 0x04 +#define CM_REFERENCE_DEBUG 0x08 +#define CM_CALLBACK_DEBUG 0x10 + +// +// Debug/Tracing support +// +#if _CM_DEBUG_ +#ifdef NEW_DEBUG_SYSTEM_IMPLEMENTED // enable when Debug Filters are implemented +#define CMTRACE DbgPrintEx +#else +#define CMTRACE(x, ...) \ + if (x & CmpTraceLevel) DbgPrint(__VA_ARGS__) +#endif +#else +#define CMTRACE(x, ...) DPRINT(__VA_ARGS__) +#endif + +// +// Tag for all registry allocations +// +#define TAG_CM \ + TAG('C', 'm', ' ', ' ') + +// +// Hive operations +// +#define HINIT_CREATE 0 +#define HINIT_MEMORY 1 +#define HINIT_FILE 2 +#define HINIT_MEMORY_INPLACE 3 +#define HINIT_FLAT 4 +#define HINIT_MAPFILE 5 + +// +// Hive flags +// +#define HIVE_VOLATILE 1 +#define HIVE_NOLAZYFLUSH 2 + +// +// Hive types +// +#define HFILE_TYPE_PRIMARY 0 +#define HFILE_TYPE_ALTERNATE 1 +#define HFILE_TYPE_LOG 2 +#define HFILE_TYPE_EXTERNAL 3 +#define HFILE_TYPE_MAX 4 + +// +// Hive sizes +// +#define HBLOCK_SIZE 0x1000 +#define HSECTOR_SIZE 0x200 +#define HSECTOR_COUNT 8 + +// +// Hive versions +// +#define HSYS_MAJOR 1 +#define HSYS_MINOR 3 +#define HSYS_WHISTLER_BETA1 4 + +// +// Cell Masks +// +#define HCELL_NIL 0 +#define HCELL_CACHED 1 + +// +// Key Types +// +#define CM_KEY_INDEX_ROOT 0x6972 +#define CM_KEY_INDEX_LEAF 0x696c +#define CM_KEY_FAST_LEAF 0x666c +#define CM_KEY_HASH_LEAF 0x686c + +// +// CM_KEY_CONTROL_BLOCK Flags +// +#define CM_KCB_NO_SUBKEY 0x01 +#define CM_KCB_SUBKEY_ONE 0x02 +#define CM_KCB_SUBKEY_HINT 0x04 +#define CM_KCB_SYM_LINK_FOUND 0x08 +#define CM_KCB_KEY_NON_EXIST 0x10 +#define CM_KCB_NO_DELAY_CLOSE 0x20 +#define CM_KCB_INVALID_CACHED_INFO 0x40 +#define CM_KEY_READ_ONLY_KEY 0x80 + +// +// CM_KEY_NODE Signature and Flags +// +#define CM_KEY_NODE_SIGNATURE 0x6B6E +#define CM_LINK_NODE_SIGNATURE 0x6B6C +#define KEY_IS_VOLATILE 0x01 +#define KEY_HIVE_EXIT 0x02 +#define KEY_HIVE_ENTRY 0x04 +#define KEY_NO_DELETE 0x08 +#define KEY_SYM_LINK 0x10 +#define KEY_COMP_NAME 0x20 +#define KEY_PREFEF_HANDLE 0x40 +#define KEY_VIRT_MIRRORED 0x80 +#define KEY_VIRT_TARGET 0x100 +#define KEY_VIRTUAL_STORE 0x200 + +// +// CM_KEY_VALUE Signature and Flags +// +#define CM_KEY_VALUE_SIGNATURE 0x6b76 +#define CM_KEY_VALUE_SMALL 0x4 +#define CM_KEY_VALUE_BIG 0x3FD8 +#define CM_KEY_VALUE_SPECIAL_SIZE 0x80000000 +#define VALUE_COMP_NAME 0x0001 + +// +// Number of various lists and hashes +// +#define CMP_SECURITY_HASH_LISTS 64 +#define CMP_MAX_CALLBACKS 100 + +// +// Hashing Constants +// +#define CMP_HASH_IRRATIONAL 314159269 +#define CMP_HASH_PRIME 1000000007 + +// +// CmpCreateKcb Flags +// +#define CMP_CREATE_FAKE_KCB 0x1 +#define CMP_LOCK_HASHES_FOR_KCB 0x2 + +// +// Number of items that can fit inside an Allocation Page +// +#define CM_KCBS_PER_PAGE \ + PAGE_SIZE / sizeof(CM_KEY_CONTROL_BLOCK) +#define CM_DELAYS_PER_PAGE \ + PAGE_SIZE / sizeof(CM_DELAYED_CLOSE_ENTRY) + +// +// Key Hash +// +typedef struct _CM_KEY_HASH +{ + ULONG ConvKey; + struct _CM_KEY_HASH *NextHash; + PHHIVE KeyHive; + HCELL_INDEX KeyCell; +} CM_KEY_HASH, *PCM_KEY_HASH; + +// +// Key Hash Table Entry +// +typedef struct _CM_KEY_HASH_TABLE_ENTRY +{ + EX_PUSH_LOCK Lock; + PKTHREAD Owner; + PCM_KEY_HASH Entry; +} CM_KEY_HASH_TABLE_ENTRY, *PCM_KEY_HASH_TABLE_ENTRY; + +// +// Name Hash +// +typedef struct _CM_NAME_HASH +{ + ULONG ConvKey; + struct _CM_NAME_HASH *NextHash; + USHORT NameLength; + WCHAR Name[ANYSIZE_ARRAY]; +} CM_NAME_HASH, *PCM_NAME_HASH; + +// +// Name Hash Table Entry +// +typedef struct _CM_NAME_HASH_TABLE_ENTRY +{ + EX_PUSH_LOCK Lock; + PCM_NAME_HASH Entry; +} CM_NAME_HASH_TABLE_ENTRY, *PCM_NAME_HASH_TABLE_ENTRY; + +// +// Key Security Cache +// +typedef struct _CM_KEY_SECURITY_CACHE +{ + HCELL_INDEX Cell; + ULONG ConvKey; + LIST_ENTRY List; + ULONG DescriptorLength; + SECURITY_DESCRIPTOR_RELATIVE Descriptor; +} CM_KEY_SECURITY_CACHE, *PCM_KEY_SECURITY_CACHE; + +// +// Key Security Cache Entry +// +typedef struct _CM_KEY_SECURITY_CACHE_ENTRY +{ + HCELL_INDEX Cell; + PCM_KEY_SECURITY_CACHE CachedSecurity; +} CM_KEY_SECURITY_CACHE_ENTRY, *PCM_KEY_SECURITY_CACHE_ENTRY; + +// +// Cached Child List +// +typedef struct _CACHED_CHILD_LIST +{ + ULONG Count; + union + { + ULONG ValueList; + struct _CM_KEY_CONTROL_BLOCK *RealKcb; + }; +} CACHED_CHILD_LIST, *PCACHED_CHILD_LIST; + +// +// Index Hint Block +// +typedef struct _CM_INDEX_HINT_BLOCK +{ + ULONG Count; + ULONG HashKey[ANYSIZE_ARRAY]; +} CM_INDEX_HINT_BLOCK, *PCM_INDEX_HINT_BLOCK; + +// +// Key Reference +// +typedef struct _CM_KEY_REFERENCE +{ + HCELL_INDEX KeyCell; + PHHIVE KeyHive; +} CM_KEY_REFERENCE, *PCM_KEY_REFERENCE; + +// +// Key Body +// +typedef struct _CM_KEY_BODY +{ + ULONG Type; + struct _CM_KEY_CONTROL_BLOCK *KeyControlBlock; + struct _CM_NOTIFY_BLOCK *NotifyBlock; + HANDLE ProcessID; + ULONG Callers; + PVOID CallerAddress[10]; + LIST_ENTRY KeyBodyList; +} CM_KEY_BODY, *PCM_KEY_BODY; + +// +// Name Control Block (NCB) +// +typedef struct _CM_NAME_CONTROL_BLOCK +{ + BOOLEAN Compressed; + USHORT RefCount; + union + { + CM_NAME_HASH NameHash; + struct + { + ULONG ConvKey; + PCM_KEY_HASH NextHash; + USHORT NameLength; + WCHAR Name[ANYSIZE_ARRAY]; + }; + }; +} CM_NAME_CONTROL_BLOCK, *PCM_NAME_CONTROL_BLOCK; + +// +// Key Control Block (KCB) +// +typedef struct _CM_KEY_CONTROL_BLOCK +{ + USHORT RefCount; + USHORT Flags; + ULONG ExtFlags:8; + ULONG PrivateAlloc:1; + ULONG Delete:1; + ULONG DelayedCloseIndex:12; + ULONG TotalLevels:10; + union + { + CM_KEY_HASH KeyHash; + struct + { + ULONG ConvKey; + PCM_KEY_HASH NextHash; + PHHIVE KeyHive; + HCELL_INDEX KeyCell; + }; + }; + struct _CM_KEY_CONTROL_BLOCK *ParentKcb; + PCM_NAME_CONTROL_BLOCK NameBlock; + PCM_KEY_SECURITY_CACHE CachedSecurity; + CACHED_CHILD_LIST ValueCache; + PCM_INDEX_HINT_BLOCK IndexHint; + ULONG HashKey; + ULONG SubKeyCount; + union + { + LIST_ENTRY KeyBodyListHead; + LIST_ENTRY FreeListEntry; + }; + PCM_KEY_BODY KeyBodyArray[4]; + PVOID DelayCloseEntry; + LARGE_INTEGER KcbLastWriteTime; + USHORT KcbMaxNameLen; + USHORT KcbMaxValueNameLen; + ULONG KcbMaxValueDataLen; + ULONG InDelayClose; +} CM_KEY_CONTROL_BLOCK, *PCM_KEY_CONTROL_BLOCK; + +// +// Notify Block +// +typedef struct _CM_NOTIFY_BLOCK +{ + LIST_ENTRY HiveList; + LIST_ENTRY PostList; + PCM_KEY_CONTROL_BLOCK KeyControlBlock; + PCM_KEY_BODY KeyBody; + ULONG Filter:29; + ULONG WatchTree:30; + ULONG NotifyPending:31; +} CM_NOTIFY_BLOCK, *PCM_NOTIFY_BLOCK; + +// +// Re-map Block +// +typedef struct _CM_CELL_REMAP_BLOCK +{ + HCELL_INDEX OldCell; + HCELL_INDEX NewCell; +} CM_CELL_REMAP_BLOCK, *PCM_CELL_REMAP_BLOCK; + +// +// Allocation Page +// +typedef struct _CM_ALLOC_PAGE +{ + ULONG FreeCount; + ULONG Reserved; + PVOID AllocPage; +} CM_ALLOC_PAGE, *PCM_ALLOC_PAGE; + +// +// Delayed Close Entry +// +typedef struct _CM_DELAYED_CLOSE_ENTRY +{ + LIST_ENTRY DelayedLRUList; + PCM_KEY_CONTROL_BLOCK KeyControlBlock; +} CM_DELAYED_CLOSE_ENTRY, *PCM_DELAYED_CLOSE_ENTRY; + +// +// Delayed KCB Dereference Entry +// +typedef struct _CM_DELAY_DEREF_KCB_ITEM +{ + LIST_ENTRY ListEntry; + PCM_KEY_CONTROL_BLOCK Kcb; +} CM_DELAY_DEREF_KCB_ITEM, *PCM_DELAY_DEREF_KCB_ITEM; + +// +// Use Count Log and Entry +// +typedef struct _CM_USE_COUNT_LOG_ENTRY +{ + HCELL_INDEX Cell; + PVOID Stack[7]; +} CM_USE_COUNT_LOG_ENTRY, *PCM_USE_COUNT_LOG_ENTRY; + +typedef struct _CM_USE_COUNT_LOG +{ + USHORT Next; + USHORT Size; + CM_USE_COUNT_LOG_ENTRY Log[32]; +} CM_USE_COUNT_LOG, *PCM_USE_COUNT_LOG; + +// +// Configuration Manager Hive Structure +// +typedef struct _CMHIVE +{ + HHIVE Hive; + HANDLE FileHandles[3]; + LIST_ENTRY NotifyList; + LIST_ENTRY HiveList; + EX_PUSH_LOCK HiveLock; + PKTHREAD HiveLockOwner; + PKGUARDED_MUTEX ViewLock; + PKTHREAD ViewLockOwner; + EX_PUSH_LOCK WriterLock; + PKTHREAD WriterLockOwner; + PERESOURCE FlusherLock; + EX_PUSH_LOCK SecurityLock; + PKTHREAD HiveSecurityLockOwner; + LIST_ENTRY LRUViewListHead; + LIST_ENTRY PinViewListHead; + PFILE_OBJECT FileObject; + UNICODE_STRING FileFullPath; + UNICODE_STRING FileUserName; + USHORT MappedViews; + USHORT PinnedViews; + ULONG UseCount; + ULONG SecurityCount; + ULONG SecurityCacheSize; + LONG SecurityHitHint; + PCM_KEY_SECURITY_CACHE_ENTRY SecurityCache; + LIST_ENTRY SecurityHash[CMP_SECURITY_HASH_LISTS]; + PKEVENT UnloadEvent; + PCM_KEY_CONTROL_BLOCK RootKcb; + BOOLEAN Frozen; + PWORK_QUEUE_ITEM UnloadWorkItem; + BOOLEAN GrowOnlyMode; + ULONG GrowOffset; + LIST_ENTRY KcbConvertListHead; + LIST_ENTRY KnodeConvertListHead; + PCM_CELL_REMAP_BLOCK CellRemapArray; + CM_USE_COUNT_LOG UseCountLog; + CM_USE_COUNT_LOG LockHiveLog; + ULONG Flags; + LIST_ENTRY TrustClassEntry; + ULONG FlushCount; + BOOLEAN HiveIsLoading; + PKTHREAD CreatorOwner; +} CMHIVE, *PCMHIVE; + +#include + +typedef struct _CM_VIEW_OF_FILE +{ + LIST_ENTRY LRUViewList; + LIST_ENTRY PinViewList; + ULONG FileOffset; + ULONG Size; + PULONG ViewAddress; + PVOID Bcb; + ULONG UseCount; +} CM_VIEW_OF_FILE, *PCM_VIEW_OF_FILE; + +typedef struct _CHILD_LIST +{ + ULONG Count; + HCELL_INDEX List; +} CHILD_LIST, *PCHILD_LIST; + +typedef struct _CM_KEY_NODE +{ + USHORT Id; + USHORT Flags; + LARGE_INTEGER LastWriteTime; + ULONG Spare; + HCELL_INDEX Parent; + ULONG SubKeyCounts[HvMaxStorageType]; + HCELL_INDEX SubKeyLists[HvMaxStorageType]; + CHILD_LIST ValueList; + HCELL_INDEX SecurityKeyOffset; + HCELL_INDEX ClassNameOffset; + ULONG MaxNameLen; + ULONG MaxClassLen; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + ULONG WorkVar; + USHORT NameLength; + USHORT ClassSize; + WCHAR Name[0]; +} CM_KEY_NODE, *PCM_KEY_NODE; + +typedef struct _VALUE_LIST_CELL +{ + HCELL_INDEX ValueOffset[0]; +} VALUE_LIST_CELL, *PVALUE_LIST_CELL; + +typedef struct _CM_KEY_VALUE +{ + USHORT Signature; // "kv" + USHORT NameLength; // length of Name + ULONG DataLength; // length of datas in the cell pointed by DataOffset + HCELL_INDEX Data;// datas are here if high bit of DataSize is set + ULONG Type; + USHORT Flags; + USHORT Unused1; + WCHAR Name[0]; /* warning : not zero terminated */ +} CM_KEY_VALUE, *PCM_KEY_VALUE; + +typedef struct _CM_KEY_SECURITY +{ + USHORT Signature; // "sk" + USHORT Reserved; + HCELL_INDEX Flink; + HCELL_INDEX Blink; + ULONG ReferenceCount; + ULONG DescriptorLength; + //SECURITY_DESCRIPTOR_RELATIVE Descriptor; + UCHAR Data[0]; +} CM_KEY_SECURITY, *PCM_KEY_SECURITY; + +#include + +// +// Generic Index Entry +// +typedef struct _CM_INDEX +{ + HCELL_INDEX Cell; + union + { + UCHAR NameHint[4]; + ULONG HashKey; + }; +} CM_INDEX, *PCM_INDEX; + +// +// Key Index +// +typedef struct _CM_KEY_INDEX +{ + USHORT Signature; + USHORT Count; + HCELL_INDEX List[ANYSIZE_ARRAY]; +} CM_KEY_INDEX, *PCM_KEY_INDEX; + +// +// Fast/Hash Key Index +// +typedef struct _CM_KEY_FAST_INDEX +{ + USHORT Signature; + USHORT Count; + CM_INDEX List[ANYSIZE_ARRAY]; +} CM_KEY_FAST_INDEX, *PCM_KEY_FAST_INDEX; + +// +// Cell Data +// +typedef struct _CELL_DATA +{ + union + { + CM_KEY_NODE KeyNode; + CM_KEY_VALUE KeyValue; + CM_KEY_SECURITY KeySecurity; + CM_KEY_INDEX KeyIndex; + HCELL_INDEX KeyList[ANYSIZE_ARRAY]; + WCHAR KeyString[ANYSIZE_ARRAY]; + } u; +} CELL_DATA, *PCELL_DATA; + +// +// Cached Value Index +// +typedef struct _CM_CACHED_VALUE_INDEX +{ + HCELL_INDEX CellIndex; + union + { + CELL_DATA CellData; + ULONG_PTR List[ANYSIZE_ARRAY]; + } Data; +} CM_CACHED_VALUE_INDEX, *PCM_CACHED_VALUE_INDEX; + +// +// Cached Value +// +typedef struct _CM_CACHED_VALUE +{ + USHORT DataCacheType; + USHORT ValueKeySize; + CM_KEY_VALUE KeyValue; +} CM_CACHED_VALUE, *PCM_CACHED_VALUE; + +// +// Hive List Entry +// +typedef struct _HIVE_LIST_ENTRY +{ + PWCHAR FileName; + PWCHAR BaseName; + PWCHAR RegRootName; + PCMHIVE CmHive; + ULONG HHiveFlags; + ULONG CmHiveFlags; + PCMHIVE CmHive2; + BOOLEAN ThreadFinished; + BOOLEAN ThreadStarted; + BOOLEAN Allocate; + BOOLEAN WinPERequired; +} HIVE_LIST_ENTRY, *PHIVE_LIST_ENTRY; + +// +// Parse context for Key Object +// +typedef struct _CM_PARSE_CONTEXT +{ + ULONG TitleIndex; + UNICODE_STRING Class; + ULONG CreateOptions; + ULONG Disposition; + CM_KEY_REFERENCE ChildHive; + BOOLEAN CreateLink; + BOOLEAN Flag2; + HANDLE PredefinedHandle; + ULONG PostActions; +} CM_PARSE_CONTEXT, *PCM_PARSE_CONTEXT; + +// +// System Control Vector +// +typedef struct _CM_SYSTEM_CONTROL_VECTOR +{ + PWCHAR KeyPath; + PWCHAR ValueName; + PVOID Buffer; + PULONG BufferLength; + PULONG Type; +} CM_SYSTEM_CONTROL_VECTOR, *PCM_SYSTEM_CONTROL_VECTOR; + +// +// Mapped View Hive Functions +// +VOID +NTAPI +CmpInitHiveViewList( + IN PCMHIVE Hive +); + +// +// Security Cache Functions +// +VOID +NTAPI +CmpInitSecurityCache( + IN PCMHIVE Hive +); + +// +// Registry Validation Functions +// +BOOLEAN +NTAPI +CmCheckRegistry( + IN PCMHIVE Hive, + IN BOOLEAN CleanFlag +); + +// +// Notification Routines +// +VOID +CmpReportNotify( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN PHHIVE Hive, + IN HCELL_INDEX Cell, + IN ULONG Filter +); + +// +// KCB Cache/Delay Routines +// +VOID +NTAPI +CmpInitializeCache( + VOID +); + +VOID +NTAPI +CmpInitializeCmAllocations( + VOID +); + +VOID +NTAPI +CmpInitializeKcbDelayedDeref( + VOID +); + +// +// Key Object Routines +// +VOID +NTAPI +CmpCloseKeyObject( + IN PEPROCESS Process OPTIONAL, + IN PVOID Object, + IN ACCESS_MASK GrantedAccess, + IN ULONG ProcessHandleCount, + IN ULONG SystemHandleCount +); + +VOID +NTAPI +CmpDeleteKeyObject( + IN PVOID Object +); + +NTSTATUS +NTAPI +CmpParseKey( + IN PVOID ParseObject, + IN PVOID ObjectType, + IN OUT PACCESS_STATE AccessState, + IN KPROCESSOR_MODE AccessMode, + IN ULONG Attributes, + IN OUT PUNICODE_STRING CompleteName, + IN OUT PUNICODE_STRING RemainingName, + IN OUT PVOID Context OPTIONAL, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, + OUT PVOID *Object +); + +NTSTATUS +NTAPI +CmpSecurityMethod( + IN PVOID Object, + IN SECURITY_OPERATION_CODE OperationType, + IN PSECURITY_INFORMATION SecurityInformation, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PULONG CapturedLength, + IN OUT PSECURITY_DESCRIPTOR *ObjectSecurityDescriptor, + IN POOL_TYPE PoolType, + IN PGENERIC_MAPPING GenericMapping +); + +NTSTATUS +NTAPI +CmpQueryKeyName( + IN PVOID Object, + IN BOOLEAN HasObjectName, + OUT POBJECT_NAME_INFORMATION ObjectNameInfo, + IN ULONG Length, + OUT PULONG ReturnLength, + IN KPROCESSOR_MODE AccessMode +); + +// +// Hive Routines +// +NTSTATUS +NTAPI +CmpInitializeHive( + OUT PCMHIVE *CmHive, + IN ULONG Operation, + IN ULONG Flags, + IN ULONG FileType, + IN PVOID HiveData, + IN HANDLE Primary, + IN HANDLE Alternate, + IN HANDLE Log, + IN HANDLE External, + IN PUNICODE_STRING FileName +); + +PSECURITY_DESCRIPTOR +NTAPI +CmpHiveRootSecurityDescriptor( + VOID +); + +NTSTATUS +NTAPI +CmpLinkHiveToMaster( + IN PUNICODE_STRING LinkName, + IN HANDLE RootDirectory, + IN PCMHIVE CmHive, + IN BOOLEAN Allocate, + IN PSECURITY_DESCRIPTOR SecurityDescriptor +); + +// +// Registry Utility Functions +// +BOOLEAN +NTAPI +CmpTestRegistryLockExclusive( + VOID +); + +VOID +NTAPI +CmpLockRegistryExclusive( + VOID +); + +VOID +NTAPI +CmpUnlockRegistry( + VOID +); + +PVOID +NTAPI +CmpAllocateDelayItem( + VOID +); + +VOID +NTAPI +CmpFreeDelayItem( + PVOID Entry +); + +// +// KCB Functions +// +PCM_KEY_CONTROL_BLOCK +NTAPI +CmpCreateKcb( + IN PHHIVE Hive, + IN HCELL_INDEX Index, + IN PCM_KEY_NODE Node, + IN PCM_KEY_CONTROL_BLOCK Parent, + IN ULONG Flags, + IN PUNICODE_STRING KeyName +); + +VOID +NTAPI +CmpDereferenceKcbWithLock( + IN PCM_KEY_CONTROL_BLOCK Kcb, + IN BOOLEAN LockHeldExclusively +); + +// +// Name Functions +// +LONG +NTAPI +CmpCompareCompressedName( + IN PUNICODE_STRING SearchName, + IN PWCHAR CompressedName, + IN ULONG NameLength +); + +USHORT +NTAPI +CmpNameSize( + IN PHHIVE Hive, + IN PUNICODE_STRING Name +); + +USHORT +NTAPI +CmpCopyName( + IN PHHIVE Hive, + IN PWCHAR Destination, + IN PUNICODE_STRING Source +); + +BOOLEAN +NTAPI +CmpFindNameInList( + IN PHHIVE Hive, + IN PCHILD_LIST ChildList, + IN PUNICODE_STRING Name, + IN PULONG ChildIndex, + IN PHCELL_INDEX CellIndex +); + +// +// Parse Routines +// +BOOLEAN +NTAPI +CmpGetNextName( + IN OUT PUNICODE_STRING RemainingName, + OUT PUNICODE_STRING NextName, + OUT PBOOLEAN LastName +); + +// +// Flush Routines +// +BOOLEAN +NTAPI +CmpFlushEntireRegistry( + IN BOOLEAN ForceFlush +); + +// +// Cell Index Routines +// +HCELL_INDEX +NTAPI +CmpFindSubKeyByName( + IN PHHIVE Hive, + IN PCM_KEY_NODE Parent, + IN PUNICODE_STRING SearchName +); + +// +// Cell Value Routines +// +HCELL_INDEX +NTAPI +CmpFindValueByName( + IN PHHIVE Hive, + IN PCM_KEY_NODE KeyNode, + IN PUNICODE_STRING Name +); + +PCELL_DATA +NTAPI +CmpValueToData( + IN PHHIVE Hive, + IN PCM_KEY_VALUE Value, + OUT PULONG Length +); + +// +// Boot Routines +// +HCELL_INDEX +NTAPI +CmpFindControlSet( + IN PHHIVE SystemHive, + IN HCELL_INDEX RootCell, + IN PUNICODE_STRING SelectKeyName, + OUT PBOOLEAN AutoSelect +); + +// +// Global variables accessible from all of Cm +// +extern BOOLEAN CmpSpecialBootCondition; +extern BOOLEAN CmpFlushOnLockRelease; +extern EX_PUSH_LOCK CmpHiveListHeadLock; +extern LIST_ENTRY CmpHiveListHead; +extern POBJECT_TYPE CmpKeyObjectType; +extern ERESOURCE CmpRegistryLock; +extern PCM_KEY_HASH_TABLE_ENTRY *CmpCacheTable; +extern PCM_NAME_HASH_TABLE_ENTRY *CmpNameCacheTable; +extern KGUARDED_MUTEX CmpDelayedCloseTableLock; +extern CMHIVE CmControlHive; +extern WCHAR CmDefaultLanguageId[]; +extern ULONG CmDefaultLanguageIdLength; +extern ULONG CmDefaultLanguageIdType; +extern WCHAR CmInstallUILanguageId[]; +extern ULONG CmInstallUILanguageIdLength; +extern ULONG CmInstallUILanguageIdType; +extern LANGID PsInstallUILanguageId; +extern LANGID PsDefaultUILanguageId; +extern CM_SYSTEM_CONTROL_VECTOR CmControlVector[]; + +// +// Inlined functions +// +#include "cm_x.h" diff --git a/reactos/ntoskrnl/config/cm_x.h b/reactos/ntoskrnl/config/cm_x.h new file mode 100644 index 00000000000..35500c310bc --- /dev/null +++ b/reactos/ntoskrnl/config/cm_x.h @@ -0,0 +1,143 @@ +/* +* PROJECT: ReactOS Kernel +* LICENSE: GPL - See COPYING in the top level directory +* FILE: ntoskrnl/cm/cm_x.h +* PURPOSE: Inlined Functions for the Configuration Manager +* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) +*/ + +// +// Returns whether or not this is a small valued key +// +BOOLEAN +FORCEINLINE +CmpIsKeyValueSmall(OUT PULONG RealLength, + IN ULONG Length) +{ + /* Check if the length has the special size value */ + if (Length >= CM_KEY_VALUE_SPECIAL_SIZE) + { + /* It does, so this is a small key: return the real length */ + *RealLength = Length - CM_KEY_VALUE_SPECIAL_SIZE; + return TRUE; + } + + /* This is not a small key, return the length we read */ + *RealLength = Length; + return FALSE; +} + +// +// Returns whether or not this is a big valued key +// +BOOLEAN +FORCEINLINE +CmpIsKeyValueBig(IN PHHIVE Hive, + IN ULONG Length) +{ + /* Check if the hive is XP Beta 1 or newer */ + if (Hive->Version >= HSYS_WHISTLER_BETA1) + { + /* Check if the key length is valid for a big value key */ + if ((Length < CM_KEY_VALUE_SPECIAL_SIZE) && (Length > CM_KEY_VALUE_BIG)) + { + /* Yes, this value is big */ + return TRUE; + } + } + + /* Not a big value key */ + return FALSE; +} + +// +// Returns the hashkey corresponding to a convkey +// +#define GET_HASH_KEY(ConvKey) \ + ((CMP_HASH_IRRATIONAL * (ConvKey)) % CMP_HASH_PRIME) + +// +// Returns the index into the hash table, or the entry itself +// +#define GET_HASH_INDEX(ConvKey) \ + GET_HASH_KEY(ConvKey) % CmpHashTableSize +#define GET_HASH_ENTRY(Table, ConvKey) \ + (*Table[GET_HASH_INDEX(ConvKey)]) + +// +// Returns whether or not the cell is cached +// +#define CMP_IS_CELL_CACHED(c) \ + (((c) & HCELL_CACHED) && ((c) != HCELL_NIL)) + +// +// Return data from a cached cell +// +#define CMP_GET_CACHED_CELL(c) \ + (ULONG_PTR)((c) & ~HCELL_CACHED) +#define CMP_GET_CACHED_DATA(c) \ + (&(((PCM_CACHED_VALUE_INDEX)(CMP_GET_CACHED_CELL(c)))->Data.CellData)) +#define CMP_GET_CACHED_INDEX(c) \ + (&(((PCM_CACHED_ENTRY)(CMP_GET_CACHED_CELL(c)))->CellIndex)) +#define CMP_GET_CACHED_VALUE(c) \ + (&(((PCM_CACHED_VALUE)(CMP_GET_CACHED_CELL(c)))->KeyValue)) + +// +// Makes sure that the registry is locked +// +#define CMP_ASSERT_REGISTRY_LOCK() \ + ASSERT((CmpSpecialBootCondition == TRUE) || \ + (CmpTestRegistryLock() == TRUE)) + +// +// Makes sure that the registry is exclusively locked +// +#define CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK() \ + ASSERT((CmpSpecialBootCondition == TRUE) || \ + (CmpTestRegistryLockExclusive() == TRUE)) + +// +// Checks if a KCB is exclusively locked +// +#define CmpIsKcbLockedExclusive(k) \ + (GET_HASH_ENTRY(CmpCacheTable, \ + (k)->ConvKey).Owner == KeGetCurrentThread()) + +// +// Exclusively acquires a KCB +// +#define CmpAcquireKcbLockExclusive(k) \ +{ \ + ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpCacheTable, \ + (k)->ConvKey).Lock); \ + GET_HASH_ENTRY(CmpCacheTable, \ + (k)->ConvKey).Owner = KeGetCurrentThread(); \ +} + +// +// Releases an exlusively or shared acquired KCB +// +#define CmpReleaseKcbLock(k) \ +{ \ + GET_HASH_ENTRY(CmpCacheTable, (k)->ConvKey).Owner = NULL; \ + ExReleasePushLock(&GET_HASH_ENTRY(CmpCacheTable, \ + (k)->ConvKey).Lock); \ +} + +// +// Exclusively acquires an NCB +// +#define CmpAcquireNcbLockExclusive(n) \ +{ \ + ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpNameCacheTable, \ + (n)->ConvKey).Lock); \ +} + +// +// Releases an exlusively or shared acquired NCB +// +#define CmpReleaseNcbLock(k) \ +{ \ + ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \ + (k)->ConvKey).Lock); \ +} diff --git a/reactos/ntoskrnl/config/cmboot.c b/reactos/ntoskrnl/config/cmboot.c new file mode 100644 index 00000000000..6ac1f22bb35 --- /dev/null +++ b/reactos/ntoskrnl/config/cmboot.c @@ -0,0 +1,127 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmboot.c + * PURPOSE: Configuration Manager - Boot Initialization + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#include "cm.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +HCELL_INDEX +NTAPI +CmpFindControlSet(IN PHHIVE SystemHive, + IN HCELL_INDEX RootCell, + IN PUNICODE_STRING SelectKeyName, + OUT PBOOLEAN AutoSelect) +{ + UNICODE_STRING KeyName; + PCM_KEY_NODE Node; + HCELL_INDEX SelectCell, AutoSelectCell, SelectValueCell, ControlSetCell; + HCELL_INDEX CurrentValueCell; + PCM_KEY_VALUE KeyValue; + ULONG Length; + PULONG ControlSetId; + ANSI_STRING ControlSetAnsiName; + CHAR Buffer[128]; + WCHAR WideBuffer[128]; + NTSTATUS Status; + PULONG CurrentData; + + /* Sanity check */ + ASSERT(SystemHive->ReleaseCellRoutine == NULL); + + /* Get the Select subkey */ + RtlInitUnicodeString(&KeyName, L"select"); + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell); + if (!Node) return HCELL_NIL; + SelectCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); + if (SelectCell == HCELL_NIL) return SelectCell; + + /* Get AutoSelect value */ + RtlInitUnicodeString(&KeyName, L"AutoSelect"); + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); + if (!Node) return HCELL_NIL; + AutoSelectCell = CmpFindValueByName(SystemHive, Node, &KeyName); + if (AutoSelectCell == HCELL_NIL) + { + /* Assume TRUE if the value is missing. */ + *AutoSelect = TRUE; + } + else + { + /* Read the value */ + KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, AutoSelectCell); + if (KeyValue == NULL) return HCELL_NIL; + + /* Convert it to a boolean */ + *AutoSelect = *(PBOOLEAN)CmpValueToData(SystemHive, KeyValue, &Length); + } + + /* Now find the control set being looked up */ + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); + if (!Node) return HCELL_NIL; + SelectValueCell = CmpFindValueByName(SystemHive, Node, SelectKeyName); + if (SelectValueCell == HCELL_NIL) return SelectValueCell; + + /* Read the value (corresponding to the CCS ID) */ + KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, SelectValueCell); + if (!KeyValue) return HCELL_NIL; + if (KeyValue->Type != REG_DWORD) return HCELL_NIL; + ControlSetId = (PULONG)CmpValueToData(SystemHive, KeyValue, &Length); + + /* Now build an Ansi String for the CCS's Name */ + sprintf(Buffer, "ControlSet%03lu", *ControlSetId); + ControlSetAnsiName.Length = (USHORT)strlen(Buffer); + ControlSetAnsiName.MaximumLength = (USHORT)strlen(Buffer); + ControlSetAnsiName.Buffer = Buffer; + + /* And convert it to Unicode... */ + KeyName.MaximumLength = 256; + KeyName.Buffer = WideBuffer; + Status = RtlAnsiStringToUnicodeString(&KeyName, + &ControlSetAnsiName, + FALSE); + if (!NT_SUCCESS(Status)) return HCELL_NIL; + + /* Now open it */ + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, RootCell); + if (!Node) return HCELL_NIL; + ControlSetCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); + if (ControlSetCell == HCELL_NIL) return ControlSetCell; + + /* Get the value of the "Current" CCS */ + RtlInitUnicodeString(&KeyName, L"Current"); + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, SelectCell); + if (!Node) return HCELL_NIL; + CurrentValueCell = CmpFindValueByName(SystemHive, Node, &KeyName); + + /* Make sure it exists */ + if (CurrentValueCell != HCELL_NIL) + { + /* Get the current value and make sure its a ULONG */ + KeyValue = (PCM_KEY_VALUE)HvGetCell(SystemHive, CurrentValueCell); + if (!KeyValue) return HCELL_NIL; + if (KeyValue->Type == REG_DWORD) + { + /* Get the data and update it */ + CurrentData = (PULONG)CmpValueToData(SystemHive, + KeyValue, + &Length); + if (!CurrentData) return HCELL_NIL; + *CurrentData = *ControlSetId; + } + } + + /* Return the CCS Cell */ + return ControlSetCell; +} diff --git a/reactos/ntoskrnl/config/cmcontrl.c b/reactos/ntoskrnl/config/cmcontrl.c new file mode 100644 index 00000000000..8d261282b52 --- /dev/null +++ b/reactos/ntoskrnl/config/cmcontrl.c @@ -0,0 +1,262 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmcontrl.c + * PURPOSE: Configuration Manager - Control Set Management + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#include "cm.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +LANGID +NTAPI +CmpConvertLangId(IN LPWSTR Name, + IN ULONG NameLength) +{ + ULONG i; + WCHAR p; + LANGID LangId = 0; + ULONG IdCode; + + /* Convert the length in chars and loop */ + NameLength = NameLength / sizeof(WCHAR); + for (i = 0; i < NameLength; i++) + { + /* Get the character */ + p = Name[i]; + + /* Handle each case */ + if ((p >= L'0') && (p <= L'9')) + { + /* Handle digits*/ + IdCode = p - L'0'; + } + else if ((p >= L'A') && (p <= L'F')) + { + /* Handle upper-case letters */ + IdCode = p - L'A' + 10; + } + else if ((p >= L'a') && (p <= L'f')) + { + /* Handle lower-case letters */ + IdCode = p - L'a' + 10; + } + else + { + /* Unhandled case, return what we have till now */ + break; + } + + /* If the ID Code is >= 16, then we're done */ + if (IdCode >= 16) break; + + /* Build the Language ID */ + LangId = (LangId << 4) | (LANGID)IdCode; + } + + /* Return the Language ID */ + return LangId; +} + +HCELL_INDEX +NTAPI +CmpWalkPath(IN PHHIVE SystemHive, + IN HCELL_INDEX ParentCell, + IN LPWSTR Path) +{ + UNICODE_STRING UnicodePath, NextName; + BOOLEAN LastName; + HCELL_INDEX CurrentCell = ParentCell; + PCM_KEY_NODE Node; + + /* We shouldn't have a release routine at this point */ + ASSERT(SystemHive->ReleaseCellRoutine == NULL); + + /* Initialize the Unicode path and start looping */ + RtlInitUnicodeString(&UnicodePath, Path); + while (TRUE) + { + /* Get the next name */ + CmpGetNextName(&UnicodePath, &NextName, &LastName); + if (!NextName.Length) return CurrentCell; + + /* Get the subkey */ + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, CurrentCell); + if (!Node) return HCELL_NIL; + CurrentCell = CmpFindSubKeyByName(SystemHive, Node, &NextName); + if (CurrentCell == HCELL_NIL) return CurrentCell; + } +} + +VOID +NTAPI +CmGetSystemControlValues(IN PVOID SystemHiveData, + IN PCM_SYSTEM_CONTROL_VECTOR ControlVector) +{ + PHHIVE SystemHive = (PHHIVE)&CmControlHive; + NTSTATUS Status; + HCELL_INDEX RootCell, BaseCell, KeyCell, ValueCell; + ULONG Length, DataSize; + PCM_KEY_NODE Node; + PCM_KEY_VALUE ValueData; + UNICODE_STRING KeyName; + BOOLEAN Auto, IsSmallKey; + PVOID Buffer; + + /* Initialize the Hive View List and the security cache */ + RtlZeroMemory(SystemHive, sizeof(SystemHive)); + CmpInitHiveViewList((PCMHIVE)SystemHive); + CmpInitSecurityCache((PCMHIVE)SystemHive); + + /* Initialize the Hive */ + Status = HvInitialize(SystemHive, + HINIT_MEMORY_INPLACE, /* FIXME: Should be flat */ + HIVE_VOLATILE, + HFILE_TYPE_PRIMARY, + (ULONG_PTR)SystemHiveData, + 1, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + if (!NT_SUCCESS(Status)) KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 1, 1, 0, 0); + + /* Sanity check, flat hives don't have release routines */ + ASSERT(SystemHive->ReleaseCellRoutine == NULL); + + /* FIXME: Prepare it */ + CmPrepareHive(SystemHive); + + /* Set the Root Cell */ + RootCell = ((PHBASE_BLOCK)SystemHiveData)->RootCell; + + /* Find the current control set */ + RtlInitUnicodeString(&KeyName, L"current"); + BaseCell = CmpFindControlSet(SystemHive, RootCell, &KeyName, &Auto); + if (BaseCell == HCELL_NIL) KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 1, 2, 0, 0); + + /* Find the control subkey */ + RtlInitUnicodeString(&KeyName, L"control"); + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, BaseCell); + BaseCell = CmpFindSubKeyByName(SystemHive, Node, &KeyName); + if (BaseCell == HCELL_NIL) KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO,1 , 3, 0, 0); + + /* Loop each key */ + while (ControlVector->KeyPath) + { + /* Assume failure */ + Length = -1; + + /* Get the cell for this key */ + KeyCell = CmpWalkPath(SystemHive, BaseCell, ControlVector->KeyPath); + if (KeyCell != HCELL_NIL) + { + /* Now get the cell for the value */ + RtlInitUnicodeString(&KeyName, ControlVector->ValueName); + Node = (PCM_KEY_NODE)HvGetCell(SystemHive, KeyCell); + ValueCell = CmpFindValueByName(SystemHive, Node, &KeyName); + if (ValueCell != HCELL_NIL) + { + /* Check if there's any data */ + if (!ControlVector->BufferLength) + { + /* No, the buffer will only be large enough for a ULONG */ + DataSize = sizeof(ULONG); + } + else + { + /* Yes, save the data size */ + DataSize = *ControlVector->BufferLength; + } + + /* Get the actual data */ + ValueData = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell); + + /* Check if this is a small key */ + IsSmallKey = CmpIsKeyValueSmall(&Length, ValueData->DataLength); + + /* If the length is bigger then our buffer, normalize it */ + if (DataSize < Length) Length = DataSize; + + /* Make sure we have some data */ + if (Length > 0) + { + /* Check if this was a small key */ + if (IsSmallKey) + { + /* The buffer is directly safe to read */ + Buffer = (PVOID)(&(ValueData->Data)); + } + else + { + /* Use the longer path */ + Buffer = (PVOID)HvGetCell(SystemHive, ValueData->Data); + } + + /* Sanity check if this is a small key */ + ASSERT((IsSmallKey ? + (Length <= CM_KEY_VALUE_SMALL) : TRUE)); + + /* Copy the data in the buffer */ + RtlCopyMemory(ControlVector->Buffer, Buffer, Length); + } + + /* Check if we should return the data type */ + if (ControlVector->Type) + { + /* Return the type that we read */ + *ControlVector->Type = ValueData->Type; + } + } + } + + /* Return the size that we read */ + if (ControlVector->BufferLength) *ControlVector->BufferLength = Length; + + /* Go to the next entry */ + ControlVector++; + } + + /* Check if the ID is in the registry */ + if (CmDefaultLanguageIdType == REG_SZ) + { + /* Read it */ + PsDefaultSystemLocaleId = + (LCID)CmpConvertLangId(CmDefaultLanguageId, + CmDefaultLanguageIdLength); + } + else + { + /* Use EN_US by default */ + PsDefaultSystemLocaleId = 0x409; + } + + /* Check if the ID Is in the registry */ + if (CmInstallUILanguageIdType == REG_SZ) + { + /* Read it */ + PsInstallUILanguageId = CmpConvertLangId(CmInstallUILanguageId, + CmInstallUILanguageIdLength); + } + else + { + /* Otherwise, use the default */ + PsInstallUILanguageId = LANGIDFROMLCID(PsDefaultSystemLocaleId); + } + + /* Set the defaults for the Thread UI */ + PsDefaultThreadLocaleId = PsDefaultSystemLocaleId; + PsDefaultUILanguageId = PsInstallUILanguageId; +} diff --git a/reactos/ntoskrnl/config/cmdata.c b/reactos/ntoskrnl/config/cmdata.c new file mode 100644 index 00000000000..2335f68142c --- /dev/null +++ b/reactos/ntoskrnl/config/cmdata.c @@ -0,0 +1,718 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmdata.c + * PURPOSE: Configuration Manager - Global Configuration Data + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#include "cm.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +ULONG DummyData; +ULONG CmNtGlobalFlag; +ULONG CmNtCSDVersion; + +WCHAR CmDefaultLanguageId[12]; +ULONG CmDefaultLanguageIdLength = sizeof(CmDefaultLanguageId); +ULONG CmDefaultLanguageIdType; + +WCHAR CmInstallUILanguageId[12]; +ULONG CmInstallUILanguageIdLength = sizeof(CmInstallUILanguageId); +ULONG CmInstallUILanguageIdType; + +WCHAR CmSuiteBuffer[128]; +ULONG CmSuiteBufferLength = sizeof(CmSuiteBuffer); +ULONG CmSuiteBufferType; + +CMHIVE CmControlHive; + +CM_SYSTEM_CONTROL_VECTOR CmControlVector[] = +{ + { + L"Session Manager", + L"ProtectionMode", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"ObjectSecurityMode", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"LUIDDeviceMapsDisabled", + &DummyData, + NULL, + NULL + }, + + { + L"LSA", + L"AuditBaseDirectories", + &DummyData, + NULL, + NULL + }, + + { + L"LSA", + L"AuditBaseObjects", + &DummyData, + NULL, + NULL + }, + + { + L"LSA\\audit", + L"ProcessAccessesToAudit", + &DummyData, + NULL, + NULL + }, + + { + L"TimeZoneInformation", + L"ActiveTimeBias", + &DummyData, + NULL, + NULL + }, + + { + L"TimeZoneInformation", + L"Bias", + &DummyData, + NULL, + NULL + }, + + { + L"TimeZoneInformation", + L"RealTimeIsUniversal", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"GlobalFlag", + &CmNtGlobalFlag, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PagedPoolQuota", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"NonPagedPoolQuota", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PagingFileQuota", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"AllocationPreference", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"DynamicMemory", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"Mirroring", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"Mirroring", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SystemViewSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SessionViewSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SessionImageSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SessionPoolSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PoolUsageMaximum", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"MapAllocationFragment", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PagedPoolSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"NonPagedPoolSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"NonPagedPoolMaximumPercent", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"LargeSystemCache", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"LargeStackSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SystemPages", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"LowMemoryThreshold", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"HighMemoryThreshold", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"DisablePagingExecutive", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"ModifiedPageLife", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SecondLevelDataCache", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"ClearPageFileAtShutdown", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PoolTagSmallTableSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PoolTagBigTableSize", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PoolTag", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"PoolTagOverruns", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"SnapUnloads", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"ProtectNonPagedPool", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"TrackLockedPages", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"TrackPtes", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"VerifyDrivers", + &DummyData, + &DummyData, + &DummyData + }, + + { + L"Session Manager\\Memory Management", + L"VerifyDriverLevel", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"VerifyMode", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"LargePageMinimum", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"EnforceWriteProtection", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"MakeLowMemory", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Memory Management", + L"WriteWatch", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Executive", + L"AdditionalCriticalWorkerThreads", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Executive", + L"AdditionalDelayedWorkerThreads", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Executive", + L"PriorityQuantumMatrix", + &DummyData, + &DummyData, + NULL + }, + + { + L"Session Manager\\Kernel", + L"DpcQueueDepth", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Kernel", + L"MinimumDpcRate", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Kernel", + L"AdjustDpcThreshold", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Kernel", + L"IdealDpcRate", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\I/O System", + L"CountOperations", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\I/O System", + L"LargeIrpStackLocations", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\I/O System", + L"IoVerifierLevel", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"ResourceTimeoutCount", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"CriticalSectionTimeout", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"HeapSegmentReserve", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"HeapSegmentCommit", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"HeapDeCommitTotalFreeThreshold", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"HeapDeCommitFreeBlockThreshold", + &DummyData, + NULL, + NULL + }, + + { + L"ProductOptions", + L"ProductType", + &DummyData, + NULL, + NULL + }, + + { + L"Terminal Server", + L"TSEnabled", + &DummyData, + NULL, + NULL + }, + + { + L"Terminal Server", + L"TSAppCompat", + &DummyData, + NULL, + NULL + }, + + + { + L"ProductOptions", + L"ProductSuite", + CmSuiteBuffer, + &CmSuiteBufferLength, + &CmSuiteBufferType + }, + + { + L"Windows", + L"CSDVersion", + &CmNtCSDVersion, + NULL, + NULL + }, + + { + L"Nls\\Language", + L"Default", + CmDefaultLanguageId, + &CmDefaultLanguageIdLength, + &CmDefaultLanguageIdType + }, + + { + L"Nls\\Language", + L"InstallLanguage", + CmInstallUILanguageId, + &CmInstallUILanguageIdLength, + &CmInstallUILanguageIdType + }, + + { + L"\0\0", + L"RegistrySizeLimit", + &DummyData, + &DummyData, + &DummyData + }, + + { + L"Session Manager", + L"ForceNpxEmulation", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"PowerPolicySimulate", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager\\Executive", + L"MaxTimeSeparationBeforeCorrect", + &DummyData, + NULL, + NULL + }, + + { + L"Windows", + L"ShutdownTime", + &DummyData, + &DummyData, + NULL + }, + + { + L"PriorityControl", + L"Win32PrioritySeparation", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"EnableTimerWatchdog", + &DummyData, + NULL, + NULL + }, + + { + L"Session Manager", + L"Debugger Retries", + &DummyData, + NULL, + NULL + }, + + { + L"WMI", + L"MaxEventSize", + &DummyData, + NULL, + NULL + }, + + { + L"WMI\\Trace", + L"UsePerformanceClock", + &DummyData, + NULL, + NULL + }, + + { + L"WMI\\Trace", + L"TraceAlignment", + &DummyData, + NULL, + NULL + }, + + { + NULL, + NULL, + NULL, + NULL, + NULL + } +}; diff --git a/reactos/ntoskrnl/config/cmindex.c b/reactos/ntoskrnl/config/cmindex.c new file mode 100644 index 00000000000..f39b8860f3c --- /dev/null +++ b/reactos/ntoskrnl/config/cmindex.c @@ -0,0 +1,646 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmindex.c + * PURPOSE: Configuration Manager - Cell Indexes + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#include "cm.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +LONG +NTAPI +CmpDoCompareKeyName(IN PHHIVE Hive, + IN PUNICODE_STRING SearchName, + IN HCELL_INDEX Cell) +{ + PCM_KEY_NODE Node; + UNICODE_STRING KeyName; + LONG Result; + + /* Get the node */ + Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); + if (!Node) return 2; + + /* Check if it's compressed */ + if (Node->Flags & KEY_COMP_NAME) + { + /* Compare compressed names */ + Result = CmpCompareCompressedName(SearchName, + Node->Name, + Node->NameLength); + } + else + { + /* Compare the Unicode name directly */ + KeyName.Buffer = Node->Name; + KeyName.Length = Node->NameLength; + KeyName.MaximumLength = KeyName.Length; + Result = RtlCompareUnicodeString(SearchName, &KeyName, TRUE); + } + + /* Release the cell and return the normalized result */ + HvReleaseCell(Hive, Cell); + return (Result == 0) ? Result : ((Result > 0) ? 1 : -1); +} + +LONG +NTAPI +CmpCompareInIndex(IN PHHIVE Hive, + IN PUNICODE_STRING SearchName, + IN ULONG Count, + IN PCM_KEY_INDEX Index, + IN PHCELL_INDEX SubKey) +{ + PCM_KEY_FAST_INDEX FastIndex; + PCM_INDEX FastEntry; + LONG Result; + ULONG i; + ULONG ActualNameLength = 4, CompareLength, NameLength; + WCHAR p, pp; + + /* Assume failure */ + *SubKey = HCELL_NIL; + + /* Check if we are a fast or hashed leaf */ + if ((Index->Signature == CM_KEY_FAST_LEAF) || + (Index->Signature == CM_KEY_HASH_LEAF)) + { + /* Get the Fast/Hash Index */ + FastIndex = (PCM_KEY_FAST_INDEX)Index; + FastEntry = &FastIndex->List[Count]; + + /* Check if we are a hash leaf, in which case we skip all this */ + if (Index->Signature == CM_KEY_FAST_LEAF) + { + /* Find out just how much of the name is there */ + for (i = 0; i < 4; i++) + { + /* Check if this entry is empty */ + if (!FastEntry->NameHint[i]) + { + /* Only this much! */ + ActualNameLength = i; + break; + } + } + + /* How large is the name and how many characters to compare */ + NameLength = SearchName->Length / sizeof(WCHAR); + CompareLength = min(NameLength, ActualNameLength); + + /* Loop all the chars we'll test */ + for (i = 0; i < CompareLength; i++) + { + /* Get one char from each buffer */ + p = SearchName->Buffer[i]; + pp = FastEntry->NameHint[i]; + + /* See if they match and return result if they don't */ + Result = (LONG)RtlUpcaseUnicodeChar(p) - + (LONG)RtlUpcaseUnicodeChar(pp); + if (Result) return (Result > 0) ? 1 : -1; + } + } + + /* If we got here then we have to do a full compare */ + Result = CmpDoCompareKeyName(Hive, SearchName, FastEntry->Cell); + if (Result == 2) return Result; + if (!Result) *SubKey = FastEntry->Cell; + } + else + { + /* We aren't, so do a name compare and return the subkey found */ + Result = CmpDoCompareKeyName(Hive, SearchName, Index->List[Count]); + if (Result == 2) return Result; + if (!Result) *SubKey = Index->List[Count]; + } + + /* Return the comparison result */ + return Result; +} + +ULONG +NTAPI +CmpFindSubKeyInRoot(IN PHHIVE Hive, + IN PCM_KEY_INDEX Index, + IN PUNICODE_STRING SearchName, + IN PHCELL_INDEX SubKey) +{ + ULONG High, Low = 0, i, ReturnIndex; + HCELL_INDEX LeafCell; + PCM_KEY_INDEX Leaf; + LONG Result; + + /* Verify Index for validity */ + ASSERTMSG("We don't do a linear search yet!\n", FALSE); + ASSERT(Index->Count != 0); + ASSERT(Index->Signature == CM_KEY_INDEX_ROOT); + + /* Set high limit and loop */ + High = Index->Count - 1; + while (TRUE) + { + /* Choose next entry */ + i = ((High - Low) / 2) + Low; + + /* Get the leaf cell and then the leaf itself */ + LeafCell = Index->List[i]; + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (Leaf) + { + /* Make sure the leaf is valid */ + ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) || + (Leaf->Signature == CM_KEY_FAST_LEAF) || + (Leaf->Signature == CM_KEY_HASH_LEAF)); + ASSERT(Leaf->Count != 0); + + /* Do the compare */ + Result = CmpCompareInIndex(Hive, + SearchName, + Leaf->Count - 1, + Leaf, + SubKey); + if (Result == 2) goto Big; + + /* Check if we found the leaf */ + if (!Result) + { + /* We found the leaf */ + *SubKey = LeafCell; + ReturnIndex = i; + goto Return; + } + + /* Check for negative result */ + if (Result < 0) + { + /* If we got here, we should be at -1 */ + ASSERT(Result == -1); + + /* Do another lookup, since we might still be in the right leaf */ + Result = CmpCompareInIndex(Hive, + SearchName, + 0, + Leaf, + SubKey); + if (Result == 2) goto Big; + + /* Check if it's not below */ + if (Result >= 0) + { + /* + * If the name was first below, and now it is above, + * then this means that it is somewhere in this leaf. + * Make sure we didn't get some weird result + */ + ASSERT((Result == 1) || (Result == 0)); + + /* Return it */ + *SubKey = LeafCell; + ReturnIndex = Low; + goto Return; + } + + /* Update the limit to this index, since we know it's not higher. */ + High = i; + } + else + { + /* Update the base to this index, since we know it's not lower. */ + Low = i; + } + } + else + { +Big: + /* This was some sort of special key */ + ReturnIndex = 0x80000000; + goto ReturnFailure; + } + + /* Check if there is only one entry left */ + if ((High - Low) <= 1) break; + + /* Release the leaf cell */ + HvReleaseCell(Hive, LeafCell); + } + + /* Make sure we got here for the right reasons */ + ASSERT((High - Low == 1) || (High == Low)); + + /* Get the leaf cell and the leaf */ + LeafCell = Index->List[Low]; + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (!Leaf) goto Big; + + /* Do the compare */ + Result = CmpCompareInIndex(Hive, + SearchName, + Leaf->Count-1, + Leaf, + SubKey); + if (Result == 2) goto Big; + + /* Check if we found it */ + if (!Result) + { + /* We got lucky...return it */ + *SubKey = LeafCell; + ReturnIndex = Low; + goto Return; + } + + /* It's below, so could still be in this leaf */ + if (Result < 0) + { + /* Make sure we're -1 */ + ASSERT(Result == -1); + + /* Do a search from the bottom */ + Result = CmpCompareInIndex(Hive, SearchName, 0, Leaf, SubKey); + if (Result == 2) goto Big; + + /* + * Check if it's above, which means that it's within the ranges of our + * leaf (since we were below before). + */ + if (Result >= 0) + { + /* Sanity check */ + ASSERT((Result == 1) || (Result == 0)); + + /* Yep, so we're in the right leaf; return it. */ + *SubKey = LeafCell; + ReturnIndex = Low; + goto Return; + } + + /* It's still below us, so fail */ + ReturnIndex = Low; + goto ReturnFailure; + } + + /* Release the leaf cell */ + HvReleaseCell(Hive, LeafCell); + + /* Well the low didn't work too well, so try the high. */ + LeafCell = Index->List[High]; + Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); + if (!Leaf) goto Big; + + /* Do the compare */ + Result = CmpCompareInIndex(Hive, + SearchName, + Leaf->Count - 1, + Leaf, + SubKey); + if (Result == 2) goto Big; + + /* Check if we found it */ + if (Result == 0) + { + /* We got lucky... return it */ + *SubKey = LeafCell; + ReturnIndex = High; + goto Return; + } + + /* Check if we are too high */ + if (Result < 0) + { + /* Make sure we're -1 */ + ASSERT(Result == -1); + + /* + * Once again... since we were first too low and now too high, then + * this means we are within the range of this leaf... return it. + */ + *SubKey = LeafCell; + ReturnIndex = High; + goto Return; + } + + /* If we got here, then we are too low, again. */ + ReturnIndex = High; + + /* Failure path */ +ReturnFailure: + *SubKey = HCELL_NIL; + + /* Return path...check if we have a leaf to free */ +Return: + if (Leaf) HvReleaseCell(Hive, LeafCell); + + /* Return the index */ + return ReturnIndex; +} + +ULONG +NTAPI +CmpFindSubKeyInLeaf(IN PHHIVE Hive, + IN PCM_KEY_INDEX Index, + IN PUNICODE_STRING SearchName, + IN PHCELL_INDEX SubKey) +{ + ULONG High, Low = 0, i; + LONG Result; + + /* Verify Index for validity */ + ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) || + (Index->Signature == CM_KEY_FAST_LEAF) || + (Index->Signature == CM_KEY_HASH_LEAF)); + + /* Get the upper bound and middle entry */ + High = Index->Count - 1; +#ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED + i = High / 2; +#else + i = 0; +#endif + + /* Check if we don't actually have any entries */ + if (!Index->Count) + { + /* Return failure */ + *SubKey = HCELL_NIL; + return 0; + } + + /* Start compare loop */ + while (TRUE) + { + /* Do the actual comparison and check the result */ + Result = CmpCompareInIndex(Hive, SearchName, i, Index, SubKey); + if (Result == 2) + { + /* Fail with special value */ + *SubKey = HCELL_NIL; + return 0x80000000; + } + + /* Check if we got lucky and found it */ + if (!Result) return i; + + /* Check if the result is below us */ + if (Result < 0) + { + /* Set the new bound; it can't be higher then where we are now. */ + ASSERT(Result == -1); + High = i; + } + else + { + /* Set the new bound... it can't be lower then where we are now. */ + ASSERT(Result == 1); + Low = i; + } + +#ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED + /* Check if this is the last entry, if so, break out and handle it */ + if ((High - Low) <= 1) break; + + /* Set the new index */ + i = ((High - Low) / 2) + Low; +#else + if (++i > High) + { + /* Return failure */ + *SubKey = HCELL_NIL; + return 0; + } +#endif + } + + /* + * If we get here, High - Low = 1 or High == Low + * Simply look first at Low, then at High + */ + Result = CmpCompareInIndex(Hive, SearchName, Low, Index, SubKey); + if (Result == 2) + { + /* Fail with special value */ + *SubKey = HCELL_NIL; + return 0x80000000; + } + + /* Check if we got lucky and found it */ + if (!Result) return Low; + + /* Check if the result is below us */ + if (Result < 0) + { + /* Return the low entry */ + ASSERT(Result == -1); + return Low; + } + + /* + * If we got here, then just check the high and return it no matter what + * the result is (since we're a leaf, it has to be near there anyway). + */ + Result = CmpCompareInIndex(Hive, SearchName, High, Index, SubKey); + if (Result == 2) + { + /* Fail with special value */ + *SubKey = HCELL_NIL; + return 0x80000000; + } + + /* Return the high */ + return High; +} + +ULONG +NTAPI +CmpComputeHashKey(IN ULONG Hash, + IN PUNICODE_STRING Name, + IN BOOLEAN AllowSeparators) +{ + LPWSTR Cp; + ULONG Value, i; + + /* Make some sanity checks on our parameters */ + ASSERT((Name->Length == 0) || + (AllowSeparators) || + (Name->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)); + + /* If the name is empty, there is nothing to hash! */ + if (!Name->Length) return Hash; + + /* Set the buffer and loop every character */ + Cp = Name->Buffer; + for (i = 0; i < Name->Length; i += sizeof(WCHAR), Cp++) + { + /* Make sure we don't have a separator when we shouldn't */ + ASSERT(AllowSeparators || (*Cp != OBJ_NAME_PATH_SEPARATOR)); + + /* Check what kind of char we have */ + if (*Cp >= L'a') + { + /* In the lower case region... is it truly lower case? */ + if (*Cp < L'z') + { + /* Yes! Calculate it ourselves! */ + Value = *Cp - L'a' + L'A'; + } + else + { + /* No, use the API */ + Value = RtlUpcaseUnicodeChar(*Cp); + } + } + else + { + /* Reuse the char, it's already upcased */ + Value = *Cp; + } + + /* Multiply by a prime and add our value */ + Hash *= 37; + Hash += Value; + } + + /* Return the hash */ + return Hash; +} + +HCELL_INDEX +NTAPI +CmpFindSubKeyByHash(IN PHHIVE Hive, + IN PCM_KEY_FAST_INDEX FastIndex, + IN PUNICODE_STRING SearchName) +{ + ULONG HashKey, i; + PCM_INDEX FastEntry; + + /* Make sure it's really a hash */ + ASSERT(FastIndex->Signature == CM_KEY_HASH_LEAF); + + /* Compute the hash key for the name */ + HashKey = CmpComputeHashKey(0, SearchName, FALSE); + + /* Loop all the entries */ + for (i = 0; i < FastIndex->Count; i++) + { + /* Get the entry */ + FastEntry = &FastIndex->List[i]; + + /* Compare the hash first */ + if (FastEntry->HashKey == HashKey) + { + /* Go ahead for a full compare */ + if (!(CmpDoCompareKeyName(Hive, SearchName, FastEntry->Cell))) + { + /* It matched, return the cell */ + return FastEntry->Cell; + } + } + } + + /* If we got here then we failed */ + return HCELL_NIL; +} + +HCELL_INDEX +NTAPI +CmpFindSubKeyByName(IN PHHIVE Hive, + IN PCM_KEY_NODE Parent, + IN PUNICODE_STRING SearchName) +{ + ULONG i; + PCM_KEY_INDEX IndexRoot; + HCELL_INDEX SubKey, CellToRelease; + ULONG Found; + + /* Loop each storage type */ + for (i = 0; i < Hive->StorageTypeCount; i++) + { + /* Make sure the parent node has subkeys */ + if (Parent->SubKeyCounts[i]) + { + /* Get the Index */ + IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, Parent->SubKeyLists[i]); +#if 0 + /* Make sure we have one and that the cell is allocated */ + ASSERT((IndexRoot == NULL) || + HvIsCellAllocated(Hive, Parent->SubKeyLists[i])); +#endif + /* Fail if we don't actually have an index root */ + if (!IndexRoot) return HCELL_NIL; + + /* Get the cell we'll need to release */ + CellToRelease = Parent->SubKeyLists[i]; + + /* Check if this is another index root */ + if (IndexRoot->Signature == CM_KEY_INDEX_ROOT) + { + /* Lookup the name in the root */ + Found = CmpFindSubKeyInRoot(Hive, + IndexRoot, + SearchName, + &SubKey); + + /* Release the previous cell */ + ASSERT(CellToRelease != HCELL_NIL); + HvReleaseCell(Hive, CellToRelease); + + /* Make sure we found something valid */ + if (Found < 0) break; + + /* Get the new Index Root and set the new cell to be released */ + if (SubKey == HCELL_NIL) continue; + CellToRelease = SubKey; + IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, SubKey); + } + + /* Make sure the signature is what we expect it to be */ + ASSERT((IndexRoot->Signature == CM_KEY_INDEX_LEAF) || + (IndexRoot->Signature == CM_KEY_FAST_LEAF) || + (IndexRoot->Signature == CM_KEY_HASH_LEAF)); + + /* Check if this isn't a hashed leaf */ + if (IndexRoot->Signature != CM_KEY_HASH_LEAF) + { + /* Find the subkey in the leaf */ + Found = CmpFindSubKeyInLeaf(Hive, + IndexRoot, + SearchName, + &SubKey); + + /* Release the previous cell */ + ASSERT(CellToRelease != HCELL_NIL); + HvReleaseCell(Hive, CellToRelease); + + /* Make sure we found a valid index */ + if (Found < 0) break; + } + else + { + /* Find the subkey in the hash */ + SubKey = CmpFindSubKeyByHash(Hive, + (PCM_KEY_FAST_INDEX)IndexRoot, + SearchName); + + /* Release the previous cell */ + ASSERT(CellToRelease != HCELL_NIL); + HvReleaseCell(Hive, CellToRelease); + } + + /* Make sure we got a valid subkey and return it */ + if (SubKey != HCELL_NIL) return SubKey; + } + } + + /* If we got here, then we failed */ + return HCELL_NIL; +} diff --git a/reactos/ntoskrnl/config/cmmapvw.c b/reactos/ntoskrnl/config/cmmapvw.c new file mode 100644 index 00000000000..ae5009e1f66 --- /dev/null +++ b/reactos/ntoskrnl/config/cmmapvw.c @@ -0,0 +1,33 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmmapvw.c + * PURPOSE: Configuration Manager - Map-Viewed Hive Support + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#include "cm.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +CmpInitHiveViewList(IN PCMHIVE Hive) +{ + /* Initialize the list heads */ + InitializeListHead(&Hive->LRUViewListHead); + InitializeListHead(&Hive->PinViewListHead); + + /* Reset data */ + Hive->MappedViews = 0; + Hive->PinnedViews = 0; + Hive->UseCount = 0; +} + diff --git a/reactos/ntoskrnl/config/cmname.c b/reactos/ntoskrnl/config/cmname.c new file mode 100644 index 00000000000..7affc6f6a83 --- /dev/null +++ b/reactos/ntoskrnl/config/cmname.c @@ -0,0 +1,166 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmname.c + * PURPOSE: Configuration Manager - Name Management + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#include "cm.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +LONG +NTAPI +CmpCompareCompressedName(IN PUNICODE_STRING SearchName, + IN PWCHAR CompressedName, + IN ULONG NameLength) +{ + WCHAR *p; + CHAR *pp; + WCHAR p1, p2; + USHORT SearchLength; + LONG Result; + + /* Set the pointers and length and then loop */ + p = SearchName->Buffer; + pp = (PCHAR)CompressedName; + SearchLength = (SearchName->Length / sizeof(WCHAR)); + while ((SearchLength) && (NameLength)) + { + /* Get the characters */ + p1 = *p++; + p2 = (WCHAR)(*pp++); + + /* Check if we have a direct match */ + if (p1 != p2) + { + /* See if they match and return result if they don't */ + Result = (LONG)RtlUpcaseUnicodeChar(p1) - + (LONG)RtlUpcaseUnicodeChar(p2); + if (Result) return Result; + } + + /* Next chars */ + SearchLength--; + NameLength--; + } + + /* Return the difference directly */ + return SearchLength - NameLength; +} + +BOOLEAN +NTAPI +CmpFindNameInList(IN PHHIVE Hive, + IN PCHILD_LIST ChildList, + IN PUNICODE_STRING Name, + IN PULONG ChildIndex, + IN PHCELL_INDEX CellIndex) +{ + PCELL_DATA CellData; + HCELL_INDEX CellToRelease = HCELL_NIL; + ULONG i; + PCM_KEY_VALUE KeyValue; + LONG Result; + UNICODE_STRING SearchName; + BOOLEAN Success; + + /* Make sure there's actually something on the list */ + if (ChildList->Count != 0) + { + /* Get the cell data */ + CellData = (PCELL_DATA)HvGetCell(Hive, ChildList->List); + if (!CellData) + { + /* Couldn't get the cell... tell the caller */ + *CellIndex = HCELL_NIL; + return FALSE; + } + + /* Now loop every entry */ + for (i = 0; i < ChildList->Count; i++) + { + /* Check if we have a cell to release */ + if (CellToRelease != HCELL_NIL) + { + /* Release it */ + HvReleaseCell(Hive, CellToRelease); + CellToRelease = HCELL_NIL; + } + + /* Get this value */ + KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, CellData->u.KeyList[i]); + if (!KeyValue) + { + /* Return with no data found */ + *CellIndex = HCELL_NIL; + Success = FALSE; + goto Return; + } + + /* Save the cell to release */ + CellToRelease = CellData->u.KeyList[i]; + + /* Check if it's a compressed value name */ + if (KeyValue->Flags & VALUE_COMP_NAME) + { + /* Use the compressed name check */ + Result = CmpCompareCompressedName(Name, + KeyValue->Name, + KeyValue->NameLength); + } + else + { + /* Setup the Unicode string */ + SearchName.Length = KeyValue->NameLength; + SearchName.MaximumLength = SearchName.Length; + SearchName.Buffer = KeyValue->Name; + Result = RtlCompareUnicodeString(Name, &SearchName, TRUE); + } + + /* Check if we found it */ + if (!Result) + { + /* We did...return info to caller */ + if (ChildIndex) *ChildIndex = i; + *CellIndex = CellData->u.KeyList[i]; + + /* Set success state */ + Success = TRUE; + goto Return; + } + } + + /* Got to the end of the list */ + if (ChildIndex) *ChildIndex = i; + *CellIndex = HCELL_NIL; + + /* Nothing found if we got here */ + Success = TRUE; + goto Return; + } + + /* Nothing found...check if the caller wanted more info */ + ASSERT(ChildList->Count == 0); + if (ChildIndex) *ChildIndex = 0; + *CellIndex = HCELL_NIL; + + /* Nothing found if we got here */ + return TRUE; + +Return: + /* Release the first cell we got */ + if (CellData) HvReleaseCell(Hive, ChildList->List); + + /* Release the secondary one, if we have one */ + if (CellToRelease) HvReleaseCell(Hive, CellToRelease); + return Success; +} diff --git a/reactos/ntoskrnl/config/cmparse.c b/reactos/ntoskrnl/config/cmparse.c new file mode 100644 index 00000000000..e1773781795 --- /dev/null +++ b/reactos/ntoskrnl/config/cmparse.c @@ -0,0 +1,75 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmparse.c + * PURPOSE: Configuration Manager - Object Manager Parse Interface + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#include "cm.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +BOOLEAN +NTAPI +CmpGetNextName(IN OUT PUNICODE_STRING RemainingName, + OUT PUNICODE_STRING NextName, + OUT PBOOLEAN LastName) +{ + BOOLEAN NameValid = TRUE; + + /* Check if there's nothing left in the name */ + if (!(RemainingName->Buffer) || + (!RemainingName->Length) || + !(*RemainingName->Buffer)) + { + /* Clear the next name and set this as last */ + *LastName = TRUE; + NextName->Buffer = NULL; + NextName->Length = 0; + return TRUE; + } + + /* Check if we have a path separator */ + if (*RemainingName->Buffer == OBJ_NAME_PATH_SEPARATOR) + { + /* Skip it */ + RemainingName->Buffer++; + RemainingName->Length -= sizeof(WCHAR); + RemainingName->MaximumLength -= sizeof(WCHAR); + } + + /* Start loop at where the current buffer is */ + NextName->Buffer = RemainingName->Buffer; + while (TRUE) + { + /* Break out if we ran out or hit a path separator */ + if (!(RemainingName->Length) || + (*RemainingName->Buffer == OBJ_NAME_PATH_SEPARATOR)) + { + break; + } + + /* Move to the next character */ + RemainingName->Buffer++; + RemainingName->Length -= sizeof(WCHAR); + RemainingName->MaximumLength -= sizeof(WCHAR); + } + + /* See how many chars we parsed and validate the length */ + NextName->Length = (USHORT)((ULONG_PTR)RemainingName->Buffer - + (ULONG_PTR)NextName->Buffer); + if (NextName->Length > 512) NameValid = FALSE; + NextName->MaximumLength = NextName->Length; + + /* If there's nothing left, we're last */ + *LastName = !RemainingName->Length; + return NameValid; +} diff --git a/reactos/ntoskrnl/config/cmsecach.c b/reactos/ntoskrnl/config/cmsecach.c new file mode 100644 index 00000000000..f2ed365d852 --- /dev/null +++ b/reactos/ntoskrnl/config/cmsecach.c @@ -0,0 +1,38 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmsecach.c + * PURPOSE: Configuration Manager - Security Cache + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#include "cm.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +CmpInitSecurityCache(IN PCMHIVE Hive) +{ + ULONG i; + + /* Reset data */ + Hive->SecurityCount = 0; + Hive->SecurityCacheSize = 0; + Hive->SecurityHitHint = -1; + Hive->SecurityCache = NULL; + + /* Loop every security hash */ + for (i = 0; i < 64; i++) + { + /* Initialize it */ + InitializeListHead(&Hive->SecurityHash[i]); + } +} diff --git a/reactos/ntoskrnl/config/cmvalue.c b/reactos/ntoskrnl/config/cmvalue.c new file mode 100644 index 00000000000..212100c2b5c --- /dev/null +++ b/reactos/ntoskrnl/config/cmvalue.c @@ -0,0 +1,125 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/config/cmvalue.c + * PURPOSE: Configuration Manager - Cell Values + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include "ntoskrnl.h" +#include "cm.h" +#define NDEBUG +#include "debug.h" + +/* GLOBALS *******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +HCELL_INDEX +NTAPI +CmpFindValueByName(IN PHHIVE Hive, + IN PCM_KEY_NODE KeyNode, + IN PUNICODE_STRING Name) +{ + HCELL_INDEX CellIndex; + + /* Call the main function */ + if (!CmpFindNameInList(Hive, + &KeyNode->ValueList, + Name, + NULL, + &CellIndex)) + { + /* Santy check */ + ASSERT(CellIndex == HCELL_NIL); + } + + /* Return the index */ + return CellIndex; +} + +BOOLEAN +NTAPI +CmpGetValueData(IN PHHIVE Hive, + IN PCM_KEY_VALUE Value, + IN PULONG Length, + OUT PVOID *Buffer, + OUT PBOOLEAN BufferAllocated, + OUT PHCELL_INDEX CellToRelease) +{ + PAGED_CODE(); + + /* Sanity check */ + ASSERT(Value->Signature == CM_KEY_VALUE_SIGNATURE); + + /* Set failure defaults */ + *BufferAllocated = FALSE; + *Buffer = NULL; + *CellToRelease = HCELL_NIL; + + /* Check if this is a small key */ + if (CmpIsKeyValueSmall(Length, Value->DataLength)) + { + /* Return the data immediately */ + *Buffer = &Value->Data; + return TRUE; + } + + /* Check if this is a big cell */ + if (CmpIsKeyValueBig(Hive, *Length)) + { + /* FIXME: We don't support big cells */ + DPRINT1("Unsupported cell type!\n"); + while (TRUE); + } + + /* Get the data from the cell */ + *Buffer = HvGetCell(Hive, Value->Data); + if (!(*Buffer)) return FALSE; + + /* Return success and the cell to be released */ + *CellToRelease = Value->Data; + return TRUE; +} + +PCELL_DATA +NTAPI +CmpValueToData(IN PHHIVE Hive, + IN PCM_KEY_VALUE Value, + OUT PULONG Length) +{ + PCELL_DATA Buffer; + BOOLEAN BufferAllocated; + HCELL_INDEX CellToRelease; + PAGED_CODE(); + + /* Sanity check */ + ASSERT(Hive->ReleaseCellRoutine == NULL); + + /* Get the actual data */ + if (!CmpGetValueData(Hive, + Value, + Length, + (PVOID)&Buffer, + &BufferAllocated, + &CellToRelease)) + { + /* We failed */ + ASSERT(BufferAllocated == FALSE); + ASSERT(Buffer == NULL); + return NULL; + } + + /* This should never happen!*/ + if (BufferAllocated) + { + /* Free the buffer and bugcheck */ + ExFreePool(Buffer); + KEBUGCHECKEX(REGISTRY_ERROR, 8, 0, (ULONG_PTR)Hive, (ULONG_PTR)Value); + } + + /* Otherwise, return the cell data */ + return Buffer; +} diff --git a/reactos/ntoskrnl/ntoskrnl.rbuild b/reactos/ntoskrnl/ntoskrnl.rbuild index c3798a45627..e081c6948bc 100644 --- a/reactos/ntoskrnl/ntoskrnl.rbuild +++ b/reactos/ntoskrnl/ntoskrnl.rbuild @@ -83,14 +83,23 @@ pin.c view.c + + cmboot.c + cmcontrl.c + cmdata.c + cmindex.c + cmmapvw.c + cmname.c + cmparse.c + cmsecach.c + cmvalue.c + import.c ntfunc.c regfile.c registry.c regobj.c - newcm.c - cmdata.c dbgkutil.c