From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/os2/os2ses/ntinitss.c | 1650 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1650 insertions(+) create mode 100644 private/os2/os2ses/ntinitss.c (limited to 'private/os2/os2ses/ntinitss.c') diff --git a/private/os2/os2ses/ntinitss.c b/private/os2/os2ses/ntinitss.c new file mode 100644 index 000000000..449c81c34 --- /dev/null +++ b/private/os2/os2ses/ntinitss.c @@ -0,0 +1,1650 @@ +/*++ + +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 +#include +#include +#define NTOS2_ONLY +#include "os2ses.h" +#include "os2tile.h" +#if PMNT +#define INCL_32BIT +#include "pmnt.h" +#endif +#include + +#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 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 -- cgit v1.2.3