/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
srvname.c
Abstract:
This is the name space module for the OS/2 Subsystem Server
Author:
Steve Wood (stevewo) 22-Aug-1989
Environment:
User Mode Only
Revision History:
Yaron Shamir (yarons) 4-Apr-91: Added Os2ComputeValidDrives, to
fix initialization and computation of valid drives, to cope
with new SM initialization and with redirected drives .
Yaron Shamir (yarons) 6-May-91: changed the way we get at default
and boot drives (matches Dos now).
Yaron Shamir (yarons) 6-Aug-91: support named pipes.
Yaron Shamir (yarons) 26-Aug-91: support UNC names.
Beni Lavi (benil) 3-Mar-92: support mailslots
Michael Jarus (mjaruss) 31-Mar-93: Remove Os2ComputeValidDrives
Patrick Questembert (PatrickQ) 19-Mar-1995: Add COM10-16
--*/
#include "os2srv.h"
#include "os2win.h"
char * __cdecl getenv(char *varname);
PSECURITY_DESCRIPTOR securityDescriptor;
struct _INITIAL_OBJDIRS {
PWSTR Name;
PHANDLE Handle;
} InitialObjectDirectories[] = {
{L"DEVICES", &Os2DevicesDirectory},
{L"QUEUES", NULL},
{L"SHAREMEM", NULL},
{L"SEMAPHORES", NULL},
{NULL, NULL}
};
struct _INITIAL_OBJDIRS Os2Drives =
{L"DRIVES", &Os2DrivesDirectory};
HANDLE Os2NamedPipesDirectory;
HANDLE Os2UNCDirectory;
HANDLE Os2MailslotDirectory;
HANDLE Os2RegistryDirectory;
struct _INITIAL_RMT_OBJDIRS {
PWSTR Name;
PHANDLE Handle;
PWSTR TargetName;
} InitialRmtObjectDirectories[] = {
{L"PIPE", &Os2NamedPipesDirectory, L"\\DosDevices\\PIPE" },
{L"UNC", &Os2UNCDirectory, L"\\DosDevices\\UNC" },
{L"MAILSLOT", &Os2MailslotDirectory, L"\\DosDevices\\MAILSLOT" },
{NULL, NULL, NULL}
};
//
// The InitialDevices table contains the values of symbolic links for
// special OS/2 files (devices).
// The first character of the Target field is used to specifiy the type
// of the device so that Od2Canonicalize() (in client\dllname.c) can
// determine and return it. Following characters are the value of the
// symbolic link which Od2Canonicalize returns as the canonicalized
// file name.
//
// Current defined types (first character of the Target field) are:
//
// @ FILE_TYPE_PSDEV
// # FILE_TYPE_COM
// (space) FILE_TYPE_DEV
//
struct _INITIAL_DEVICES {
PWSTR Name;
PWSTR Target;
} InitialDevices[] = {
{L"NUL" , L"@@0"},
{L"CON" , L"@@1"},
{L"AUX" , L"#\\DosDevices\\COM1"},
{L"COM1" , L"#\\DosDevices\\COM1"},
{L"COM2" , L"#\\DosDevices\\COM2"},
{L"COM3" , L"#\\DosDevices\\COM3"},
{L"COM4" , L"#\\DosDevices\\COM4"},
{L"COM5" , L"#\\DosDevices\\COM5"},
{L"COM6" , L"#\\DosDevices\\COM6"},
{L"COM7" , L"#\\DosDevices\\COM7"},
{L"COM8" , L"#\\DosDevices\\COM8"},
{L"COM9" , L"#\\DosDevices\\COM9"},
{L"COM10" , L"#\\DosDevices\\COM10"},
{L"COM11" , L"#\\DosDevices\\COM11"},
{L"COM12" , L"#\\DosDevices\\COM12"},
{L"COM13" , L"#\\DosDevices\\COM13"},
{L"COM14" , L"#\\DosDevices\\COM14"},
{L"COM15" , L"#\\DosDevices\\COM15"},
{L"COM16" , L"#\\DosDevices\\COM16"},
{L"PRN" , L" \\DosDevices\\LPT1"},
{L"LPT1" , L" \\DosDevices\\LPT1"},
{L"LPT2" , L" \\DosDevices\\LPT2"},
{L"LPT3" , L" \\DosDevices\\LPT3"},
{L"LPT4" , L" \\DosDevices\\LPT4"},
{L"LPT5" , L" \\DosDevices\\LPT5"},
{L"LPT6" , L" \\DosDevices\\LPT6"},
{L"LPT7" , L" \\DosDevices\\LPT7"},
{L"LPT8" , L" \\DosDevices\\LPT8"},
{L"LPT9" , L" \\DosDevices\\LPT9"},
{L"KBD$" , L"@@4"},
{L"MOUSE$" , L"@@5"},
{L"CLOCK$" , L"@@6"},
{L"SCREEN$" , L"@@7"},
{L"POINTER$" , L"@@8"},
{NULL, NULL}
};
CHAR DeviceDirectoryName[] = "\\Device\\";
CHAR DeviceNameStr[] = "DEVICENAME";
//
// Information relevant for config.sys processing by the server
//
static WCHAR ConfigSysRegDir[] =
L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\OS/2 Subsystem for NT\\1.0\\config.sys";
static WCHAR ConfigSysValue[] = L"Config.Sys";
// BUGBUG - Beni, move those to GetNextDeviceNameFromConfigDotSys
static BOOLEAN ConfigDotSysWasRead = FALSE;
static ULONG FileSize = 0;
static ULONG CurrentOffset = 0;
static ANSI_STRING ConfigSysValueData_A = {0, 0, NULL};
//
// Process the config.sys file
// Returns TRUE if a line of the form:
//
// DEVICENAME=xxx [yyy]
//
// was detected in config.sys
// The string 'xxx' is returned in DeviceName
// If string 'yyy' is present its value is returned in TargetName
// Otherwise, a NUL string is returned in TargetName
//
// This routine may be called multiple time. Each time it returns the next
// DEVICENAME value string. When there are no more such values, the routine
// returns FALSE.
//
// The information read from the registry is of type REG_MULTI_SZ
// It used to be REG_SZ with CR-LF separating the lines. Therefore,
// the code accepts both lines that terminate with CR-LF and lined
// that terminate with NUL.
//
BOOLEAN
GetNextDeviceNameFromConfigDotSys(
PSZ DeviceName,
PSZ TargetName
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
PSZ Name;
PSZ TName;
CHAR ch;
UNICODE_STRING ConfigSysRegDir_U;
UNICODE_STRING ConfigSysValue_U;
UNICODE_STRING ConfigSysValueData_U;
HANDLE ConfigSysKeyHandle;
ULONG ResultLength;
KEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
PKEY_VALUE_PARTIAL_INFORMATION pInfo;
if (!ConfigDotSysWasRead)
{
//
// Copy the config.sys image from the registry to memory
//
RtlInitUnicodeString(&ConfigSysRegDir_U, ConfigSysRegDir);
InitializeObjectAttributes(&Obja,
&ConfigSysRegDir_U,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenKey(&ConfigSysKeyHandle,
KEY_READ,
&Obja
);
if (!NT_SUCCESS(Status))
{
#if DBG
IF_OS2_DEBUG(CLEANUP)
{
KdPrint(("OS2SRV: FAILED - NtOpenKey() of config.sys %lx\n",
Status));
}
#endif
return (FALSE);
}
RtlInitUnicodeString(&ConfigSysValue_U, ConfigSysValue);
Status = NtQueryValueKey(ConfigSysKeyHandle,
&ConfigSysValue_U,
KeyValuePartialInformation,
&KeyValuePartialInfo,
sizeof(KeyValuePartialInfo),
&ResultLength
);
if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_OVERFLOW))
{
#if DBG
IF_OS2_DEBUG(CLEANUP) {
KdPrint(("OS2SRV: FAILED - NtQueryValueKey-1 %lx\n",
Status));
}
#endif
return (FALSE);
}
pInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap(Os2Heap, 0, ResultLength);
if (pInfo == NULL)
{
#if DBG
IF_OS2_DEBUG(CLEANUP)
{
KdPrint(("OS2SRV: FAILED - RtlAllocateHeap\n"));
}
#endif
return (FALSE);
}
Status = NtQueryValueKey(ConfigSysKeyHandle,
&ConfigSysValue_U,
KeyValuePartialInformation,
pInfo,
ResultLength,
&ResultLength
);
NtClose(ConfigSysKeyHandle);
if (!NT_SUCCESS(Status))
{
#if DBG
IF_OS2_DEBUG(CLEANUP)
{
KdPrint(("OS2SRV: FAILED - NtQueryValueKey %lx\n",
Status));
}
#endif
RtlFreeHeap(Os2Heap, 0, pInfo);
return (FALSE);
}
//
// The information in the registry is Unicode.
// Convert it to ANSI. Initialize explicity the UNICODE_STRING
// structure since the data in the registry is of type REG_MULTI_SZ
// and hence contains embedded NULs.
//
ConfigSysValueData_U.Buffer = (PWSTR)pInfo->Data;
ConfigSysValueData_U.Length = (USHORT)pInfo->DataLength - 2;
ConfigSysValueData_U.MaximumLength = (USHORT)pInfo->DataLength;
Status = RtlUnicodeStringToAnsiString(&ConfigSysValueData_A,
&ConfigSysValueData_U, TRUE);
RtlFreeHeap(Os2Heap, 0, pInfo);
if (!NT_SUCCESS(Status))
{
#if DBG
IF_OS2_DEBUG(CLEANUP)
{
KdPrint(("OS2SRV: FAILED - RtlUnicodeStringToAnsiString %lx\n",
Status));
}
#endif
return (FALSE);
}
FileSize = ConfigSysValueData_A.Length;
CurrentOffset = 0;
ConfigDotSysWasRead = TRUE;
}
while (CurrentOffset < FileSize)
{
// skip leading blanks
while ((ConfigSysValueData_A.Buffer[CurrentOffset] == ' ') ||
(ConfigSysValueData_A.Buffer[CurrentOffset] == '\t'))
{
CurrentOffset++;
if (CurrentOffset >= FileSize)
{
RtlFreeAnsiString(&ConfigSysValueData_A);
return (FALSE);
}
}
if ((CurrentOffset + sizeof(DeviceNameStr) - 1) >= FileSize)
{
RtlFreeAnsiString(&ConfigSysValueData_A);
return (FALSE);
}
// check if the first name in the line is DEVICENAME
if (_strnicmp(&ConfigSysValueData_A.Buffer[CurrentOffset], DeviceNameStr, sizeof(DeviceNameStr)-1)) {
while ((ConfigSysValueData_A.Buffer[CurrentOffset] != '\n') &&
(ConfigSysValueData_A.Buffer[CurrentOffset] != '\0'))
{
CurrentOffset++;
if (CurrentOffset >= FileSize)
{
RtlFreeAnsiString(&ConfigSysValueData_A);
return (FALSE);
}
}
CurrentOffset++;
continue;
}
CurrentOffset += sizeof(DeviceNameStr)-1;
// skip possible blanks between DEVICENAME and =
while ((ConfigSysValueData_A.Buffer[CurrentOffset] == ' ') ||
(ConfigSysValueData_A.Buffer[CurrentOffset] == '\t'))
{
CurrentOffset++;
if (CurrentOffset >= FileSize)
{
RtlFreeAnsiString(&ConfigSysValueData_A);
return (FALSE);
}
}
// verify that there is an = after the DEVICENAME
if (ConfigSysValueData_A.Buffer[CurrentOffset] != '=')
{
while ((ConfigSysValueData_A.Buffer[CurrentOffset] != '\n') &&
(ConfigSysValueData_A.Buffer[CurrentOffset] != '\0'))
{
CurrentOffset++;
if (CurrentOffset >= FileSize)
{
RtlFreeAnsiString(&ConfigSysValueData_A);
return (FALSE);
}
}
CurrentOffset++;
continue;
}
else
{
CurrentOffset++; // skip the '='
if (CurrentOffset >= FileSize)
{
RtlFreeAnsiString(&ConfigSysValueData_A);
return (FALSE);
}
}
// skip possible blanks between = and the device name
while ((ConfigSysValueData_A.Buffer[CurrentOffset] == ' ') ||
(ConfigSysValueData_A.Buffer[CurrentOffset] == '\t'))
{
CurrentOffset++;
if (CurrentOffset >= FileSize)
{
RtlFreeAnsiString(&ConfigSysValueData_A);
return (FALSE);
}
}
// process the device name
Name = DeviceName;
while (((ch = ConfigSysValueData_A.Buffer[CurrentOffset]) != '\r') &&
(ch != '\n') &&
(ch != ' ') &&
(ch != '\t') &&
(ch != '\0')
)
{
*Name++ = ch;
CurrentOffset++;
if (CurrentOffset >= FileSize)
{
*Name = '\0';
return (TRUE);
}
}
*Name = '\0';
if (*DeviceName == '\0')
{
//
// Null device name, return false
//
RtlFreeAnsiString(&ConfigSysValueData_A);
return (FALSE);
}
// skip possible blanks and commas between the Device name and the Target name
while ((ConfigSysValueData_A.Buffer[CurrentOffset] == ' ') ||
(ConfigSysValueData_A.Buffer[CurrentOffset] == ',') ||
(ConfigSysValueData_A.Buffer[CurrentOffset] == '\t'))
{
CurrentOffset++;
if (CurrentOffset >= FileSize)
{
RtlFreeAnsiString(&ConfigSysValueData_A);
return (FALSE);
}
}
// process the device target name
TName = TargetName;
// first put a blank to match the rest of the devices
*TName++ = ' ';
while (((ch = ConfigSysValueData_A.Buffer[CurrentOffset]) != '\r') &&
(ch != '\n') &&
(ch != ' ') &&
(ch != '\t') &&
(ch != '\0')
)
{
*TName++ = ch;
CurrentOffset++;
if (CurrentOffset >= FileSize)
{
*TName = '\0';
return (TRUE);
}
}
*TName = '\0';
// did we have a target name?
if (TName == (TargetName+1))
{
// No - it's only the space we had put - nullify
*TargetName = '\0';
}
while ((ConfigSysValueData_A.Buffer[CurrentOffset] != '\n') &&
(ConfigSysValueData_A.Buffer[CurrentOffset] != '\0'))
{
CurrentOffset++;
if (CurrentOffset >= FileSize)
{
return (TRUE);
}
}
CurrentOffset++;
return (TRUE);
}
RtlFreeAnsiString(&ConfigSysValueData_A);
return (FALSE);
}
NTSTATUS
Os2InitializeNameSpace( VOID )
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING DirectoryName_U;
HANDLE DirectoryHandle;
PHANDLE Directory;
UNICODE_STRING LinkTarget_U, LinkName_U;
HANDLE LinkHandle;
CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
ULONG i;
ANSI_STRING DeviceName_A;
ANSI_STRING TargetDeviceName_A;
CHAR DeviceName[32];
CHAR TargetDeviceName[48];
//
// Create a root directory in the object name space that will be used
// to contain all of the named objects created by the OS/2 Emulation
// subsystem.
//
RtlInitUnicodeString( &DirectoryName_U, OS2_SS_ROOT_OBJECT_DIRECTORY );
Status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR)
&localSecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION );
ASSERT( NT_SUCCESS( Status ) );
if (! NT_SUCCESS( Status )) {
return Status;
}
Status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR)
&localSecurityDescriptor,
(BOOLEAN)TRUE,
(PACL) NULL,
(BOOLEAN)FALSE );
ASSERT (NT_SUCCESS(Status));
if (! NT_SUCCESS( Status )) {
return Status;
}
securityDescriptor = (PSECURITY_DESCRIPTOR) &localSecurityDescriptor;
InitializeObjectAttributes(
&ObjectAttributes,
&DirectoryName_U,
OBJ_CASE_INSENSITIVE,
// OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
NULL,
securityDescriptor
);
Status = NtOpenDirectoryObject( &Os2RootDirectory,
DIRECTORY_ALL_ACCESS,
&ObjectAttributes
);
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
ULONG i = 100; // 10 seconds
#if DBG
KdPrint(("OS2SRV: wait for os2ss to initialize\n"));
#endif
while (Status == STATUS_OBJECT_NAME_NOT_FOUND && i > 0)
{
//
// Wait 0.1 sec for os2ss to complete initialization
//
Sleep (100L);
#if DBG
KdPrint(("."));
#endif
Status = NtOpenDirectoryObject( &Os2RootDirectory,
DIRECTORY_ALL_ACCESS,
&ObjectAttributes
);
i--;
}
}
if (! NT_SUCCESS( Status ))
{
#if DBG
KdPrint(("OS2SRV: SubSystem = Can't open \\os2ss directory object\n"));
#endif
return Status;
}
//
// Make the Drives directory a symbolic link
// of \DosDevices
//
RtlInitUnicodeString( &DirectoryName_U, Os2Drives.Name );
RtlInitUnicodeString( &LinkTarget_U, L"\\DosDevices" );
InitializeObjectAttributes( &ObjectAttributes,
&DirectoryName_U,
// OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
OBJ_CASE_INSENSITIVE,
Os2RootDirectory,
securityDescriptor
);
Status = NtCreateSymbolicLinkObject( Os2Drives.Handle,
SYMBOLIC_LINK_ALL_ACCESS,
&ObjectAttributes,
&LinkTarget_U
);
if (Status == STATUS_OBJECT_NAME_COLLISION) {
//
// An os2srv is already present, print out and exit
//
#if DBG
KdPrint(( "OS2SRV: Unable to initialize server. An instance of OS2SRV already runs. Status == %X\n",
Status
));
#endif
NtTerminateProcess( NtCurrentProcess(), Status );
}
ASSERT (NT_SUCCESS(Status));
if (! NT_SUCCESS( Status )) {
return Status;
}
for (i=0; InitialObjectDirectories[ i ].Name; i++) {
RtlInitUnicodeString( &DirectoryName_U, InitialObjectDirectories[ i ].Name );
Directory = InitialObjectDirectories[ i ].Handle;
if (Directory == NULL) {
Directory = &DirectoryHandle;
}
InitializeObjectAttributes( &ObjectAttributes,
&DirectoryName_U,
// OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
OBJ_CASE_INSENSITIVE,
Os2RootDirectory,
securityDescriptor
);
Status = NtCreateDirectoryObject( Directory,
DIRECTORY_ALL_ACCESS,
&ObjectAttributes
);
ASSERT( NT_SUCCESS( Status ) );
if (! NT_SUCCESS( Status )) {
KdPrint(("OS2SRV: FAILED - NtCreateDirectoryObject stts= %lx\n",
Status));
return Status;
}
if (Directory == &DirectoryHandle) {
NtClose( DirectoryHandle );
}
}
for (i=0; InitialDevices[ i ].Name; i++) {
RtlInitUnicodeString( &LinkName_U, InitialDevices[ i ].Name );
RtlInitUnicodeString( &LinkTarget_U, InitialDevices[ i ].Target );
InitializeObjectAttributes( &ObjectAttributes,
&LinkName_U,
// OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
OBJ_CASE_INSENSITIVE,
Os2DevicesDirectory,
securityDescriptor
);
Status = NtCreateSymbolicLinkObject( &LinkHandle,
SYMBOLIC_LINK_ALL_ACCESS,
&ObjectAttributes,
&LinkTarget_U
);
ASSERT( NT_SUCCESS( Status ) );
if (! NT_SUCCESS( Status )) {
return Status;
}
// NtClose( LinkHandle );
}
//
// Make the remote directories a symbolic link of \DosDevices\*
//
for (i =0; InitialRmtObjectDirectories[i].Name != NULL; i++) {
RtlInitUnicodeString( &DirectoryName_U, InitialRmtObjectDirectories[i].Name );
RtlInitUnicodeString( &LinkTarget_U, InitialRmtObjectDirectories[i].TargetName);
InitializeObjectAttributes( &ObjectAttributes,
&DirectoryName_U,
OBJ_CASE_INSENSITIVE,
// OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
Os2RootDirectory,
securityDescriptor
);
Status = NtCreateSymbolicLinkObject( InitialRmtObjectDirectories[i].Handle,
SYMBOLIC_LINK_ALL_ACCESS,
&ObjectAttributes,
&LinkTarget_U
);
ASSERT( NT_SUCCESS( Status ) );
if (! NT_SUCCESS( Status )) {
return Status;
}
}
//
// Process config.sys for the DEVICENAME= definitions
//
while (GetNextDeviceNameFromConfigDotSys(DeviceName, TargetDeviceName))
{
#if DBG
if (TargetDeviceName[0] == '\0') {
KdPrint(("OS2SRV: Read DEVICENAME=%s from config.sys\n", DeviceName));
}
else {
KdPrint(("OS2SRV: Read DEVICENAME=%s %s from config.sys\n",
DeviceName, TargetDeviceName));
}
#endif
RtlInitAnsiString(&DeviceName_A, DeviceName);
RtlAnsiStringToUnicodeString( &LinkName_U, &DeviceName_A, (BOOLEAN)TRUE );
if (TargetDeviceName[0] == '\0') {
strcpy(TargetDeviceName, DeviceDirectoryName);
strcat(TargetDeviceName, DeviceName);
}
RtlInitAnsiString(&TargetDeviceName_A, TargetDeviceName);
RtlAnsiStringToUnicodeString( &LinkTarget_U, &TargetDeviceName_A, (BOOLEAN)TRUE );
InitializeObjectAttributes( &ObjectAttributes,
&LinkName_U,
OBJ_CASE_INSENSITIVE,
Os2DevicesDirectory,
securityDescriptor
);
Status = NtCreateSymbolicLinkObject( &LinkHandle,
SYMBOLIC_LINK_ALL_ACCESS,
&ObjectAttributes,
&LinkTarget_U
);
RtlFreeUnicodeString(&LinkName_U);
RtlFreeUnicodeString(&LinkTarget_U);
if (! NT_SUCCESS( Status )) {
#if DBG
KdPrint(("OS2SRV: Could not Link Device '%s' to target devices\n", DeviceName));
#endif
}
}
return( Os2InitializeDriveLetters() );
}
BOOLEAN
Os2CheckValidCDrives(VOID)
{
NTSTATUS Status;
HANDLE LinkHandle;
UNICODE_STRING DriveName_U;
WCHAR DriveString[15] = L"\\DosDevices\\C:";
OBJECT_ATTRIBUTES Attributes;
//
// compute the valid drives from scratch, since
// redirected drives appear and disappear dynamically
//
RtlInitUnicodeString(&DriveName_U, DriveString);
InitializeObjectAttributes(
&Attributes,
&DriveName_U,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenSymbolicLinkObject( &LinkHandle,
SYMBOLIC_LINK_QUERY,
&Attributes
);
if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
NtClose( LinkHandle );
return(TRUE);
}
return (FALSE);
}
NTSTATUS
Os2InitializeDriveLetters( VOID )
{
//
// Set the SystemDrive number from the environment
//
SystemRootValuePtr = getenv("SYSTEMROOT");
if (SystemRootValuePtr == NULL) {
SystemRootValuePtr = "C:\\";
}
Os2DefaultDrive = (ULONG)(RtlUpperChar(*SystemRootValuePtr) - 'A');
Os2BootDrive = 2; // C:
//
// check if not C:
//
if (!Os2CheckValidCDrives()) {
Os2BootDrive = 0; // A:
if (Os2DefaultDrive == 2) {
Os2DefaultDrive = 0; // A:
}
}
return STATUS_SUCCESS;
}
NTSTATUS
Os2GetClientId( VOID )
{
NTSTATUS Status;
HANDLE LinkHandle;
OBJECT_ATTRIBUTES Attributes;
UNICODE_STRING DebugClientId_U;
UNICODE_STRING ClientIdString_U;
Os2DebugUserClientId.UniqueProcess = NULL;
RtlInitUnicodeString(&DebugClientId_U, L"DebugClientId");
InitializeObjectAttributes(
&Attributes,
&DebugClientId_U,
OBJ_CASE_INSENSITIVE,
Os2RootDirectory,
NULL);
Status = NtOpenSymbolicLinkObject( &LinkHandle,
SYMBOLIC_LINK_QUERY,
&Attributes
);
if (!NT_SUCCESS( Status )) {
return Status;
}
ClientIdString_U.Buffer = (PWSTR)&Os2DebugUserClientId;
ClientIdString_U.Length = 0;
ClientIdString_U.MaximumLength = sizeof( Os2DebugUserClientId );
Status = NtQuerySymbolicLinkObject( LinkHandle,
&ClientIdString_U,
NULL
);
if (!NT_SUCCESS( Status )) {
return Status;
}
return Status;
}