/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
ntinitss.c
Abstract:
This module contains the code to establish the connection between
the session console process and the OS2 Emulation Subsystem.
Author:
Avi Nathan (avin) 17-Jul-1991
Environment:
User Mode Only
Revision History:
--*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define NTOS2_ONLY
#include "os2ses.h"
#include "os2tile.h"
#if PMNT
#define INCL_32BIT
#include "pmnt.h"
#endif
#include <winerror.h>
#define OD2_PORT_MEMORY_SIZE 0x10000
extern PVOID Od2PortHeap;
extern ULONG Od2PortMemoryRemoteDelta;
extern PSZ Od2PgmFilePath;
extern HANDLE Od2PortHandle;
#if PMNT
extern ULONG PMSubprocSem32;
extern BOOLEAN Ow2WriteBackCloseEvent();
extern APIRET DosSemClear(ULONG hsem);
#endif //PMNT
HANDLE
CreateEventW(
PVOID lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCWSTR lpName
);
ULONG
KbdInitAfterSesGrp(IN VOID);
APIRET
Od2WaitForSingleObject(
IN HANDLE Handle,
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Timeout OPTIONAL
);
BOOLEAN
Od2InitCreateProcessMessage(
OUT PSCREQ_CREATE pCreate
);
VOID
Od2HandleCreateProcessRespond(
IN PSCREQ_CREATE pCreate
);
VOID
ExitThread(
ULONG dwExitCode
);
APIRET
OpenLVBsection(VOID);
DWORD
GetCurrentDirectoryW(
DWORD nBufferLength,
LPWSTR lpBuffer
);
BOOLEAN
InitializeSecurityDescriptor (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD dwRevision
);
BOOLEAN
SetSecurityDescriptorDacl (
PSECURITY_DESCRIPTOR pSecurityDescriptor,
BOOLEAN bDaclPresent,
PACL pDacl,
BOOLEAN bDaclDefaulted
);
// Defined in <winbase.h> but we can't include it in this file
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
PVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
BOOLEAN Ow2ExitInProcess = (BOOLEAN)FALSE;
HANDLE hOs2Srv;
ULONG Ow2bNewSession = 0;
OEM_STRING Ow2CommandLineString;
HANDLE CtrlDataSemaphore;
HANDLE KbdDataSemaphore;
HANDLE FocusSemaphore;
HANDLE MouDataSemaphore;
HANDLE PopUpSemaphore;
HANDLE ScreenLockSemaphore;
HANDLE Od2StdHandleLockHandle;
HANDLE Od2VioWriteSemHandle;
BOOLEAN Od2ReceivedSignalAtInit = FALSE;
ULONG Od2InitSignalType;
BYTE NtInitssFail[] = "OS2SES(ntinitss) - error %X at %s\n";
/*
* This is the table of Secions to initialize.
*
* Section
* SectionSize - the size of the section (0 - no section, -1 - for LVB)
* DataNamePrefix - the prefix added to get section name
* SectionDataBaseAddress - where to put the base address of the section
* SectionDataHandle - where to put the handle of the section
*/
struct
{
ULONG SectionSize;
WCHAR DataNamePrefix;
PVOID *SectionDataBaseAddress;
HANDLE *SectionDataHandle;
} PORT_TABLE[] =
{
{
OS2SES_CTRL_SECTION_SIZE,
U_OS2_SES_BASE_DATA_PREFIX,
&Os2SessionCtrlDataBaseAddress,
&Os2SessionCtrlDataSectionHandle
},
{
OS2SES_GROUP_SECTION_SIZE,
U_OS2_SES_GROUP_PREFIX,
&Os2SessionDataBaseAddress,
&Os2SessionSesGrpDataSectionHandle
},
{
// Warning: MUST BE THE LAST ENTRY OF THE TABLE
(ULONG)(-1L),
U_OS2_SES_BASE_LVB_PREFIX,
&(PVOID)(LVBBuffer),
&LVBHandle
},
{
0, // End of Table
0,
NULL,
NULL
}
};
/*
* This is a table of semaphores to create (and close).
* All (but PauseEvent which is Event) are Semaphores.
*/
struct
{
WCHAR NamePrefix;
HANDLE * SemaphoreHandle;
} SEMAPHORE_TABLE [] =
{
{
U_OS2_SES_CTRL_PORT_SEMAPHORE_PREFIX,
&CtrlDataSemaphore,
},
{
U_OS2_SES_KBD_PORT_SEMAPHORE_PREFIX,
&KbdDataSemaphore,
},
{
U_OS2_SES_KBD_FOCUS_SEMAPHORE_PREFIX,
&FocusSemaphore,
},
{
U_OS2_SES_MOU_PORT_SEMAPHORE_PREFIX,
&MouDataSemaphore,
},
{
U_OS2_SES_POPUP_SEMAPHORE_PREFIX,
&PopUpSemaphore,
},
{
U_OS2_SES_SLOCK_SEMAPHORE_PREFIX,
&ScreenLockSemaphore,
},
{
U_OS2_SES_STD_HANDLE_LOCK_PREFIX,
&Od2StdHandleLockHandle,
},
{
U_OS2_SES_PAUSE_EVENT_PREFIX,
&PauseEvent,
},
{
U_OS2_SES_VIOWRITE_SEMAPHORE_PREFIX,
&Od2VioWriteSemHandle,
},
{
0,
NULL
}
};
#if DBG
PSZ SEMAPHORE_NAME_TABLE[] =
{
"CtrlDataSemaphore",
"KbdDataSemaphore",
"FocusSemaphore",
"MouDataSemaphore",
"PopUpSemaphore",
"ScreenLockSemaphore",
"PauseEvent",
"VioWriteSemaphore",
NULL
};
#endif
//
// A routine that wait for os2srv to connect
//
NTSTATUS
CtrlListen()
{
NTSTATUS Status;
PSCCONNECTINFO ConnectionInfo;
SCREQUESTMSG ConnectionRequest;
HANDLE CommPortHandle;
/*
* Listen to the os2ss connection and then too all
* processes created in this session.
*/
// Non-alertable, indefinite wait listen
Status = NtListenPort( Ow2hOs2sesPort,
(PPORT_MESSAGE) &ConnectionRequest);
if (!NT_SUCCESS( Status ))
{
KdPrint(( NtInitssFail, Status, "NtListenPort"));
return Status;
} else
{
// ??? Any reply
ConnectionInfo = &ConnectionRequest.ConnectionRequest;
ConnectionInfo->dummy = 0;
// BUGBUG!
// ServerView.Length = sizeof(ServerView);
// ServerView.SectionOffset = 0L;
// ServerView.ViewSize = 0L;
Status = NtAcceptConnectPort(
& CommPortHandle,
NULL,
(PPORT_MESSAGE) &ConnectionRequest,
(BOOLEAN)TRUE,
NULL, // &ServerView,
NULL);
if ( !NT_SUCCESS(Status) )
{
#if DBG
KdPrint(( NtInitssFail, Status, "NtAcceptConnectPort"));
#endif
return Status;
} else
{
/*
* Record the view section address in a global variable.
*/
// BUGBUG! Os2SesConPortBaseAddress = ServerView.ViewBase;
Status = NtCompleteConnectPort( CommPortHandle );
ASSERT( NT_SUCCESS( Status) );
return Status;
}
}
}
DWORD
SessionRequestThread(IN PVOID Parameter)
{
NTSTATUS Status;
UNREFERENCED_PARAMETER(Parameter);
try {
//
// Listen and accept session request port
//
Status = CtrlListen();
if ( !NT_SUCCESS( Status ))
{
#if DBG
KdPrint(( NtInitssFail, Status, "CtrlListen"));
ASSERT( FALSE );
#endif
Ow2Exit( 0, NULL, 1);
}
ServeSessionRequests();
}
//
// if Os2Debug is on, and ntsd is attached, it will get the second chance
//
#if DBG
except( (Os2Debug ? Ow2FaultFilter(EXCEPTION_CONTINUE_SEARCH, GetExceptionInformation()):
Ow2FaultFilter(EXCEPTION_EXECUTE_HANDLER, GetExceptionInformation())) ) {
#else
except( Ow2FaultFilter(EXCEPTION_EXECUTE_HANDLER, GetExceptionInformation()) ) {
#endif
#if DBG
KdPrint(("OS2SES: Internal error - Exception occured in EventServerThread\n"));
#endif
Ow2DisplayExceptionInfo();
ExitThread(1L);
}
ExitThread(0L);
return(0L);
}
CONST WCHAR OS2SSInitializationEvent[] = U_OS2_SS_INITIALIZATION_EVENT;
/*
* OS2 Session console - protocol with OS2SS
*
* Connect
* 1. OS2SES ----------> OS2SRV
*
*
* Accept
* 2. OS2SES <---------- OS2SRV
* session
*
*
* Create process
* (also checkport for root process)
* 3. OS2SES ----------> OS2SRV
* session
*
* / Connect
* | 4. OS2SES <---------- OS2SRV
* root only by |
* ServerRequest|
* | Accept
* | 5. OS2SES ----------> OS2SRV
* \
*
* Returns:
* 0L - problem with resources, like memory
* -1L - problem connecting to os2srv
* 01L - OK
*
*/
DWORD
InitOs2ssSessionPort()
{
NTSTATUS Status;
ULONG ConnectionInfoLen, i, j, ViewSize = 0L;
HANDLE SessionUniqueId;
OS2SESCONNECTINFO ConnectionInfo;
OBJECT_ATTRIBUTES ObjectAttributes;
LARGE_INTEGER SectionSize;
UNICODE_STRING Name_U;
HANDLE SectionHandle;
HANDLE hCurrentProcess;
HANDLE hOs2srvProcess = NULL;
PWSTR BasePrefix;
PVOID PhyKbd;
REMOTE_PORT_VIEW ServerView;
PORT_VIEW ClientView;
OS2SESREQUESTMSG RequestMsg, ReplyMsg;
WCHAR SessionName_U[U_OS2_SES_BASE_PORT_NAME_LENGTH];
SECURITY_QUALITY_OF_SERVICE DynamicQos;
ULONG Length;
#if DBG
BOOLEAN DebugOnStartup = FALSE;
#endif
HANDLE InitialEventHandle;
DWORD NonFirstClient;
DWORD WaitState;
SECURITY_ATTRIBUTES Sa;
CHAR localSecurityDescriptor[SECURITY_DESCRIPTOR_MIN_LENGTH];
//
// Create a section to contain the Port Memory. Port Memory is private
// memory that is shared between the OS/2 client and server processes.
// This allows data that is too large to fit into an API request message
// to be passed to the OS/2 server.
//
// Create the client section now, to pass is to the server on the
// connection request.
//
SectionSize.HighPart = 0L;
SectionSize.LowPart = OD2_PORT_MEMORY_SIZE;
Status = NtCreateSection( &SectionHandle,
SECTION_ALL_ACCESS,
NULL,
&SectionSize,
PAGE_READWRITE,
SEC_RESERVE,
NULL
);
if (!NT_SUCCESS( Status ))
{
#if DBG
KdPrint(( NtInitssFail, Status, "NtCreateSection"));
ASSERT( FALSE );
#endif
return( 0L );
}
/*
* connect to OS2SS and notify of the new session and the port associated
* with it.
*/
#if DBG
if ( fBrkOnStart )
{
ConnectionInfo.In.SessionDbg = TRUE;
} else
{
ConnectionInfo.In.SessionDbg = FALSE;
}
#else
ConnectionInfo.In.SessionDbg = FALSE;
#endif
ConnectionInfo.In.ExpectedVersion = OS2_SS_VERSION;
ConnectionInfo.In.Win32ForegroundWindow = Ow2ForegroundWindow;
ConnectionInfoLen = sizeof(ConnectionInfo);
RtlInitUnicodeString( &Name_U, U_OS2_SS_SESSION_PORT_NAME );
//
// Set up the security quality of service parameters to use over the
// port. Use the most efficient (least overhead) - which is dynamic
// rather than static tracking.
//
DynamicQos.ImpersonationLevel = SecurityImpersonation;
DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
DynamicQos.EffectiveOnly = TRUE;
ClientView.Length = sizeof( ClientView );
ClientView.SectionHandle = SectionHandle;
ClientView.SectionOffset = 0;
ClientView.ViewSize = OD2_PORT_MEMORY_SIZE;
ClientView.ViewBase = 0;
ClientView.ViewRemoteBase = 0;
ServerView.Length = sizeof( ServerView );
ServerView.ViewSize = 0;
ServerView.ViewBase = 0;
// Create security attribute record granting access to all
Sa.nLength = sizeof(Sa);
Sa.bInheritHandle = TRUE;
Status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR)
&localSecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION );
if (!NT_SUCCESS( Status ))
{
#if DBG
KdPrint(("OS2SES: failed at RtlCreateSecurityDescriptor %x\n", Status));
ASSERT(FALSE);
#endif
return 0L;
}
Status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR)
&localSecurityDescriptor,
(BOOLEAN)TRUE,
(PACL) NULL,
(BOOLEAN)FALSE );
if (!NT_SUCCESS( Status ))
{
#if DBG
KdPrint(("OS2SES: failed at RtlSetDaclSecurityDescriptor %x\n", Status));
ASSERT(FALSE);
#endif
return 0L;
}
Sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR) &localSecurityDescriptor;
InitialEventHandle = CreateEventW(
&Sa,
TRUE, // Notification event
FALSE, // Nonsignaled
OS2SSInitializationEvent
);
if ((NonFirstClient = GetLastError()) || !InitialEventHandle) {
if (NonFirstClient != ERROR_ALREADY_EXISTS) {
#if DBG
KdPrint(("OS2SES: Cannot create initialization event, error %d\n", NonFirstClient));
#endif
return 0L;
}
}
if (!NonFirstClient) {
Status = (NTSTATUS) CreateOS2SRV(&hOs2srvProcess);
if (!NT_SUCCESS(Status) || !hOs2srvProcess) {
#if DBG
KdPrint(("OS2SES: Fail to start server process, status %x\n", Status));
#endif
return 0L;
}
NtClose(hOs2srvProcess);
}
//
// Wait for server. We want to see messages printed in debugger in the case that
// client waits too much (or may be it will wait forever).
//
while (TRUE) {
WaitState = WaitForSingleObject(
InitialEventHandle,
(DWORD) 4900L
);
if (WaitState == STATUS_TIMEOUT) {
#ifdef DBG
KdPrint(("OS2SES: Waiting for server\n"));
#endif
}
else {
break;
}
}
if (WaitState != WAIT_OBJECT_0) {
#if DBG
KdPrint(("OS2SES: Initialization event wasn't set by the server, wait_state %d\n", WaitState));
#endif
return (DWORD) -1L;
}
CloseHandle(InitialEventHandle);
Status = NtConnectPort(
&Ow2hOs2srvPort,
&Name_U,
&DynamicQos, // Security Quality
&ClientView,
&ServerView,
NULL, // MaxMessageLength,
(PVOID) &ConnectionInfo,
&ConnectionInfoLen
);
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(("OS2SES: Fail to connect to port, status %x\n", Status));
#endif
return (DWORD) -1L;
}
NtClose( SectionHandle );
//
// Now capture the fact if we were exec'd with the DEBUG command
//
#if DBG
if (ConnectionInfo.Out.Od2Debug)
{
Os2Debug |= ConnectionInfo.Out.Od2Debug;
DebugOnStartup = TRUE;
}
#endif
Od2PortMemoryRemoteDelta = (ULONG)ClientView.ViewRemoteBase -
(ULONG)ClientView.ViewBase;
#if DBG
IF_OD2_DEBUG( LPC )
{
KdPrint(( "OS2: ClientView: Base=%lX RemoteBase=%lX Delta: %lX Size=%lX\n",
(ULONG)ClientView.ViewBase, (ULONG)ClientView.ViewRemoteBase,
Od2PortMemoryRemoteDelta, (ULONG)ClientView.ViewSize
));
}
#endif
SessionUniqueId = (HANDLE)(ConnectionInfo.Out.SessionUniqueID);
Ow2bNewSession = ConnectionInfo.Out.IsNewSession;
Od2PortHeap = RtlCreateHeap( 0,
ClientView.ViewBase,
ClientView.ViewSize,
0,
0,
0
);
if (Od2PortHeap == NULL)
{
#if DBG
KdPrint(( NtInitssFail, Status, "RtlCreateHeap"));
ASSERT( FALSE );
#endif
return 0L;
}
hOs2Srv = OpenProcess(
PROCESS_DUP_HANDLE,
FALSE, // no inherit
(DWORD)(ConnectionInfo.Out.Os2SrvId));
if (!hOs2Srv){
#if DBG
KdPrint(( NtInitssFail, GetLastError(), "OpenProcess"));
#endif
return((DWORD)-1L);
}
#if DBG
if ( fVerbose )
{
KdPrint(("OS2SES: id =%d, Unique id=%d\n",
ConnectionInfo.Out.ProcessUniqueID, (ULONG)SessionUniqueId));
}
#endif
CONSTRUCT_U_OS2_SES_NAME(SessionName_U, U_OS2_SES_BASE_PORT_PREFIX, (ULONG)SessionUniqueId);
RtlInitUnicodeString( &Name_U, SessionName_U );
/*
* used later to fix to the data section/port name
*/
BasePrefix = &Name_U.Buffer[sizeof(U_OS2_SES_BASE_PORT_NAME) / 2];
#if DBG
IF_OD2_DEBUG( OS2_EXE )
{
PRTL_USER_PROCESS_PARAMETERS ProcessParameters =
(NtCurrentPeb())->ProcessParameters;
KdPrint(( "OS2SES(Win-Handles): hConsole %lx, StdIn %lx, StdOut %lx, StdErr %lx\n",
ProcessParameters->ConsoleHandle,
ProcessParameters->StandardInput,
ProcessParameters->StandardOutput,
ProcessParameters->StandardError ));
}
#endif
/*
* Create 7 NT Semaphore and 1 Event that will be used to:
*
* 1. mutex use of CtrlDataSection
* 2. mutex use of KbdDataSection
* 3. focus the Kbd-handle
* 4. mutex enable PopUp
* 5. mutex screen lock
* 6. Pause event
* 7. mutex read Mouse Event
*/
for ( i = 0, j = 0 ; SEMAPHORE_TABLE[i].NamePrefix ;)
{
*BasePrefix = SEMAPHORE_TABLE[i].NamePrefix;
InitializeObjectAttributes( &ObjectAttributes,
&Name_U,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
if ( OS2SS_IS_SESSION( Ow2bNewSession ))
{
if (*BasePrefix == U_OS2_SES_PAUSE_EVENT_PREFIX)
{
Status = NtCreateEvent( SEMAPHORE_TABLE[i].SemaphoreHandle,
EVENT_ALL_ACCESS,
&ObjectAttributes,
1,
(BOOLEAN)1);
} else if ((*BasePrefix == U_OS2_SES_VIOWRITE_SEMAPHORE_PREFIX) ||
(*BasePrefix == U_OS2_SES_KBD_PORT_SEMAPHORE_PREFIX) ||
(*BasePrefix == U_OS2_SES_MOU_PORT_SEMAPHORE_PREFIX))
{
Status = NtCreateMutant( SEMAPHORE_TABLE[i].SemaphoreHandle,
MUTANT_ALL_ACCESS,
&ObjectAttributes,
FALSE); // not owned
} else
{
Status = NtCreateSemaphore( SEMAPHORE_TABLE[i].SemaphoreHandle,
SEMAPHORE_ALL_ACCESS,
&ObjectAttributes,
1,
1);
}
} else
{
if (*BasePrefix == U_OS2_SES_PAUSE_EVENT_PREFIX)
{
Status = NtOpenEvent( SEMAPHORE_TABLE[i].SemaphoreHandle,
EVENT_ALL_ACCESS,
&ObjectAttributes);
} else if ((*BasePrefix == U_OS2_SES_VIOWRITE_SEMAPHORE_PREFIX) ||
(*BasePrefix == U_OS2_SES_KBD_PORT_SEMAPHORE_PREFIX) ||
(*BasePrefix == U_OS2_SES_MOU_PORT_SEMAPHORE_PREFIX))
{
Status = NtOpenMutant( SEMAPHORE_TABLE[i].SemaphoreHandle,
MUTANT_ALL_ACCESS,
&ObjectAttributes);
} else
{
Status = NtOpenSemaphore( SEMAPHORE_TABLE[i].SemaphoreHandle,
SEMAPHORE_ALL_ACCESS,
&ObjectAttributes);
}
}
if ( ! NT_SUCCESS( Status ) )
{
if (i==0 && OS2SS_IS_SESSION( Ow2bNewSession ) &&
Status == STATUS_OBJECT_NAME_COLLISION )
{
//
// A previous sesssion with the same cookie is being cleaned up - wait
// 30 seconds (600 times 50 ms is 30 seconds)
//
j++;
if (j<600)
{
#if DBG
if (j == 1)
{
KdPrint(( "OS2SES(ntinitss) - waiting for previous os2 session cleanup\n"));
}
else {
KdPrint(( "."));
}
#endif
Sleep(50L);
continue;
}
}
#if DBG
KdPrint(( "OS2SES(ntinitss) - error %X at NtCreate/OpenSemaphore/Event #%u (%c-%s)\n",
Status, i, SEMAPHORE_TABLE[i].NamePrefix, SEMAPHORE_NAME_TABLE[i]));
ASSERT( FALSE );
#endif
return(0L);
}
//
// increment i only if the create/open above was successful
//
i++;
}
/*
* Map the the whole section to virtual address.
* Let MM locate the view.
*
* The Vio case is different, since it has to be mapped
* into app space below 512M
*/
Os2SessionCtrlDataBaseAddress = 0L;
Os2SessionDataBaseAddress = 0L;
LVBBuffer = (PUCHAR)(VIOSECTION_BASE);
for ( i = 0 ; PORT_TABLE[i].SectionSize ; i++ )
{
/*
* create 3 sections to be shared by all client processes runing in this
* session: Ctrl, SesGrp & LVB.
*/
//
// Only for LVB the section size is unknon until OS2 is started.
// For the LVB< there is -1 at the SectionSize field in the table
//
if ( PORT_TABLE[i].SectionSize != -1L )
{
SectionSize.LowPart = PORT_TABLE[i].SectionSize;
} else
{
//
// This is the time to continue initiliziation: SesGrp
// is available.
//
SesGrp = (POS2_SES_GROUP_PARMS)Os2SessionDataBaseAddress;
PortMessageHeaderSize = sizeof(PORT_MESSAGE);
if (OS2SS_IS_PROCESS( Ow2bNewSession ))
{
if ((PhyKbd = StartEventHandler()) == NULL)
{
return(0);
}
} else
{
RtlZeroMemory(SesGrp, sizeof(OS2_SES_GROUP_PARMS));
if ((PhyKbd = StartEventHandlerForSession()) == NULL)
{
return(0);
}
SesGrp->PhyKbd = PhyKbd;
}
SectionSize.LowPart = SesGrp->MaxLVBsize; // LVB Buffer
}
ViewSize = 0L;
/*
* Get a private ID for the session data.
*/
*BasePrefix = PORT_TABLE[i].DataNamePrefix;
/*
* create a 64k section.
* BUGBUG! - cruiser apis allow io of more then 64k
*/
if (OS2SS_IS_SESSION( Ow2bNewSession ))
{
SECURITY_DESCRIPTOR SecurityDescriptor;
Status = RtlCreateSecurityDescriptor( &SecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION );
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(( NtInitssFail, Status, "RtlCreateSecurityDescriptor"));
ASSERT( FALSE );
#endif
return(0L);
}
Status = RtlSetDaclSecurityDescriptor( &SecurityDescriptor,
TRUE,
NULL,
FALSE );
if (!NT_SUCCESS(Status)) {
#if DBG
KdPrint(( NtInitssFail, Status, "RtlSetDaclSecurityDescriptor"));
ASSERT(FALSE);
#endif
return(0L);
}
InitializeObjectAttributes(&ObjectAttributes,
&Name_U,
OBJ_CASE_INSENSITIVE,
NULL,
&SecurityDescriptor);
Status = NtCreateSection ( &SectionHandle,
/* BUGBUG! SECTION_ALL_ACCESS, */ SECTION_MAP_WRITE,
&ObjectAttributes,
&SectionSize,
PAGE_READWRITE,
SEC_COMMIT,
NULL);
} else
{
InitializeObjectAttributes(&ObjectAttributes,
&Name_U,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenSection ( &SectionHandle,
SECTION_MAP_WRITE,
&ObjectAttributes);
}
if ( !NT_SUCCESS( Status ) )
{
#if DBG
KdPrint(( NtInitssFail, Status, "NtCreate/OpenSection"));
ASSERT( FALSE );
#endif
return(0L);
}
//
// Map the the whole section to virtual address.
//
Status = NtMapViewOfSection( SectionHandle,
NtCurrentProcess(),
PORT_TABLE[i].SectionDataBaseAddress,
0L,
0L,
NULL,
&ViewSize,
ViewUnmap,
0L,
PAGE_READWRITE);
if ( !NT_SUCCESS( Status ) )
{
#if DBG
KdPrint(( NtInitssFail, Status, "NtMapViewOfSection"));
ASSERT( FALSE );
#endif
return(0L);
}
*(PORT_TABLE[i].SectionDataHandle) = SectionHandle;
}
OpenLVBsection();
Ow2hOs2sesPort = NULL;
//
// Connect to the OS/2 Emulation Subsystem server. Also pass information
// the OS/2 server needs in the connection information structure.
//
/*
* Set Header info
*/
PORT_MSG_DATA_LENGTH(RequestMsg) = sizeof(RequestMsg) - sizeof(PORT_MESSAGE);
PORT_MSG_TOTAL_LENGTH(RequestMsg) = sizeof(RequestMsg); // BUGBUG! too much
PORT_MSG_ZERO_INIT(RequestMsg) = 0L;
RequestMsg.PortType = 1;
RequestMsg.Request = SesConCreate;
RequestMsg.d.Create.d.In.IsNewSession = Ow2bNewSession;
if ( !Od2InitCreateProcessMessage(&RequestMsg.d.Create) )
{
#if DBG
KdPrint(( NtInitssFail, Status, "Od2InitCreateProcessMessage"));
#endif
return(0L);
}
/*
* for all request pass the session handle
*/
RequestMsg.Session = SessionUniqueId;
strncpy(&RequestMsg.d.Create.d.In.ApplName[0],
Od2PgmFilePath,
OS2_MAX_APPL_NAME
);
RequestMsg.d.Create.d.In.ApplName[OS2_MAX_APPL_NAME - 1] = '\0';
// server doesn't need the LPC, except for
// the root process in the session, so we'll create port only for it.
if (OS2SS_IS_SESSION( Ow2bNewSession ))
{
CHAR sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)&sd;
*BasePrefix = U_OS2_SES_BASE_PORT_PREFIX;
/*
* create (session) LPC port to be connected to all client processes
* runing in this session for Kbd, Mou, Mon, Tm and Prt.
*/
InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(psd, TRUE, NULL, FALSE); // NULL DACL means access free to all
InitializeObjectAttributes(&ObjectAttributes,
&Name_U,
OBJ_CASE_INSENSITIVE,
NULL,
psd);
Status = NtCreatePort( &Ow2hOs2sesPort,
&ObjectAttributes,
sizeof( SCCONNECTINFO ),
U_OS2_SES_BASE_PORT_PREFIX,
32 * U_OS2_SES_BASE_PORT_PREFIX);
if ( ! NT_SUCCESS( Status ) )
{
#if DBG
KdPrint(( NtInitssFail, Status, "NtCreatePort"));
ASSERT( FALSE );
#endif
return(0L);
}
//
// create 2 threads: one to read input from console
// and second to server requsets thru LPC
//
if (timing)
{
printf("Os2 time before CreateServerThreads is %d\n", (GetTickCount()) - timing);
}
if (CreateServerThreads())
{
#if DBG
KdPrint(( NtInitssFail, GetLastError(), "CreateServerThread"));
ASSERT( FALSE );
#endif
return(0L);
}
/*
* Set request info
*/
RequestMsg.Request = SesCheckPortAndConCreate;
//
// duplicate handles for os2srv,
//
if (timing)
{
printf("Os2 time before DuplicateHandle is %d\n", (GetTickCount()) - timing);
}
hCurrentProcess = GetCurrentProcess();
//
// duplicate process and thread handles for os2srv
//
if (OS2SS_IS_NEW_SESSION( Ow2bNewSession ))
{
/*
* a new session, which isn't a child session
*/
if (!DuplicateHandle(
hCurrentProcess,
hCurrentProcess,
hOs2Srv,
&RequestMsg.d.Create.d.In.hProcess,
0,
FALSE,
DUPLICATE_SAME_ACCESS
))
{
#if DBG
KdPrint(( NtInitssFail, GetLastError(), "DuplicateHandle(Process)"));
#endif
}
if (!DuplicateHandle(
hCurrentProcess,
GetCurrentThread(),
hOs2Srv,
&RequestMsg.d.Create.d.In.hThread,
0,
FALSE,
DUPLICATE_SAME_ACCESS
))
{
#if DBG
KdPrint(( NtInitssFail, GetLastError(), "DuplicateHandle(Thread)"));
#endif
}
}
//
// Duplicate the event thread handle, so os2srv can debug it
//
if (!DuplicateHandle(
hCurrentProcess,
EventServerThreadHandle,
hOs2Srv,
&RequestMsg.d.Create.d.In.hEventThread,
0,
FALSE,
DUPLICATE_SAME_ACCESS
))
{
#if DBG
KdPrint(( NtInitssFail, GetLastError(), "DuplicateHandle(EventServerThread)"));
#endif
}
//
// Duplicate the session request thread handle, so os2srv can debug it
//
if (!DuplicateHandle(
hCurrentProcess,
Ow2hSessionRequestThread,
hOs2Srv,
&RequestMsg.d.Create.d.In.hSessionRequestThread,
0,
FALSE,
DUPLICATE_SAME_ACCESS
))
{
#if DBG
KdPrint(( NtInitssFail, GetLastError(), "DuplicateHandle(SessionRequestTread)"));
#endif
}
}
Status = NtRequestWaitReplyPort( Ow2hOs2srvPort,
(PPORT_MESSAGE) &RequestMsg,
(PPORT_MESSAGE) &ReplyMsg);
if ( !NT_SUCCESS( Status ))
{
#if DBG
KdPrint(( NtInitssFail, Status, "NtRequestWaitReplyPort"));
ASSERT( FALSE );
#endif
return((DWORD)-1L );
}
if (!NT_SUCCESS(ReplyMsg.Status)){
//
// Could not initiate with os2srv - exit
//
#if DBG
KdPrint(( NtInitssFail, ReplyMsg.Status, "Os2ConCreate"));
#endif
return( (DWORD)-1L );
}
//
// Now capture the fact if we were exec'd with the DEBUG command
//
#if DBG
if (DebugOnStartup)
{
DbgBreakPoint();
}
#endif
Od2HandleCreateProcessRespond(&ReplyMsg.d.Create);
Ow2hSession = SessionUniqueId;
if (OS2SS_IS_SESSION( Ow2bNewSession ))
{
/*
* Complete all initializations that are depend on SesGrp from os2srv
*/
if (timing)
{
printf("Os2 time before KbdInitAfterSesGrp is %d\n", (GetTickCount()) - timing);
}
if( KbdInitAfterSesGrp() )
{
#if DBG
KdPrint(( NtInitssFail, GetLastError(), "KbdInitAfterSesGrp"));
ASSERT( FALSE );
#endif
return( 0L );
}
/*
* Complete NLS initialization
*/
if (timing)
{
printf("Os2 time before NlsInit is %d\n", (GetTickCount()) - timing);
}
if( NLSInit() )
{
#if DBG
KdPrint(( NtInitssFail, GetLastError(), "NlsInit"));
ASSERT( FALSE );
#endif
return( 0L );
}
//
// resume remaining threads
//
if (timing)
{
printf("Os2 time before ResumeServerThreads is %d\n", (GetTickCount()) - timing);
}
if (ResumeServerThreads())
{
#if DBG
KdPrint(( NtInitssFail, GetLastError(), "ReleaseServerThreads"));
ASSERT( FALSE );
#endif
return( 0L );
}
}
Length = SesGrp->LVBsize;
Ow2VioGetLVBBuf(&Length);
/*
* Don't put parameters into SesGrp before this point
* (since it's clear by the server when coping the NLS definitions).
*/
return ( 1L );
}
VOID TerminateSession(VOID)
{
//NTSTATUS Status;
Ow2ExitInProcess = (BOOLEAN)TRUE;
if (timing)
{
printf("Os2 main->Exit time is %d\n", (GetTickCount()) - timing);
}
/*
* remove event handler so we don't try to send a message
* for a dying session.
*/
SetEventHandlers( FALSE );
if (OS2SS_IS_SESSION( Ow2bNewSession ))
{
RestoreWin32ParmsBeforeTermination();
}
// Close the named objects: port, section
NtClose(Ow2hOs2srvPort);
NtClose(Os2SessionCtrlDataSectionHandle);
NtClose(Os2SessionSesGrpDataSectionHandle);
NtClose(Ow2hOs2sesPort);
NtClose(hOs2Srv);
// Jul-2-1995 YosefD:
// Od2PortHandle is the same value as Ow2hOs2srvPort. This handle is already closed. An
// attemt to close it once more is a bug. On build 1096 this cause exception and
// process termination. The return value of the terminated process isn't right in this
// case.
//NtClose(Od2PortHandle);
/* =>? what about the following handles:
HANDLE hConsoleInput;
HANDLE hConsoleOutput;
HANDLE hConsoleStdIn; if diff from hConsoleInput
HANDLE hConsoleStdOut; if diff from hConsoleOutput
HANDLE hConsoleStdErr;
HANDLE hPopUpOutput; if not NULL
HANDLE LVBHandle;
HANDLE PauseEvent;
HANDLE CtrlDataSemaphore;
HANDLE KbdDataSemaphore;
HANDLE FocusSemaphore;
HANDLE MouDataSemaphore;
HANDLE PopUpSemaphore;
HANDLE ScreenLockSemaphore;
HANDLE EventServerThreadHandle;
HANDLE Ow2hSessionRequestThread;
*/
// notify OS2SS
// Cleanup TaskMan stuff
}
BOOL
SendSignalToOs2Srv(
IN int SignalType
)
{
OS2SESREQUESTMSG RequestMsg;
OS2SESREQUESTMSG ReplyMsg;
NTSTATUS Status;
#if DBG
IF_OD2_DEBUG2( OS2_EXE, SIG )
{
KdPrint(("OS2SES(SendSignalToOs2Srv): Signal %u\n", SignalType));
}
#endif
/*
* Set Header info
*/
PORT_MSG_DATA_LENGTH(RequestMsg) = sizeof(RequestMsg) - sizeof(PORT_MESSAGE);
PORT_MSG_TOTAL_LENGTH(RequestMsg) = sizeof(RequestMsg); // BUGBUG! too much
PORT_MSG_ZERO_INIT(RequestMsg) = 0L;
RequestMsg.PortType = 1;
RequestMsg.Request = SesConSignal;
RequestMsg.Session = Ow2hSession;
RequestMsg.d.Signal.Type = SignalType;
Status = NtRequestWaitReplyPort( Ow2hOs2srvPort,
(PPORT_MESSAGE) &RequestMsg,
(PPORT_MESSAGE) &ReplyMsg);
if ( !NT_SUCCESS( Status ))
{
#if DBG
KdPrint(( "OS2SES: Unable to send signal - Status == %X\n",
Status));
#endif
TerminateSession();
Ow2Exit(0, NULL, 15);
}
ASSERT ( PORT_MSG_TYPE(ReplyMsg) == LPC_REPLY );
if ( Ow2ExitInProcess )
{
return FALSE;
}
return TRUE;
}
BOOL
EventHandlerRoutine (IN ULONG CtrlType)
{
int SignalType;
BOOL Rc;
ULONG i=0;
//
// If Ow2hSession is null - os2srv is not ready yet to kill,
// wait so we don't loose the signal
//
if (!Od2SignalEnabled)
{
#if DBG
IF_OD2_DEBUG2( OS2_EXE, SIG )
{
KdPrint(("OS2SES(EventHandlerRoutine): Ctr-Type %u before loading completed, handle later\n", CtrlType));
}
#endif
Od2ReceivedSignalAtInit = TRUE;
Od2InitSignalType = CtrlType;
return(TRUE);
}
#if DBG
IF_OD2_DEBUG2( OS2_EXE, SIG )
{
KdPrint(("OS2SES(EventHandlerRoutine): Ctr-Type %u\n", CtrlType));
}
#endif
switch (CtrlType) {
case CTRL_C_EVENT:
if ((SesGrp->ModeFlag & 1 ) || // ^C in binary mode
SesGrp->WinProcessNumberInSession ) // There is a child Win process
{
return (TRUE);
}
SignalType = XCPT_SIGNAL_INTR;
break;
case CTRL_BREAK_EVENT:
if (SesGrp->WinProcessNumberInSession ) // There is a child Win process
{
return (TRUE);
}
SignalType = XCPT_SIGNAL_BREAK;
break;
case CTRL_CLOSE_EVENT:
SignalType = XCPT_SIGNAL_KILLPROC;
#if PMNT
CloseApp:
//
// PM apps handling
//
if (ProcessIsPMProcess())
{
// Regular app (i.e. not PMShell)
if (!ProcessIsPMShell())
{
if (Ow2WriteBackCloseEvent())
{
Sleep(7900L);
if (Ow2ExitInProcess)
return(FALSE);
else
return(TRUE);
}
else
{
// We failed to write-back a close event:
// must be DosExecPgm proc; Pass event through semaphore
DosSemClear(PMSubprocSem32);
Sleep(7900L);
if (Ow2ExitInProcess)
return(FALSE);
else
return(TRUE);
}
return(TRUE);
}
else // PMSHELL
{
if (Ow2WriteBackCloseEvent())
{
return(TRUE);
}
}
}
#endif // PMNT
break;
case CTRL_LOGOFF_EVENT:
if (fService) // Are we running as a service ?
{
#if DBG
DbgPrint("OS2: service - ignoring CTRL_LOGOFF_EVENT !\n");
#endif
return FALSE;
}
SignalType = XCPT_SIGNAL_KILLPROC;
#if PMNT
// Jump to CloseApp only for PM apps !
if (ProcessIsPMProcess())
goto CloseApp;
#endif // PMNT
break;
case CTRL_SHUTDOWN_EVENT:
SignalType = XCPT_SIGNAL_KILLPROC;
#if PMNT
// Jump to CloseApp only for PM apps !
if (ProcessIsPMProcess())
goto CloseApp;
#endif // PMNT
break;
default:
#if DBG
IF_OD2_DEBUG2( OS2_EXE, SIG )
{
KdPrint(("OS2SES(EventHandlerRoutine): Unknown CtrlType %lu\n", CtrlType));
}
#endif
SignalType = CtrlType;
break;
}
//if (OS2SS_IS_SESSION( Ow2bNewSession )){
if (SesGrp->InTermination == 0){
//
// The root process of a session handles singals with os2srv
// always. child processes in the session only need to send
// the signal if they where in initialization when a CtrlC/CtrlBrk
// happened (server ignore signal in this case)
//
Rc = SendSignalToOs2Srv(SignalType);
} else{
Rc = TRUE;
}
if (Rc && ((CtrlType == CTRL_CLOSE_EVENT) ||
(CtrlType == CTRL_LOGOFF_EVENT) ||
(CtrlType == CTRL_SHUTDOWN_EVENT)))
{
//
// Cmd wait 10 sec before it popup a time-out fail message
// We are waiting 5 sec to give the application (client)
// time to clean-up before we return TRUE.
Sleep(5000);
if ( Ow2ExitInProcess )
{
Rc = FALSE;
}
} else if (Rc && SesGrp->InTermination && Od2SignalEnabled) {
Rc = SendSignalToOs2Srv(SignalType);
}
return (Rc);
}
ULONG
Ow2GetProcessIdFromLPCMessage(
IN PVOID LPCMessage
)
{
return((ULONG) ((PPORT_MESSAGE)LPCMessage)->ClientId.UniqueProcess);
}
DWORD
Ow2CommandLineWToCommandLineA(
IN LPWSTR CommandLineW,
OUT PSZ *CommandLineA
)
{
UNICODE_STRING CommandLine_U;
UNICODE_STRING CommandLineUpcase;
UNICODE_STRING CurrentDir_U;
UNICODE_STRING CurrentDirUpcase;
WCHAR CurrentDirectory[MAX_PATH];
WCHAR *pWchar;
NTSTATUS Status;
RtlInitUnicodeString(
&CommandLine_U,
CommandLineW
);
if (GetCurrentDirectoryW((DWORD)MAX_PATH, CurrentDirectory))
{
RtlInitUnicodeString(
&CurrentDir_U,
CurrentDirectory
);
//
// Prepare the structures for upcase strings and then upcase.
//
if (NULL == (CommandLineUpcase.Buffer =
RtlAllocateHeap(RtlProcessHeap(), 0, CommandLine_U.MaximumLength))) {
KdPrint(( NtInitssFail, 0, "RtlAllocateHeap(CommandLine)"));
return ((DWORD)-1L);
}
if (NULL == (CurrentDirUpcase.Buffer =
RtlAllocateHeap(RtlProcessHeap(), 0, CurrentDir_U.MaximumLength))) {
KdPrint(( NtInitssFail, 0, "RtlAllocateHeap(CurrentDir)"));
RtlFreeHeap(RtlProcessHeap(), 0, CommandLineUpcase.Buffer);
return ((DWORD)-1L);
}
CurrentDirUpcase.Length = CurrentDir_U.Length;
CurrentDirUpcase.MaximumLength = CurrentDir_U.MaximumLength;
Status = RtlUpcaseUnicodeString(&CurrentDirUpcase, &CurrentDir_U, FALSE);
if (!NT_SUCCESS(Status)) {
KdPrint(( NtInitssFail, 0, "RtlUpcaseUnicodeString(CurrentDirUpcase)"));
RtlFreeHeap(RtlProcessHeap(), 0, CommandLineUpcase.Buffer);
RtlFreeHeap(RtlProcessHeap(), 0, CurrentDirUpcase.Buffer);
return ((DWORD)-1L);
}
CommandLineUpcase.Length = CommandLine_U.Length;
CommandLineUpcase.MaximumLength = CommandLine_U.MaximumLength;
Status = RtlUpcaseUnicodeString(&CommandLineUpcase, &CommandLine_U, FALSE);
if (!NT_SUCCESS(Status)) {
KdPrint(( NtInitssFail, 0, "RtlUpcaseUnicodeString(CommandLineUpcase)"));
RtlFreeHeap(RtlProcessHeap(), 0, CommandLineUpcase.Buffer);
RtlFreeHeap(RtlProcessHeap(), 0, CurrentDirUpcase.Buffer);
return ((DWORD)-1L);
}
//
// Initialize pWchar and append NULL to the end of the upcased strings
// for the search of wsstr().
//
pWchar = CommandLineUpcase.Buffer;
CurrentDirUpcase.Buffer[CurrentDirUpcase.Length / 2] = (WCHAR)NULL;
CommandLineUpcase.Buffer[CommandLineUpcase.Length / 2] = (WCHAR)NULL;
//
// Replace every prefix of the current directory in the command
// line with what GetCurrentDirectoryW() returned. This resolves
// problems caused by apps transfering the command line in
// apper/lower case.
//
while ((pWchar < &CommandLineUpcase.Buffer[CommandLineUpcase.Length / 2]) &&
(pWchar = wcsstr(pWchar, CurrentDirUpcase.Buffer))) {
wcsncpy(&CommandLine_U.Buffer[pWchar - CommandLineUpcase.Buffer],
CurrentDirectory,
CurrentDirUpcase.Length / 2);
pWchar += CurrentDirUpcase.Length / 2;
}
//
// Free the allocated buffers.
//
RtlFreeHeap(RtlProcessHeap(), 0, CommandLineUpcase.Buffer);
RtlFreeHeap(RtlProcessHeap(), 0, CurrentDirUpcase.Buffer);
}
Status = RtlUnicodeStringToOemString(
&Ow2CommandLineString,
&CommandLine_U,
TRUE
);
if (!NT_SUCCESS( Status ))
{
KdPrint(( NtInitssFail, Status, "CommandLine-UnicodeToOemString"));
return ((DWORD)-1L);
}
*CommandLineA = Ow2CommandLineString.Buffer;
return(0L);
}
#if PMNT
// Returns true if process is the root process of a session
// otherwise returns false
// This procedure was written to enable 16 Bit dll init routine (PMWIN)
// to check if the it is executed from the root process of a session.
APIRET PMNTIsSessionRoot()
{
if ( OS2SS_IS_SESSION( Ow2bNewSession ))
return(TRUE);
else
return(FALSE);
}
#endif // PMNT