533 lines
15 KiB
C
533 lines
15 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
sysenv.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the NT query and set system environment
|
||
variable services.
|
||
|
||
Author:
|
||
|
||
David N. Cutler (davec) 10-Nov-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "exp.h"
|
||
#pragma hdrstop
|
||
|
||
#include "arccodes.h"
|
||
|
||
#if defined(ALLOC_PRAGMA)
|
||
#pragma alloc_text(PAGELK, NtQuerySystemEnvironmentValue)
|
||
#pragma alloc_text(PAGELK, NtSetSystemEnvironmentValue)
|
||
#endif
|
||
|
||
//
|
||
// Define maximum size of environment value.
|
||
//
|
||
|
||
#define MAXIMUM_ENVIRONMENT_VALUE 1024
|
||
|
||
//
|
||
// Define query/set environment variable synchronization fast mutex.
|
||
//
|
||
|
||
FAST_MUTEX ExpEnvironmentLock;
|
||
|
||
NTSTATUS
|
||
NtQuerySystemEnvironmentValue (
|
||
IN PUNICODE_STRING VariableName,
|
||
OUT PWSTR VariableValue,
|
||
IN USHORT ValueLength,
|
||
OUT PUSHORT ReturnLength OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function locates the specified system environment variable and
|
||
return its value.
|
||
|
||
N.B. This service requires the system environment privilege.
|
||
|
||
Arguments:
|
||
|
||
Variable - Supplies a pointer to a UNICODE descriptor for the specified
|
||
system environment variable.
|
||
|
||
Value - Supplies a pointer to a buffer that receives the value of the
|
||
specified system environment variable.
|
||
|
||
ValueLength - Supplies the length of the value buffer in bytes.
|
||
|
||
ReturnLength - Supplies an optional pointer to a variable that receives
|
||
the length of the system environment variable value.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS is returned if the service is successfully executed.
|
||
|
||
STATUS_PRIVILEGE_NOT_HELD is returned if the caller does not have the
|
||
privilege to query a system environment variable.
|
||
|
||
STATUS_ACCESS_VIOLATION is returned if the output parameter for the
|
||
system environment value or the return length cannot be written,
|
||
or the descriptor or the name of the system environment variable
|
||
cannot be read.
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
|
||
for this request to complete.
|
||
|
||
STATUS_UNSUCCESSFUL - The specified environment variable could not
|
||
be located.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ULONG AnsiLength;
|
||
ANSI_STRING AnsiString;
|
||
ARC_STATUS ArcStatus;
|
||
BOOLEAN HasPrivilege;
|
||
NTSTATUS NtStatus;
|
||
KPROCESSOR_MODE PreviousMode;
|
||
UNICODE_STRING UnicodeString;
|
||
PCHAR ValueBuffer;
|
||
|
||
//
|
||
// Clear address of ANSI buffer.
|
||
//
|
||
|
||
AnsiString.Buffer = NULL;
|
||
|
||
//
|
||
// Establish an exception handler and attempt to probe and read the
|
||
// name of the specified system environment variable, and probe the
|
||
// variable value buffer and return length. If the probe or read
|
||
// attempt fails, then return the exception code as the service status.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Get previous processor mode and probe arguments if necessary.
|
||
//
|
||
|
||
PreviousMode = KeGetPreviousMode();
|
||
if (PreviousMode != KernelMode) {
|
||
|
||
//
|
||
// Probe and capture the string descriptor for the system
|
||
// environment variable name.
|
||
//
|
||
|
||
ProbeForRead((PVOID)VariableName,
|
||
sizeof(UNICODE_STRING),
|
||
sizeof(ULONG));
|
||
|
||
UnicodeString = *VariableName;
|
||
|
||
//
|
||
// Probe the system environment variable name.
|
||
//
|
||
|
||
ProbeForRead((PVOID)UnicodeString.Buffer,
|
||
UnicodeString.Length,
|
||
sizeof(WCHAR));
|
||
|
||
//
|
||
// Probe the system environment value buffer.
|
||
//
|
||
|
||
ProbeForWrite((PVOID)VariableValue, ValueLength, sizeof(WCHAR));
|
||
|
||
//
|
||
// If argument is present, probe the return length value.
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT(ReturnLength)) {
|
||
ProbeForWriteUshort(ReturnLength);
|
||
}
|
||
|
||
//
|
||
// Check if the current thread has the privilege to query a system
|
||
// environment variable.
|
||
//
|
||
|
||
HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
|
||
PreviousMode);
|
||
|
||
if (HasPrivilege == FALSE) {
|
||
return(STATUS_PRIVILEGE_NOT_HELD);
|
||
}
|
||
|
||
} else {
|
||
UnicodeString = *VariableName;
|
||
}
|
||
|
||
|
||
//
|
||
// Compute the size of the ANSI variable name, allocate a nonpaged
|
||
// buffer, and convert the specified UNICODE variable name to ANSI.
|
||
//
|
||
|
||
AnsiLength = RtlUnicodeStringToAnsiSize(&UnicodeString);
|
||
AnsiString.Buffer = (PCHAR)ExAllocatePool(NonPagedPool, AnsiLength);
|
||
if (AnsiString.Buffer == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
AnsiString.MaximumLength = (USHORT)AnsiLength;
|
||
NtStatus = RtlUnicodeStringToAnsiString(&AnsiString,
|
||
&UnicodeString,
|
||
FALSE);
|
||
|
||
if (NT_SUCCESS(NtStatus) == FALSE) {
|
||
ExFreePool((PVOID)AnsiString.Buffer);
|
||
return NtStatus;
|
||
}
|
||
|
||
//
|
||
// If an exception occurs during the read of the variable descriptor,
|
||
// the read of the variable name, the probe of the variable value, or
|
||
// the probe of the return length, then always handle the exception,
|
||
// free the ANSI string buffer if necessary, and return the exception
|
||
// code as the status value.
|
||
//
|
||
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
if (AnsiString.Buffer != NULL) {
|
||
ExFreePool((PVOID)AnsiString.Buffer);
|
||
}
|
||
|
||
return GetExceptionCode();
|
||
}
|
||
|
||
//
|
||
// Allocate nonpaged pool to receive variable value.
|
||
//
|
||
|
||
ValueBuffer = (PCHAR)ExAllocatePool(NonPagedPool, MAXIMUM_ENVIRONMENT_VALUE);
|
||
if (ValueBuffer == NULL) {
|
||
ExFreePool((PVOID)AnsiString.Buffer);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// Lock paged code in memory, acquire environment spin lock, get the
|
||
// system environment variable value, release the environment spin
|
||
// lock, and unlock pageable code.
|
||
//
|
||
|
||
MmLockPagableSectionByHandle (ExPageLockHandle);
|
||
ExAcquireFastMutex(&ExpEnvironmentLock);
|
||
ArcStatus = HalGetEnvironmentVariable(AnsiString.Buffer,
|
||
MAXIMUM_ENVIRONMENT_VALUE,
|
||
ValueBuffer);
|
||
|
||
ExReleaseFastMutex(&ExpEnvironmentLock);
|
||
MmUnlockPagableImageSection(ExPageLockHandle);
|
||
|
||
//
|
||
// Free the ANSI string buffer used to hold the variable name.
|
||
//
|
||
|
||
ExFreePool((PVOID)AnsiString.Buffer);
|
||
|
||
//
|
||
// If the specified environemnt variable was not found, then free
|
||
// the value buffer and return an unsuccessful status.
|
||
//
|
||
|
||
if (ArcStatus != ESUCCESS) {
|
||
ExFreePool((PVOID)ValueBuffer);
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Establish an exception handler and attempt to write the value of the
|
||
// specified system environment variable. If the write attempt fails,
|
||
// then return the exception code as the service status.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Initialize an ANSI string descriptor, set the maximum length and
|
||
// buffer address for a UNICODE string descriptor, and convert the
|
||
// ANSI variable value to UNICODE.
|
||
//
|
||
|
||
RtlInitString(&AnsiString, ValueBuffer);
|
||
UnicodeString.Buffer = (PWSTR)VariableValue;
|
||
UnicodeString.MaximumLength = ValueLength;
|
||
NtStatus = RtlAnsiStringToUnicodeString(&UnicodeString,
|
||
&AnsiString,
|
||
FALSE);
|
||
|
||
//
|
||
// If argument is present, then write the length of the UNICODE
|
||
// variable value.
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT(ReturnLength)) {
|
||
*ReturnLength = UnicodeString.Length;
|
||
}
|
||
|
||
//
|
||
// Free the value buffer used to hold the variable value.
|
||
//
|
||
|
||
ExFreePool((PVOID)ValueBuffer);
|
||
return NtStatus;
|
||
|
||
//
|
||
// If an exception occurs during the write of the variable value, or
|
||
// the write of the return length, then always handle the exception
|
||
// and return the exception code as the status value.
|
||
//
|
||
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
ExFreePool((PVOID)ValueBuffer);
|
||
return GetExceptionCode();
|
||
}
|
||
}
|
||
|
||
NTSTATUS
|
||
NtSetSystemEnvironmentValue (
|
||
IN PUNICODE_STRING VariableName,
|
||
IN PUNICODE_STRING VariableValue
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sets the specified system environment variable to the
|
||
specified value.
|
||
|
||
N.B. This service requires the system environment privilege.
|
||
|
||
Arguments:
|
||
|
||
Variable - Supplies a pointer to a UNICODE descriptor for the specified
|
||
system environment variable name.
|
||
|
||
Value - Supplies a pointer to a UNICODE descriptor for the specified
|
||
system environment variable value.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS is returned if the service is successfully executed.
|
||
|
||
STATUS_PRIVILEGE_NOT_HELD is returned if the caller does not have the
|
||
privilege to set a system environment variable.
|
||
|
||
STATUS_ACCESS_VIOLATION is returned if the input parameter for the
|
||
system environment variable or value cannot be read.
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
|
||
for this request to complete.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ULONG AnsiLength1;
|
||
ULONG AnsiLength2;
|
||
ANSI_STRING AnsiString1;
|
||
ANSI_STRING AnsiString2;
|
||
ARC_STATUS ArcStatus;
|
||
BOOLEAN HasPrivilege;
|
||
KPROCESSOR_MODE PreviousMode;
|
||
NTSTATUS NtStatus;
|
||
UNICODE_STRING UnicodeString1;
|
||
UNICODE_STRING UnicodeString2;
|
||
|
||
//
|
||
// Clear address of ANSI buffers.
|
||
//
|
||
|
||
AnsiString1.Buffer = NULL;
|
||
AnsiString2.Buffer = NULL;
|
||
|
||
//
|
||
// Establish an exception handler and attempt to set the value of the
|
||
// specified system environment variable. If the read attempt for the
|
||
// system environment variable or value fails, then return the exception
|
||
// code as the service status. Otherwise, return either success or access
|
||
// denied as the service status.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Get previous processor mode and probe arguments if necessary.
|
||
//
|
||
|
||
PreviousMode = KeGetPreviousMode();
|
||
if (PreviousMode != KernelMode) {
|
||
|
||
//
|
||
// Probe and capture the string descriptor for the system
|
||
// environment variable name.
|
||
//
|
||
|
||
ProbeForRead((PVOID)VariableName,
|
||
sizeof(UNICODE_STRING),
|
||
sizeof(ULONG));
|
||
|
||
UnicodeString1 = *VariableName;
|
||
|
||
//
|
||
// Probe the system environment variable name.
|
||
//
|
||
|
||
ProbeForRead((PVOID)UnicodeString1.Buffer,
|
||
UnicodeString1.Length,
|
||
sizeof(WCHAR));
|
||
|
||
//
|
||
// Probe and capture the string descriptor for the system
|
||
// environment variable value.
|
||
//
|
||
|
||
ProbeForRead((PVOID)VariableValue,
|
||
sizeof(UNICODE_STRING),
|
||
sizeof(ULONG));
|
||
|
||
UnicodeString2 = *VariableValue;
|
||
|
||
//
|
||
// Probe the system environment variable value.
|
||
//
|
||
|
||
ProbeForRead((PVOID)UnicodeString2.Buffer,
|
||
UnicodeString2.Length,
|
||
sizeof(WCHAR));
|
||
|
||
//
|
||
// Check if the current thread has the privilege to query a system
|
||
// environment variable.
|
||
//
|
||
|
||
HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
|
||
PreviousMode);
|
||
|
||
if (HasPrivilege == FALSE) {
|
||
return(STATUS_PRIVILEGE_NOT_HELD);
|
||
}
|
||
|
||
} else {
|
||
UnicodeString1 = *VariableName;
|
||
UnicodeString2 = *VariableValue;
|
||
}
|
||
|
||
|
||
//
|
||
// Compute the size of the ANSI variable name, allocate a nonpaged
|
||
// buffer, and convert the specified UNICODE variable name to ANSI.
|
||
//
|
||
|
||
AnsiLength1 = RtlUnicodeStringToAnsiSize(&UnicodeString1);
|
||
AnsiString1.Buffer = (PCHAR)ExAllocatePool(NonPagedPool, AnsiLength1);
|
||
if (AnsiString1.Buffer == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
AnsiString1.MaximumLength = (USHORT)AnsiLength1;
|
||
NtStatus = RtlUnicodeStringToAnsiString(&AnsiString1,
|
||
&UnicodeString1,
|
||
FALSE);
|
||
|
||
if (NT_SUCCESS(NtStatus) == FALSE) {
|
||
ExFreePool((PVOID)AnsiString1.Buffer);
|
||
return NtStatus;
|
||
}
|
||
|
||
//
|
||
// Compute the size of the ANSI variable value, allocate a nonpaged
|
||
// buffer, and convert the specified UNICODE variable value to ANSI.
|
||
//
|
||
|
||
AnsiLength2 = RtlUnicodeStringToAnsiSize(&UnicodeString2);
|
||
AnsiString2.Buffer = (PCHAR)ExAllocatePool(NonPagedPool, AnsiLength2);
|
||
if (AnsiString2.Buffer == NULL) {
|
||
ExFreePool((PVOID)AnsiString1.Buffer);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
AnsiString2.MaximumLength = (USHORT)AnsiLength2;
|
||
NtStatus = RtlUnicodeStringToAnsiString(&AnsiString2,
|
||
&UnicodeString2,
|
||
FALSE);
|
||
|
||
if (NT_SUCCESS(NtStatus) == FALSE) {
|
||
ExFreePool((PVOID)AnsiString1.Buffer);
|
||
ExFreePool((PVOID)AnsiString2.Buffer);
|
||
return NtStatus;
|
||
}
|
||
|
||
//
|
||
// If an exception occurs during the read of the variable descriptor,
|
||
// the read of the variable name, the read of the value descriptor, or
|
||
// the read of the value, then always handle the exception, free the
|
||
// ANSI string buffers if necessary, and return the exception code as
|
||
// the status value.
|
||
//
|
||
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
if (AnsiString1.Buffer != NULL) {
|
||
ExFreePool((PVOID)AnsiString1.Buffer);
|
||
}
|
||
|
||
if (AnsiString2.Buffer != NULL) {
|
||
ExFreePool((PVOID)AnsiString2.Buffer);
|
||
}
|
||
|
||
return GetExceptionCode();
|
||
}
|
||
|
||
//
|
||
// Lock paged code in memory, acquire environment spin lock, set the
|
||
// system environment variable value, release the environment spin
|
||
// lock, and unlock pageable code.
|
||
//
|
||
|
||
MmLockPagableSectionByHandle (ExPageLockHandle);
|
||
ExAcquireFastMutex(&ExpEnvironmentLock);
|
||
ArcStatus = HalSetEnvironmentVariable(AnsiString1.Buffer,
|
||
AnsiString2.Buffer);
|
||
|
||
ExReleaseFastMutex(&ExpEnvironmentLock);
|
||
MmUnlockPagableImageSection(ExPageLockHandle);
|
||
|
||
//
|
||
// Free the ANSI string buffers used to hold the variable name and value.
|
||
//
|
||
|
||
ExFreePool((PVOID)AnsiString1.Buffer);
|
||
ExFreePool((PVOID)AnsiString2.Buffer);
|
||
|
||
//
|
||
// If the specified value of the specified environment variable was
|
||
// successfully set, then return a success status. Otherwise, return
|
||
// insufficient resources.
|
||
//
|
||
|
||
if (ArcStatus == ESUCCESS) {
|
||
return STATUS_SUCCESS;
|
||
|
||
} else {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
}
|