diff --git a/reactos/drivers/dd/ramdrv/ramdrv.c b/reactos/drivers/dd/ramdrv/ramdrv.c index 0f4772853ab..b3304be5bf9 100644 --- a/reactos/drivers/dd/ramdrv/ramdrv.c +++ b/reactos/drivers/dd/ramdrv/ramdrv.c @@ -139,7 +139,7 @@ NTSTATUS STDCALL DriverEntry(IN PDRIVER_OBJECT DriverObject, 0 ); allocsize.u.LowPart = allocsize.u.HighPart = 0; - Status = NtOpenFile( &file, + Status = ZwOpenFile( &file, GENERIC_READ, &objattr, &iosb, @@ -157,7 +157,7 @@ NTSTATUS STDCALL DriverEntry(IN PDRIVER_OBJECT DriverObject, 0, 0, 0 ); - Status = NtCreateEvent( &event, + Status = ZwCreateEvent( &event, 0, &objattr, NotificationEvent, @@ -168,7 +168,7 @@ NTSTATUS STDCALL DriverEntry(IN PDRIVER_OBJECT DriverObject, goto cleanfile; } - Status = NtQueryInformationFile( file, + Status = ZwQueryInformationFile( file, &iosb, &finfo, sizeof( finfo ), @@ -187,7 +187,7 @@ NTSTATUS STDCALL DriverEntry(IN PDRIVER_OBJECT DriverObject, goto cleanevent; } - Status = NtReadFile( file, + Status = ZwReadFile( file, event, 0, 0, @@ -202,7 +202,7 @@ NTSTATUS STDCALL DriverEntry(IN PDRIVER_OBJECT DriverObject, DPRINT( "Failed to read floppy\n" ); goto cleantbuff; } - Status = NtWaitForSingleObject( event, FALSE, 0 ); + Status = ZwWaitForSingleObject( event, FALSE, 0 ); if( Status != STATUS_WAIT_0 || !NT_SUCCESS( iosb.Status ) ) { DPRINT( "Failed to read floppy\n" ); @@ -221,16 +221,16 @@ NTSTATUS STDCALL DriverEntry(IN PDRIVER_OBJECT DriverObject, } else DbgPrint( "RAMDRV: Failed to decomparess image, error: %d\n", err ); ExFreePool( tbuff ); - NtClose( file ); - NtClose( event ); + ZwClose( file ); + ZwClose( event ); return STATUS_SUCCESS; cleantbuff: ExFreePool( tbuff ); cleanevent: - NtClose( event ); + ZwClose( event ); cleanfile: - NtClose( file ); + ZwClose( file ); cleanbuffer: ExFreePool( devext->Buffer ); diff --git a/reactos/include/ntos/zw.h b/reactos/include/ntos/zw.h index 3ddda643c1a..f0ea0861940 100755 --- a/reactos/include/ntos/zw.h +++ b/reactos/include/ntos/zw.h @@ -3107,19 +3107,19 @@ ZwQuerySymbolicLinkObject( NTSTATUS STDCALL NtQuerySystemEnvironmentValue( - IN PUNICODE_STRING Name, - OUT PVOID Value, - ULONG Length, - PULONG ReturnLength + IN PUNICODE_STRING VariableName, + OUT PWSTR ValueBuffer, + IN ULONG ValueBufferLength, + OUT PULONG ReturnLength OPTIONAL ); NTSTATUS STDCALL ZwQuerySystemEnvironmentValue( - IN PUNICODE_STRING Name, - OUT PVOID Value, - ULONG Length, - PULONG ReturnLength + IN PUNICODE_STRING VariableName, + OUT PWSTR ValueBuffer, + IN ULONG ValueBufferLength, + OUT PULONG ReturnLength OPTIONAL ); diff --git a/reactos/ntoskrnl/ex/sysinfo.c b/reactos/ntoskrnl/ex/sysinfo.c index b11629e2fea..a9903effe61 100644 --- a/reactos/ntoskrnl/ex/sysinfo.c +++ b/reactos/ntoskrnl/ex/sysinfo.c @@ -90,10 +90,10 @@ ExGetCurrentProcessorCounts ( } NTSTATUS STDCALL -NtQuerySystemEnvironmentValue (IN PUNICODE_STRING UnsafeName, - OUT PVOID UnsafeValue, - IN ULONG Length, - IN OUT PULONG UnsafeReturnLength) +NtQuerySystemEnvironmentValue (IN PUNICODE_STRING VariableName, + OUT PWCHAR ValueBuffer, + IN ULONG ValueBufferLength, + IN OUT PULONG ReturnLength OPTIONAL) { NTSTATUS Status; ANSI_STRING AName; @@ -102,225 +102,197 @@ NtQuerySystemEnvironmentValue (IN PUNICODE_STRING UnsafeName, PCH Value; ANSI_STRING AValue; UNICODE_STRING WValue; - ULONG ReturnLength; + KPROCESSOR_MODE PreviousMode; + + PreviousMode = ExGetPreviousMode(); /* * Copy the name to kernel space if necessary and convert it to ANSI. */ - if (ExGetPreviousMode() != KernelMode) + Status = RtlCaptureUnicodeString(&WName, + PreviousMode, + NonPagedPool, + FALSE, + VariableName); + if(NT_SUCCESS(Status)) + { + if(PreviousMode != KernelMode) { - Status = RtlCaptureUnicodeString(&WName, UnsafeName); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - Status = RtlUnicodeStringToAnsiString(&AName, UnsafeName, TRUE); - if (!NT_SUCCESS(Status)) - { - return(Status); - } + ProbeForWrite(ValueBuffer, + ValueBufferLength, + sizeof(WCHAR)); + if(ReturnLength != NULL) + { + ProbeForWrite(ReturnLength, + sizeof(ULONG), + sizeof(ULONG)); + } } - else + + /* + * according to ntinternals the SeSystemEnvironmentName privilege is required! + */ + if(!SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege, + PreviousMode)) { - Status = RtlUnicodeStringToAnsiString(&AName, UnsafeName, TRUE); - if (!NT_SUCCESS(Status)) - { - return(Status); - } + RtlRelaseCapturedUnicodeString(&WName, + PreviousMode, + FALSE); + return STATUS_PRIVILEGE_NOT_HELD; } - + + /* + * convert the value name to ansi + */ + Status = RtlUnicodeStringToAnsiString(&AName, &WName, TRUE); + RtlRelaseCapturedUnicodeString(&WName, + PreviousMode, + FALSE); + if(!NT_SUCCESS(Status)) + { + return Status; + } + /* * Create a temporary buffer for the value */ - Value = ExAllocatePool(NonPagedPool, Length); - if (Value == NULL) + Value = ExAllocatePool(NonPagedPool, ValueBufferLength); + if (Value == NULL) { RtlFreeAnsiString(&AName); - if (ExGetPreviousMode() != KernelMode) - { - RtlFreeUnicodeString(&WName); - } - return(STATUS_NO_MEMORY); + return STATUS_INSUFFICIENT_RESOURCES; } - - /* - * Get the environment variable - */ - Result = HalGetEnvironmentVariable(AName.Buffer, Value, Length); - if (!Result) + + /* + * Get the environment variable + */ + Result = HalGetEnvironmentVariable(AName.Buffer, Value, ValueBufferLength); + if(!Result) { RtlFreeAnsiString(&AName); - if (ExGetPreviousMode() != KernelMode) - { - RtlFreeUnicodeString(&WName); - } ExFreePool(Value); - return(STATUS_UNSUCCESSFUL); + return STATUS_UNSUCCESSFUL; } - - /* - * Convert the result to UNICODE. - */ - RtlInitAnsiString(&AValue, Value); - Status = RtlAnsiStringToUnicodeString(&WValue, &AValue, TRUE); - if (!NT_SUCCESS(Status)) + + /* + * Convert the result to UNICODE, protect with SEH in case the value buffer + * isn't NULL-terminated! + */ + _SEH_TRY { - RtlFreeAnsiString(&AName); - if (ExGetPreviousMode() != KernelMode) - { - RtlFreeUnicodeString(&WName); - } - ExFreePool(Value); - return(Status); + RtlInitAnsiString(&AValue, Value); + Status = RtlAnsiStringToUnicodeString(&WValue, &AValue, TRUE); } - ReturnLength = WValue.Length; - - /* - * Copy the result back to the caller. - */ - if (ExGetPreviousMode() != KernelMode) + _SEH_HANDLE { - Status = MmCopyToCaller(UnsafeValue, WValue.Buffer, ReturnLength); - if (!NT_SUCCESS(Status)) - { - RtlFreeAnsiString(&AName); - if (ExGetPreviousMode() != KernelMode) - { - RtlFreeUnicodeString(&WName); - } - ExFreePool(Value); - RtlFreeUnicodeString(&WValue); - return(Status); - } - - Status = MmCopyToCaller(UnsafeReturnLength, &ReturnLength, - sizeof(ULONG)); - if (!NT_SUCCESS(Status)) - { - RtlFreeAnsiString(&AName); - if (ExGetPreviousMode() != KernelMode) - { - RtlFreeUnicodeString(&WName); - } - ExFreePool(Value); - RtlFreeUnicodeString(&WValue); - return(Status); - } + Status = _SEH_GetExceptionCode(); } - else + _SEH_END; + + if(NT_SUCCESS(Status)) { - memcpy(UnsafeValue, WValue.Buffer, ReturnLength); - memcpy(UnsafeReturnLength, &ReturnLength, sizeof(ULONG)); - } + /* + * Copy the result back to the caller. + */ + _SEH_TRY + { + RtlCopyMemory(ValueBuffer, WValue.Buffer, WValue.Length); + ValueBuffer[WValue.Length / sizeof(WCHAR)] = L'\0'; + if(ReturnLength != NULL) + { + *ReturnLength = WValue.Length + sizeof(WCHAR); + } - /* - * Free temporary buffers. - */ - RtlFreeAnsiString(&AName); - if (ExGetPreviousMode() != KernelMode) - { - RtlFreeUnicodeString(&WName); + Status = STATUS_SUCCESS; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; } - ExFreePool(Value); - RtlFreeUnicodeString(&WValue); + + /* + * Cleanup allocated resources. + */ + RtlFreeAnsiString(&AName); + ExFreePool(Value); + } - return(STATUS_SUCCESS); + return Status; } NTSTATUS STDCALL -NtSetSystemEnvironmentValue (IN PUNICODE_STRING UnsafeName, - IN PUNICODE_STRING UnsafeValue) +NtSetSystemEnvironmentValue (IN PUNICODE_STRING VariableName, + IN PUNICODE_STRING Value) { - UNICODE_STRING WName; - ANSI_STRING AName; - UNICODE_STRING WValue; - ANSI_STRING AValue; - BOOLEAN Result; + UNICODE_STRING CapturedName, CapturedValue; + ANSI_STRING AName, AValue; + KPROCESSOR_MODE PreviousMode; NTSTATUS Status; + PreviousMode = ExGetPreviousMode(); + /* - * Check for required privilege. + * Copy the strings to kernel space if necessary */ - /* FIXME: Not implemented. */ + Status = RtlCaptureUnicodeString(&CapturedName, + PreviousMode, + NonPagedPool, + FALSE, + VariableName); + if(NT_SUCCESS(Status)) + { + Status = RtlCaptureUnicodeString(&CapturedValue, + PreviousMode, + NonPagedPool, + FALSE, + Value); + if(NT_SUCCESS(Status)) + { + /* + * according to ntinternals the SeSystemEnvironmentName privilege is required! + */ + if(SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege, + PreviousMode)) + { + /* + * convert the strings to ANSI + */ + Status = RtlUnicodeStringToAnsiString(&AName, + &CapturedName, + TRUE); + if(NT_SUCCESS(Status)) + { + Status = RtlUnicodeStringToAnsiString(&AValue, + &CapturedValue, + TRUE); + if(NT_SUCCESS(Status)) + { + BOOLEAN Result = HalSetEnvironmentVariable(AName.Buffer, + AValue.Buffer); - /* - * Copy the name to kernel space if necessary and convert it to ANSI. - */ - if (ExGetPreviousMode() != KernelMode) - { - Status = RtlCaptureUnicodeString(&WName, UnsafeName); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - Status = RtlUnicodeStringToAnsiString(&AName, UnsafeName, TRUE); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - } - else - { - Status = RtlUnicodeStringToAnsiString(&AName, UnsafeName, TRUE); - if (!NT_SUCCESS(Status)) - { - return(Status); - } + Status = (Result ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); + } + } + } + else + { + Status = STATUS_PRIVILEGE_NOT_HELD; + } + + RtlRelaseCapturedUnicodeString(&CapturedValue, + PreviousMode, + FALSE); } - /* - * Copy the value to kernel space and convert to ANSI. - */ - if (ExGetPreviousMode() != KernelMode) - { - Status = RtlCaptureUnicodeString(&WValue, UnsafeValue); - if (!NT_SUCCESS(Status)) - { - RtlFreeUnicodeString(&WName); - RtlFreeAnsiString(&AName); - return(Status); - } - Status = RtlUnicodeStringToAnsiString(&AValue, UnsafeValue, TRUE); - if (!NT_SUCCESS(Status)) - { - RtlFreeUnicodeString(&WName); - RtlFreeAnsiString(&AName); - RtlFreeUnicodeString(&WValue); - return(Status); - } - } - else - { - Status = RtlUnicodeStringToAnsiString(&AValue, UnsafeValue, TRUE); - if (!NT_SUCCESS(Status)) - { - RtlFreeAnsiString(&AName); - return(Status); - } - } - - /* - * Set the environment variable - */ - Result = HalSetEnvironmentVariable(AName.Buffer, AValue.Buffer); - - /* - * Free everything and return status. - */ - RtlFreeAnsiString(&AName); - RtlFreeAnsiString(&AValue); - if (ExGetPreviousMode() != KernelMode) - { - RtlFreeUnicodeString(&WName); - RtlFreeUnicodeString(&WValue); - } - - if (!Result) - { - return(STATUS_UNSUCCESSFUL); - } - return(STATUS_SUCCESS); + RtlRelaseCapturedUnicodeString(&CapturedName, + PreviousMode, + FALSE); + } + + return Status; } diff --git a/reactos/ntoskrnl/include/internal/safe.h b/reactos/ntoskrnl/include/internal/safe.h index 340811c306e..9cae21b5164 100644 --- a/reactos/ntoskrnl/include/internal/safe.h +++ b/reactos/ntoskrnl/include/internal/safe.h @@ -10,7 +10,15 @@ NTSTATUS STDCALL MmCopyToCaller(PVOID Dest, const VOID *Src, ULONG NumberOfBytes); NTSTATUS -RtlCaptureUnicodeString(PUNICODE_STRING Dest, - PUNICODE_STRING UnsafeSrc); +RtlCaptureUnicodeString(OUT PUNICODE_STRING Dest, + IN KPROCESSOR_MODE CurrentMode, + IN POOL_TYPE PoolType, + IN BOOLEAN CaptureIfKernel, + IN PUNICODE_STRING UnsafeSrc); + +VOID +RtlRelaseCapturedUnicodeString(IN PUNICODE_STRING CapturedString, + IN KPROCESSOR_MODE CurrentMode, + IN BOOLEAN CaptureIfKernel); #endif /* __NTOSKRNL_INCLUDE_INTERNAL_SAFE_Hb */ diff --git a/reactos/ntoskrnl/io/event.c b/reactos/ntoskrnl/io/event.c index 2afe8dba027..edd8c25bb56 100644 --- a/reactos/ntoskrnl/io/event.c +++ b/reactos/ntoskrnl/io/event.c @@ -34,7 +34,7 @@ IoCreateNotificationEvent(PUNICODE_STRING EventName, NULL, NULL); - Status = NtCreateEvent(&Handle, + Status = ZwCreateEvent(&Handle, EVENT_ALL_ACCESS, &ObjectAttributes, NotificationEvent, @@ -65,21 +65,40 @@ IoCreateSynchronizationEvent(PUNICODE_STRING EventName, PHANDLE EventHandle) { OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING CapturedEventName; + KPROCESSOR_MODE PreviousMode; PKEVENT Event; HANDLE Handle; NTSTATUS Status; + + PreviousMode = ExGetPreviousMode(); + + Status = RtlCaptureUnicodeString(&CapturedEventName, + PreviousMode, + NonPagedPool, + FALSE, + EventName); + if (!NT_SUCCESS(Status)) + { + return NULL; + } InitializeObjectAttributes(&ObjectAttributes, - EventName, + &CapturedEventName, OBJ_OPENIF, NULL, NULL); - Status = NtCreateEvent(&Handle, + Status = ZwCreateEvent(&Handle, EVENT_ALL_ACCESS, &ObjectAttributes, SynchronizationEvent, TRUE); + + RtlRelaseCapturedUnicodeString(&CapturedEventName, + PreviousMode, + FALSE); + if (!NT_SUCCESS(Status)) { return NULL; diff --git a/reactos/ntoskrnl/ke/main.c b/reactos/ntoskrnl/ke/main.c index bbe4d3b2b63..0f56046a651 100644 --- a/reactos/ntoskrnl/ke/main.c +++ b/reactos/ntoskrnl/ke/main.c @@ -748,7 +748,7 @@ ExpInitializeExecutive(VOID) 0, NULL, NULL); - Status = NtCreateEvent(&InitDoneEventHandle, + Status = ZwCreateEvent(&InitDoneEventHandle, EVENT_ALL_ACCESS, &ObjectAttributes, SynchronizationEvent, @@ -778,7 +778,7 @@ ExpInitializeExecutive(VOID) /* Wait for the system to be initialized */ Timeout.QuadPart = (LONGLONG)-1200000000; /* 120 second timeout */ - Status = NtWaitForMultipleObjects(((LONG) sizeof(Handles) / sizeof(HANDLE)), + Status = ZwWaitForMultipleObjects(((LONG) sizeof(Handles) / sizeof(HANDLE)), Handles, WaitAny, FALSE, /* Non-alertable */ @@ -804,9 +804,9 @@ ExpInitializeExecutive(VOID) InbvEnableBootDriver(FALSE); } - NtSetEvent(InitDoneEventHandle, NULL); + ZwSetEvent(InitDoneEventHandle, NULL); - NtClose(InitDoneEventHandle); + ZwClose(InitDoneEventHandle); } else { @@ -820,7 +820,7 @@ ExpInitializeExecutive(VOID) * Crash the system if the initial process terminates within 5 seconds. */ Timeout.QuadPart = (LONGLONG)-50000000; /* 5 second timeout */ - Status = NtWaitForSingleObject(ProcessHandle, + Status = ZwWaitForSingleObject(ProcessHandle, FALSE, &Timeout); if (Status != STATUS_TIMEOUT) @@ -834,8 +834,8 @@ ExpInitializeExecutive(VOID) KiTimerSystemAuditing = 1; - NtClose(ThreadHandle); - NtClose(ProcessHandle); + ZwClose(ThreadHandle); + ZwClose(ProcessHandle); } VOID __attribute((noinline)) diff --git a/reactos/ntoskrnl/rtl/capture.c b/reactos/ntoskrnl/rtl/capture.c index 08053c387c0..54c6e525886 100644 --- a/reactos/ntoskrnl/rtl/capture.c +++ b/reactos/ntoskrnl/rtl/capture.c @@ -35,43 +35,95 @@ /* FUNCTIONS *****************************************************************/ NTSTATUS -RtlCaptureUnicodeString(PUNICODE_STRING Dest, - PUNICODE_STRING UnsafeSrc) +RtlCaptureUnicodeString(OUT PUNICODE_STRING Dest, + IN KPROCESSOR_MODE CurrentMode, + IN POOL_TYPE PoolType, + IN BOOLEAN CaptureIfKernel, + IN PUNICODE_STRING UnsafeSrc) { - PUNICODE_STRING Src; - NTSTATUS Status; - + UNICODE_STRING Src; + NTSTATUS Status = STATUS_SUCCESS; + + ASSERT(Dest != NULL); + /* * Copy the source string structure to kernel space. */ - Status = MmCopyFromCaller(&Src, UnsafeSrc, sizeof(UNICODE_STRING)); - if (!NT_SUCCESS(Status)) + + if(CurrentMode == UserMode) + { + _SEH_TRY { - return(Status); + ProbeForRead(UnsafeSrc, + sizeof(UNICODE_STRING), + sizeof(ULONG)); + Src = *UnsafeSrc; } - + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + else if(!CaptureIfKernel) + { + /* just copy the UNICODE_STRING structure, the pointers are considered valid */ + *Dest = *UnsafeSrc; + return STATUS_SUCCESS; + } + else + { + /* capture the string even though it is considered to be valid */ + Src = *UnsafeSrc; + } + /* * Initialize the destination string. */ - Dest->Length = Src->Length; - Dest->MaximumLength = Src->MaximumLength; - Dest->Buffer = ExAllocatePool(NonPagedPool, Dest->MaximumLength); + Dest->Length = Src.Length; + Dest->MaximumLength = Src.Length + sizeof(WCHAR); + Dest->Buffer = ExAllocatePool(PoolType, Dest->MaximumLength); if (Dest->Buffer == NULL) - { - return(STATUS_NO_MEMORY); - } + { + Dest->Length = Dest->MaximumLength = 0; + Dest->Buffer = NULL; + return STATUS_INSUFFICIENT_RESOURCES; + } /* * Copy the source string to kernel space. */ - Status = MmCopyFromCaller(Dest->Buffer, Src->Buffer, Dest->Length); - if (!NT_SUCCESS(Status)) + if(Src.Length > 0) + { + _SEH_TRY { - ExFreePool(Dest->Buffer); - return(Status); + RtlCopyMemory(Dest->Buffer, Src.Buffer, Src.Length); + Dest->Buffer[Src.Length / sizeof(WCHAR)] = L'\0'; } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + return Status; +} - return(STATUS_SUCCESS); +VOID +RtlRelaseCapturedUnicodeString(IN PUNICODE_STRING CapturedString, + IN KPROCESSOR_MODE CurrentMode, + IN BOOLEAN CaptureIfKernel) +{ + if(CurrentMode != KernelMode || CaptureIfKernel ) + { + RtlFreeUnicodeString(CapturedString); + } } NTSTATUS diff --git a/reactos/ntoskrnl/se/semgr.c b/reactos/ntoskrnl/se/semgr.c index 0e6ad3b99a4..b5126b5a7f1 100644 --- a/reactos/ntoskrnl/se/semgr.c +++ b/reactos/ntoskrnl/se/semgr.c @@ -84,7 +84,7 @@ SeInitSRM(VOID) OBJ_PERMANENT, 0, NULL); - Status = NtCreateDirectoryObject(&DirectoryHandle, + Status = ZwCreateDirectoryObject(&DirectoryHandle, DIRECTORY_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) @@ -101,7 +101,7 @@ SeInitSRM(VOID) OBJ_PERMANENT, DirectoryHandle, SePublicDefaultSd); - Status = NtCreateEvent(&EventHandle, + Status = ZwCreateEvent(&EventHandle, EVENT_ALL_ACCESS, &ObjectAttributes, SynchronizationEvent, @@ -113,8 +113,8 @@ SeInitSRM(VOID) return FALSE; } - NtClose(EventHandle); - NtClose(DirectoryHandle); + ZwClose(EventHandle); + ZwClose(DirectoryHandle); /* FIXME: Create SRM port and listener thread */ diff --git a/reactos/w32api/include/ddk/ntapi.h b/reactos/w32api/include/ddk/ntapi.h index 8ebf9274465..79aecb3a52c 100644 --- a/reactos/w32api/include/ddk/ntapi.h +++ b/reactos/w32api/include/ddk/ntapi.h @@ -735,16 +735,16 @@ NTOSAPI NTSTATUS NTAPI ZwQuerySystemEnvironmentValue( - IN PUNICODE_STRING Name, - OUT PVOID Value, - IN ULONG ValueLength, - OUT PULONG ReturnLength OPTIONAL); + IN PUNICODE_STRING VariableName, + OUT PWSTR ValueBuffer, + IN ULONG ValueBufferLength, + OUT PULONG ReturnLength OPTIONAL); NTOSAPI NTSTATUS NTAPI ZwSetSystemEnvironmentValue( - IN PUNICODE_STRING Name, + IN PUNICODE_STRING VariableName, IN PUNICODE_STRING Value); typedef enum _SHUTDOWN_ACTION {