Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/config/ntapi.c * PURPOSE: Configuration Manager - Internal Registry APIs * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Eric Kohl */
/* INCLUDES ******************************************************************/
#include "ntoskrnl.h"#define NDEBUG#include "debug.h"
BOOLEAN CmBootAcceptFirstTime = TRUE;BOOLEAN CmFirstTime = TRUE;extern ULONG InitSafeBootMode;
/* PRIVATE FUNCTIONS *********************************************************/
/* * Adapted from ntoskrnl/include/internal/ob_x.h:ObpReleaseObjectCreateInformation() */VOIDReleaseCapturedObjectAttributes( _In_ POBJECT_ATTRIBUTES CapturedObjectAttributes, _In_ KPROCESSOR_MODE AccessMode){ /* Check if we have a security descriptor */ if (CapturedObjectAttributes->SecurityDescriptor) { /* Release it */ SeReleaseSecurityDescriptor(CapturedObjectAttributes->SecurityDescriptor, AccessMode, TRUE); CapturedObjectAttributes->SecurityDescriptor = NULL; }
/* Check if we have an object name */ if (CapturedObjectAttributes->ObjectName) { /* Release it */ ReleaseCapturedUnicodeString(CapturedObjectAttributes->ObjectName, AccessMode); }}
/* * Adapted from ntoskrnl/ob/oblife.c:ObpCaptureObjectCreateInformation() */NTSTATUSProbeAndCaptureObjectAttributes( _Out_ POBJECT_ATTRIBUTES CapturedObjectAttributes, _Out_ PUNICODE_STRING ObjectName, _In_ KPROCESSOR_MODE AccessMode, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _In_ BOOLEAN CaptureSecurity){ NTSTATUS Status = STATUS_SUCCESS; PSECURITY_DESCRIPTOR SecurityDescriptor; // PSECURITY_QUALITY_OF_SERVICE SecurityQos; PUNICODE_STRING LocalObjectName = NULL;
/* Zero out the Capture Data */ RtlZeroMemory(CapturedObjectAttributes, sizeof(*CapturedObjectAttributes));
/* SEH everything here for protection */ _SEH2_TRY { /* Check if we got attributes */ if (ObjectAttributes) { /* Check if we're in user mode */ if (AccessMode != KernelMode) { /* Probe the attributes */ ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG)); }
/* Validate the Size and Attributes */ if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) || (ObjectAttributes->Attributes & ~OBJ_VALID_KERNEL_ATTRIBUTES)) // Understood as all the possible valid attributes { /* Invalid combination, fail */ _SEH2_YIELD(return STATUS_INVALID_PARAMETER); }
/* Set some Create Info and do not allow user-mode kernel handles */ CapturedObjectAttributes->Length = sizeof(OBJECT_ATTRIBUTES); CapturedObjectAttributes->RootDirectory = ObjectAttributes->RootDirectory; CapturedObjectAttributes->Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, AccessMode); LocalObjectName = ObjectAttributes->ObjectName; SecurityDescriptor = ObjectAttributes->SecurityDescriptor; // SecurityQos = ObjectAttributes->SecurityQualityOfService;
/* Check if we have a security descriptor */ if (CaptureSecurity && SecurityDescriptor) { /* * Capture it. * Note: This has an implicit memory barrier due * to the function call, so cleanup is safe here. */ Status = SeCaptureSecurityDescriptor(SecurityDescriptor, AccessMode, NonPagedPool, TRUE, &CapturedObjectAttributes-> SecurityDescriptor); if (!NT_SUCCESS(Status)) { /* Capture failed, quit */ CapturedObjectAttributes->SecurityDescriptor = NULL; _SEH2_YIELD(return Status); } } else { CapturedObjectAttributes->SecurityDescriptor = NULL; }
#if 0// We don't use the QoS!
/* Check if we have QoS */ if (SecurityQos) { /* Check if we came from user mode */ if (AccessMode != KernelMode) { /* Validate the QoS */ ProbeForRead(SecurityQos, sizeof(SECURITY_QUALITY_OF_SERVICE), sizeof(ULONG)); }
/* Save Info */ CapturedObjectAttributes->SecurityQualityOfService = *SecurityQos; CapturedObjectAttributes->SecurityQos = &CapturedObjectAttributes->SecurityQualityOfService; }#else CapturedObjectAttributes->SecurityQualityOfService = NULL;#endif } else { /* We don't have a name */ LocalObjectName = NULL; } } _SEH2_EXCEPT(ExSystemExceptionFilter()) { /* Cleanup and return the exception code */ ReleaseCapturedObjectAttributes(CapturedObjectAttributes, AccessMode); _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END;
/* Now check if the Object Attributes had an Object Name */ if (LocalObjectName) { Status = ProbeAndCaptureUnicodeString(ObjectName, AccessMode, LocalObjectName); } else { /* Clear the string */ RtlInitEmptyUnicodeString(ObjectName, NULL, 0);
/* It cannot have specified a Root Directory */ if (CapturedObjectAttributes->RootDirectory) { Status = STATUS_OBJECT_NAME_INVALID; } }
/* Set the caputured object attributes name pointer to the one the user gave to us */ CapturedObjectAttributes->ObjectName = ObjectName;
/* Cleanup if we failed */ if (!NT_SUCCESS(Status)) { ReleaseCapturedObjectAttributes(CapturedObjectAttributes, AccessMode); }
/* Return status to caller */ return Status;}
staticNTSTATUSCmpConvertHandleToKernelHandle( _In_ HANDLE SourceHandle, _In_opt_ POBJECT_TYPE ObjectType, _In_ ACCESS_MASK DesiredAccess, _In_ KPROCESSOR_MODE AccessMode, _Out_ PHANDLE KernelHandle){ NTSTATUS Status; PVOID Object;
*KernelHandle = NULL;
/* NULL handle is valid */ if (SourceHandle == NULL) return STATUS_SUCCESS;
/* Get the object pointer */ Status = ObReferenceObjectByHandle(SourceHandle, DesiredAccess, ObjectType, AccessMode, &Object, NULL); if (!NT_SUCCESS(Status)) return Status;
/* Create a kernel handle from the pointer */ Status = ObOpenObjectByPointer(Object, OBJ_KERNEL_HANDLE, NULL, DesiredAccess, ObjectType, KernelMode, KernelHandle);
/* Dereference the object */ ObDereferenceObject(Object); return Status;}
/* FUNCTIONS *****************************************************************/
NTSTATUSNTAPINtCreateKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG TitleIndex, IN PUNICODE_STRING Class OPTIONAL, IN ULONG CreateOptions, OUT PULONG Disposition OPTIONAL){ NTSTATUS Status; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); CM_PARSE_CONTEXT ParseContext = {0}; HANDLE Handle; PAGED_CODE();
DPRINT("NtCreateKey(Path: %wZ, Root %x, Access: %x, CreateOptions %x)\n", ObjectAttributes->ObjectName, ObjectAttributes->RootDirectory, DesiredAccess, CreateOptions);
/* Ignore the WOW64 flag, it's not valid in the kernel */ DesiredAccess &= ~KEY_WOW64_RES;
/* Check for user-mode caller */ if (PreviousMode != KernelMode) { /* Prepare to probe parameters */ _SEH2_TRY { /* Check if we have a class */ if (Class) { /* Probe it */ ParseContext.Class = ProbeForReadUnicodeString(Class); ProbeForRead(ParseContext.Class.Buffer, ParseContext.Class.Length, sizeof(WCHAR)); }
/* Probe the key handle */ ProbeForWriteHandle(KeyHandle); *KeyHandle = NULL;
/* Probe object attributes */ ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
if (Disposition) ProbeForWriteUlong(Disposition); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else { /* Save the class directly */ if (Class) ParseContext.Class = *Class; }
/* Setup the parse context */ ParseContext.CreateOperation = TRUE; ParseContext.CreateOptions = CreateOptions;
/* Do the create */ Status = ObOpenObjectByName(ObjectAttributes, CmpKeyObjectType, PreviousMode, NULL, DesiredAccess, &ParseContext, &Handle);
_SEH2_TRY { /* Return data to user */ if (NT_SUCCESS(Status)) *KeyHandle = Handle; if (Disposition) *Disposition = ParseContext.Disposition; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Get the status */ Status = _SEH2_GetExceptionCode(); } _SEH2_END;
DPRINT("Returning handle %x, Status %x.\n", Handle, Status);
/* Return status */ return Status;}
NTSTATUSNTAPINtOpenKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes){ CM_PARSE_CONTEXT ParseContext = {0}; HANDLE Handle; NTSTATUS Status; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); PAGED_CODE(); DPRINT("NtOpenKey(Path: %wZ, Root %x, Access: %x)\n", ObjectAttributes->ObjectName, ObjectAttributes->RootDirectory, DesiredAccess);
/* Ignore the WOW64 flag, it's not valid in the kernel */ DesiredAccess &= ~KEY_WOW64_RES;
/* Check for user-mode caller */ if (PreviousMode != KernelMode) { /* Prepare to probe parameters */ _SEH2_TRY { /* Probe the key handle */ ProbeForWriteHandle(KeyHandle); *KeyHandle = NULL;
/* Probe object attributes */ ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
/* Just let the object manager handle this */ Status = ObOpenObjectByName(ObjectAttributes, CmpKeyObjectType, PreviousMode, NULL, DesiredAccess, &ParseContext, &Handle);
/* Only do this if we succeeded */ if (NT_SUCCESS(Status)) { _SEH2_TRY { /* Return the handle to caller */ *KeyHandle = Handle; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Get the status */ Status = _SEH2_GetExceptionCode(); } _SEH2_END; }
DPRINT("Returning handle %x, Status %x.\n", Handle, Status);
/* Return status */ return Status;}
NTSTATUSNTAPINtDeleteKey(IN HANDLE KeyHandle){ PCM_KEY_BODY KeyObject; NTSTATUS Status; REG_DELETE_KEY_INFORMATION DeleteKeyInfo; REG_POST_OPERATION_INFORMATION PostOperationInfo; PAGED_CODE(); DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle);
/* Verify that the handle is valid and is a registry key */ Status = ObReferenceObjectByHandle(KeyHandle, DELETE, CmpKeyObjectType, ExGetPreviousMode(), (PVOID*)&KeyObject, NULL); if (!NT_SUCCESS(Status)) return Status;
/* Setup the callback */ PostOperationInfo.Object = (PVOID)KeyObject; DeleteKeyInfo.Object = (PVOID)KeyObject; Status = CmiCallRegisteredCallbacks(RegNtPreDeleteKey, &DeleteKeyInfo); if (NT_SUCCESS(Status)) { /* Check if we are read-only */ if ((KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) || (KeyObject->KeyControlBlock->ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY)) { /* Fail */ Status = STATUS_ACCESS_DENIED; } else { /* Call the internal API */ Status = CmDeleteKey(KeyObject); }
/* Do post callback */ PostOperationInfo.Status = Status; CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo); }
/* Dereference and return status */ ObDereferenceObject(KeyObject); return Status;}
NTSTATUSNTAPINtEnumerateKey(IN HANDLE KeyHandle, IN ULONG Index, IN KEY_INFORMATION_CLASS KeyInformationClass, OUT PVOID KeyInformation, IN ULONG Length, OUT PULONG ResultLength){ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status; PCM_KEY_BODY KeyObject; REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo; REG_POST_OPERATION_INFORMATION PostOperationInfo; PAGED_CODE(); DPRINT("NtEnumerateKey() KH 0x%p, Index 0x%x, KIC %d, Length %lu\n", KeyHandle, Index, KeyInformationClass, Length);
/* Reject classes we don't know about */ if ((KeyInformationClass != KeyBasicInformation) && (KeyInformationClass != KeyNodeInformation) && (KeyInformationClass != KeyFullInformation)) { /* Fail */ return STATUS_INVALID_PARAMETER; }
/* Verify that the handle is valid and is a registry key */ Status = ObReferenceObjectByHandle(KeyHandle, KEY_ENUMERATE_SUB_KEYS, CmpKeyObjectType, PreviousMode, (PVOID*)&KeyObject, NULL); if (!NT_SUCCESS(Status)) return Status;
if (PreviousMode != KernelMode) { _SEH2_TRY { ProbeForWriteUlong(ResultLength); ProbeForWrite(KeyInformation, Length, sizeof(ULONG)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Dereference and return status */ ObDereferenceObject(KeyObject); _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
/* Setup the callback */ PostOperationInfo.Object = (PVOID)KeyObject; EnumerateKeyInfo.Object = (PVOID)KeyObject; EnumerateKeyInfo.Index = Index; EnumerateKeyInfo.KeyInformationClass = KeyInformationClass; EnumerateKeyInfo.Length = Length; EnumerateKeyInfo.ResultLength = ResultLength;
/* Do the callback */ Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateKey, &EnumerateKeyInfo); if (NT_SUCCESS(Status)) { /* Call the internal API */ Status = CmEnumerateKey(KeyObject->KeyControlBlock, Index, KeyInformationClass, KeyInformation, Length, ResultLength);
/* Do the post callback */ PostOperationInfo.Status = Status; CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo); }
/* Dereference and return status */ ObDereferenceObject(KeyObject); DPRINT("Returning status %x.\n", Status); return Status;}
NTSTATUSNTAPINtEnumerateValueKey(IN HANDLE KeyHandle, IN ULONG Index, IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, OUT PVOID KeyValueInformation, IN ULONG Length, OUT PULONG ResultLength){ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status; PCM_KEY_BODY KeyObject; REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo; REG_POST_OPERATION_INFORMATION PostOperationInfo;
PAGED_CODE();
DPRINT("NtEnumerateValueKey() KH 0x%p, Index 0x%x, KVIC %d, Length %lu\n", KeyHandle, Index, KeyValueInformationClass, Length);
/* Reject classes we don't know about */ if ((KeyValueInformationClass != KeyValueBasicInformation) && (KeyValueInformationClass != KeyValueFullInformation) && (KeyValueInformationClass != KeyValuePartialInformation) && (KeyValueInformationClass != KeyValueFullInformationAlign64) && (KeyValueInformationClass != KeyValuePartialInformationAlign64)) { /* Fail */ return STATUS_INVALID_PARAMETER; }
/* Verify that the handle is valid and is a registry key */ Status = ObReferenceObjectByHandle(KeyHandle, KEY_QUERY_VALUE, CmpKeyObjectType, PreviousMode, (PVOID*)&KeyObject, NULL); if (!NT_SUCCESS(Status)) return Status;
if (PreviousMode != KernelMode) { _SEH2_TRY { ProbeForWriteUlong(ResultLength); ProbeForWrite(KeyValueInformation, Length, sizeof(ULONG)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Dereference and return status */ ObDereferenceObject(KeyObject); _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
/* Setup the callback */ PostOperationInfo.Object = (PVOID)KeyObject; EnumerateValueKeyInfo.Object = (PVOID)KeyObject; EnumerateValueKeyInfo.Index = Index; EnumerateValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass; EnumerateValueKeyInfo.KeyValueInformation = KeyValueInformation; EnumerateValueKeyInfo.Length = Length; EnumerateValueKeyInfo.ResultLength = ResultLength;
/* Do the callback */ Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey, &EnumerateValueKeyInfo); if (NT_SUCCESS(Status)) { /* Call the internal API */ Status = CmEnumerateValueKey(KeyObject->KeyControlBlock, Index, KeyValueInformationClass, KeyValueInformation, Length, ResultLength);
/* Do the post callback */ PostOperationInfo.Status = Status; CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &PostOperationInfo); }
/* Dereference and return status */ ObDereferenceObject(KeyObject); return Status;}
NTSTATUSNTAPINtQueryKey(IN HANDLE KeyHandle, IN KEY_INFORMATION_CLASS KeyInformationClass, OUT PVOID KeyInformation, IN ULONG Length, OUT PULONG ResultLength){ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status; PCM_KEY_BODY KeyObject; REG_QUERY_KEY_INFORMATION QueryKeyInfo; REG_POST_OPERATION_INFORMATION PostOperationInfo; OBJECT_HANDLE_INFORMATION HandleInfo; PAGED_CODE(); DPRINT("NtQueryKey() KH 0x%p, KIC %d, Length %lu\n", KeyHandle, KeyInformationClass, Length);
/* Reject invalid classes */ if ((KeyInformationClass != KeyBasicInformation) && (KeyInformationClass != KeyNodeInformation) && (KeyInformationClass != KeyFullInformation) && (KeyInformationClass != KeyNameInformation) && (KeyInformationClass != KeyCachedInformation) && (KeyInformationClass != KeyFlagsInformation)) { /* Fail */ return STATUS_INVALID_PARAMETER; }
/* Check if just the name is required */ if (KeyInformationClass == KeyNameInformation) { /* Ignore access level */ Status = ObReferenceObjectByHandle(KeyHandle, 0, CmpKeyObjectType, PreviousMode, (PVOID*)&KeyObject, &HandleInfo); if (NT_SUCCESS(Status)) { /* At least a single bit of access is required */ if (!HandleInfo.GrantedAccess) { /* No such luck */ ObDereferenceObject(KeyObject); Status = STATUS_ACCESS_DENIED; } } } else { /* Get a reference */ Status = ObReferenceObjectByHandle(KeyHandle, KEY_QUERY_VALUE, CmpKeyObjectType, PreviousMode, (PVOID*)&KeyObject, NULL); }
/* Quit on failure */ if (!NT_SUCCESS(Status)) return Status;
if (PreviousMode != KernelMode) { _SEH2_TRY { ProbeForWriteUlong(ResultLength); ProbeForWrite(KeyInformation, Length, sizeof(ULONG)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Dereference and return status */ ObDereferenceObject(KeyObject); _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
/* Setup the callback */ PostOperationInfo.Object = (PVOID)KeyObject; QueryKeyInfo.Object = (PVOID)KeyObject; QueryKeyInfo.KeyInformationClass = KeyInformationClass; QueryKeyInfo.KeyInformation = KeyInformation; QueryKeyInfo.Length = Length; QueryKeyInfo.ResultLength = ResultLength;
/* Do the callback */ Status = CmiCallRegisteredCallbacks(RegNtPreQueryKey, &QueryKeyInfo); if (NT_SUCCESS(Status)) { /* Call the internal API */ Status = CmQueryKey(KeyObject->KeyControlBlock, KeyInformationClass, KeyInformation, Length, ResultLength);
/* Do the post callback */ PostOperationInfo.Status = Status; CmiCallRegisteredCallbacks(RegNtPostQueryKey, &PostOperationInfo); }
/* Dereference and return status */ ObDereferenceObject(KeyObject); return Status;}
NTSTATUSNTAPINtQueryValueKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, OUT PVOID KeyValueInformation, IN ULONG Length, OUT PULONG ResultLength){ NTSTATUS Status; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); PCM_KEY_BODY KeyObject; REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo; REG_POST_OPERATION_INFORMATION PostOperationInfo; UNICODE_STRING ValueNameCopy;
PAGED_CODE();
DPRINT("NtQueryValueKey() KH 0x%p, VN '%wZ', KVIC %d, Length %lu\n", KeyHandle, ValueName, KeyValueInformationClass, Length);
/* Reject classes we don't know about */ if ((KeyValueInformationClass != KeyValueBasicInformation) && (KeyValueInformationClass != KeyValueFullInformation) && (KeyValueInformationClass != KeyValuePartialInformation) && (KeyValueInformationClass != KeyValueFullInformationAlign64) && (KeyValueInformationClass != KeyValuePartialInformationAlign64)) { /* Fail */ return STATUS_INVALID_PARAMETER; }
/* Verify that the handle is valid and is a registry key */ Status = ObReferenceObjectByHandle(KeyHandle, KEY_QUERY_VALUE, CmpKeyObjectType, PreviousMode, (PVOID*)&KeyObject, NULL); if (!NT_SUCCESS(Status)) return Status;
if (PreviousMode != KernelMode) { _SEH2_TRY { ProbeForWriteUlong(ResultLength); ProbeForWrite(KeyValueInformation, Length, sizeof(ULONG)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Dereference and return status */ ObDereferenceObject(KeyObject); _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
/* Capture the string */ Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName); if (!NT_SUCCESS(Status)) goto Quit;
/* Make sure the name is aligned properly */ if (ValueNameCopy.Length & (sizeof(WCHAR) - 1)) { /* It isn't, so we'll fail */ Status = STATUS_INVALID_PARAMETER; goto Quit; }
/* Ignore any null characters at the end */ while (ValueNameCopy.Length && !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1])) { /* Skip it */ ValueNameCopy.Length -= sizeof(WCHAR); }
/* Setup the callback */ PostOperationInfo.Object = (PVOID)KeyObject; QueryValueKeyInfo.Object = (PVOID)KeyObject; QueryValueKeyInfo.ValueName = &ValueNameCopy; QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass; QueryValueKeyInfo.Length = Length; QueryValueKeyInfo.ResultLength = ResultLength;
/* Do the callback */ Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo); if (NT_SUCCESS(Status)) { /* Call the internal API */ Status = CmQueryValueKey(KeyObject->KeyControlBlock, ValueNameCopy, KeyValueInformationClass, KeyValueInformation, Length, ResultLength);
/* Do the post callback */ PostOperationInfo.Status = Status; CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo); }
Quit: if (ValueNameCopy.Buffer) ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
/* Dereference and return status */ ObDereferenceObject(KeyObject); return Status;}
NTSTATUSNTAPINtSetValueKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN ULONG TitleIndex, IN ULONG Type, IN PVOID Data, IN ULONG DataSize){ NTSTATUS Status = STATUS_SUCCESS; KPROCESSOR_MODE PreviousMode; PCM_KEY_BODY KeyObject; REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo; REG_POST_OPERATION_INFORMATION PostOperationInfo; UNICODE_STRING ValueNameCopy;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
/* Verify that the handle is valid and is a registry key */ Status = ObReferenceObjectByHandle(KeyHandle, KEY_SET_VALUE, CmpKeyObjectType, PreviousMode, (PVOID*)&KeyObject, NULL); if (!NT_SUCCESS(Status)) return Status;
if (!DataSize) Data = NULL;
/* Probe and copy the data */ if ((PreviousMode != KernelMode) && (DataSize != 0)) { PVOID DataCopy = NULL;
_SEH2_TRY { ProbeForRead(Data, DataSize, 1); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END;
if (!NT_SUCCESS(Status)) { /* Dereference and return status */ ObDereferenceObject(KeyObject); return Status; }
DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM); if (!DataCopy) { /* Dereference and return status */ ObDereferenceObject(KeyObject); return STATUS_INSUFFICIENT_RESOURCES; }
_SEH2_TRY { RtlCopyMemory(DataCopy, Data, DataSize); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END;
if (!NT_SUCCESS(Status)) { /* Dereference and return status */ ExFreePoolWithTag(DataCopy, TAG_CM); ObDereferenceObject(KeyObject); return Status; }
Data = DataCopy; }
/* Capture the string */ Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName); if (!NT_SUCCESS(Status)) goto Quit;
DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n", KeyHandle, &ValueNameCopy, TitleIndex, Type, DataSize);
/* Make sure the name is aligned, not too long, and the data under 4GB */ if ((ValueNameCopy.Length > 32767) || (ValueNameCopy.Length & (sizeof(WCHAR) - 1)) || (DataSize > 0x80000000)) { /* Fail */ Status = STATUS_INVALID_PARAMETER; goto Quit; }
/* Ignore any null characters at the end */ while (ValueNameCopy.Length && !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1])) { /* Skip it */ ValueNameCopy.Length -= sizeof(WCHAR); }
/* Don't touch read-only keys */ if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) { /* Fail */ Status = STATUS_ACCESS_DENIED; goto Quit; }
/* Setup callback */ PostOperationInfo.Object = (PVOID)KeyObject; SetValueKeyInfo.Object = (PVOID)KeyObject; SetValueKeyInfo.ValueName = &ValueNameCopy; SetValueKeyInfo.TitleIndex = TitleIndex; SetValueKeyInfo.Type = Type; SetValueKeyInfo.Data = Data; SetValueKeyInfo.DataSize = DataSize;
/* Do the callback */ Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo); if (NT_SUCCESS(Status)) { /* Call the internal API */ Status = CmSetValueKey(KeyObject->KeyControlBlock, &ValueNameCopy, Type, Data, DataSize);
/* Do the post-callback */ PostOperationInfo.Status = Status; CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo); }
Quit: if (ValueNameCopy.Buffer) ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
if ((PreviousMode != KernelMode) && Data) ExFreePoolWithTag(Data, TAG_CM);
/* Dereference and return status */ ObDereferenceObject(KeyObject); return Status;}
NTSTATUSNTAPINtDeleteValueKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName){ NTSTATUS Status; PCM_KEY_BODY KeyObject; REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo; REG_POST_OPERATION_INFORMATION PostOperationInfo; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); UNICODE_STRING ValueNameCopy;
PAGED_CODE();
/* Verify that the handle is valid and is a registry key */ Status = ObReferenceObjectByHandle(KeyHandle, KEY_SET_VALUE, CmpKeyObjectType, PreviousMode, (PVOID*)&KeyObject, NULL); if (!NT_SUCCESS(Status)) return Status;
/* Capture the string */ Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName); if (!NT_SUCCESS(Status)) goto Quit;
/* Make sure the name is aligned properly */ if (ValueNameCopy.Length & (sizeof(WCHAR) - 1)) { /* It isn't, so we'll fail */ Status = STATUS_INVALID_PARAMETER; goto Quit; }
/* Don't touch read-only keys */ if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) { /* Fail */ Status = STATUS_ACCESS_DENIED; goto Quit; }
/* Do the callback */ DeleteValueKeyInfo.Object = (PVOID)KeyObject; DeleteValueKeyInfo.ValueName = ValueName; Status = CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey, &DeleteValueKeyInfo); if (NT_SUCCESS(Status)) { /* Call the internal API */ Status = CmDeleteValueKey(KeyObject->KeyControlBlock, ValueNameCopy);
/* Do the post callback */ PostOperationInfo.Object = (PVOID)KeyObject; PostOperationInfo.Status = Status; CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey, &PostOperationInfo); }
Quit: if (ValueNameCopy.Buffer) ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
/* Dereference and return status */ ObDereferenceObject(KeyObject); return Status;}
NTSTATUSNTAPINtFlushKey(IN HANDLE KeyHandle){ NTSTATUS Status; PCM_KEY_BODY KeyObject; PAGED_CODE();
/* Get the key object */ Status = ObReferenceObjectByHandle(KeyHandle, 0, CmpKeyObjectType, ExGetPreviousMode(), (PVOID*)&KeyObject, NULL); if (!NT_SUCCESS(Status)) return Status;
/* Lock the registry */ CmpLockRegistry();
/* Lock the KCB */ CmpAcquireKcbLockShared(KeyObject->KeyControlBlock);
/* Make sure KCB isn't deleted */ if (KeyObject->KeyControlBlock->Delete) { /* Fail */ Status = STATUS_KEY_DELETED; } else { /* Call the internal API */ Status = CmFlushKey(KeyObject->KeyControlBlock, FALSE); }
/* Release the locks */ CmpReleaseKcbLock(KeyObject->KeyControlBlock); CmpUnlockRegistry();
/* Dereference the object and return status */ ObDereferenceObject(KeyObject); return Status;}
NTSTATUSNTAPINtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes, IN POBJECT_ATTRIBUTES FileObjectAttributes){ /* Call the newer API */ return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, 0, NULL);}
NTSTATUSNTAPINtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes, IN POBJECT_ATTRIBUTES FileObjectAttributes, IN ULONG Flags){ /* Call the newer API */ return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, Flags, NULL);}
NTSTATUSNTAPINtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey, IN POBJECT_ATTRIBUTES SourceFile, IN ULONG Flags, IN HANDLE TrustClassKey){ NTSTATUS Status; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); OBJECT_ATTRIBUTES CapturedTargetKey; OBJECT_ATTRIBUTES CapturedSourceFile; UNICODE_STRING TargetKeyName, SourceFileName; HANDLE KmTargetKeyRootDir = NULL, KmSourceFileRootDir = NULL; PCM_KEY_BODY KeyBody = NULL;
PAGED_CODE();
/* Validate flags */ if (Flags & ~REG_NO_LAZY_FLUSH) return STATUS_INVALID_PARAMETER;
/* Validate privilege */ if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode)) { DPRINT1("Restore Privilege missing!\n"); return STATUS_PRIVILEGE_NOT_HELD; }
/* Block APCs */ KeEnterCriticalRegion();
/* Check for user-mode caller */ if (PreviousMode != KernelMode) { /* Prepare to probe parameters */ _SEH2_TRY { /* Probe target key */ ProbeForRead(TargetKey, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
/* Probe source file */ ProbeForRead(SourceFile, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ Status = _SEH2_GetExceptionCode(); _SEH2_YIELD(goto Quit); } _SEH2_END; }
/* Probe and capture the target key attributes, including the security */ Status = ProbeAndCaptureObjectAttributes(&CapturedTargetKey, &TargetKeyName, PreviousMode, TargetKey, TRUE); if (!NT_SUCCESS(Status)) goto Quit;
/* * Probe and capture the source file attributes, but not the security. * A proper security context is built by CmLoadKey(). */ Status = ProbeAndCaptureObjectAttributes(&CapturedSourceFile, &SourceFileName, PreviousMode, SourceFile, FALSE); if (!NT_SUCCESS(Status)) { ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode); goto Quit; }
/* Make sure the target key root directory handle is a kernel handle */ Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory, CmpKeyObjectType, KEY_READ, PreviousMode, &KmTargetKeyRootDir); if (!NT_SUCCESS(Status)) goto Cleanup; CapturedTargetKey.RootDirectory = KmTargetKeyRootDir; CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE;
/* Make sure the source file root directory handle is a kernel handle */ Status = CmpConvertHandleToKernelHandle(CapturedSourceFile.RootDirectory, IoFileObjectType, FILE_TRAVERSE, PreviousMode, &KmSourceFileRootDir); if (!NT_SUCCESS(Status)) goto Cleanup; CapturedSourceFile.RootDirectory = KmSourceFileRootDir; CapturedSourceFile.Attributes |= OBJ_KERNEL_HANDLE;
/* Check if we have a trust class */ if (TrustClassKey) { /* Reference it */ Status = ObReferenceObjectByHandle(TrustClassKey, 0, CmpKeyObjectType, PreviousMode, (PVOID*)&KeyBody, NULL); }
/* Call the internal API */ Status = CmLoadKey(&CapturedTargetKey, &CapturedSourceFile, Flags, KeyBody);
/* Dereference the trust key, if any */ if (KeyBody) ObDereferenceObject(KeyBody);
Cleanup: /* Close the local kernel handles */ if (KmSourceFileRootDir) ObCloseHandle(KmSourceFileRootDir, KernelMode); if (KmTargetKeyRootDir) ObCloseHandle(KmTargetKeyRootDir, KernelMode);
/* Release the captured object attributes */ ReleaseCapturedObjectAttributes(&CapturedSourceFile, PreviousMode); ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode);
Quit: /* Bring back APCs */ KeLeaveCriticalRegion();
/* Return status */ return Status;}
NTSTATUSNTAPINtNotifyChangeKey(IN HANDLE KeyHandle, IN HANDLE Event, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG CompletionFilter, IN BOOLEAN WatchTree, OUT PVOID Buffer, IN ULONG Length, IN BOOLEAN Asynchronous){ /* Call the newer API */ return NtNotifyChangeMultipleKeys(KeyHandle, 0, NULL, Event, ApcRoutine, ApcContext, IoStatusBlock, CompletionFilter, WatchTree, Buffer, Length, Asynchronous);}
NTSTATUSNTAPINtInitializeRegistry(IN USHORT Flag){ BOOLEAN SetupBoot; NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE();
/* Always do this as kernel mode */ if (KeGetPreviousMode() == UserMode) return ZwInitializeRegistry(Flag);
/* Enough of the system has booted by now */ Ki386PerfEnd();
/* Validate flag */ if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER;
/* Check if boot was accepted */ if ((Flag >= CM_BOOT_FLAG_ACCEPTED) && (Flag <= CM_BOOT_FLAG_MAX)) { /* Only allow once */ if (!CmBootAcceptFirstTime) return STATUS_ACCESS_DENIED; CmBootAcceptFirstTime = FALSE;
/* Get the control set accepted */ Flag -= CM_BOOT_FLAG_ACCEPTED; if (Flag) { /* Save the last known good boot */ Status = CmpSaveBootControlSet(Flag);
/* Notify HAL */ HalEndOfBoot();
/* Enable lazy flush */ CmpHoldLazyFlush = FALSE; CmpLazyFlush(); return Status; }
/* Otherwise, invalid boot */ return STATUS_INVALID_PARAMETER; }
/* Check if this was a setup boot */ SetupBoot = (Flag == CM_BOOT_FLAG_SETUP ? TRUE : FALSE);
/* Make sure we're only called once */ if (!CmFirstTime) return STATUS_ACCESS_DENIED; CmFirstTime = FALSE;
/* Lock the registry exclusively */ CmpLockRegistryExclusive();
/* Initialize the hives and lazy flusher */ CmpCmdInit(SetupBoot);
/* Save version data */ CmpSetVersionData();
/* Release the registry lock */ CmpUnlockRegistry(); return STATUS_SUCCESS;}
NTSTATUSNTAPINtCompactKeys(IN ULONG Count, IN PHANDLE KeyArray){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPINtCompressKey(IN HANDLE Key){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
// FIXME: different for different windows versions!#define PRODUCT_ACTIVATION_VERSION 7749
NTSTATUSNTAPINtLockProductActivationKeys(IN PULONG pPrivateVer, IN PULONG pSafeMode){ KPROCESSOR_MODE PreviousMode;
PreviousMode = ExGetPreviousMode(); _SEH2_TRY { /* Check if the caller asked for the version */ if (pPrivateVer != NULL) { /* For user mode, probe it */ if (PreviousMode != KernelMode) { ProbeForWriteUlong(pPrivateVer); }
/* Return the expected version */ *pPrivateVer = PRODUCT_ACTIVATION_VERSION; }
/* Check if the caller asked for safe mode mode state */ if (pSafeMode != NULL) { /* For user mode, probe it */ if (PreviousMode != KernelMode) { ProbeForWriteUlong(pSafeMode); }
/* Return the safe boot mode state */ *pSafeMode = InitSafeBootMode; } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END;
return STATUS_SUCCESS;}
NTSTATUSNTAPINtLockRegistryKey(IN HANDLE KeyHandle){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPINtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle, IN ULONG Count, IN POBJECT_ATTRIBUTES SlaveObjects, IN HANDLE Event, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG CompletionFilter, IN BOOLEAN WatchTree, OUT PVOID Buffer, IN ULONG Length, IN BOOLEAN Asynchronous){ UNIMPLEMENTED_ONCE; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPINtQueryMultipleValueKey(IN HANDLE KeyHandle, IN OUT PKEY_VALUE_ENTRY ValueList, IN ULONG NumberOfValues, OUT PVOID Buffer, IN OUT PULONG Length, OUT PULONG ReturnLength){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPINtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey, OUT PULONG HandleCount){ KPROCESSOR_MODE PreviousMode; PCM_KEY_BODY KeyBody = NULL; HANDLE KeyHandle; NTSTATUS Status; ULONG SubKeys;
DPRINT("NtQueryOpenSubKeys()\n");
PAGED_CODE();
/* Get the processor mode */ PreviousMode = KeGetPreviousMode();
/* Check for user-mode caller */ if (PreviousMode != KernelMode) { /* Prepare to probe parameters */ _SEH2_TRY { /* Probe target key */ ProbeForRead(TargetKey, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
/* Probe handle count */ ProbeForWriteUlong(HandleCount); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
/* Open a handle to the key */ Status = ObOpenObjectByName(TargetKey, CmpKeyObjectType, PreviousMode, NULL, KEY_READ, NULL, &KeyHandle); if (NT_SUCCESS(Status)) { /* Reference the key object */ Status = ObReferenceObjectByHandle(KeyHandle, KEY_READ, CmpKeyObjectType, PreviousMode, (PVOID*)&KeyBody, NULL);
/* Close the handle */ NtClose(KeyHandle); }
/* Fail, if the key object could not be referenced */ if (!NT_SUCCESS(Status)) return Status;
/* Lock the registry exclusively */ CmpLockRegistryExclusive();
/* Fail, if we did not open a hive root key */ if (KeyBody->KeyControlBlock->KeyCell != KeyBody->KeyControlBlock->KeyHive->BaseBlock->RootCell) { DPRINT("Error: Key is not a hive root key!\n"); CmpUnlockRegistry(); ObDereferenceObject(KeyBody); return STATUS_INVALID_PARAMETER; }
/* Call the internal API */ SubKeys = CmpEnumerateOpenSubKeys(KeyBody->KeyControlBlock, FALSE, FALSE);
/* Unlock the registry */ CmpUnlockRegistry();
/* Dereference the key object */ ObDereferenceObject(KeyBody);
/* Write back the result */ _SEH2_TRY { *HandleCount = SubKeys; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END;
DPRINT("Done.\n");
return Status;}
NTSTATUSNTAPINtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey, IN ULONG BufferLength, IN PVOID Buffer, IN PULONG RequiredSize){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPINtRenameKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ReplacementName){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPINtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE Key, IN POBJECT_ATTRIBUTES ReplacedObjectAttributes){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPINtRestoreKey(IN HANDLE KeyHandle, IN HANDLE FileHandle, IN ULONG RestoreFlags){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPINtSaveKey(IN HANDLE KeyHandle, IN HANDLE FileHandle){ /* Call the extended API */ return NtSaveKeyEx(KeyHandle, FileHandle, REG_STANDARD_FORMAT);}
NTSTATUSNTAPINtSaveKeyEx(IN HANDLE KeyHandle, IN HANDLE FileHandle, IN ULONG Flags){ NTSTATUS Status; HANDLE KmFileHandle = NULL; PCM_KEY_BODY KeyObject; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PAGED_CODE();
DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle, FileHandle, Flags);
/* Verify the flags */ if ((Flags != REG_STANDARD_FORMAT) && (Flags != REG_LATEST_FORMAT) && (Flags != REG_NO_COMPRESSION)) { /* Only one of these values can be specified */ return STATUS_INVALID_PARAMETER; }
/* Validate privilege */ if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode)) { return STATUS_PRIVILEGE_NOT_HELD; }
/* Make sure the target file handle is a kernel handle */ Status = CmpConvertHandleToKernelHandle(FileHandle, IoFileObjectType, FILE_WRITE_DATA, PreviousMode, &KmFileHandle); if (!NT_SUCCESS(Status)) goto Quit;
/* Verify that the handle is valid and is a registry key */ Status = ObReferenceObjectByHandle(KeyHandle, KEY_READ, CmpKeyObjectType, PreviousMode, (PVOID*)&KeyObject, NULL); if (!NT_SUCCESS(Status)) goto Quit;
/* Call the internal API */ Status = CmSaveKey(KeyObject->KeyControlBlock, KmFileHandle, Flags);
/* Dereference the registry key */ ObDereferenceObject(KeyObject);
Quit: /* Close the local kernel handle */ if (KmFileHandle) ObCloseHandle(KmFileHandle, KernelMode);
return Status;}
NTSTATUSNTAPINtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle, IN HANDLE LowPrecedenceKeyHandle, IN HANDLE FileHandle){ NTSTATUS Status; KPROCESSOR_MODE PreviousMode; HANDLE KmFileHandle = NULL; PCM_KEY_BODY HighPrecedenceKeyObject = NULL; PCM_KEY_BODY LowPrecedenceKeyObject = NULL;
PAGED_CODE();
DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n", HighPrecedenceKeyHandle, LowPrecedenceKeyHandle, FileHandle);
PreviousMode = ExGetPreviousMode();
/* Validate privilege */ if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode)) { return STATUS_PRIVILEGE_NOT_HELD; }
/* Make sure the target file handle is a kernel handle */ Status = CmpConvertHandleToKernelHandle(FileHandle, IoFileObjectType, FILE_WRITE_DATA, PreviousMode, &KmFileHandle); if (!NT_SUCCESS(Status)) goto Quit;
/* Verify that the handles are valid and are registry keys */ Status = ObReferenceObjectByHandle(HighPrecedenceKeyHandle, KEY_READ, CmpKeyObjectType, PreviousMode, (PVOID*)&HighPrecedenceKeyObject, NULL); if (!NT_SUCCESS(Status)) goto Quit;
Status = ObReferenceObjectByHandle(LowPrecedenceKeyHandle, KEY_READ, CmpKeyObjectType, PreviousMode, (PVOID*)&LowPrecedenceKeyObject, NULL); if (!NT_SUCCESS(Status)) goto Quit;
/* Call the internal API */ Status = CmSaveMergedKeys(HighPrecedenceKeyObject->KeyControlBlock, LowPrecedenceKeyObject->KeyControlBlock, KmFileHandle);
Quit: /* Dereference the opened key objects */ if (LowPrecedenceKeyObject) ObDereferenceObject(LowPrecedenceKeyObject); if (HighPrecedenceKeyObject) ObDereferenceObject(HighPrecedenceKeyObject);
/* Close the local kernel handle */ if (KmFileHandle) ObCloseHandle(KmFileHandle, KernelMode);
return Status;}
NTSTATUSNTAPINtSetInformationKey(IN HANDLE KeyHandle, IN KEY_SET_INFORMATION_CLASS KeyInformationClass, IN PVOID KeyInformation, IN ULONG KeyInformationLength){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPINtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes){ return NtUnloadKey2(KeyObjectAttributes, 0);}
NTSTATUSNTAPINtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey, IN ULONG Flags){ NTSTATUS Status; OBJECT_ATTRIBUTES CapturedTargetKey; UNICODE_STRING ObjectName; HANDLE KmTargetKeyRootDir = NULL; CM_PARSE_CONTEXT ParseContext = {0}; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); PCM_KEY_BODY KeyBody = NULL; HANDLE Handle;
PAGED_CODE();
/* Validate privilege */ if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode)) { DPRINT1("Restore Privilege missing!\n"); return STATUS_PRIVILEGE_NOT_HELD; }
/* Check for user-mode caller */ if (PreviousMode != KernelMode) { /* Prepare to probe parameters */ _SEH2_TRY { /* Probe object attributes */ ProbeForRead(TargetKey, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
CapturedTargetKey = *TargetKey;
/* Probe the string */ ObjectName = ProbeForReadUnicodeString(CapturedTargetKey.ObjectName); ProbeForRead(ObjectName.Buffer, ObjectName.Length, sizeof(WCHAR));
CapturedTargetKey.ObjectName = &ObjectName; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else { /* Save the target attributes directly */ CapturedTargetKey = *TargetKey; }
/* Make sure the target key root directory handle is a kernel handle */ Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory, CmpKeyObjectType, KEY_WRITE, PreviousMode, &KmTargetKeyRootDir); if (!NT_SUCCESS(Status)) return Status; CapturedTargetKey.RootDirectory = KmTargetKeyRootDir; CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE;
/* Setup the parse context */ ParseContext.CreateOperation = TRUE; ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE;
/* Do the create */ /* Open a local handle to the key */ Status = ObOpenObjectByName(&CapturedTargetKey, CmpKeyObjectType, KernelMode, NULL, KEY_WRITE, &ParseContext, &Handle); if (NT_SUCCESS(Status)) { /* Reference the key object */ Status = ObReferenceObjectByHandle(Handle, KEY_WRITE, CmpKeyObjectType, KernelMode, (PVOID*)&KeyBody, NULL);
/* Close the handle */ ObCloseHandle(Handle, KernelMode); }
/* Close the local kernel handle */ if (KmTargetKeyRootDir) ObCloseHandle(KmTargetKeyRootDir, KernelMode);
/* Return if a failure was encountered */ if (!NT_SUCCESS(Status)) return Status;
/* * Lock down the entire registry when we unload a hive. * * NOTE: We might block other threads of other processes that do * operations with unrelated keys of other hives when we lock * the registry for exclusive use by the calling thread that does * the unloading. If this turns out to cause a major overhead we * have to rethink the locking mechanism here (prior commit - f1d2a44). */ CmpLockRegistryExclusive(); ExAcquirePushLockExclusive(&CmpLoadHiveLock);
/* Check if it's being deleted already */ if (KeyBody->KeyControlBlock->Delete) { /* Return appropriate status */ Status = STATUS_KEY_DELETED; goto Quit; }
/* Check if it's a read-only key */ if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) { /* Return appropriate status */ Status = STATUS_ACCESS_DENIED; goto Quit; }
/* Call the internal API. Note that CmUnloadKey() unlocks the registry only on success. */ Status = CmUnloadKey(KeyBody->KeyControlBlock, Flags);
Quit: /* If CmUnloadKey() failed we need to unlock registry ourselves */ if (!NT_SUCCESS(Status)) { /* Unlock the hive loading and registry locks */ ExReleasePushLockExclusive(&CmpLoadHiveLock); CmpUnlockRegistry(); }
/* Dereference the key */ ObDereferenceObject(KeyBody);
/* Return status */ return Status;}
NTSTATUSNTAPINtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey, IN HANDLE Event){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
/* EOF */