WindowsXP-SP1/base/subsys/posix/client/dllinit.c
2020-09-30 16:53:49 +02:00

382 lines
9.9 KiB
C

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
dllinit.c
Abstract:
This module contains the initialization code for the POSIX Subsystem
Client DLL.
Author:
Mark Lucovsky (markl) 27-Jun-1989
Environment:
User Mode only
Revision History:
Ellen Aycock-Wright (ellena) 03-Jan-1991
Converted to DLL initialization routine.
--*/
#include <nt.h>
#include <ntrtl.h>
#include "psxdll.h"
extern void ClientOpen(int);
ULONG_PTR PsxPortMemoryRemoteDelta;
PVOID PsxPortMemoryBase;
BOOLEAN
PsxDllInitialize(
IN PVOID DllHandle,
IN ULONG Reason,
IN PCONTEXT Context OPTIONAL
)
/*++
Routine Description:
This function is the DLL initialization routine for the POSIX Emulation
Subsystem Client DLL. This function gets control when the applications
links to this DLL are snapped.
Arguments:
Context - Supplies an optional context buffer that will be restored
after all DLL initialization has been completed. If this
parameter is NULL then this is a dynamic snap of this module.
Otherwise this is a static snap prior to the user process
gaining control.
Return Value:
False if initialization failed.
--*/
{
PPEB Peb;
PPEB_PSX_DATA PebPsxData;
NTSTATUS Status;
if (Reason != DLL_PROCESS_ATTACH) {
return TRUE;
}
//
// Remember our DLL handle in a global variable.
//
PsxDllHandle = DllHandle;
PdxHeap = RtlCreateHeap( HEAP_GROWABLE | HEAP_NO_SERIALIZE,
NULL,
64 * 1024, // Initial size of heap is 64K
4 * 1024,
0,
NULL
);
if (PdxHeap == NULL) {
return FALSE;
}
Status = PsxInitDirectories();
if ( !NT_SUCCESS( Status )) {
return FALSE;
}
Status = PsxConnectToServer();
if (!NT_SUCCESS(Status)) {
return FALSE;
}
Peb = NtCurrentPeb();
//
// This is not really an ANSI_STRING but an undocumented data
// structure. Read crt32psx\startup\crt0.c for the code that
// interprets this.
//
PsxAnsiCommandLine = *(PANSI_STRING)&(Peb->ProcessParameters->CommandLine);
if (ARGUMENT_PRESENT(Context)) {
PebPsxData = (PPEB_PSX_DATA)Peb->SubSystemData;
PebPsxData->ClientStartAddress = (PVOID)CONTEXT_TO_PROGRAM_COUNTER(Context);
PROGRAM_COUNTER_TO_CONTEXT(Context, (ULONG_PTR) PdxProcessStartup);
}
return TRUE;
}
NTSTATUS
PsxInitDirectories()
{
PdxDirectoryPrefix.NtCurrentWorkingDirectory.Buffer =
RtlAllocateHeap(PdxHeap, 0,2*PATH_MAX);
PdxDirectoryPrefix.NtCurrentWorkingDirectory.Length = 0;
PdxDirectoryPrefix.NtCurrentWorkingDirectory.MaximumLength = 2*PATH_MAX;
PdxDirectoryPrefix.PsxCurrentWorkingDirectory.Buffer =
RtlAllocateHeap(PdxHeap, 0,PATH_MAX+1);
PdxDirectoryPrefix.PsxCurrentWorkingDirectory.Length = 0;
PdxDirectoryPrefix.PsxCurrentWorkingDirectory.MaximumLength = PATH_MAX+1;
PdxDirectoryPrefix.PsxRoot.Buffer = RtlAllocateHeap(PdxHeap, 0,2*PATH_MAX);
PdxDirectoryPrefix.PsxRoot.Length = 0;
PdxDirectoryPrefix.PsxRoot.MaximumLength = 2*PATH_MAX;
//
// Check that memory allocations worked. If not, then bail out
//
ASSERT(PdxDirectoryPrefix.NtCurrentWorkingDirectory.Buffer);
ASSERT(PdxDirectoryPrefix.PsxCurrentWorkingDirectory.Buffer);
ASSERT(PdxDirectoryPrefix.PsxRoot.Buffer);
if ( (PdxDirectoryPrefix.NtCurrentWorkingDirectory.Buffer == NULL) ||
(PdxDirectoryPrefix.PsxCurrentWorkingDirectory.Buffer == NULL) ||
(PdxDirectoryPrefix.PsxRoot.Buffer == NULL) ) {
return ( STATUS_NO_MEMORY );
}
return ( STATUS_SUCCESS );
}
NTSTATUS
PsxConnectToServer(VOID)
{
UNICODE_STRING PsxPortName;
PSX_API_CONNECTINFO ConnectionInformation;
ULONG ConnectionInformationLength;
PULONG AmIBeingDebugged;
REMOTE_PORT_VIEW ServerView;
HANDLE PortSection;
PPEB Peb;
PPEB_PSX_DATA PebPsxData;
PORT_VIEW ClientView;
LARGE_INTEGER SectionSize;
SECURITY_QUALITY_OF_SERVICE DynamicQos;
NTSTATUS Status;
ConnectionInformationLength = sizeof(ConnectionInformation);
//
// Create a section to contain the Port Memory. Port Memory is private
// memory that is shared between the POSIX client and server processes.
// This allows data that is too large to fit into an API request message
// to be passed to the POSIX server.
//
SectionSize.LowPart = PSX_CLIENT_PORT_MEMORY_SIZE;
SectionSize.HighPart = 0;
// SEC_RESERVE
Status = NtCreateSection(&PortSection, SECTION_ALL_ACCESS, NULL,
&SectionSize, PAGE_READWRITE, SEC_COMMIT, NULL);
if (!NT_SUCCESS(Status)) {
KdPrint(("PSXDLL: NtCreateSection: 0x%x\n", Status));
return Status;
}
//
// Get the Peb address. Allocate the POSIX subsystem specific portion
// within the Peb. This structure will be filled in by the server
// process as part of the connect logic.
//
Peb = NtCurrentPeb();
Peb->SubSystemData = RtlAllocateHeap(Peb->ProcessHeap, 0,
sizeof(PEB_PSX_DATA));
if (! Peb->SubSystemData) {
NtClose(PortSection);
return STATUS_NO_MEMORY;
}
PebPsxData = (PPEB_PSX_DATA)Peb->SubSystemData;
PebPsxData->Length = sizeof(PEB_PSX_DATA);
//
// Connect to the POSIX Emulation Subsystem server. This includes a
// description of the Port Memory section so that the LPC connection
// logic can make the section visible to both the client and server
// processes. Also pass information the POSIX server needs in the
// connection information structure.
//
ClientView.Length = sizeof(ClientView);
ClientView.SectionHandle = PortSection;
ClientView.SectionOffset = 0;
ClientView.ViewSize = SectionSize.LowPart;
ClientView.ViewBase = 0;
ClientView.ViewRemoteBase = 0;
ServerView.Length = sizeof(ServerView);
ServerView.ViewSize = 0;
ServerView.ViewBase = 0;
ConnectionInformation.SignalDeliverer = _PdxSignalDeliverer;
ConnectionInformation.NullApiCaller = _PdxNullApiCaller;
ConnectionInformation.DirectoryPrefix = &PdxDirectoryPrefix;
ConnectionInformation.InitialPebPsxData.Length = PebPsxData->Length;
//
// Set up the security quality of service parameters to use over the
// port.
//
DynamicQos.ImpersonationLevel = SecurityImpersonation;
DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
DynamicQos.EffectiveOnly = TRUE;
PSX_GET_SESSION_OBJECT_NAME(&PsxPortName, PSX_SS_API_PORT_NAME);
Status = NtConnectPort(&PsxPortHandle, &PsxPortName, &DynamicQos,
&ClientView, &ServerView, NULL,
(PVOID)&ConnectionInformation,
(PULONG)&ConnectionInformationLength);
NtClose(PortSection);
if (!NT_SUCCESS(Status)) {
KdPrint(("PSXDLL: Unable to connect to Posix server: %lx\n",
Status));
return Status;
}
Status = NtRegisterThreadTerminatePort(PsxPortHandle);
ASSERT(NT_SUCCESS(Status));
PsxPortMemoryBase = ClientView.ViewBase;
PsxPortMemoryRemoteDelta = (ULONG_PTR)ClientView.ViewRemoteBase -
(ULONG_PTR)ClientView.ViewBase;
RtlMoveMemory((PVOID)PebPsxData,
(PVOID)&ConnectionInformation.InitialPebPsxData,
PebPsxData->Length);
PdxPortHeap = RtlCreateHeap( HEAP_NO_SERIALIZE,
ClientView.ViewBase,
ClientView.ViewSize,
ClientView.ViewSize,
0,
0
);
if (PdxPortHeap == NULL) {
KdPrint(("PsxConnectToServer: RtlCreateHeap failed\n"));
return STATUS_NO_MEMORY;
}
//
// Connect to the session console port and
// set the port handle in the PEB.
//
Status = PsxInitializeSessionPort(HandleToUlong(PebPsxData->SessionPortHandle));
if (!NT_SUCCESS(Status)) {
KdPrint(("PsxConnectToServer: PsxInitSessionPort failed\n"));
return Status;
}
return STATUS_SUCCESS;
}
//
// User mode process entry point.
//
VOID
PdxProcessStartup(
IN PPEB Peb
)
{
PPEB_PSX_DATA PebPsxData;
PFNPROCESS StartAddress;
int ReturnCodeFromMain;
PebPsxData = (PPEB_PSX_DATA)Peb->SubSystemData;
StartAddress = (PFNPROCESS)(PebPsxData->ClientStartAddress);
ReturnCodeFromMain = (*StartAddress) (0, NULL);
_exit(ReturnCodeFromMain);
NtTerminateProcess(NtCurrentProcess(),STATUS_ACCESS_DENIED);
}
VOID
PdxNullApiCaller(
IN PCONTEXT Context
)
{
PdxNullPosixApi();
#ifdef _X86_
Context->Eax = 0;
#endif
NtContinue(Context,FALSE);
//NOTREACHED
}
VOID
PdxSignalDeliverer (
IN PCONTEXT Context,
IN sigset_t PreviousBlockMask,
IN int Signal,
IN _handler Handler
)
{
(Handler)(Signal);
sigprocmask(SIG_SETMASK, &PreviousBlockMask, NULL);
#ifdef _X86_
Context->Eax = 0;
#endif
NtContinue(Context, FALSE);
//NOTREACHED
}
VOID
__PdxInitializeData(
IN int *perrno,
IN char ***penviron
)
/*++
Routine Description:
This function is called from the RTL startup code to notify the DLL of
the location of the variable 'errno'. Necessary because DLLs cannot
export data.
Arguments:
perrno - Supplies the address of errno - declared in rtl/startup.c
Return Value:
None.
--*/
{
Errno = perrno;
Environ = penviron;
}