mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
694 lines
17 KiB
694 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
util.c
|
|
|
|
Abstract:
|
|
|
|
This module implements all utility functions.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 21-Oct-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "cmdcons.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
#include "remboot.h"
|
|
|
|
HANDLE NetUseHandles[26] = { NULL };
|
|
BOOLEAN RdrIsInKernelMode = FALSE;
|
|
|
|
RC_ALLOWED_DIRECTORY AllowedDirs[] = {
|
|
{ FALSE, L"$WIN_NT$.~BT" },
|
|
{ FALSE, L"$WIN_NT$.~LS" },
|
|
{ FALSE, L"CMDCONS" },
|
|
{ TRUE, L"SYSTEM VOLUME INFORMATION" }
|
|
};
|
|
|
|
BOOLEAN
|
|
RcIsPathNameAllowed(
|
|
IN LPCWSTR FullPath,
|
|
IN BOOLEAN RemovableMediaOk,
|
|
IN BOOLEAN Mkdir
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine verifies that the specified path name is
|
|
allowed based on the security context that the console
|
|
user is logged into.
|
|
|
|
Arguments:
|
|
|
|
FullPath - specifies the full path to be verified.
|
|
|
|
Return Value:
|
|
|
|
FALSE if failure, indicating the path is not allowed.
|
|
TRUE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR TempBuf[MAX_PATH*2];
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
HANDLE Handle;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
NTSTATUS Status;
|
|
BOOL isDirectory = TRUE;
|
|
|
|
//
|
|
// should we bypass security?
|
|
//
|
|
|
|
if (AllowAllPaths) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// some special processing for dos paths
|
|
// we must make sure that only the root and %systemdir% are allowed.
|
|
//
|
|
|
|
if (FullPath[1] == L':' && FullPath[2] == L'\\' && FullPath[3] == 0) {
|
|
//
|
|
// root directory is ok.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
SpStringToUpper((PWSTR)FullPath);
|
|
|
|
if (!RcGetNTFileName((PWSTR)FullPath,TempBuf))
|
|
return FALSE;
|
|
|
|
INIT_OBJA(&Obja,&UnicodeString,TempBuf);
|
|
|
|
Status = ZwOpenFile(
|
|
&Handle,
|
|
FILE_READ_ATTRIBUTES,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_DIRECTORY_FILE
|
|
);
|
|
if( !NT_SUCCESS(Status) ) {
|
|
isDirectory = FALSE;
|
|
|
|
} else {
|
|
ZwClose( Handle );
|
|
}
|
|
|
|
if (isDirectory == FALSE && wcsrchr( FullPath, L'\\' ) == ( &FullPath[2] )) {
|
|
//
|
|
// if the cannonicalized path has only one slash the user is trying to do something
|
|
// to the files in the root, which we allow.
|
|
//
|
|
// however we do not allow users to mess with directories at the root
|
|
//
|
|
if (Mkdir) {
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
ASSERT(SelectedInstall != NULL);
|
|
|
|
if(SelectedInstall != NULL) {
|
|
//
|
|
// Get the length of the first element in the path
|
|
//
|
|
PCWSTR sz;
|
|
DWORD Len;
|
|
DWORD i;
|
|
WCHAR SelectedInstallDrive;
|
|
|
|
sz = wcschr(FullPath + 3, L'\\');
|
|
|
|
if(NULL == sz) {
|
|
sz = FullPath + wcslen(FullPath);
|
|
}
|
|
|
|
Len = (DWORD) ((sz - FullPath) - 3);
|
|
SelectedInstallDrive = RcToUpper(SelectedInstall->DriveLetter);
|
|
|
|
//
|
|
// See if path begins with the install path
|
|
//
|
|
if(FullPath[0] == SelectedInstallDrive && 0 == _wcsnicmp(FullPath + 3, SelectedInstall->Path, Len)) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// See if the path begins with an allowed dir
|
|
//
|
|
for(i = 0; i < sizeof(AllowedDirs) / sizeof(AllowedDirs[0]); ++i) {
|
|
if((!AllowedDirs[i].MustBeOnInstallDrive || FullPath[0] == SelectedInstallDrive) &&
|
|
0 == _wcsnicmp(FullPath + 3, AllowedDirs[i].Directory, Len)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (RcIsFileOnRemovableMedia(TempBuf) == STATUS_SUCCESS) {
|
|
if (RemovableMediaOk) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (RcIsNetworkDrive(TempBuf) == STATUS_SUCCESS) {
|
|
//
|
|
// Context that was used for connection will do appropriate security checking.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
RcDoesPathHaveWildCards(
|
|
IN LPCWSTR FullPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine verifies that the specified path name is
|
|
allowed based on the security context that the console
|
|
user is logged into.
|
|
|
|
Arguments:
|
|
|
|
FullPath - specifies the full path to be verified.
|
|
|
|
Return Value:
|
|
|
|
FALSE if failure, indicating the path is not allowed.
|
|
TRUE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (wcsrchr( FullPath, L'*' )) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (wcsrchr( FullPath, L'?' )) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
NTSTATUS
|
|
RcIsNetworkDrive(
|
|
IN PWSTR FileName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns if the FileName given is a network path.
|
|
|
|
Arguments:
|
|
|
|
FileName - specifies the full path to be checked.
|
|
|
|
Return Value:
|
|
|
|
Any other than STATUS_SUCCESS if failure, indicating the path is not on the network,
|
|
STATUS_SUCCESS otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
FILE_FS_DEVICE_INFORMATION DeviceInfo;
|
|
PWSTR BaseNtName;
|
|
|
|
if (wcsncmp(FileName, L"\\DosDevice", wcslen(L"\\DosDevice")) == 0) {
|
|
Status = GetDriveLetterLinkTarget( FileName, &BaseNtName );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
} else {
|
|
BaseNtName = FileName;
|
|
}
|
|
|
|
Status = pRcGetDeviceInfo( BaseNtName, &DeviceInfo );
|
|
if(NT_SUCCESS(Status)) {
|
|
if (DeviceInfo.DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM) {
|
|
Status = STATUS_NO_MEDIA;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RcDoNetUse(
|
|
PWSTR Share,
|
|
PWSTR User,
|
|
PWSTR Password,
|
|
PWSTR Drive
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine attempts to make a connection using the redirector to the remote server.
|
|
|
|
Arguments:
|
|
|
|
Share - A string of the form "\\server\share"
|
|
|
|
User - A string of the form "domain\user"
|
|
|
|
Password - A string containing the password information.
|
|
|
|
Drive - Filled in with a string of the form "X", where X is the drive letter the share
|
|
has been mapped to.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, indicating Drive contains the mapped drive letter,
|
|
otherwise the appropriate error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PWSTR NtDeviceName;
|
|
ULONG ShareLength;
|
|
WCHAR DriveLetter;
|
|
WCHAR temporaryBuffer[128];
|
|
PWCHAR Temp, Temp2;
|
|
HANDLE Handle;
|
|
ULONG EaBufferLength;
|
|
PWSTR UserName;
|
|
PWSTR DomainName;
|
|
PVOID EaBuffer;
|
|
UNICODE_STRING UnicodeString;
|
|
UNICODE_STRING UnicodeString2;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PFILE_FULL_EA_INFORMATION FullEaInfo;
|
|
|
|
//
|
|
// Switch the redirector to kernel-mode security if it is not.
|
|
//
|
|
if (!RdrIsInKernelMode) {
|
|
Status = PutRdrInKernelMode();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
RdrIsInKernelMode = TRUE;
|
|
}
|
|
|
|
//
|
|
// Search for an open drive letter, starting at D: and working up.
|
|
//
|
|
wcscpy(temporaryBuffer, L"\\DosDevices\\D:");
|
|
Temp = wcsstr(temporaryBuffer, L"D:");
|
|
|
|
for (DriveLetter = L'D'; (Temp && (DriveLetter <= L'Z')); DriveLetter++) {
|
|
*Temp = DriveLetter;
|
|
|
|
Status = GetDriveLetterLinkTarget( temporaryBuffer, &Temp2 );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (DriveLetter > L'Z') {
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
}
|
|
|
|
//
|
|
// Build the NT device name.
|
|
//
|
|
ShareLength = wcslen(Share);
|
|
NtDeviceName = SpMemAlloc(ShareLength * sizeof(WCHAR) + sizeof(L"\\Device\\LanmanRedirector\\;X:0"));
|
|
if (NtDeviceName == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
wcscpy(NtDeviceName, L"\\Device\\LanmanRedirector\\;");
|
|
temporaryBuffer[0] = DriveLetter;
|
|
temporaryBuffer[1] = UNICODE_NULL;
|
|
wcscat(NtDeviceName, temporaryBuffer);
|
|
wcscat(NtDeviceName, L":0");
|
|
wcscat(NtDeviceName, Share + 1);
|
|
|
|
//
|
|
// Chop the username and domainname into individual values.
|
|
//
|
|
wcscpy(temporaryBuffer, User);
|
|
DomainName = temporaryBuffer;
|
|
UserName = wcsstr(temporaryBuffer, L"\\");
|
|
|
|
if (UserName == NULL) {
|
|
SpMemFree(NtDeviceName);
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
}
|
|
*UserName = UNICODE_NULL;
|
|
UserName++;
|
|
|
|
//
|
|
// Create buffer with user credentials
|
|
//
|
|
|
|
EaBufferLength = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]);
|
|
EaBufferLength += sizeof(EA_NAME_DOMAIN);
|
|
EaBufferLength += (wcslen(DomainName) * sizeof(WCHAR));
|
|
if (EaBufferLength & (sizeof(ULONG) - 1)) {
|
|
//
|
|
// Long align the next entry
|
|
//
|
|
EaBufferLength += (sizeof(ULONG) - (EaBufferLength & (sizeof(ULONG) - 1)));
|
|
}
|
|
|
|
EaBufferLength += FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]);
|
|
EaBufferLength += sizeof(EA_NAME_USERNAME);
|
|
EaBufferLength += (wcslen(UserName) * sizeof(WCHAR));
|
|
if (EaBufferLength & (sizeof(ULONG) - 1)) {
|
|
//
|
|
// Long align the next entry
|
|
//
|
|
EaBufferLength += (sizeof(ULONG) - (EaBufferLength & (sizeof(ULONG) - 1)));
|
|
}
|
|
|
|
EaBufferLength += FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]);
|
|
EaBufferLength += sizeof(EA_NAME_PASSWORD);
|
|
EaBufferLength += (wcslen(Password) * sizeof(WCHAR));
|
|
|
|
EaBuffer = SpMemAlloc(EaBufferLength);
|
|
if (EaBuffer == NULL) {
|
|
SpMemFree(NtDeviceName);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
FullEaInfo = (PFILE_FULL_EA_INFORMATION)EaBuffer;
|
|
|
|
FullEaInfo->Flags = 0;
|
|
FullEaInfo->EaNameLength = sizeof(EA_NAME_DOMAIN) - 1;
|
|
FullEaInfo->EaValueLength = (wcslen(DomainName)) * sizeof(WCHAR);
|
|
strcpy(&(FullEaInfo->EaName[0]), EA_NAME_DOMAIN);
|
|
memcpy(&(FullEaInfo->EaName[FullEaInfo->EaNameLength + 1]), DomainName, FullEaInfo->EaValueLength);
|
|
FullEaInfo->NextEntryOffset = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
|
|
FullEaInfo->EaNameLength + 1 +
|
|
FullEaInfo->EaValueLength;
|
|
if (FullEaInfo->NextEntryOffset & (sizeof(ULONG) - 1)) {
|
|
FullEaInfo->NextEntryOffset += (sizeof(ULONG) -
|
|
(FullEaInfo->NextEntryOffset &
|
|
(sizeof(ULONG) - 1)));
|
|
}
|
|
|
|
|
|
FullEaInfo = (PFILE_FULL_EA_INFORMATION)(((char *)FullEaInfo) + FullEaInfo->NextEntryOffset);
|
|
|
|
FullEaInfo->Flags = 0;
|
|
FullEaInfo->EaNameLength = sizeof(EA_NAME_USERNAME) - 1;
|
|
FullEaInfo->EaValueLength = (wcslen(UserName)) * sizeof(WCHAR);
|
|
strcpy(&(FullEaInfo->EaName[0]), EA_NAME_USERNAME);
|
|
memcpy(&(FullEaInfo->EaName[FullEaInfo->EaNameLength + 1]), UserName, FullEaInfo->EaValueLength);
|
|
FullEaInfo->NextEntryOffset = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
|
|
FullEaInfo->EaNameLength + 1 +
|
|
FullEaInfo->EaValueLength;
|
|
if (FullEaInfo->NextEntryOffset & (sizeof(ULONG) - 1)) {
|
|
FullEaInfo->NextEntryOffset += (sizeof(ULONG) -
|
|
(FullEaInfo->NextEntryOffset &
|
|
(sizeof(ULONG) - 1)));
|
|
}
|
|
|
|
|
|
FullEaInfo = (PFILE_FULL_EA_INFORMATION)(((char *)FullEaInfo) + FullEaInfo->NextEntryOffset);
|
|
|
|
FullEaInfo->Flags = 0;
|
|
FullEaInfo->EaNameLength = sizeof(EA_NAME_PASSWORD) - 1;
|
|
FullEaInfo->EaValueLength = (wcslen(Password)) * sizeof(WCHAR);
|
|
strcpy(&(FullEaInfo->EaName[0]), EA_NAME_PASSWORD);
|
|
memcpy(&(FullEaInfo->EaName[FullEaInfo->EaNameLength + 1]), Password, FullEaInfo->EaValueLength);
|
|
FullEaInfo->NextEntryOffset = 0;
|
|
|
|
//
|
|
// Now make the connection
|
|
//
|
|
RtlInitUnicodeString(&UnicodeString, NtDeviceName);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = ZwCreateFile(&Handle,
|
|
SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ,
|
|
FILE_OPEN_IF,
|
|
(FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT),
|
|
EaBuffer,
|
|
EaBufferLength
|
|
);
|
|
|
|
if (NT_SUCCESS(Status) && NT_SUCCESS(IoStatusBlock.Status)) {
|
|
//
|
|
// Save off the handle so we can close it later if need be
|
|
//
|
|
NetUseHandles[DriveLetter - L'A'] = Handle;
|
|
Drive[0] = DriveLetter;
|
|
Drive[1] = L':';
|
|
Drive[2] = UNICODE_NULL;
|
|
|
|
//
|
|
// Now create a symbolic link from the dos drive letter to the redirector
|
|
//
|
|
wcscpy(temporaryBuffer, L"\\DosDevices\\");
|
|
wcscat(temporaryBuffer, Drive);
|
|
RtlInitUnicodeString(&UnicodeString2, temporaryBuffer);
|
|
|
|
Status = IoCreateSymbolicLink(&UnicodeString2, &UnicodeString);
|
|
if (!NT_SUCCESS(Status)) {
|
|
ZwClose(Handle);
|
|
NetUseHandles[DriveLetter - L'A'] = NULL;
|
|
} else {
|
|
RcAddDrive(DriveLetter);
|
|
}
|
|
|
|
}
|
|
|
|
SpMemFree(NtDeviceName);
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RcNetUnuse(
|
|
PWSTR Drive
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine closes a network connection.
|
|
|
|
Arguments:
|
|
|
|
Drive - A string of the form "X:", where X is the drive letter returned by a previous call to
|
|
NetDoNetUse().
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, indicating the drive letter has been unmapped,
|
|
otherwise the appropriate error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
WCHAR DriveLetter;
|
|
WCHAR temporaryBuffer[128];
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
DriveLetter = *Drive;
|
|
if ((DriveLetter >= L'a') && (DriveLetter <= L'z')) {
|
|
DriveLetter = L'A' + (DriveLetter - L'a');
|
|
}
|
|
|
|
if ((DriveLetter < L'A') | (DriveLetter > L'Z')) {
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
}
|
|
|
|
if (NetUseHandles[DriveLetter - L'A'] == NULL) {
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
}
|
|
|
|
if (RcGetCurrentDriveLetter() == DriveLetter) {
|
|
return STATUS_CONNECTION_IN_USE;
|
|
}
|
|
|
|
wcscpy(temporaryBuffer, L"\\DosDevices\\");
|
|
wcscat(temporaryBuffer, Drive);
|
|
RtlInitUnicodeString(&UnicodeString, temporaryBuffer);
|
|
|
|
Status = IoDeleteSymbolicLink(&UnicodeString);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
ZwClose(NetUseHandles[DriveLetter - L'A']);
|
|
NetUseHandles[DriveLetter - L'A'] = NULL;
|
|
RcRemoveDrive(DriveLetter);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PutRdrInKernelMode(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine IOCTLs down to the rdr to force it to use kernel-mode security.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful, otherwise the appropriate error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
NTSTATUS Status;
|
|
HANDLE Handle;
|
|
|
|
RtlInitUnicodeString(&UnicodeString, DD_NFS_DEVICE_NAME_U);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = ZwCreateFile(
|
|
&Handle,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("SPCMDCON: Unable to open redirector. %x\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
Status = ZwDeviceIoControlFile(Handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
IOCTL_LMMR_USEKERNELSEC,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = IoStatusBlock.Status;
|
|
}
|
|
|
|
ZwClose(Handle);
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
RcIsArc(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Run time check to determine if this is an Arc system. We attempt to read an
|
|
Arc variable using the Hal. This will fail for Bios based systems.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
True = This is an Arc system.
|
|
|
|
--*/
|
|
|
|
{
|
|
#ifdef _X86_
|
|
ARC_STATUS ArcStatus = EBADF;
|
|
//
|
|
// Get the env var into the temp buffer.
|
|
//
|
|
UCHAR wbuff[130];
|
|
//
|
|
// Get the env var into the temp buffer.
|
|
//
|
|
ArcStatus = HalGetEnvironmentVariable(
|
|
"OsLoader",
|
|
sizeof(wbuff),
|
|
wbuff
|
|
);
|
|
|
|
return((ArcStatus == ESUCCESS) ? TRUE: FALSE);
|
|
#else
|
|
return TRUE;
|
|
#endif
|
|
}
|