mirror of https://github.com/lianthony/NT4.0
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.
1674 lines
46 KiB
1674 lines
46 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sbcnfg.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code necessary to initialize the
|
|
OS/2 SS entries in the registry. Since the SS modifies the
|
|
system environment, we need a privileged process to do this,
|
|
and so we run it in os2ss.exe. This initialization takes
|
|
place the 1st time that os2ss.exe is run after system setup,
|
|
or whenever the CONFIG.SYS entry in the registry disappears.
|
|
|
|
Author:
|
|
|
|
Ofer Porat (oferp) 16-Mar-1993
|
|
|
|
Environment:
|
|
|
|
User Mode only
|
|
|
|
Revision History:
|
|
|
|
Code was originally in server\srvcnfg.c.
|
|
|
|
--*/
|
|
|
|
//
|
|
// Only compiled for PMNT
|
|
//
|
|
|
|
#ifdef PMNT
|
|
|
|
#include <wchar.h>
|
|
#include "os2srv.h"
|
|
|
|
#define PATHLIST_MAX 1024 // max length of pathlists such as Os2LibPath (in characters)
|
|
#define MAX_CONSYS_SIZE 16384 // max size of config.sys buffers (in bytes)
|
|
#define DOS_DEV_LEN 12 // length of "\\DosDevices\\"
|
|
|
|
static WCHAR Os2SoftwareDirectory[] = L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft";
|
|
static WCHAR Os2ProductDirectory[] = L"OS/2 Subsystem for NT";
|
|
static WCHAR Os2VersionDirectory[] = L"1.0";
|
|
static WCHAR Os2IniName[] = L"os2.ini";
|
|
static WCHAR Os2ConfigSysName[] = L"config.sys";
|
|
static WCHAR Os2Class[] = L"OS2SS";
|
|
static CHAR Os2ConfigSysDefaultValue[] =
|
|
//
|
|
// The '\a' in the following strings will be replaced by the SystemDirectory Value
|
|
//
|
|
"NTREM Here is a summary of what is allowed to appear in this registry entry:\0"
|
|
"NTREM Comments starting with REM will be visible to the user when s/he opens\0"
|
|
"NTREM c:\\config.sys.\0"
|
|
"NTREM Comments starting with NTREM are only visible by direct access to the\0"
|
|
"NTREM registry.\0"
|
|
"NTREM The following OS/2 configuration commands are significant:\0"
|
|
"NTREM COUNTRY=\0"
|
|
"NTREM CODEPAGE=\0"
|
|
"NTREM DEVINFO=KBD,\0"
|
|
"NTREM Any other commands apart from the exceptions listed below will be\0"
|
|
"NTREM visible to an OS/2 program that opens c:\\config.sys, however they are\0"
|
|
"NTREM not used internally by the NT OS/2 SubSystem.\0"
|
|
"NTREM Exceptions:\0"
|
|
"NTREM The following commands are completely ignored. Their true values\0"
|
|
"NTREM appear in the system environment and should be modified using the\0"
|
|
"NTREM Control Panel System applet. Note that LIBPATH is called Os2LibPath\0"
|
|
"NTREM in the NT system environment.\0"
|
|
"SET PATH=<ignored>\0"
|
|
"LIBPATH=<ignored>\0"
|
|
"NTREM In addition, any \"SET=\" commands (except COMSPEC) will be\0"
|
|
"NTREM completely ignored. You should set OS/2 environment variables just\0"
|
|
"NTREM like any other Windows NT environment variables by using the Control\0"
|
|
"NTREM Panel System applet.\0"
|
|
"NTREM If you have an OS/2 editor available, it is highly recommended that you\0"
|
|
"NTREM modify NT OS/2 config.sys coniguration by editing c:\\config.sys with\0"
|
|
"NTREM this editor. This is the documented way to make such modification, and\0"
|
|
"NTREM is therefore less error-prone.\0"
|
|
"NTREM Now comes the actual text.\0"
|
|
"REM\0"
|
|
"REM This is a fake OS/2 config.sys file used by the NT OS/2 SubSystem.\0"
|
|
"REM The following information resides in the Registry and NOT in a disk file.\0"
|
|
"REM OS/2 Apps that access c:\\config.sys actually manipulate this information.\0"
|
|
"REM\0"
|
|
"PROTSHELL=c:\\os2\\pmshell.exe c:\\os2\\os2.ini c:\\os2\\os2sys.ini \a\\cmd.exe\0"
|
|
"SET COMSPEC=\a\\cmd.exe\0"
|
|
;
|
|
|
|
static WCHAR Os2ConfigSysKeyName[] =
|
|
L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\OS/2 Subsystem for NT\\1.0\\config.sys";
|
|
static WCHAR Os2EnvironmentDirectory[] =
|
|
L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
|
|
static HANDLE Os2EnvironmentKeyHandle = NULL;
|
|
|
|
static WCHAR Os2OriginalCanonicalConfigSys[] = L"\\DosDevices\\C:\\CONFIG.SYS";
|
|
|
|
static BOOLEAN Os2LibPathFound = FALSE;
|
|
static WCHAR Os2LibPathValueName[] = L"Os2LibPath";
|
|
static UNICODE_STRING Os2LibPathValueData_U;
|
|
|
|
static PWSTR pOs2ConfigSys = NULL;
|
|
static ULONG Os2SizeOfConfigSys = 0;
|
|
static PWSTR pOs2UpperCaseConfigSys = NULL;
|
|
|
|
static WCHAR Os2SystemDirectory[DOS_MAX_PATH_LENGTH];
|
|
|
|
|
|
VOID
|
|
Os2InitMBString(
|
|
PANSI_STRING DestinationString,
|
|
PCSZ SourceString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine init an ASCII character string (buffer and length)
|
|
|
|
Arguments:
|
|
|
|
DestinationString - pointer to ansi string to put the result in
|
|
|
|
SourceString - pointer to ansi null terminated string to read from
|
|
|
|
Return Value:
|
|
|
|
|
|
Note:
|
|
|
|
Od2ProcessCodePage is used as the code page for the mapping.
|
|
|
|
Od2CurrentCodePageIsOem is check to see if RtlOem NLS routines
|
|
can be used.
|
|
--*/
|
|
|
|
{
|
|
|
|
// BUGBUG: add support if Code Page is diff from OEMCP
|
|
|
|
RtlInitAnsiString(
|
|
DestinationString,
|
|
SourceString);
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Os2MBStringToUnicodeString(
|
|
PUNICODE_STRING DestinationString,
|
|
PANSI_STRING SourceString,
|
|
BOOLEAN AllocateDestinationString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine map a multibyte character string to its unicode character
|
|
counterpart.
|
|
|
|
Arguments:
|
|
|
|
DestinationString - pointer to unicode string to get the mapping result
|
|
|
|
SourceString - pointer to ansi string to read string to map from
|
|
|
|
AllocateDestinationString - flag indicating if need to allocate space
|
|
for destination string
|
|
|
|
Return Value:
|
|
|
|
|
|
Note:
|
|
|
|
Od2ProcessCodePage is used as the code page for the mapping.
|
|
|
|
Od2CurrentCodePageIsOem is check to see if RtlOem NLS routines
|
|
can be used.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
// BUGBUG: add support if Code Page is diff from OEMCP (use Od2CurrentCodePageIsOem)
|
|
|
|
Status = RtlOemStringToUnicodeString(
|
|
DestinationString,
|
|
(POEM_STRING)SourceString,
|
|
AllocateDestinationString
|
|
);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Os2InitOriginalConfigSysProcessing(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function checks if there is an OS/2 config.sys configuration file on the
|
|
disk. If so, it opens it and reads it in. The file is converted to UNICODE,
|
|
and an upper case copy of it is made.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if there's an OS/2 config.sys, and all the operations needed to prepare
|
|
it have succeeded. FALSE otherwise.
|
|
|
|
Notes:
|
|
On success Sets global variables as follows:
|
|
pOs2ConfigSys - a null-terminated UNICODE copy of the OS/2 config.sys.
|
|
pOs2UpperCaseConfigSys - an upper case copy of pOs2ConfigSys.
|
|
Os2SizeOfConfigSys - the number of characters in the above strings.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING CanonicalConfigDotSys_U;
|
|
UNICODE_STRING Tmp_U;
|
|
ANSI_STRING Tmp_MB;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
FILE_STANDARD_INFORMATION FileStandardInfo;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
HANDLE ConfigSysFileHandle;
|
|
PSZ pTempOs2ConfigSys;
|
|
|
|
// Try opening OS/2's config.sys file
|
|
|
|
RtlInitUnicodeString(&CanonicalConfigDotSys_U, Os2OriginalCanonicalConfigSys);
|
|
|
|
InitializeObjectAttributes(&Obja,
|
|
&CanonicalConfigDotSys_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenFile(&ConfigSysFileHandle,
|
|
FILE_GENERIC_READ,
|
|
&Obja,
|
|
&IoStatus,
|
|
FILE_SHARE_READ,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT )
|
|
{
|
|
KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - NtOpenFile-1 %lx\n", Status));
|
|
}
|
|
#endif
|
|
return (FALSE);
|
|
}
|
|
|
|
// Get the file length
|
|
|
|
Status = NtQueryInformationFile(ConfigSysFileHandle,
|
|
&IoStatus,
|
|
&FileStandardInfo,
|
|
sizeof(FileStandardInfo),
|
|
FileStandardInformation
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT )
|
|
{
|
|
KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - NtQueryInformationFile %lx\n", Status));
|
|
}
|
|
#endif
|
|
NtClose(ConfigSysFileHandle);
|
|
return (FALSE);
|
|
}
|
|
|
|
Os2SizeOfConfigSys = FileStandardInfo.EndOfFile.LowPart;
|
|
|
|
// Allocate space for reading it in
|
|
|
|
// the + 1 in following parameter is for inserting the NUL character
|
|
|
|
pTempOs2ConfigSys = (PSZ) RtlAllocateHeap(Os2Heap, 0, Os2SizeOfConfigSys + 1);
|
|
|
|
if (pTempOs2ConfigSys == NULL) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT )
|
|
{
|
|
KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - RtlAllocateHeap pTempOs2ConfigSys\n"));
|
|
}
|
|
#endif
|
|
Os2SizeOfConfigSys = 0;
|
|
NtClose(ConfigSysFileHandle);
|
|
return (FALSE);
|
|
}
|
|
|
|
pOs2ConfigSys = (PWSTR) RtlAllocateHeap(Os2Heap, 0, (Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
|
|
|
|
if (pOs2ConfigSys == NULL) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT )
|
|
{
|
|
KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - RtlAllocateHeap pOs2ConfigSys\n"));
|
|
}
|
|
#endif
|
|
Os2SizeOfConfigSys = 0;
|
|
RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
|
|
NtClose(ConfigSysFileHandle);
|
|
return (FALSE);
|
|
}
|
|
|
|
// Read it in
|
|
|
|
Status = NtReadFile(ConfigSysFileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
(PVOID)pTempOs2ConfigSys,
|
|
Os2SizeOfConfigSys,
|
|
NULL,
|
|
NULL
|
|
);
|
|
NtClose(ConfigSysFileHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT )
|
|
{
|
|
KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - NtReadFile %lx\n", Status));
|
|
}
|
|
#endif
|
|
Os2SizeOfConfigSys = 0;
|
|
RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
|
|
RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
|
|
pOs2ConfigSys = NULL;
|
|
return (FALSE);
|
|
}
|
|
|
|
pTempOs2ConfigSys[Os2SizeOfConfigSys] = '\0';
|
|
|
|
// Convert to UNICODE
|
|
|
|
Os2InitMBString(&Tmp_MB, pTempOs2ConfigSys);
|
|
|
|
Tmp_U.Buffer = pOs2ConfigSys;
|
|
Tmp_U.MaximumLength = (USHORT) ((Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
|
|
|
|
Os2MBStringToUnicodeString(&Tmp_U, &Tmp_MB ,FALSE);
|
|
|
|
Os2SizeOfConfigSys = Tmp_U.Length / sizeof(WCHAR);
|
|
|
|
pOs2ConfigSys[Os2SizeOfConfigSys] = UNICODE_NULL;
|
|
|
|
RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
|
|
|
|
// Prepare the upper case copy
|
|
|
|
pOs2UpperCaseConfigSys = (PWSTR) RtlAllocateHeap(Os2Heap, 0, (Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
|
|
if (pOs2UpperCaseConfigSys == NULL) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT )
|
|
{
|
|
KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - RtlAllocateHeap pOs2UpperConfigSys\n"));
|
|
}
|
|
#endif
|
|
Os2SizeOfConfigSys = 0;
|
|
RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
|
|
pOs2ConfigSys = NULL;
|
|
return (FALSE);
|
|
}
|
|
|
|
wcscpy(pOs2UpperCaseConfigSys, pOs2ConfigSys);
|
|
Or2UnicodeStrupr(pOs2UpperCaseConfigSys);
|
|
|
|
//
|
|
// Verify that the CONFIG.SYS file is really an OS/2 file and not a
|
|
// DOS file.
|
|
// Look for certain strings that MUST appear in an OS/2 CONFIG.SYS
|
|
// file and don't appear in DOS CONFIG.SYS files
|
|
//
|
|
|
|
if ((wcsstr(pOs2UpperCaseConfigSys, L"LIBPATH") == NULL) ||
|
|
(wcsstr(pOs2UpperCaseConfigSys, L"PROTSHELL") == NULL) ||
|
|
(wcsstr(pOs2UpperCaseConfigSys, L"PROTECTONLY") == NULL)
|
|
) {
|
|
Os2SizeOfConfigSys = 0;
|
|
RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
|
|
RtlFreeHeap(Os2Heap, 0, pOs2UpperCaseConfigSys);
|
|
pOs2UpperCaseConfigSys = pOs2ConfigSys = NULL;
|
|
return (FALSE);
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
VOID
|
|
Os2SetDirectiveProcessingDispatchFunction(
|
|
IN ULONG DispatchTableIndex,
|
|
IN PVOID UserParameter,
|
|
IN PWSTR Name,
|
|
IN ULONG NameLen,
|
|
IN PWSTR Value,
|
|
IN ULONG ValueLen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a Dispatch Routine that is used to process SET directives in OS/2's config.sys
|
|
file. The directives are entered into the system environment.
|
|
|
|
Arguments:
|
|
|
|
Standard arguments passed to a Dispatch Function, see the description of
|
|
Or2IterateEnvironment in ssrtl\consys.c
|
|
|
|
UserParameter - points to a pointer which indicates the current position in the
|
|
config.sys registry entry we're building.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
UNICODE_STRING VarName_U; // for setting up variable name
|
|
UNICODE_STRING VarValue_U; // for setting up variable value
|
|
PWSTR Dest = *(PWSTR *) UserParameter;
|
|
NTSTATUS Status;
|
|
ULONG ResultLength;
|
|
WCHAR wch;
|
|
KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
|
|
|
|
// Set up variable name
|
|
|
|
VarName_U.Buffer = Value;
|
|
VarName_U.Length = 0;
|
|
|
|
while ((ValueLen > 0) && (*Value != L'=')) {
|
|
Value++;
|
|
VarName_U.Length += sizeof(WCHAR);
|
|
ValueLen--;
|
|
}
|
|
|
|
if (ValueLen == 0 || // End of line reached without finding '='
|
|
VarName_U.Length == 0) { // Empty name
|
|
return;
|
|
}
|
|
|
|
VarName_U.MaximumLength = VarName_U.Length;
|
|
|
|
// Following SET directives are ignored
|
|
|
|
if (Or2UnicodeEqualCI(VarName_U.Buffer, L"COMSPEC=", 8) ||
|
|
Or2UnicodeEqualCI(VarName_U.Buffer, L"PATH=", 5) ||
|
|
Or2UnicodeEqualCI(VarName_U.Buffer, L"VIDEO_DEVICES=", 14) ||
|
|
Or2UnicodeEqualCI(VarName_U.Buffer, L"VIO_IBMVGA=", 11) ||
|
|
Or2UnicodeEqualCI(VarName_U.Buffer, L"VIO_VGA=", 8) ||
|
|
Or2UnicodeEqualCI(VarName_U.Buffer, L"PROMPT=", 7)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
// Here, we have a valid name, followed by '='
|
|
Value++; // Skip the '='
|
|
ValueLen--;
|
|
|
|
// Set up variable value
|
|
|
|
VarValue_U.Buffer = Value;
|
|
VarValue_U.Length = (USHORT) (ValueLen * sizeof(WCHAR)); // what's left of the line
|
|
VarValue_U.MaximumLength = VarValue_U.Length;
|
|
|
|
//
|
|
// Update the information in the registry with the info
|
|
// in the file
|
|
//
|
|
|
|
#if 0
|
|
// not in effect anymore
|
|
//
|
|
// The KEYS variable is handled in a special way.
|
|
// It's put in the registry config.sys in order to prevent possible
|
|
// conflict.
|
|
//
|
|
|
|
if (Or2UnicodeEqualCI(VarName_U.Buffer, L"KEYS=", 5)) {
|
|
RtlMoveMemory(Dest, L"SET ", 8);
|
|
Dest += 4;
|
|
RtlMoveMemory(Dest, VarName_U.Buffer, VarName_U.Length);
|
|
Dest += VarName_U.Length / sizeof(WCHAR);
|
|
*Dest++ = L'=';
|
|
RtlMoveMemory(Dest, VarValue_U.Buffer, VarValue_U.Length);
|
|
Dest += VarValue_U.Length / sizeof(WCHAR);
|
|
*Dest++ = UNICODE_NULL;
|
|
*(PWSTR *) UserParameter = Dest;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Otherwise, it's stored in the system environment
|
|
//
|
|
|
|
//
|
|
// If Os2EnvironmentKeyHandle is NULL, we don't have
|
|
// write access to the system environment, and we skip
|
|
// setting the variable.
|
|
//
|
|
|
|
if (Os2EnvironmentKeyHandle == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If a value key of the same name already exists,
|
|
// don't replace it. This is done in order to prevent
|
|
// the OS/2 SS from overriding possible NT definitions
|
|
//
|
|
|
|
Status = NtQueryValueKey(Os2EnvironmentKeyHandle,
|
|
&VarName_U,
|
|
KeyValuePartialInformation,
|
|
&KeyValueInfo,
|
|
sizeof(KeyValueInfo),
|
|
&ResultLength
|
|
);
|
|
|
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
|
|
//
|
|
// Set the system wide variable to the value specified
|
|
// in the original OS/2 config.sys
|
|
//
|
|
|
|
wch = Value[ValueLen];
|
|
Value[ValueLen] = UNICODE_NULL;
|
|
|
|
Status = NtSetValueKey(Os2EnvironmentKeyHandle,
|
|
&VarName_U,
|
|
(ULONG)0,
|
|
REG_EXPAND_SZ,
|
|
VarValue_U.Buffer,
|
|
VarValue_U.Length + sizeof(WCHAR)
|
|
);
|
|
|
|
Value[ValueLen] = wch;
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SetDirectiveProcessingDispatchFunction: Unable to NtSetValueKey() system env, rc = %X\n",
|
|
Status));
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
} else {
|
|
#if DBG
|
|
if (Status != STATUS_BUFFER_OVERFLOW) {
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SetDirectiveProcessingDispatchFunction: Unable to NtQueryValueKey() system env, rc = %X\n",
|
|
Status));
|
|
}
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
Os2CommaProcessingDispatchFunction(
|
|
IN ULONG DispatchTableIndex,
|
|
IN PVOID UserParameter,
|
|
IN PWSTR Name,
|
|
IN ULONG NameLen,
|
|
IN PWSTR Value,
|
|
IN ULONG ValueLen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a Dispatch Routine that is used to process certain directives in OS/2's config.sys
|
|
file. The directives are copied into the config.sys registry entry we're building.
|
|
Some directives are truncated after a certain number of commas.
|
|
|
|
Arguments:
|
|
|
|
Standard arguments passed to a Dispatch Function, see the description of
|
|
Or2IterateEnvironment in ssrtl\consys.c
|
|
|
|
UserParameter - points to a pointer which indicates the current position in the
|
|
config.sys registry entry we're building.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Lines passed to this dispatch function need to be copied to the output as are
|
|
// except they should be truncated after a certain number of commas. The
|
|
// following table lists the number of commas. 0 means no truncation.
|
|
//
|
|
ULONG ItemTable[] = { 1, // COUNTRY
|
|
0, // CODEPAGE
|
|
2 // DEVINFO (only with KBD)
|
|
};
|
|
PWSTR Dest = *(PWSTR *) UserParameter;
|
|
ULONG CommaCtr;
|
|
|
|
if (DispatchTableIndex== 2 && !Or2UnicodeEqualCI(Value, L"KBD,", 4)) {
|
|
return;
|
|
}
|
|
|
|
// First, copy the Name
|
|
|
|
RtlMoveMemory(Dest, Name, NameLen * sizeof(WCHAR));
|
|
Dest += NameLen;
|
|
*Dest++ = L'=';
|
|
|
|
// Now, copy the value for the right number of commas
|
|
|
|
CommaCtr = 0;
|
|
|
|
while (ValueLen > 0) {
|
|
if (ItemTable[DispatchTableIndex] != 0 && *Value == L',') {
|
|
CommaCtr++;
|
|
if (CommaCtr == ItemTable[DispatchTableIndex]) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
*Dest++ = *Value++;
|
|
ValueLen--;
|
|
}
|
|
*Dest++ = UNICODE_NULL;
|
|
*(PWSTR *) UserParameter = Dest;
|
|
}
|
|
|
|
|
|
VOID
|
|
Os2ProcessOriginalConfigSys(
|
|
IN OUT PWSTR *DestPtr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function processes OS/2's config.sys file after it has been properly initialized
|
|
by Os2InitOriginalConfigSysProcessing.
|
|
|
|
Arguments:
|
|
|
|
DestPtr - points to a pointer which indicates the current position in the
|
|
config.sys registry entry we're building.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
static ENVIRONMENT_DISPATCH_TABLE_ENTRY DispatchTable[] =
|
|
{
|
|
{ L"COUNTRY", L"=", Os2CommaProcessingDispatchFunction, NULL },
|
|
{ L"CODEPAGE", L"=", Os2CommaProcessingDispatchFunction, NULL },
|
|
{ L"DEVINFO", L"=", Os2CommaProcessingDispatchFunction, NULL },
|
|
{ L"LIBPATH", L"=", Or2FillInSearchRecordDispatchFunction, NULL },
|
|
{ L"SET", L" \t", Os2SetDirectiveProcessingDispatchFunction, NULL }
|
|
};
|
|
ENVIRONMENT_SEARCH_RECORD LibPathRecord;
|
|
ULONG i;
|
|
PWSTR p;
|
|
WCHAR ch;
|
|
|
|
//
|
|
// Most of the job is done by Or2IterateEnvironment which processes the file
|
|
// according to a dispatch table.
|
|
//
|
|
// LibPath needs to be handled a little differently. We need to process only
|
|
// the *last* occurence of LIBPATH= in the file (this is the same as OS/2).
|
|
// Therefore we only record the position of the LIBPATH= statments as we run
|
|
// into them. After we're finished we'll have the position of the last one,
|
|
// and we can process that line.
|
|
//
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
DispatchTable[i].UserParameter = (PVOID) DestPtr;
|
|
}
|
|
|
|
DispatchTable[3].UserParameter = (PVOID)&LibPathRecord;
|
|
LibPathRecord.DispatchTableIndex = (ULONG)-1;
|
|
|
|
Or2IterateEnvironment(pOs2ConfigSys,
|
|
DispatchTable,
|
|
5,
|
|
CRLF_DELIM);
|
|
|
|
|
|
if (Os2LibPathFound && LibPathRecord.DispatchTableIndex != (ULONG)-1) {
|
|
|
|
// handle LIBPATH if there was one
|
|
|
|
// get a pointer to the upper case version, so we can append it
|
|
|
|
p = pOs2UpperCaseConfigSys + (LibPathRecord.Value - pOs2ConfigSys);
|
|
|
|
ch = p[LibPathRecord.ValueLen];
|
|
p[LibPathRecord.ValueLen] = UNICODE_NULL;
|
|
|
|
Or2AppendPathToPath(Os2Heap,
|
|
p,
|
|
&Os2LibPathValueData_U,
|
|
TRUE);
|
|
p[LibPathRecord.ValueLen] = ch;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
Os2TerminateOriginalConfigSysProcessing(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleans up processing of OS/2's config.sys. Releases the storage used to store the
|
|
file.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
|
|
RtlFreeHeap(Os2Heap, 0, pOs2UpperCaseConfigSys);
|
|
pOs2UpperCaseConfigSys = pOs2ConfigSys = NULL;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Os2SbBuildSD(
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
|
PACL *pDacl
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Builds a security descriptor for creating our registry keys.
|
|
|
|
Administrators -- all access
|
|
everyone -- read access
|
|
|
|
Arguments:
|
|
|
|
SecurityDescriptor -- supplies a pointer to a preallocated SD that will be built
|
|
pDacl -- returns a pointer to a dacl that should be released from Os2Heap after
|
|
we're finished using the security descriptor.
|
|
|
|
Return Value:
|
|
|
|
NT error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
PACL Dacl;
|
|
PACE_HEADER Pace;
|
|
PSID AdminAliasSid;
|
|
ULONG DaclSize;
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
|
|
PSID WorldSid;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Create the SIDs for local admin and World.
|
|
//
|
|
|
|
Status = RtlAllocateAndInitializeSid(
|
|
&NtAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&AdminAliasSid
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbBuildSD: RtlAllocateAndInitializeSid(Admin), Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
return (Status);
|
|
}
|
|
|
|
Status = RtlAllocateAndInitializeSid(
|
|
&WorldSidAuthority,
|
|
1,
|
|
SECURITY_WORLD_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&WorldSid
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbBuildSD: RtlAllocateAndInitializeSid(World), Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
return (Status);
|
|
}
|
|
|
|
Status = RtlCreateSecurityDescriptor( SecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbBuildSD: RtlCreateSecurityDescriptor, Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
return (Status);
|
|
}
|
|
|
|
|
|
//
|
|
// Compute the size of the buffer needed for the
|
|
// DACL.
|
|
//
|
|
|
|
DaclSize = sizeof( ACL ) +
|
|
2 * (sizeof( ACCESS_ALLOWED_ACE ) - sizeof( ULONG ))
|
|
+
|
|
RtlLengthSid( AdminAliasSid ) +
|
|
RtlLengthSid( WorldSid );
|
|
|
|
Dacl = (PACL) RtlAllocateHeap(Os2Heap, 0, DaclSize);
|
|
|
|
if (Dacl == NULL) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbBuildSD: RtlAllocateHeap failed\n"));
|
|
}
|
|
#endif
|
|
return(STATUS_NO_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Build the ACL
|
|
//
|
|
|
|
Status = RtlCreateAcl ( Dacl, DaclSize, ACL_REVISION2 );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbBuildSD: RtlCreateAcl, Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Os2Heap, 0, Dacl);
|
|
return (Status);
|
|
}
|
|
|
|
Status = RtlAddAccessAllowedAce (
|
|
Dacl,
|
|
ACL_REVISION2,
|
|
GENERIC_ALL,
|
|
AdminAliasSid
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbBuildSD: RtlAddAccessAllowedAce(Admin), Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Os2Heap, 0, Dacl);
|
|
return (Status);
|
|
}
|
|
|
|
Status = RtlAddAccessAllowedAce (
|
|
Dacl,
|
|
ACL_REVISION2,
|
|
GENERIC_READ,
|
|
WorldSid
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbBuildSD: RtlAddAccessAllowedAce(World), Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Os2Heap, 0, Dacl);
|
|
return (Status);
|
|
}
|
|
|
|
Status = RtlGetAce(
|
|
Dacl,
|
|
0L,
|
|
&Pace
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbBuildSD: RtlGetAce(Admin), Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Os2Heap, 0, Dacl);
|
|
return (Status);
|
|
}
|
|
|
|
Pace->AceFlags |= CONTAINER_INHERIT_ACE;
|
|
|
|
Status = RtlGetAce(
|
|
Dacl,
|
|
1L,
|
|
&Pace
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbBuildSD: RtlGetAce(World), Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Os2Heap, 0, Dacl);
|
|
return (Status);
|
|
}
|
|
|
|
Pace->AceFlags |= CONTAINER_INHERIT_ACE;
|
|
|
|
//
|
|
// Add the ACL to the security descriptor
|
|
//
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(
|
|
SecurityDescriptor,
|
|
TRUE,
|
|
Dacl, // put (PACL) NULL to allow everyone all access
|
|
FALSE );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbBuildSD: RtlSetDaclSecurityDescriptor, Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
RtlFreeHeap(Os2Heap, 0, Dacl);
|
|
return (Status);
|
|
}
|
|
|
|
//
|
|
// These have been copied into the security descriptor, so
|
|
// we can free them.
|
|
//
|
|
|
|
RtlFreeSid( AdminAliasSid );
|
|
|
|
RtlFreeSid( WorldSid );
|
|
|
|
*pDacl = Dacl;
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Os2SbInitializeRegistryKeys(
|
|
OUT PHANDLE phConfigSysKeyHandle,
|
|
OUT PHANDLE phEnvironmentKeyHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates the OS/2 subsystem key hierarchy in the registry. It also opens
|
|
the config.sys key, and opens the system environment key.
|
|
|
|
Arguments:
|
|
|
|
phConfigSysKeyHandle - Returns a READ/WRITE handle to the config.sys key in the registry.
|
|
|
|
phEnvironmentKeyHandle - Returns a READ/WRITE handle to the system environment key.
|
|
If this key can't be opened due to access denied, NULL is returned and the
|
|
return value will be STATUS_SUCCESS.
|
|
|
|
Note --- If the return value is not a success return value, none of the above return
|
|
variables can be considered to be valid.
|
|
|
|
Return Value:
|
|
|
|
The value is an NTSTATUS type that is returned when some failure occurs. It may
|
|
indicate any of several errors that occur during the APIs called in this function.
|
|
The return value should be tested with NT_SUCCESS().
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES Obja;
|
|
UNICODE_STRING Class_U;
|
|
UNICODE_STRING SoftwareDirectory_U;
|
|
UNICODE_STRING ProductDirectory_U;
|
|
UNICODE_STRING VersionDirectory_U;
|
|
UNICODE_STRING Os2IniName_U;
|
|
UNICODE_STRING ConfigSysName_U;
|
|
UNICODE_STRING EnvRegDir_U;
|
|
HANDLE SoftwareKeyHandle;
|
|
HANDLE ProductKeyHandle;
|
|
HANDLE VersionKeyHandle;
|
|
HANDLE Os2IniKeyHandle;
|
|
HANDLE ConfigSysKeyHandle;
|
|
HANDLE EnvironmentKeyHandle;
|
|
ULONG Disposition;
|
|
NTSTATUS Status;
|
|
SECURITY_DESCRIPTOR localSecurityDescriptor;
|
|
PSECURITY_DESCRIPTOR securityDescriptor;
|
|
PACL Dacl = NULL;
|
|
|
|
|
|
*phConfigSysKeyHandle = NULL;
|
|
*phEnvironmentKeyHandle = NULL;
|
|
|
|
// We start off by creating/opening the registry key hierarchy for our subsystem
|
|
|
|
securityDescriptor = &localSecurityDescriptor;
|
|
|
|
Status = Os2SbBuildSD(securityDescriptor,
|
|
&Dacl);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbInitializeRegistryKeys: Os2SbBuildSD failed, Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
return (Status);
|
|
}
|
|
|
|
RtlInitUnicodeString(&Class_U, Os2Class);
|
|
|
|
RtlInitUnicodeString(&SoftwareDirectory_U, Os2SoftwareDirectory);
|
|
InitializeObjectAttributes(&Obja,
|
|
&SoftwareDirectory_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&SoftwareKeyHandle,
|
|
KEY_CREATE_SUB_KEY,
|
|
&Obja
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbInitializeRegistryKeys: Can't open software key, rc = %lx\n", Status));
|
|
}
|
|
#endif
|
|
if (Dacl != NULL) {
|
|
RtlFreeHeap(Os2Heap, 0, Dacl);
|
|
}
|
|
return (Status);
|
|
}
|
|
|
|
RtlInitUnicodeString(&ProductDirectory_U, Os2ProductDirectory);
|
|
InitializeObjectAttributes(&Obja,
|
|
&ProductDirectory_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
SoftwareKeyHandle,
|
|
securityDescriptor);
|
|
|
|
Status = NtCreateKey(&ProductKeyHandle,
|
|
KEY_CREATE_SUB_KEY,
|
|
&Obja,
|
|
0,
|
|
&Class_U,
|
|
REG_OPTION_NON_VOLATILE,
|
|
&Disposition
|
|
);
|
|
NtClose(SoftwareKeyHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbInitializeRegistryKeys: Can't create product key, rc = %lx\n", Status));
|
|
}
|
|
#endif
|
|
if (Dacl != NULL) {
|
|
RtlFreeHeap(Os2Heap, 0, Dacl);
|
|
}
|
|
return (Status);
|
|
}
|
|
|
|
RtlInitUnicodeString(&VersionDirectory_U, Os2VersionDirectory);
|
|
InitializeObjectAttributes(&Obja,
|
|
&VersionDirectory_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
ProductKeyHandle,
|
|
securityDescriptor);
|
|
|
|
Status = NtCreateKey(&VersionKeyHandle,
|
|
KEY_CREATE_SUB_KEY,
|
|
&Obja,
|
|
0,
|
|
&Class_U,
|
|
REG_OPTION_NON_VOLATILE,
|
|
&Disposition
|
|
);
|
|
NtClose(ProductKeyHandle);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbInitializeRegistryKeys: Can't create version key, rc = %lx\n", Status));
|
|
}
|
|
#endif
|
|
if (Dacl != NULL) {
|
|
RtlFreeHeap(Os2Heap, 0, Dacl);
|
|
}
|
|
return (Status);
|
|
}
|
|
|
|
RtlInitUnicodeString(&Os2IniName_U, Os2IniName);
|
|
InitializeObjectAttributes(&Obja,
|
|
&Os2IniName_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
VersionKeyHandle,
|
|
securityDescriptor);
|
|
|
|
Status = NtCreateKey(&Os2IniKeyHandle,
|
|
KEY_CREATE_SUB_KEY,
|
|
&Obja,
|
|
0,
|
|
&Class_U,
|
|
REG_OPTION_NON_VOLATILE,
|
|
&Disposition
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbInitializeRegistryKeys: Can't create os2ini key, rc = %lx\n", Status));
|
|
}
|
|
#endif
|
|
NtClose(VersionKeyHandle);
|
|
if (Dacl != NULL) {
|
|
RtlFreeHeap(Os2Heap, 0, Dacl);
|
|
}
|
|
return (Status);
|
|
}
|
|
NtClose(Os2IniKeyHandle);
|
|
|
|
RtlInitUnicodeString(&ConfigSysName_U, Os2ConfigSysName);
|
|
InitializeObjectAttributes(&Obja,
|
|
&ConfigSysName_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
VersionKeyHandle,
|
|
securityDescriptor);
|
|
|
|
Status = NtCreateKey(&ConfigSysKeyHandle,
|
|
KEY_READ | KEY_WRITE,
|
|
&Obja,
|
|
0,
|
|
&Class_U,
|
|
REG_OPTION_NON_VOLATILE,
|
|
&Disposition
|
|
);
|
|
|
|
if (Dacl != NULL) {
|
|
RtlFreeHeap(Os2Heap, 0, Dacl);
|
|
}
|
|
NtClose(VersionKeyHandle);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbInitializeRegistryKeys: Can't create/open config.sys key, rc = %lx\n",
|
|
Status));
|
|
}
|
|
#endif
|
|
return(Status);
|
|
}
|
|
|
|
// Open the environment.
|
|
|
|
RtlInitUnicodeString(&EnvRegDir_U, Os2EnvironmentDirectory);
|
|
InitializeObjectAttributes(&Obja,
|
|
&EnvRegDir_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&EnvironmentKeyHandle,
|
|
KEY_READ | KEY_WRITE,
|
|
&Obja
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbInitializeRegistryKeys: Unable to NtOpenKey() the system environment, rc = %lx\n",
|
|
Status));
|
|
}
|
|
#endif
|
|
if (Status != STATUS_ACCESS_DENIED) {
|
|
NtClose(ConfigSysKeyHandle);
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// on denied access, return with no error so we can at least create the
|
|
// config.sys value entry
|
|
// The caller will know this occured because the environment handle is null.
|
|
//
|
|
|
|
} else {
|
|
*phEnvironmentKeyHandle = EnvironmentKeyHandle;
|
|
}
|
|
|
|
*phConfigSysKeyHandle = ConfigSysKeyHandle;
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Os2SbInitializeRegistry(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is responsible for initializing the entire Registry component of the
|
|
Subsystem. It generates the key hierarchy in the registry.
|
|
|
|
In the generation of the key hierarchy, it also generates a config.sys entry.
|
|
The information in this entry is taken from the following sources:
|
|
|
|
-- some default strings we put in (see Os2ConfigSysDefaultValue).
|
|
-- Information from OS/2's config.sys file is added as follows:
|
|
|
|
> SET commands are put in the system environment.
|
|
Some SET commands are ignored (see Os2SetDirectiveProcessingDispatchFunction)
|
|
> LIBPATH commands are merged to the Os2LibPath variable in the
|
|
system environment. A terminating semicolon is added if there
|
|
is only one path in the path list.
|
|
> SET PATH= is ignored, and the system path remains the same.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The value is an NTSTATUS type that is returned when some failure occurs. It may
|
|
indicate any of several errors that occur during the APIs called in this function.
|
|
The return value should be tested with NT_SUCCESS(). If an unsuccessful value
|
|
is returned, it means the registry component was not properly initialized.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING Os2LibPathValueName_U;
|
|
HANDLE ConfigSysKeyHandle;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING ConfigSysName_U;
|
|
PWCHAR pInfo;
|
|
PUCHAR Src;
|
|
PWCHAR Src1;
|
|
PWCHAR Dest;
|
|
WCHAR ch, ch1;
|
|
|
|
// Create the key hierarchy
|
|
|
|
Status = Os2SbInitializeRegistryKeys(&ConfigSysKeyHandle,
|
|
&Os2EnvironmentKeyHandle);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("OS2SS - Os2SbInitializeRegistry: failed Os2SbInitializeRegistryKeys, rc = %lx\n", Status));
|
|
}
|
|
#endif
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// This is the 1st time the subsystem is running, create the config.sys entry
|
|
// and migrate information from os/2's config.sys file.
|
|
//
|
|
|
|
Os2LibPathFound = FALSE;
|
|
Os2LibPathValueData_U.Buffer = NULL;
|
|
|
|
if (Os2EnvironmentKeyHandle == NULL) { // we have no write access to the environment
|
|
goto Os2NoEnvAccess; // skip over the Os2LibPath stuff
|
|
}
|
|
|
|
// Get Os2LibPath from sys env so we can update it.
|
|
|
|
if (!Or2GetEnvPath(&Os2LibPathValueData_U,
|
|
Os2Heap,
|
|
PATHLIST_MAX,
|
|
Os2EnvironmentKeyHandle,
|
|
Os2LibPathValueName,
|
|
FALSE)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbInitializeRegistry: Unable to fetch Os2LibPath from sys env\n"));
|
|
}
|
|
#endif
|
|
} else {
|
|
|
|
// make sure there's at lease one semicolon
|
|
|
|
Or2CheckSemicolon(&Os2LibPathValueData_U);
|
|
|
|
Os2LibPathFound = TRUE;
|
|
}
|
|
|
|
if (Os2LibPathFound && Os2LibPathValueData_U.Length == 0) { // it's empty (or nonexistent)
|
|
// set up a default
|
|
UNICODE_STRING tmp;
|
|
|
|
RtlInitUnicodeString(&tmp, Os2SystemDirectory);
|
|
|
|
RtlCopyUnicodeString(&Os2LibPathValueData_U, &tmp);
|
|
|
|
RtlAppendUnicodeToString(&Os2LibPathValueData_U, L"\\os2\\dll;");
|
|
|
|
Os2LibPathValueData_U.Buffer[Os2LibPathValueData_U.Length/sizeof(WCHAR)] = UNICODE_NULL;
|
|
}
|
|
|
|
Os2NoEnvAccess:
|
|
|
|
// Now set up the initial regisry config.sys entry.
|
|
|
|
// Allocate a buffer to build the config.sys entry in. (it's a multi-string)
|
|
|
|
pInfo = (PWCHAR) RtlAllocateHeap(Os2Heap, 0, MAX_CONSYS_SIZE);
|
|
if (pInfo == NULL)
|
|
{
|
|
if (Os2LibPathValueData_U.Buffer != NULL) {
|
|
RtlFreeHeap(Os2Heap, 0, Os2LibPathValueData_U.Buffer);
|
|
Os2LibPathValueData_U.Buffer = NULL;
|
|
Os2LibPathFound = FALSE;
|
|
}
|
|
if (Os2EnvironmentKeyHandle != NULL) {
|
|
NtClose(Os2EnvironmentKeyHandle);
|
|
Os2EnvironmentKeyHandle = NULL;
|
|
}
|
|
NtClose(ConfigSysKeyHandle);
|
|
|
|
return (STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
// Initially, copy our default value into the entry.
|
|
|
|
Src = (PUCHAR) Os2ConfigSysDefaultValue;
|
|
Dest = pInfo;
|
|
do
|
|
{
|
|
ch = (WCHAR) *Src++;
|
|
if (ch == L'\a')
|
|
{
|
|
Src1 = Os2SystemDirectory;
|
|
ch1 = *Src1++;
|
|
while (ch1 != UNICODE_NULL)
|
|
{
|
|
*Dest++ = ch1;
|
|
ch1 = *Src1++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*Dest++ = ch;
|
|
}
|
|
} while (!((ch == UNICODE_NULL) && (*Src == '\0')));
|
|
|
|
|
|
// check if the an OS/2 CONFIG.SYS file already exists on
|
|
// the drive. Its name will be C:\CONFIG.SYS
|
|
// If it exists, process it for additional information
|
|
// The system env will also be updated
|
|
|
|
if (Os2InitOriginalConfigSysProcessing()) {
|
|
|
|
if (Os2EnvironmentKeyHandle == NULL) { // we have no write access to the environment
|
|
|
|
//
|
|
// We couldn't open a write key to the sys env for some reason, so we
|
|
// won't be able to migrate SET variables to NT from config.sys.
|
|
// Perhaps a popup should be generated to notify the user of this at
|
|
// this point.
|
|
// Anyway, we go on and only write the config.sys entry, skipping
|
|
// variable migration.
|
|
//
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbInitializeRegistry: Initializing registry without writing system env\n"));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
Os2ProcessOriginalConfigSys(&Dest);
|
|
Os2TerminateOriginalConfigSysProcessing();
|
|
} else {
|
|
|
|
//
|
|
// add a default "COUNTRY=" line
|
|
//
|
|
|
|
RtlMoveMemory(Dest, L"COUNTRY=", 16);
|
|
Dest += 8;
|
|
#if 0
|
|
Dest += swprintf(Dest, L"%.3hu", LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale));
|
|
#else
|
|
RtlMoveMemory(Dest, L"001", 6);
|
|
Dest += 3;
|
|
#endif
|
|
*Dest++ = UNICODE_NULL;
|
|
|
|
}
|
|
|
|
// Write the new Os2LibPath
|
|
|
|
if (Os2LibPathFound) {
|
|
|
|
RtlInitUnicodeString(&Os2LibPathValueName_U, Os2LibPathValueName);
|
|
Status = NtSetValueKey(Os2EnvironmentKeyHandle,
|
|
&Os2LibPathValueName_U,
|
|
(ULONG)0,
|
|
REG_EXPAND_SZ,
|
|
Os2LibPathValueData_U.Buffer,
|
|
Os2LibPathValueData_U.Length + sizeof(WCHAR)
|
|
);
|
|
|
|
#if DBG
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbInitializeRegistry: Unable to NtSetValueKey() system environment, rc = %X\n",
|
|
Status));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Os2LibPathFound = FALSE;
|
|
RtlFreeHeap(Os2Heap, 0, Os2LibPathValueData_U.Buffer);
|
|
Os2LibPathValueData_U.Buffer = NULL;
|
|
}
|
|
|
|
if (Os2EnvironmentKeyHandle != NULL) {
|
|
NtClose(Os2EnvironmentKeyHandle);
|
|
Os2EnvironmentKeyHandle = NULL;
|
|
}
|
|
|
|
// set the REG_MULTI_SZ terminating NUL
|
|
|
|
*Dest++ = UNICODE_NULL;
|
|
|
|
// Finally, write the config.sys multi-string entry into the registry.
|
|
|
|
RtlInitUnicodeString(&ConfigSysName_U, Os2ConfigSysName);
|
|
Status = NtSetValueKey(ConfigSysKeyHandle,
|
|
&ConfigSysName_U,
|
|
(ULONG)0,
|
|
REG_MULTI_SZ,
|
|
(PVOID)pInfo,
|
|
(PBYTE)Dest - (PBYTE)pInfo
|
|
);
|
|
RtlFreeHeap(Os2Heap, 0, pInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("Os2SbInitializeRegistry: Unable to NtSetValueKey() registry config.sys, rc = %X\n",
|
|
Status));
|
|
}
|
|
#endif
|
|
NtClose(ConfigSysKeyHandle);
|
|
return (Status);
|
|
}
|
|
|
|
NtClose(ConfigSysKeyHandle);
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
Os2SbProbeForInitialSetup(
|
|
VOID
|
|
)
|
|
{
|
|
OBJECT_ATTRIBUTES Obja;
|
|
UNICODE_STRING ConfigSysKeyName_U;
|
|
UNICODE_STRING ConfigSysName_U;
|
|
PUNICODE_STRING SysDir_U;
|
|
HANDLE ConfigSysKeyHandle;
|
|
ULONG ResultLength;
|
|
USHORT Counter;
|
|
KEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
|
|
NTSTATUS Status;
|
|
|
|
#if DBG
|
|
Os2Debug |= OS2_DEBUG_INIT;
|
|
#endif
|
|
|
|
RtlInitUnicodeString(&ConfigSysKeyName_U, Os2ConfigSysKeyName);
|
|
InitializeObjectAttributes(&Obja,
|
|
&ConfigSysKeyName_U,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&ConfigSysKeyHandle,
|
|
KEY_READ,
|
|
&Obja
|
|
);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
RtlInitUnicodeString(&ConfigSysName_U, Os2ConfigSysName);
|
|
Status = NtQueryValueKey(ConfigSysKeyHandle,
|
|
&ConfigSysName_U,
|
|
KeyValuePartialInformation,
|
|
&ValuePartialInformation,
|
|
0,
|
|
&ResultLength
|
|
);
|
|
|
|
NtClose(ConfigSysKeyHandle);
|
|
|
|
//
|
|
// The 2 expected status results are:
|
|
//
|
|
// STATUS_OBJECT_NAME_NOT_FOUND - config.sys not yet defined
|
|
// STATUS_BUFFER_TOO_SMALL - config.sys already defined
|
|
//
|
|
|
|
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
|
return;
|
|
}
|
|
|
|
if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("OS2SS: Can't Read CONFIG.SYS registry value, Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
} else {
|
|
if (Status != STATUS_OBJECT_PATH_NOT_FOUND &&
|
|
Status != STATUS_OBJECT_NAME_NOT_FOUND &&
|
|
Status != STATUS_OBJECT_PATH_INVALID) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("OS2SS: Can't Read CONFIG.SYS registry key, Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// We need to install the registry stuff
|
|
//
|
|
|
|
//
|
|
// Create a heap to use for dynamic memory allocation.
|
|
//
|
|
|
|
Os2Heap = RtlCreateHeap( HEAP_GROWABLE,
|
|
NULL,
|
|
0x10000L, // Initial size of heap is 64K
|
|
0x1000L, // Commit an initial page
|
|
NULL,
|
|
NULL // Reserved
|
|
);
|
|
if (Os2Heap == NULL) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("OS2SS: Error at RtlCreateHeap of Os2Heap\n"));
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Figure out the system directory by cutting it out of our ImagePathName
|
|
// (should be something like \DosDevices\%SystemRoot%\system32\os2ss.exe)
|
|
//
|
|
|
|
SysDir_U = (PUNICODE_STRING) &NtCurrentPeb()->ProcessParameters->ImagePathName;
|
|
for (Counter = (SysDir_U->Length / sizeof(WCHAR)) - 1; SysDir_U->Buffer[Counter] != L'\\'; Counter--) {
|
|
}
|
|
|
|
Counter -= DOS_DEV_LEN;
|
|
|
|
RtlMoveMemory(Os2SystemDirectory,
|
|
SysDir_U->Buffer + DOS_DEV_LEN,
|
|
Counter * sizeof(WCHAR));
|
|
|
|
Os2SystemDirectory[Counter] = UNICODE_NULL;
|
|
|
|
#if 0
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("\nOS2SS: System Directory is "));
|
|
|
|
for (Counter = 0; Os2SystemDirectory[Counter] != UNICODE_NULL; Counter++) {
|
|
KdPrint(("%c", (CHAR) Os2SystemDirectory[Counter]));
|
|
}
|
|
|
|
KdPrint(("|\n"));
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
Status = Os2SbInitializeRegistry();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
IF_OS2_DEBUG( INIT ) {
|
|
KdPrint(("OS2SS: Os2SbInitializeRegistry() failed, Status = %lx\n", Status));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
RtlDestroyHeap(Os2Heap);
|
|
}
|
|
|
|
#endif // PMNT
|