2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: dll/ntdll/csr/connect.c
5 * PURPOSE: Routines for connecting and calling CSR
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
20 ULONG_PTR CsrPortMemoryDelta
;
21 BOOLEAN InsideCsrProcess
= FALSE
;
24 (NTAPI
*PCSR_SERVER_API_ROUTINE
)(IN PPORT_MESSAGE Request
,
25 IN PPORT_MESSAGE Reply
);
27 PCSR_SERVER_API_ROUTINE CsrServerApiRoutine
;
29 #define UNICODE_PATH_SEP L"\\"
31 /* FUNCTIONS ******************************************************************/
35 CsrpConnectToServer(IN PWSTR ObjectDirectory
)
39 UNICODE_STRING PortName
;
40 LARGE_INTEGER CsrSectionViewSize
;
41 HANDLE CsrSectionHandle
;
43 REMOTE_PORT_VIEW LpcRead
;
44 SECURITY_QUALITY_OF_SERVICE SecurityQos
;
45 SID_IDENTIFIER_AUTHORITY NtSidAuthority
= {SECURITY_NT_AUTHORITY
};
46 PSID SystemSid
= NULL
;
47 CSR_API_CONNECTINFO ConnectionInfo
;
48 ULONG ConnectionInfoLength
= sizeof(CSR_API_CONNECTINFO
);
50 DPRINT("%s(%S)\n", __FUNCTION__
, ObjectDirectory
);
52 /* Binary compatibility with MS KERNEL32 */
53 if (NULL
== ObjectDirectory
)
55 ObjectDirectory
= L
"\\Windows";
58 /* Calculate the total port name size */
59 PortNameLength
= ((wcslen(ObjectDirectory
) + 1) * sizeof(WCHAR
)) +
60 sizeof(CSR_PORT_NAME
);
62 /* Set the port name */
64 PortName
.MaximumLength
= PortNameLength
;
66 /* Allocate a buffer for it */
67 PortName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, PortNameLength
);
68 if (PortName
.Buffer
== NULL
)
70 return STATUS_INSUFFICIENT_RESOURCES
;
74 RtlAppendUnicodeToString(&PortName
, ObjectDirectory
);
75 RtlAppendUnicodeToString(&PortName
, UNICODE_PATH_SEP
);
76 RtlAppendUnicodeToString(&PortName
, CSR_PORT_NAME
);
78 /* Create a section for the port memory */
79 CsrSectionViewSize
.QuadPart
= CSR_CSRSS_SECTION_SIZE
;
80 Status
= NtCreateSection(&CsrSectionHandle
,
87 if (!NT_SUCCESS(Status
))
89 DPRINT1("Failure allocating CSR Section\n");
93 /* Set up the port view structures to match them with the section */
94 LpcWrite
.Length
= sizeof(PORT_VIEW
);
95 LpcWrite
.SectionHandle
= CsrSectionHandle
;
96 LpcWrite
.SectionOffset
= 0;
97 LpcWrite
.ViewSize
= CsrSectionViewSize
.u
.LowPart
;
98 LpcWrite
.ViewBase
= 0;
99 LpcWrite
.ViewRemoteBase
= 0;
100 LpcRead
.Length
= sizeof(REMOTE_PORT_VIEW
);
101 LpcRead
.ViewSize
= 0;
102 LpcRead
.ViewBase
= 0;
105 SecurityQos
.ImpersonationLevel
= SecurityImpersonation
;
106 SecurityQos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
107 SecurityQos
.EffectiveOnly
= TRUE
;
109 /* Setup the connection info */
110 ConnectionInfo
.DebugFlags
= 0;
112 /* Create a SID for us */
113 Status
= RtlAllocateAndInitializeSid(&NtSidAuthority
,
115 SECURITY_LOCAL_SYSTEM_RID
,
124 if (!NT_SUCCESS(Status
))
127 DPRINT1("Couldn't allocate SID\n");
128 NtClose(CsrSectionHandle
);
132 /* Connect to the port */
133 Status
= NtSecureConnectPort(&CsrApiPort
,
141 &ConnectionInfoLength
);
142 RtlFreeSid(SystemSid
);
143 NtClose(CsrSectionHandle
);
144 if (!NT_SUCCESS(Status
))
147 DPRINT1("Couldn't connect to CSR port\n");
151 /* Save the delta between the sections, for capture usage later */
152 CsrPortMemoryDelta
= (ULONG_PTR
)LpcWrite
.ViewRemoteBase
-
153 (ULONG_PTR
)LpcWrite
.ViewBase
;
155 /* Save the Process */
156 CsrProcessId
= ConnectionInfo
.ServerProcessId
;
158 /* Save CSR Section data */
159 NtCurrentPeb()->ReadOnlySharedMemoryBase
= ConnectionInfo
.SharedSectionBase
;
160 NtCurrentPeb()->ReadOnlySharedMemoryHeap
= ConnectionInfo
.SharedSectionHeap
;
161 NtCurrentPeb()->ReadOnlyStaticServerData
= ConnectionInfo
.SharedStaticServerData
;
163 /* Create the port heap */
164 CsrPortHeap
= RtlCreateHeap(0,
170 if (CsrPortHeap
== NULL
)
173 DPRINT1("Couldn't create heap for CSR port\n");
176 return STATUS_INSUFFICIENT_RESOURCES
;
180 return STATUS_SUCCESS
;
188 CsrClientConnectToServer(IN PWSTR ObjectDirectory
,
190 IN PVOID ConnectionInfo
,
191 IN OUT PULONG ConnectionInfoSize
,
192 OUT PBOOLEAN ServerToServerCall
)
195 PIMAGE_NT_HEADERS NtHeader
;
196 UNICODE_STRING CsrSrvName
;
198 ANSI_STRING CsrServerRoutineName
;
199 CSR_API_MESSAGE ApiMessage
;
200 PCSR_CLIENT_CONNECT ClientConnect
= &ApiMessage
.Data
.CsrClientConnect
;
201 PCSR_CAPTURE_BUFFER CaptureBuffer
;
203 DPRINT("CsrClientConnectToServer: %lx %p\n", ServerId
, ConnectionInfo
);
205 /* Validate the Connection Info */
206 if (ConnectionInfo
&& (!ConnectionInfoSize
|| !*ConnectionInfoSize
))
208 DPRINT1("Connection info given, but no length\n");
209 return STATUS_INVALID_PARAMETER
;
212 /* Check if we're inside a CSR Process */
213 if (InsideCsrProcess
)
215 /* Tell the client that we're already inside CSR */
216 if (ServerToServerCall
) *ServerToServerCall
= TRUE
;
217 return STATUS_SUCCESS
;
221 * We might be in a CSR Process but not know it, if this is the first call.
224 if (!(NtHeader
= RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
)))
226 /* The image isn't valid */
227 DPRINT1("Invalid image\n");
228 return STATUS_INVALID_IMAGE_FORMAT
;
230 InsideCsrProcess
= (NtHeader
->OptionalHeader
.Subsystem
== IMAGE_SUBSYSTEM_NATIVE
);
232 /* Now we can check if we are inside or not */
233 if (InsideCsrProcess
)
235 /* We're inside, so let's find csrsrv */
236 DPRINT("Next-GEN CSRSS support\n");
237 RtlInitUnicodeString(&CsrSrvName
, L
"csrsrv");
238 Status
= LdrGetDllHandle(NULL
,
243 /* Now get the Server to Server routine */
244 RtlInitAnsiString(&CsrServerRoutineName
, "CsrCallServerFromServer");
245 Status
= LdrGetProcedureAddress(hCsrSrv
,
246 &CsrServerRoutineName
,
248 (PVOID
*)&CsrServerApiRoutine
);
250 /* Use the local heap as port heap */
251 CsrPortHeap
= RtlGetProcessHeap();
253 /* Tell the caller we're inside the server */
254 *ServerToServerCall
= InsideCsrProcess
;
255 return STATUS_SUCCESS
;
258 /* Now check if connection info is given */
261 /* Well, we're defintely in a client now */
262 InsideCsrProcess
= FALSE
;
264 /* Do we have a connection to CSR yet? */
267 /* No, set it up now */
268 Status
= CsrpConnectToServer(ObjectDirectory
);
269 if (!NT_SUCCESS(Status
))
272 DPRINT1("Failure to connect to CSR\n");
277 /* Setup the connect message header */
278 ClientConnect
->ServerId
= ServerId
;
279 ClientConnect
->ConnectionInfoSize
= *ConnectionInfoSize
;
281 /* Setup a buffer for the connection info */
282 CaptureBuffer
= CsrAllocateCaptureBuffer(1, ClientConnect
->ConnectionInfoSize
);
283 if (CaptureBuffer
== NULL
)
285 return STATUS_INSUFFICIENT_RESOURCES
;
288 /* Capture the connection info data */
289 CsrCaptureMessageBuffer(CaptureBuffer
,
291 ClientConnect
->ConnectionInfoSize
,
292 &ClientConnect
->ConnectionInfo
);
294 /* Return the allocated length */
295 *ConnectionInfoSize
= ClientConnect
->ConnectionInfoSize
;
298 Status
= CsrClientCallServer(&ApiMessage
,
300 CSR_CREATE_API_NUMBER(CSRSRV_SERVERDLL_INDEX
, CsrpClientConnect
),
301 sizeof(CSR_CLIENT_CONNECT
));
303 /* Copy the updated connection info data back into the user buffer */
304 RtlMoveMemory(ConnectionInfo
,
305 ClientConnect
->ConnectionInfo
,
306 *ConnectionInfoSize
);
308 /* Free the capture buffer */
309 CsrFreeCaptureBuffer(CaptureBuffer
);
313 /* No connection info, just return */
314 Status
= STATUS_SUCCESS
;
317 /* Let the caller know if this was server to server */
318 DPRINT("Status was: 0x%lx. Are we in server: 0x%x\n", Status
, InsideCsrProcess
);
319 if (ServerToServerCall
) *ServerToServerCall
= InsideCsrProcess
;
326 // Structures can be padded at the end, causing the size of the entire structure
327 // minus the size of the last field, not to be equal to the offset of the last
330 typedef struct _TEST_EMBEDDED
343 C_ASSERT(sizeof(PORT_MESSAGE
) == 0x18);
344 C_ASSERT(FIELD_OFFSET(TEST
, Three
) == 0x18);
345 C_ASSERT(sizeof(TEST_EMBEDDED
) == 0xC);
347 C_ASSERT(sizeof(TEST
) != (sizeof(TEST_EMBEDDED
) + sizeof(PORT_MESSAGE
)));
348 C_ASSERT((sizeof(TEST
) - sizeof(TEST_EMBEDDED
)) != FIELD_OFFSET(TEST
, Three
));
356 CsrClientCallServer(IN OUT PCSR_API_MESSAGE ApiMessage
,
357 IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer OPTIONAL
,
358 IN CSR_API_NUMBER ApiNumber
,
363 PULONG_PTR OffsetPointer
;
365 /* Fill out the Port Message Header */
366 ApiMessage
->Header
.u2
.ZeroInit
= 0;
367 ApiMessage
->Header
.u1
.s1
.TotalLength
= DataLength
+
368 sizeof(CSR_API_MESSAGE
) - sizeof(ApiMessage
->Data
); // FIELD_OFFSET(CSR_API_MESSAGE, Data) + DataLength;
369 ApiMessage
->Header
.u1
.s1
.DataLength
= DataLength
+
370 FIELD_OFFSET(CSR_API_MESSAGE
, Data
) - sizeof(ApiMessage
->Header
);// ApiMessage->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
372 /* Fill out the CSR Header */
373 ApiMessage
->ApiNumber
= ApiNumber
;
374 ApiMessage
->CsrCaptureData
= NULL
;
376 DPRINT("API: %lx, u1.s1.DataLength: %x, u1.s1.TotalLength: %x\n",
378 ApiMessage
->Header
.u1
.s1
.DataLength
,
379 ApiMessage
->Header
.u1
.s1
.TotalLength
);
381 /* Check if we are already inside a CSR Server */
382 if (!InsideCsrProcess
)
384 /* Check if we got a Capture Buffer */
388 * We have to convert from our local (client) view
389 * to the remote (server) view.
391 ApiMessage
->CsrCaptureData
= (PCSR_CAPTURE_BUFFER
)
392 ((ULONG_PTR
)CaptureBuffer
+ CsrPortMemoryDelta
);
394 /* Lock the buffer. */
395 CaptureBuffer
->BufferEnd
= NULL
;
398 * Each client pointer inside the CSR message is converted into
399 * a server pointer, and each pointer to these message pointers
400 * is converted into an offset.
402 PointerCount
= CaptureBuffer
->PointerCount
;
403 OffsetPointer
= CaptureBuffer
->PointerOffsetsArray
;
404 while (PointerCount
--)
406 if (*OffsetPointer
!= 0)
408 *(PULONG_PTR
)*OffsetPointer
+= CsrPortMemoryDelta
;
409 *OffsetPointer
-= (ULONG_PTR
)ApiMessage
;
415 /* Send the LPC Message */
416 Status
= NtRequestWaitReplyPort(CsrApiPort
,
418 &ApiMessage
->Header
);
420 /* Check if we got a Capture Buffer */
424 * We have to convert back from the remote (server) view
425 * to our local (client) view.
427 ApiMessage
->CsrCaptureData
= (PCSR_CAPTURE_BUFFER
)
428 ((ULONG_PTR
)ApiMessage
->CsrCaptureData
- CsrPortMemoryDelta
);
431 * Convert back the offsets into pointers to CSR message
432 * pointers, and convert back these message server pointers
433 * into client pointers.
435 PointerCount
= CaptureBuffer
->PointerCount
;
436 OffsetPointer
= CaptureBuffer
->PointerOffsetsArray
;
437 while (PointerCount
--)
439 if (*OffsetPointer
!= 0)
441 *OffsetPointer
+= (ULONG_PTR
)ApiMessage
;
442 *(PULONG_PTR
)*OffsetPointer
-= CsrPortMemoryDelta
;
448 /* Check for success */
449 if (!NT_SUCCESS(Status
))
451 /* We failed. Overwrite the return value with the failure. */
452 DPRINT1("LPC Failed: %lx\n", Status
);
453 ApiMessage
->Status
= Status
;
458 /* This is a server-to-server call. Save our CID and do a direct call. */
459 DPRINT("Next gen server-to-server call\n");
461 /* We check this equality inside CsrValidateMessageBuffer */
462 ApiMessage
->Header
.ClientId
= NtCurrentTeb()->ClientId
;
464 Status
= CsrServerApiRoutine(&ApiMessage
->Header
,
465 &ApiMessage
->Header
);
467 /* Check for success */
468 if (!NT_SUCCESS(Status
))
470 /* We failed. Overwrite the return value with the failure. */
471 ApiMessage
->Status
= Status
;
475 /* Return the CSR Result */
476 DPRINT("Got back: 0x%lx\n", ApiMessage
->Status
);
477 return ApiMessage
->Status
;
485 CsrGetProcessId(VOID
)