You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
542 lines
15 KiB
542 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dllinit.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the initialization code for the Client-Server (CS)
|
|
Client DLL.
|
|
|
|
Author:
|
|
|
|
Steve Wood (stevewo) 8-Oct-1990
|
|
|
|
Environment:
|
|
|
|
User Mode only
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "ldrp.h"
|
|
#include "csrdll.h"
|
|
|
|
BOOLEAN
|
|
ProtectHandle (
|
|
HANDLE hObject
|
|
);
|
|
|
|
BOOLEAN
|
|
UnProtectHandle (
|
|
HANDLE hObject
|
|
);
|
|
|
|
|
|
BOOLEAN
|
|
CsrDllInitialize (
|
|
IN PVOID DllHandle,
|
|
IN ULONG Reason,
|
|
IN PCONTEXT Context OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the DLL initialization routine for the Client DLL
|
|
This function gets control when the application 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:
|
|
|
|
Status value.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNREFERENCED_PARAMETER (Context);
|
|
|
|
if (Reason == DLL_PROCESS_ATTACH) {
|
|
|
|
//
|
|
// Remember our DLL handle in a global variable.
|
|
//
|
|
|
|
CsrDllHandle = DllHandle;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CsrOneTimeInitialize (
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Save away system information in a global variable.
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (SystemBasicInformation,
|
|
&CsrNtSysInfo,
|
|
sizeof (CsrNtSysInfo),
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Use the process heap for memory allocations.
|
|
//
|
|
|
|
CsrHeap = RtlProcessHeap ();
|
|
|
|
CsrInitOnceDone = TRUE;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CsrClientConnectToServer (
|
|
IN PWSTR ObjectDirectory,
|
|
IN ULONG ServerDllIndex,
|
|
IN PVOID ConnectionInformation,
|
|
IN OUT PULONG ConnectionInformationLength OPTIONAL,
|
|
OUT PBOOLEAN CalledFromServer OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by the client side DLL to connect with its
|
|
server side DLL.
|
|
|
|
Arguments:
|
|
|
|
ObjectDirectory - Points to a null terminated string that is the same
|
|
as the value of the ObjectDirectory= argument passed to the CSRSS
|
|
program.
|
|
|
|
ServerDllIndex - Index of the server DLL that is being connected to.
|
|
It should match one of the ServerDll= arguments passed to the CSRSS
|
|
program.
|
|
|
|
ConnectionInformation - An optional pointer to uninterpreted data.
|
|
This data is intended for clients to pass package, version and
|
|
protocol identification information to the server to allow the
|
|
server to determine if it can satisfy the client before
|
|
accepting the connection. Upon return to the client, the
|
|
ConnectionInformation data block contains any information passed
|
|
back from the server DLL by its call to the
|
|
CsrCompleteConnection call. The output data overwrites the
|
|
input data.
|
|
|
|
ConnectionInformationLength - Pointer to the length of the
|
|
ConnectionInformation data block. The output value is the
|
|
length of the data stored in the ConnectionInformation data
|
|
block by the server's call to the NtCompleteConnectPort
|
|
service. This parameter is OPTIONAL only if the
|
|
ConnectionInformation parameter is NULL, otherwise it is
|
|
required.
|
|
|
|
CalledFromServer - On output, TRUE if the dll has been called from
|
|
a server process.
|
|
|
|
Return Value:
|
|
|
|
Status value.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
CSR_API_MSG m;
|
|
PCSR_CLIENTCONNECT_MSG a = &m.u.ClientConnect;
|
|
PCSR_CAPTURE_HEADER CaptureBuffer;
|
|
HANDLE CsrServerModuleHandle;
|
|
STRING ProcedureName;
|
|
UNICODE_STRING DllName_U;
|
|
PIMAGE_NT_HEADERS NtHeaders;
|
|
|
|
if ((ARGUMENT_PRESENT (ConnectionInformation)) &&
|
|
(!ARGUMENT_PRESENT (ConnectionInformationLength) ||
|
|
*ConnectionInformationLength == 0)) {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!CsrInitOnceDone) {
|
|
Status = CsrOneTimeInitialize();
|
|
if (!NT_SUCCESS (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we are being called by a server process, skip LPC port initialization
|
|
// and call to server connect routine and just initialize the heap. The
|
|
// dll initialization routine will do any necessary initialization. This
|
|
// stuff only needs to be done for the first connect.
|
|
//
|
|
|
|
if (CsrServerProcess == TRUE) {
|
|
if (ARGUMENT_PRESENT (CalledFromServer)) {
|
|
*CalledFromServer = CsrServerProcess;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// If the image is an NT native image, we are running in the
|
|
// context of the server.
|
|
//
|
|
|
|
NtHeaders = RtlImageNtHeader (NtCurrentPeb()->ImageBaseAddress);
|
|
|
|
if (!NtHeaders) {
|
|
return STATUS_INVALID_IMAGE_FORMAT;
|
|
}
|
|
|
|
CsrServerProcess =
|
|
(NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE) ? TRUE : FALSE;
|
|
|
|
if (CsrServerProcess) {
|
|
|
|
extern PVOID NtDllBase;
|
|
|
|
DllName_U.Buffer = L"csrsrv";
|
|
DllName_U.Length = sizeof (L"csrsrv") - sizeof (WCHAR);
|
|
DllName_U.MaximumLength = sizeof(L"csrsrv");
|
|
|
|
Status = LdrDisableThreadCalloutsForDll (NtDllBase);
|
|
if (!NT_SUCCESS (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = LdrGetDllHandle (NULL,
|
|
NULL,
|
|
&DllName_U,
|
|
(PVOID *)&CsrServerModuleHandle);
|
|
|
|
if (!NT_SUCCESS (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
RtlInitString (&ProcedureName,"CsrCallServerFromServer");
|
|
|
|
Status = LdrGetProcedureAddress (CsrServerModuleHandle,
|
|
&ProcedureName,
|
|
0L,
|
|
(PVOID *)&CsrServerApiRoutine);
|
|
|
|
if (!NT_SUCCESS (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
ASSERT (NT_SUCCESS(Status));
|
|
|
|
ASSERT (CsrPortHeap == NULL);
|
|
|
|
CsrPortHeap = RtlProcessHeap();
|
|
|
|
CsrPortBaseTag = RtlCreateTagHeap (CsrPortHeap,
|
|
0,
|
|
L"CSRPORT!",
|
|
L"CAPTURE\0");
|
|
|
|
if (ARGUMENT_PRESENT(CalledFromServer)) {
|
|
*CalledFromServer = CsrServerProcess;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(ConnectionInformation)) {
|
|
|
|
if (CsrPortHandle == NULL) {
|
|
|
|
Status = CsrpConnectToServer (ObjectDirectory);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// For basesrv this is one big noop.
|
|
//
|
|
if (ServerDllIndex != BASESRV_SERVERDLL_INDEX) {
|
|
|
|
a->ServerDllIndex = ServerDllIndex;
|
|
a->ConnectionInformationLength = *ConnectionInformationLength;
|
|
|
|
CaptureBuffer = CsrAllocateCaptureBuffer (1,
|
|
a->ConnectionInformationLength);
|
|
|
|
if (CaptureBuffer == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
CsrAllocateMessagePointer (CaptureBuffer,
|
|
a->ConnectionInformationLength,
|
|
(PVOID *)&a->ConnectionInformation);
|
|
|
|
RtlCopyMemory (a->ConnectionInformation,
|
|
ConnectionInformation,
|
|
a->ConnectionInformationLength);
|
|
|
|
*ConnectionInformationLength = a->ConnectionInformationLength;
|
|
|
|
Status = CsrClientCallServer (&m,
|
|
CaptureBuffer,
|
|
CSR_MAKE_API_NUMBER (CSRSRV_SERVERDLL_INDEX,
|
|
CsrpClientConnect),
|
|
sizeof (*a));
|
|
|
|
if (CaptureBuffer != NULL) {
|
|
|
|
RtlCopyMemory (ConnectionInformation,
|
|
a->ConnectionInformation,
|
|
*ConnectionInformationLength);
|
|
|
|
CsrFreeCaptureBuffer (CaptureBuffer);
|
|
}
|
|
}
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(CalledFromServer)) {
|
|
*CalledFromServer = CsrServerProcess;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CsrpConnectToServer (
|
|
IN PWSTR ObjectDirectory
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
REMOTE_PORT_VIEW ServerView;
|
|
ULONG MaxMessageLength;
|
|
ULONG ConnectionInformationLength;
|
|
CSR_API_CONNECTINFO ConnectionInformation;
|
|
SECURITY_QUALITY_OF_SERVICE DynamicQos;
|
|
HANDLE PortSection;
|
|
PORT_VIEW ClientView;
|
|
SIZE_T n;
|
|
LARGE_INTEGER SectionSize;
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
|
PSID SystemSid;
|
|
PPEB Peb;
|
|
SIZE_T Odl;
|
|
PWCHAR p;
|
|
|
|
//
|
|
// Create the port name string by combining the passed in object directory
|
|
// name with the port name.
|
|
//
|
|
|
|
Odl = wcslen (ObjectDirectory);
|
|
n = ((Odl + 1) * sizeof (WCHAR)) +
|
|
sizeof (CSR_API_PORT_NAME) - sizeof (WCHAR);
|
|
|
|
if (n > MAXUSHORT) {
|
|
return STATUS_NAME_TOO_LONG;
|
|
}
|
|
|
|
CsrPortName.Buffer = p = RtlAllocateHeap (CsrHeap, MAKE_TAG (CSR_TAG), n);
|
|
|
|
if (CsrPortName.Buffer == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
RtlCopyMemory (p, ObjectDirectory, Odl * sizeof (WCHAR));
|
|
p += Odl;
|
|
*p++ = L'\\';
|
|
RtlCopyMemory (p, CSR_API_PORT_NAME, sizeof (CSR_API_PORT_NAME) - sizeof (WCHAR));
|
|
|
|
CsrPortName.Length = (USHORT) n;
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// Create a section to contain the Port Memory. Port Memory is private
|
|
// memory that is shared between the client and server processes.
|
|
// This allows data that is too large to fit into an API request message
|
|
// to be passed to the server.
|
|
//
|
|
|
|
SectionSize.LowPart = CSR_PORT_MEMORY_SIZE;
|
|
SectionSize.HighPart = 0;
|
|
|
|
Status = NtCreateSection (&PortSection,
|
|
SECTION_ALL_ACCESS,
|
|
NULL,
|
|
&SectionSize,
|
|
PAGE_READWRITE,
|
|
SEC_RESERVE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Connect to the 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
|
|
// 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;
|
|
|
|
ConnectionInformationLength = sizeof (ConnectionInformation);
|
|
|
|
SystemSid = NULL;
|
|
|
|
Status = RtlAllocateAndInitializeSid (&NtAuthority,
|
|
1,
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&SystemSid);
|
|
|
|
if (!NT_SUCCESS (Status)) {
|
|
NtClose (PortSection);
|
|
return Status;
|
|
}
|
|
|
|
#if DBG
|
|
ConnectionInformation.DebugFlags = 0;
|
|
#endif
|
|
|
|
Status = NtSecureConnectPort (&CsrPortHandle,
|
|
&CsrPortName,
|
|
&DynamicQos,
|
|
&ClientView,
|
|
SystemSid,
|
|
&ServerView,
|
|
(PULONG)&MaxMessageLength,
|
|
(PVOID)&ConnectionInformation,
|
|
(PULONG)&ConnectionInformationLength);
|
|
|
|
RtlFreeSid (SystemSid);
|
|
|
|
NtClose (PortSection);
|
|
|
|
if (!NT_SUCCESS (Status)) {
|
|
|
|
IF_DEBUG {
|
|
DbgPrint ("CSRDLL: Unable to connect to %wZ Server - Status == %X\n",
|
|
&CsrPortName,
|
|
Status);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
#if DBG
|
|
ProtectHandle (CsrPortHandle);
|
|
#endif
|
|
|
|
Peb = NtCurrentPeb();
|
|
|
|
Peb->ReadOnlySharedMemoryBase = ConnectionInformation.SharedSectionBase;
|
|
Peb->ReadOnlySharedMemoryHeap = ConnectionInformation.SharedSectionHeap;
|
|
Peb->ReadOnlyStaticServerData = (PVOID *)ConnectionInformation.SharedStaticServerData;
|
|
CsrProcessId = ConnectionInformation.ServerProcessId;
|
|
|
|
#if DBG
|
|
CsrDebug = ConnectionInformation.DebugFlags;
|
|
#endif
|
|
|
|
CsrPortMemoryRemoteDelta = (ULONG_PTR)ClientView.ViewRemoteBase -
|
|
(ULONG_PTR)ClientView.ViewBase;
|
|
|
|
IF_CSR_DEBUG( LPC ) {
|
|
DbgPrint ("CSRDLL: ClientView: Base=%p RemoteBase=%p Delta: %lX Size=%lX\n",
|
|
ClientView.ViewBase,
|
|
ClientView.ViewRemoteBase,
|
|
CsrPortMemoryRemoteDelta,
|
|
(ULONG)ClientView.ViewSize);
|
|
}
|
|
|
|
//
|
|
// Create a sparse heap in the shared memory section. Initially
|
|
// commit just one page.
|
|
//
|
|
|
|
CsrPortHeap = RtlCreateHeap (HEAP_CLASS_8, // Flags
|
|
ClientView.ViewBase, // HeapBase
|
|
ClientView.ViewSize, // ReserveSize
|
|
CsrNtSysInfo.PageSize, // CommitSize
|
|
0, // Reserved
|
|
0); // GrowthThreshold
|
|
|
|
if (CsrPortHeap == NULL) {
|
|
|
|
#if DBG
|
|
UnProtectHandle (CsrPortHandle);
|
|
#endif
|
|
|
|
NtClose (CsrPortHandle);
|
|
CsrPortHandle = NULL;
|
|
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
CsrPortBaseTag = RtlCreateTagHeap (CsrPortHeap,
|
|
0,
|
|
L"CSRPORT!",
|
|
L"!CSRPORT\0"
|
|
L"CAPTURE\0");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|