Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2104 lines
60 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
os2ssmig.c
Abstract:
This module contains the code necessary to initialize the
OS/2 SS entries in the registry. It migrates information
from os/2's config.sys file to the NT registry.
Author:
Ofer Porat (oferp) 30-Mar-1993
Environment:
User Mode only
Revision History:
The code was originally in the os/2 subsystem, but was moved
to winlogon so the registry initialization can be done during
boot time. This way the registry info will be correct for the
first os/2 program to run.
--*/
#include "precomp.h"
#pragma hdrstop
#define IF_OS2_DEBUG(x) // permanently enables KdPrint()s
static PVOID Os2Heap; // private heap used for allocs
#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\\"
//
// The following constants define the meaning of the Flags value in
// the config sys key entry:
// bit CONFSYSON_DISK -- 1 = os/2 config.sys on drive c, 0 = no os/2 config.sys on drive c
// bit DISABLEMIGTRATION -- if 1, migration from os/2 config.sys to NT registry is disabled.
//
#define FLAGS_CONFIGSYSONDISK 0x1L
#define FLAGS_DISABLEMIGRATION 0x2L
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 Os2ConfigFlagName[] = L"Flags";
static WCHAR Os2ConfigStampName[] = L"FileTimeSizeStamp";
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 configuration 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 Os2PathString = NULL;
static PWSTR pOs2ConfigSys = NULL;
static ULONG Os2SizeOfConfigSys = 0;
static PWSTR pOs2UpperCaseConfigSys = NULL;
static WCHAR Os2SystemDirectory[MAX_PATH];
VOID
Os2RegSetFlags(
IN HANDLE ConfigSysKeyHandle,
IN ULONG FlagsValue
)
/*++
Routine Description:
Write the "Flags" value into the config.sys registry key.
Arguments:
ConfigSysKeyHandle -- supplies read/write handle to config.sys reg key
FlagsValue -- supplies the value to write
Return Value:
None.
Note:
Errors are ignored
--*/
{
UNICODE_STRING String_U;
NTSTATUS Status;
RtlInitUnicodeString(&String_U, Os2ConfigFlagName);
Status = NtSetValueKey(
ConfigSysKeyHandle,
&String_U,
0L,
REG_DWORD,
&FlagsValue,
sizeof(DWORD)
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("Os2RegSetFlags: NetSetValueKey failed, Status = %lx\n", Status));
#endif
}
// ignore errors
}
VOID
Os2RegSetStamp(
IN HANDLE ConfigSysKeyHandle,
IN PLARGE_INTEGER pTimeStamp,
IN PLARGE_INTEGER pSizeStamp
)
/*++
Routine Description:
Write the "FileTimeSizeStamp" value into the config.sys registry key.
Arguments:
ConfigSysKeyHandle -- supplies read/write handle to config.sys reg key
pTimeStamp, pSizeStamp -- supplies the value to write
Return Value:
None.
Note:
Errors are ignored
--*/
{
UNICODE_STRING String_U;
ULONG Buffer[4];
NTSTATUS Status;
Buffer[0] = pTimeStamp->LowPart;
Buffer[1] = (ULONG) pTimeStamp->HighPart;
Buffer[2] = pSizeStamp->LowPart;
Buffer[3] = (ULONG) pSizeStamp->HighPart;
RtlInitUnicodeString(&String_U, Os2ConfigStampName);
Status = NtSetValueKey(
ConfigSysKeyHandle,
&String_U,
0L,
REG_BINARY,
(PVOID) Buffer,
sizeof(Buffer)
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("Os2RegSetFlags: NetSetValueKey failed, Status = %lx\n", Status));
#endif
}
// ignore errors
}
BOOLEAN
Os2InitOriginalConfigSysProcessing(
IN HANDLE ConfigSysKeyHandle,
IN ULONG FlagsValue,
IN HANDLE ConfigSysFileHandle,
IN PLARGE_INTEGER pTimeStamp,
IN PLARGE_INTEGER pSizeStamp
)
/*++
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:
ConfigSysKeyHandle -- supplies a read/write handle to the config.sys reg key
this is used to update the flags/stamp values
FlagsValue -- The previously existing "Flags" value that was read in from the
registry. If this is -1, then no previous Flags value existed.
ConfigSysFileHandle -- An optional handle to an already open config.sys file
pTimeStamp, pSizeStamp -- info about the open config.sys file.
Note: The parameters ConfigSysFileHandle + pTimeStamp + pSizeStamp are optional,
and come as a packet. If the config.sys file was previously opened, the handle
will be non-null, and all 3 params must be valid. If the config.sys file was
not previously opened (successfully), the handle should be NULL, and the other
2 params need not be valid.
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.
ConfigSysFileHandle is closed before the function returns.
The flags/stamp values in the config.sys reg key are updated if necessary.
--*/
{
UNICODE_STRING CanonicalConfigDotSys_U;
UNICODE_STRING Tmp_U;
ANSI_STRING Tmp_MB;
OBJECT_ATTRIBUTES Obja;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
PSZ pTempOs2ConfigSys;
LARGE_INTEGER TimeStamp, SizeStamp;
if (FlagsValue != (ULONG)-1) {
if (FlagsValue & FLAGS_DISABLEMIGRATION) {
//
// ConfigSysFileHandle cannot be non-NULL at this point
// so there's no need to close it. Also, no need to
// update flags/stamp.
//
return(FALSE);
}
FlagsValue &= ~FLAGS_CONFIGSYSONDISK;
} else {
FlagsValue = 0;
//
// 1st time migration will always take place (after system setup)
// if you you want to disable post 1st-time migration, set FlagsValue
// to a default of FLAGS_DISABLEMIGRATION. If you don't any migration
// at all (not even 1st-time), then set the FlagsValue similarly, and
// also do a { Os2RegSetFlags(..), return FALSE }
//
}
if (ConfigSysFileHandle == NULL) {
// 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)) {
//
// Debug print removed, because this is a valid situation (no config.sys file)
//
#if 0
#if DBG
KdPrint(("Os2InitOriginalConfigSysProcessing: FAILED - NtOpenFile-1 %lx\n", Status));
#endif
#endif
Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
return (FALSE);
}
Status = Or2GetFileStamps(
ConfigSysFileHandle,
&TimeStamp,
&SizeStamp
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("Os2InitOriginalConfigSysProcessing: Can't get config.sys time/size stamp, Status = %lx\n", Status));
#endif
NtClose(ConfigSysFileHandle);
Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
return(FALSE);
}
pTimeStamp = &TimeStamp;
pSizeStamp = &SizeStamp;
}
// Get the file length
Os2SizeOfConfigSys = pSizeStamp->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
KdPrint(("Os2InitOriginalConfigSysProcessing: FAILED - RtlAllocateHeap pTempOs2ConfigSys\n"));
#endif
Os2SizeOfConfigSys = 0;
NtClose(ConfigSysFileHandle);
Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
return (FALSE);
}
pOs2ConfigSys = (PWSTR) RtlAllocateHeap(Os2Heap, 0, (Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
if (pOs2ConfigSys == NULL) {
#if DBG
KdPrint(("Os2InitOriginalConfigSysProcessing: FAILED - RtlAllocateHeap pOs2ConfigSys\n"));
#endif
Os2SizeOfConfigSys = 0;
RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
NtClose(ConfigSysFileHandle);
Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
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
KdPrint(("Os2InitOriginalConfigSysProcessing: FAILED - NtReadFile %lx\n", Status));
#endif
Os2SizeOfConfigSys = 0;
RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
pOs2ConfigSys = NULL;
Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
return (FALSE);
}
pTempOs2ConfigSys[Os2SizeOfConfigSys] = '\0';
// Convert to UNICODE
RtlInitAnsiString(&Tmp_MB, pTempOs2ConfigSys);
Tmp_U.Buffer = pOs2ConfigSys;
Tmp_U.MaximumLength = (USHORT) ((Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
RtlOemStringToUnicodeString(&Tmp_U, (POEM_STRING)&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
KdPrint(("Os2InitOriginalConfigSysProcessing: FAILED - RtlAllocateHeap pOs2UpperConfigSys\n"));
#endif
Os2SizeOfConfigSys = 0;
RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
pOs2ConfigSys = NULL;
Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
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;
Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
return (FALSE);
}
FlagsValue |= FLAGS_CONFIGSYSONDISK;
Os2RegSetFlags(ConfigSysKeyHandle, FlagsValue);
Os2RegSetStamp(ConfigSysKeyHandle, pTimeStamp, pSizeStamp);
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 os2ssrtl.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
//
// If Os2EnvironmentKeyHandle is NULL, we don't have
// write access to the system environment, and we skip
// setting the variable.
//
if (Os2EnvironmentKeyHandle == NULL) {
return;
}
//
// Special handling for PATH -- retained in the global variable
// Os2PathString. Only the last occurence of PATH is retained.
// This is compatible with OS/2 which uses the last occurence.
//
if (Or2UnicodeEqualCI(VarName_U.Buffer, L"PATH=", 5)) {
if (Os2PathString != NULL) { // already found a path?
RtlFreeHeap(Os2Heap, 0, Os2PathString); // get rid of it
Os2PathString = NULL;
}
Os2PathString = (PWSTR) RtlAllocateHeap(Os2Heap, 0, VarValue_U.Length + sizeof(WCHAR));
if (Os2PathString == NULL) {
#if DBG
KdPrint(("Os2SetDirectiveProcessingDispatchFunction: Failed to allocate heap space for PATH\n"));
#endif
return; // no space for storing the path -- skip it
}
// switch to the upper case copy...
VarValue_U.Buffer = pOs2UpperCaseConfigSys + (VarValue_U.Buffer - pOs2ConfigSys);
RtlMoveMemory(Os2PathString, VarValue_U.Buffer, VarValue_U.Length);
Os2PathString[VarValue_U.Length/sizeof(WCHAR)] = UNICODE_NULL;
return;
}
//
// Otherwise, it's stored in the system environment
//
//
// 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
//
//
// !!! Modification 5/30/93 -- We decided to be a little more brave about this.
// On one hand there doesn't seem to be any conflict between any possible OS/2
// definitions, and NT definitions. On the other hand, since we now do re-migration
// on every config.sys change, if we don't update existing variables, the user's
// important OS/2 variables (e.g. DPATH) will not get remigrated. Therefore we
// always update. -- oferp
//
#if 0
Status = NtQueryValueKey(Os2EnvironmentKeyHandle,
&VarName_U,
KeyValuePartialInformation,
&KeyValueInfo,
sizeof(KeyValueInfo),
&ResultLength
);
#else
Status = STATUS_OBJECT_NAME_NOT_FOUND;
#endif
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.
!!! Modification 5/30/93 -- Migration of the three NLS related statements has been disabled.
Reason: The intended default behavior is this: The registry config.sys entry has no
NLS entries, and the OS/2 subsystem picks up these values from NT's default values.
Supporting the registry config.sys values is only meant to be used if the user actually
wants to have separate OS/2 and NT NLS parameters. This is almost never the case. The
reason for allowing dual-NLS mode is because some NT languages may not be supported on
OS/2, and so the user may want to specify a different (existing) NLS setting for the
OS/2 subsystem. The usual setting is therefore to have no NLS directives in the registry
config.sys. That's why we shouldn't migrate. -- oferp
Arguments:
Standard arguments passed to a Dispatch Function, see the description of
Or2IterateEnvironment in os2ssrtl.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.
//
#if 0
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;
#else
return; // do nothing!
#endif
}
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;
Os2SizeOfConfigSys = 0;
}
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
RtlFreeSid( AdminAliasSid );
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
RtlFreeSid( AdminAliasSid );
RtlFreeSid( WorldSid );
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
RtlFreeSid( AdminAliasSid );
RtlFreeSid( WorldSid );
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);
RtlFreeSid( AdminAliasSid );
RtlFreeSid( WorldSid );
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);
RtlFreeSid( AdminAliasSid );
RtlFreeSid( WorldSid );
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);
RtlFreeSid( AdminAliasSid );
RtlFreeSid( WorldSid );
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);
RtlFreeSid( AdminAliasSid );
RtlFreeSid( WorldSid );
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);
RtlFreeSid( AdminAliasSid );
RtlFreeSid( WorldSid );
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);
RtlFreeSid( AdminAliasSid );
RtlFreeSid( WorldSid );
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(
IN ULONG FlagsValue,
IN HANDLE ConfigSysFileHandle,
IN PLARGE_INTEGER pTimeStamp,
IN PLARGE_INTEGER pSizeStamp
)
/*++
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:
FlagsValue -- The previously existing "Flags" value that was read in from the
registry. If this is -1, then no previous Flags value existed.
ConfigSysFileHandle -- An optional handle to an already open config.sys file
pTimeStamp, pSizeStamp -- info about the open config.sys file.
Note: The parameters ConfigSysFileHandle + pTimeStamp + pSizeStamp are optional,
and come as a packet. If the config.sys file was previously opened, the handle
will be non-null, and all 3 params must be valid. If the config.sys file was
not previously opened (successfully), the handle should be NULL, and the other
2 params need not 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(). 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(("Os2SbInitializeRegistry: failed Os2SbInitializeRegistryKeys, Status = %lx\n", Status));
}
#endif
return(Status);
}
//
// 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 DBG
IF_OS2_DEBUG( INIT ) {
KdPrint(("Os2SbInitializeRegistry: Unable to RtlAllocateHeap() space for config.sys value buffer\n"));
}
#endif
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_NO_MEMORY);
}
// 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(
ConfigSysKeyHandle,
FlagsValue,
ConfigSysFileHandle,
pTimeStamp,
pSizeStamp
)) {
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();
}
#if 0
//
// The code below is disabled. We'll add COUNTRY= when creating a fictive
// config.sys on the fly. If the code is reenabled in the future -- it
// should be fixed. It doesn't make sure there are at least three characters
// (with leading 0s) in the country code.
//
else {
WCHAR CountryCode[7];
ULONG CountryLength;
//
// add a default "COUNTRY=" line
//
CountryLength = GetLocaleInfoW(
GetSystemDefaultLCID(),
LOCALE_ICOUNTRY,
CountryCode,
6);
if (CountryLength == 0) {
#if DBG
KdPrint(("Os2SbInitializeRegistry: Cannot get locale country info, LastError = %lx\n",
GetLastError()));
#endif
} else {
RtlMoveMemory(Dest, L"COUNTRY=", 16);
Dest += 8;
RtlMoveMemory(Dest, CountryCode, CountryLength * sizeof(WCHAR));
Dest += CountryLength;
*Dest++ = UNICODE_NULL;
}
}
#endif
// 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;
}
// handle a possible PATH value setting
if (Os2PathString != NULL) {
UNICODE_STRING Os2PathValueName_U;
UNICODE_STRING Os2PathValueData_U;
//
// Os2EnvironmentKeyHandle can't be NULL at this point because
// we wouldn't have set Os2PathString...
//
if (!Or2GetEnvPath(&Os2PathValueData_U,
Os2Heap,
PATHLIST_MAX,
Os2EnvironmentKeyHandle,
L"Path",
FALSE)) {
#if DBG
KdPrint(("Os2SbInitializeRegistry: Unable to fetch Path from sys env\n"));
#endif
//
// Can't get value, skip processing
//
} else {
if (Os2PathValueData_U.Length == 0) {
//
// If we couldn't get the value, or it's empty, don't process it
//
#if DBG
KdPrint(("Os2SbInitializeRegistry: Path in sys env empty or not found\n"));
#endif
} else {
//
// Append our string...
//
Or2AppendPathToPath(Os2Heap,
Os2PathString,
&Os2PathValueData_U,
TRUE);
//
// Put it back into the registry...
//
RtlInitUnicodeString(&Os2PathValueName_U, L"Path");
Status = NtSetValueKey(Os2EnvironmentKeyHandle,
&Os2PathValueName_U,
(ULONG)0,
REG_EXPAND_SZ,
Os2PathValueData_U.Buffer,
Os2PathValueData_U.Length + sizeof(WCHAR)
);
#if DBG
if (!NT_SUCCESS(Status)) {
KdPrint(("Os2SbInitializeRegistry: Unable to NtSetValueKey() system environment (2), rc = %X\n",
Status));
}
#endif
// ignore error from setvaluekey
}
RtlFreeHeap(Os2Heap, 0, Os2PathValueData_U.Buffer);
}
RtlFreeHeap(Os2Heap, 0, Os2PathString);
Os2PathString = 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
Os2MigrationProcedure(
VOID
)
/*++
Routine Description:
This routine oversees the os/2 config.sys migration procedure. It's called from winlogon during
boot. It checks to see if the os/2ss config.sys-related registy entries are intact. If they
aren't, it rebuilds them. If they are intact, it checks if config.sys migration is enabled,
and if the os/2 config.sys file exists and has changed (size/lastwritetime) since the last migration.
If so, it remigrates the config.sys info. Note that SET variables are only added, never
removed. The same goes for LIBPATH. PATH is not migrated from os/2 config.sys to NT.
Arguments:
None.
Return Value:
None.
--*/
{
BYTE RegBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4 * sizeof(ULONG)];
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK IoStatus;
UNICODE_STRING String_U;
LARGE_INTEGER TimeStamp;
LARGE_INTEGER SizeStamp;
PKEY_VALUE_PARTIAL_INFORMATION pInfo = (PKEY_VALUE_PARTIAL_INFORMATION) RegBuffer;
PULONG RegVal;
HANDLE ConfigSysKeyHandle;
HANDLE ConfigSysFileHandle = NULL;
ULONG FlagsValue = (ULONG)-1;
ULONG ResultLength;
NTSTATUS Status;
RtlInitUnicodeString(&String_U, Os2ConfigSysKeyName);
InitializeObjectAttributes(&Obja,
&String_U,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenKey(&ConfigSysKeyHandle,
KEY_READ,
&Obja
);
if (!NT_SUCCESS(Status)) {
if (Status != STATUS_OBJECT_PATH_NOT_FOUND &&
Status != STATUS_OBJECT_NAME_NOT_FOUND &&
Status != STATUS_OBJECT_PATH_INVALID) {
#if DBG
KdPrint(("Os2MigrationProcedure: Can't Open config.sys registry key, Status = %lx\n", Status));
#endif
return;
}
goto BuildRegistry;
}
RtlInitUnicodeString(&String_U, Os2ConfigFlagName);
Status = NtQueryValueKey(ConfigSysKeyHandle,
&String_U,
KeyValuePartialInformation,
pInfo,
sizeof(RegBuffer),
&ResultLength
);
if (!NT_SUCCESS(Status)) {
NtClose(ConfigSysKeyHandle);
if (Status != STATUS_OBJECT_PATH_NOT_FOUND &&
Status != STATUS_OBJECT_NAME_NOT_FOUND &&
Status != STATUS_OBJECT_PATH_INVALID) {
#if DBG
KdPrint(("Os2MigrationProcedure: Can't Read config.sys flag value key, Status = %lx\n", Status));
#endif
return;
}
goto BuildRegistry;
}
if (pInfo->Type != REG_DWORD ||
pInfo->DataLength != sizeof(DWORD)) {
NtClose(ConfigSysKeyHandle);
goto BuildRegistry;
}
FlagsValue = *(PULONG) (pInfo->Data);
RtlInitUnicodeString(&String_U, Os2ConfigSysName);
Status = NtQueryValueKey(ConfigSysKeyHandle,
&String_U,
KeyValuePartialInformation,
NULL,
0,
&ResultLength
);
//
// 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_OBJECT_NAME_NOT_FOUND ||
Status == STATUS_OBJECT_PATH_NOT_FOUND ||
Status == STATUS_OBJECT_PATH_INVALID) {
NtClose(ConfigSysKeyHandle);
goto BuildRegistry;
}
if (Status != STATUS_BUFFER_TOO_SMALL) {
#if DBG
KdPrint(("Os2MigrationProcedure: Can't Read config.sys registry value key, Status = %lx\n", Status));
#endif
NtClose(ConfigSysKeyHandle);
return;
}
if ((FlagsValue & FLAGS_DISABLEMIGRATION) ||
!(FlagsValue & FLAGS_CONFIGSYSONDISK)) {
//
// os/2 config.sys migration disabled
// or no os/2 config.sys on disk
//
NtClose(ConfigSysKeyHandle);
return;
}
RtlInitUnicodeString(&String_U, Os2ConfigStampName);
Status = NtQueryValueKey(ConfigSysKeyHandle,
&String_U,
KeyValuePartialInformation,
pInfo,
sizeof(RegBuffer),
&ResultLength
);
NtClose(ConfigSysKeyHandle);
if (!NT_SUCCESS(Status)) {
if (Status != STATUS_OBJECT_PATH_NOT_FOUND &&
Status != STATUS_OBJECT_NAME_NOT_FOUND &&
Status != STATUS_OBJECT_PATH_INVALID) {
#if DBG
KdPrint(("Os2MigrationProcedure: Can't Read config.sys stamp value key, Status = %lx\n", Status));
#endif
return;
}
goto BuildRegistry;
}
if (pInfo->Type != REG_BINARY ||
pInfo->DataLength != 4 * sizeof(DWORD)) {
goto BuildRegistry;
}
RegVal = (PULONG) (pInfo->Data);
RtlInitUnicodeString(&String_U, Os2OriginalCanonicalConfigSys);
InitializeObjectAttributes(&Obja,
&String_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)) {
goto BuildRegistry;
}
Status = Or2GetFileStamps(
ConfigSysFileHandle,
&TimeStamp,
&SizeStamp
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("Os2MigrationProcedure: Can't get config.sys time/size stamp, Status = %lx\n", Status));
#endif
NtClose(ConfigSysFileHandle);
ConfigSysFileHandle = NULL;
goto BuildRegistry;
}
if (TimeStamp.LowPart == RegVal[0] &&
(ULONG) TimeStamp.HighPart == RegVal[1] &&
SizeStamp.LowPart == RegVal[2] &&
(ULONG) SizeStamp.HighPart == RegVal[3]) {
//
// os/2 config.sys hasn't changed, skip processing
//
NtClose(ConfigSysFileHandle);
return;
}
//
// We need to install the registry stuff
//
BuildRegistry:
if (GetSystemDirectoryW(Os2SystemDirectory, MAX_PATH) == 0) {
#if DBG
KdPrint(("Os2MigrationProcedure: Cannot obtain name of system directory, LastError = %lx\n",
GetLastError()));
#endif
if (ConfigSysFileHandle != NULL) {
NtClose(ConfigSysFileHandle);
}
return;
}
//
// 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
KdPrint(("Os2MigrationProcedure: Error at RtlCreateHeap of Os2Heap\n"));
#endif
if (ConfigSysFileHandle != NULL) {
NtClose(ConfigSysFileHandle);
}
return;
}
Status = Os2SbInitializeRegistry(
FlagsValue,
ConfigSysFileHandle,
&TimeStamp,
&SizeStamp
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("Os2MigrationProcedure: Os2SbInitializeRegistry() failed, Status = %lx\n", Status));
#endif
}
//
// ConfigSysFileHandle is closed by Os2SbInitializeRegistry
//
RtlDestroyHeap(Os2Heap);
}