e88c6022718d2328aaddd4f50d5da5ad4537d1fe
[reactos.git] / subsystems / win32 / csrsrv / api / wapi.c
1 /*
2 * subsystems/win32/csrss/csrsrv/api/wapi.c
3 *
4 * "\windows\ApiPort" port process management functions
5 * CSRSS port message processing
6 *
7 * ReactOS Operating System
8 *
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <srv.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* GLOBALS *******************************************************************/
19
20 static unsigned ApiDefinitionsCount = 0;
21 static PCSRSS_API_DEFINITION ApiDefinitions = NULL;
22 UNICODE_STRING CsrApiPortName;
23 volatile LONG CsrpStaticThreadCount;
24 volatile LONG CsrpDynamicThreadTotal;
25 extern ULONG CsrMaxApiRequestThreads;
26
27 /* FUNCTIONS *****************************************************************/
28
29 #if 0
30 NTSTATUS FASTCALL
31 CsrApiRegisterDefinitions(PCSRSS_API_DEFINITION NewDefinitions)
32 {
33 unsigned NewCount;
34 PCSRSS_API_DEFINITION Scan;
35 PCSRSS_API_DEFINITION New;
36
37 DPRINT("CSR: %s called\n", __FUNCTION__);
38
39 NewCount = 0;
40 for (Scan = NewDefinitions; 0 != Scan->Handler; Scan++)
41 {
42 NewCount++;
43 }
44
45 New = RtlAllocateHeap(CsrHeap, 0,
46 (ApiDefinitionsCount + NewCount)
47 * sizeof(CSRSS_API_DEFINITION));
48 if (NULL == New)
49 {
50 DPRINT1("Unable to allocate memory\n");
51 return STATUS_NO_MEMORY;
52 }
53 if (0 != ApiDefinitionsCount)
54 {
55 RtlCopyMemory(New, ApiDefinitions,
56 ApiDefinitionsCount * sizeof(CSRSS_API_DEFINITION));
57 RtlFreeHeap(CsrHeap, 0, ApiDefinitions);
58 }
59 RtlCopyMemory(New + ApiDefinitionsCount, NewDefinitions,
60 NewCount * sizeof(CSRSS_API_DEFINITION));
61 ApiDefinitions = New;
62 ApiDefinitionsCount += NewCount;
63
64 return STATUS_SUCCESS;
65 }
66 #endif
67
68 /*
69 VOID
70 FASTCALL
71 CsrApiCallHandler(PCSR_PROCESS ProcessData,
72 PCSR_API_MESSAGE Request)
73 */
74 VOID
75 FASTCALL
76 CsrApiCallHandler(
77 IN OUT PCSR_API_MESSAGE ApiMessage,
78 OUT PULONG Reply
79 )
80 {
81 unsigned DefIndex;
82 ULONG ApiId;
83
84 DPRINT("CSR: Calling handler for ApiNumber: %x.\n", ApiMessage->ApiNumber);
85 ApiId = CSR_API_NUMBER_TO_API_ID(ApiMessage->ApiNumber);
86 DPRINT("CSR: ApiID: %x ServerID: %x\n", ApiId, CSR_API_NUMBER_TO_SERVER_ID(ApiMessage->ApiNumber));
87
88 /* FIXME: Extract DefIndex instead of looping */
89 for (DefIndex = 0; DefIndex < ApiDefinitionsCount; DefIndex++)
90 {
91 if (ApiDefinitions[DefIndex].ApiID == ApiId)
92 {
93 if (ApiMessage->Header.u1.s1.DataLength < ApiDefinitions[DefIndex].MinRequestSize)
94 {
95 DPRINT1("Request ApiID %d min request size %d actual %d\n",
96 ApiId, ApiDefinitions[DefIndex].MinRequestSize,
97 ApiMessage->Header.u1.s1.DataLength);
98 ApiMessage->Status = STATUS_INVALID_PARAMETER;
99 }
100 else
101 {
102 ApiMessage->Status = (ApiDefinitions[DefIndex].Handler)(ApiMessage, Reply);
103 }
104 return;
105 }
106 }
107 DPRINT1("CSR: Unknown request ApiNumber 0x%x\n", ApiMessage->ApiNumber);
108 ApiMessage->Status = STATUS_INVALID_SYSTEM_SERVICE;
109 }
110
111 VOID
112 CallHardError(IN PCSR_THREAD ThreadData,
113 IN PHARDERROR_MSG HardErrorMessage);
114
115 static
116 VOID
117 NTAPI
118 CsrHandleHardError(IN PCSR_THREAD ThreadData,
119 IN OUT PHARDERROR_MSG Message)
120 {
121 DPRINT1("CSR: received hard error %lx\n", Message->Status);
122
123 /* Call the hard error handler in win32csr */
124 CallHardError(ThreadData, Message);
125 }
126
127 /*++
128 * @name CsrCallServerFromServer
129 * @implemented NT4
130 *
131 * The CsrCallServerFromServer routine calls a CSR API from within a server.
132 * It avoids using LPC messages since the request isn't coming from a client.
133 *
134 * @param ReceiveMsg
135 * Pointer to the CSR API Message to send to the server.
136 *
137 * @param ReplyMsg
138 * Pointer to the CSR API Message to receive from the server.
139 *
140 * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION
141 * if the ApiNumber is invalid, or STATUS_ACCESS_VIOLATION if there
142 * was a problem executing the API.
143 *
144 * @remarks None.
145 *
146 *--*/
147 NTSTATUS
148 NTAPI
149 CsrCallServerFromServer(PCSR_API_MESSAGE ReceiveMsg,
150 PCSR_API_MESSAGE ReplyMsg)
151 {
152 #if 1 // Real code
153 ULONG ServerId;
154 PCSR_SERVER_DLL ServerDll;
155 ULONG ApiId;
156 ULONG Reply;
157 NTSTATUS Status;
158
159 /* Get the Server ID */
160 ServerId = CSR_SERVER_ID_FROM_OPCODE(ReceiveMsg->ApiNumber);
161
162 /* Make sure that the ID is within limits, and the Server DLL loaded */
163 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
164 (!(ServerDll = CsrLoadedServerDll[ServerId])))
165 {
166 /* We are beyond the Maximum Server ID */
167 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId, ServerDll);
168 ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
169 return STATUS_ILLEGAL_FUNCTION;
170 }
171 else
172 {
173 /* Get the API ID */
174 ApiId = CSR_API_NUMBER_TO_API_ID(ReceiveMsg->ApiNumber);
175
176 /* Normalize it with our Base ID */
177 ApiId -= ServerDll->ApiBase;
178
179 /* Make sure that the ID is within limits, and the entry exists */
180 if ((ApiId >= ServerDll->HighestApiSupported) ||
181 ((ServerDll->ValidTable) && !(ServerDll->ValidTable[ApiId])))
182 {
183 /* We are beyond the Maximum API ID, or it doesn't exist */
184 DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
185 "invalid API to call from the server.\n",
186 ServerDll->ValidTable[ApiId],
187 ((ServerDll->NameTable) && (ServerDll->NameTable[ApiId])) ?
188 ServerDll->NameTable[ApiId] : "*** UNKNOWN ***", &ServerDll->Name);
189 DbgBreakPoint();
190 ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
191 return STATUS_ILLEGAL_FUNCTION;
192 }
193 }
194
195 if (CsrDebug & 2)
196 {
197 DPRINT1("CSRSS: %s Api Request received from server process\n",
198 ServerDll->NameTable[ApiId]);
199 }
200
201 /* Validation complete, start SEH */
202 _SEH2_TRY
203 {
204 /* Call the API and get the result */
205 /// CsrApiCallHandler(ReplyMsg, /*ProcessData*/ &ReplyCode); ///
206 Status = (ServerDll->DispatchTable[ApiId])(ReceiveMsg, &Reply);
207
208 /* Return the result, no matter what it is */
209 ReplyMsg->Status = Status;
210 }
211 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
212 {
213 /* If we got an exception, return access violation */
214 ReplyMsg->Status = STATUS_ACCESS_VIOLATION;
215 }
216 _SEH2_END;
217
218 /* Return success */
219 return STATUS_SUCCESS;
220
221 #else // Hacky reactos code
222
223 PCSR_PROCESS ProcessData;
224 ULONG ReplyCode;
225
226 /* Get the Process Data */
227 CsrLockProcessByClientId(&ReceiveMsg->Header.ClientId.UniqueProcess, &ProcessData);
228 if (!ProcessData)
229 {
230 DPRINT1("Message: Unable to find data for process 0x%x\n",
231 ReceiveMsg->Header.ClientId.UniqueProcess);
232 return STATUS_NOT_SUPPORTED;
233 }
234
235 /* Validation complete, start SEH */
236 _SEH2_TRY
237 {
238 /* Call the API and get the result */
239 CsrApiCallHandler(ReplyMsg, /*ProcessData*/ &ReplyCode);
240 }
241 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
242 {
243 /* If we got an exception, return access violation */
244 ReplyMsg->Status = STATUS_ACCESS_VIOLATION;
245 }
246 _SEH2_END;
247
248 /* Release the process reference */
249 CsrUnlockProcess(ProcessData);
250
251 /* Return success */
252 return STATUS_SUCCESS;
253 #endif
254 }
255
256 /*++
257 * @name CsrApiPortInitialize
258 *
259 * The CsrApiPortInitialize routine initializes the LPC Port used for
260 * communications with the Client/Server Runtime (CSR) and initializes the
261 * static thread that will handle connection requests and APIs.
262 *
263 * @param None
264 *
265 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
266 * otherwise.
267 *
268 * @remarks None.
269 *
270 *--*/
271 NTSTATUS
272 NTAPI
273 CsrApiPortInitialize(VOID)
274 {
275 ULONG Size;
276 OBJECT_ATTRIBUTES ObjectAttributes;
277 NTSTATUS Status;
278 HANDLE hRequestEvent, hThread;
279 CLIENT_ID ClientId;
280 PLIST_ENTRY ListHead, NextEntry;
281 PCSR_THREAD ServerThread;
282
283 /* Calculate how much space we'll need for the Port Name */
284 Size = CsrDirectoryName.Length + sizeof(CSR_PORT_NAME) + sizeof(WCHAR);
285
286 /* Create the buffer for it */
287 CsrApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
288 if (!CsrApiPortName.Buffer) return STATUS_NO_MEMORY;
289
290 /* Setup the rest of the empty string */
291 CsrApiPortName.Length = 0;
292 CsrApiPortName.MaximumLength = (USHORT)Size;
293 RtlAppendUnicodeStringToString(&CsrApiPortName, &CsrDirectoryName);
294 RtlAppendUnicodeToString(&CsrApiPortName, UNICODE_PATH_SEP);
295 RtlAppendUnicodeToString(&CsrApiPortName, CSR_PORT_NAME);
296 if (CsrDebug & 1)
297 {
298 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName);
299 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
300 sizeof(CSR_CONNECTION_INFO), sizeof(CSR_API_MESSAGE));
301 }
302
303 /* FIXME: Create a Security Descriptor */
304
305 /* Initialize the Attributes */
306 InitializeObjectAttributes(&ObjectAttributes,
307 &CsrApiPortName,
308 0,
309 NULL,
310 NULL /* FIXME*/);
311
312 /* Create the Port Object */
313 Status = NtCreatePort(&CsrApiPort,
314 &ObjectAttributes,
315 LPC_MAX_DATA_LENGTH, // hack ; sizeof(CSR_CONNECTION_INFO),
316 LPC_MAX_MESSAGE_LENGTH, // hack ; sizeof(CSR_API_MESSAGE),
317 16 * PAGE_SIZE);
318 if (NT_SUCCESS(Status))
319 {
320 /* Create the event the Port Thread will use */
321 Status = NtCreateEvent(&hRequestEvent,
322 EVENT_ALL_ACCESS,
323 NULL,
324 SynchronizationEvent,
325 FALSE);
326 if (NT_SUCCESS(Status))
327 {
328 /* Create the Request Thread */
329 Status = RtlCreateUserThread(NtCurrentProcess(),
330 NULL,
331 TRUE,
332 0,
333 0,
334 0,
335 (PVOID)ClientConnectionThread,//CsrApiRequestThread,
336 (PVOID)hRequestEvent,
337 &hThread,
338 &ClientId);
339 if (NT_SUCCESS(Status))
340 {
341 /* Add this as a static thread to CSRSRV */
342 CsrAddStaticServerThread(hThread, &ClientId, CsrThreadIsServerThread);
343
344 /* Get the Thread List Pointers */
345 ListHead = &CsrRootProcess->ThreadList;
346 NextEntry = ListHead->Flink;
347
348 /* Start looping the list */
349 while (NextEntry != ListHead)
350 {
351 /* Get the Thread */
352 ServerThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
353
354 /* Start it up */
355 Status = NtResumeThread(ServerThread->ThreadHandle, NULL);
356
357 /* Is this a Server Thread? */
358 if (ServerThread->Flags & CsrThreadIsServerThread)
359 {
360 /* If so, then wait for it to initialize */
361 Status = NtWaitForSingleObject(hRequestEvent, FALSE, NULL);
362 ASSERT(NT_SUCCESS(Status));
363 }
364
365 /* Next thread */
366 NextEntry = NextEntry->Flink;
367 }
368
369 /* We don't need this anymore */
370 NtClose(hRequestEvent);
371 }
372 }
373 }
374
375 /* Return */
376 return Status;
377 }
378
379 PBASE_STATIC_SERVER_DATA BaseStaticServerData;
380
381 NTSTATUS
382 NTAPI
383 CreateBaseAcls(OUT PACL* Dacl,
384 OUT PACL* RestrictedDacl)
385 {
386 PSID SystemSid, WorldSid, RestrictedSid;
387 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
388 SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
389 NTSTATUS Status;
390 UCHAR KeyValueBuffer[0x40];
391 PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
392 UNICODE_STRING KeyName;
393 ULONG ProtectionMode = 0;
394 ULONG AclLength, ResultLength;
395 HANDLE hKey;
396 OBJECT_ATTRIBUTES ObjectAttributes;
397
398 /* Open the Session Manager Key */
399 RtlInitUnicodeString(&KeyName, SM_REG_KEY);
400 InitializeObjectAttributes(&ObjectAttributes,
401 &KeyName,
402 OBJ_CASE_INSENSITIVE,
403 NULL,
404 NULL);
405 Status = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
406 if (NT_SUCCESS(Status))
407 {
408 /* Read the key value */
409 RtlInitUnicodeString(&KeyName, L"ProtectionMode");
410 Status = NtQueryValueKey(hKey,
411 &KeyName,
412 KeyValuePartialInformation,
413 KeyValueBuffer,
414 sizeof(KeyValueBuffer),
415 &ResultLength);
416
417 /* Make sure it's what we expect it to be */
418 KeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
419 if ((NT_SUCCESS(Status)) && (KeyValuePartialInfo->Type == REG_DWORD) &&
420 (*(PULONG)KeyValuePartialInfo->Data))
421 {
422 /* Save the Protection Mode */
423 ProtectionMode = *(PULONG)KeyValuePartialInfo->Data;
424 }
425
426 /* Close the handle */
427 NtClose(hKey);
428 }
429
430 /* Allocate the System SID */
431 Status = RtlAllocateAndInitializeSid(&NtAuthority,
432 1, SECURITY_LOCAL_SYSTEM_RID,
433 0, 0, 0, 0, 0, 0, 0,
434 &SystemSid);
435 ASSERT(NT_SUCCESS(Status));
436
437 /* Allocate the World SID */
438 Status = RtlAllocateAndInitializeSid(&WorldAuthority,
439 1, SECURITY_WORLD_RID,
440 0, 0, 0, 0, 0, 0, 0,
441 &WorldSid);
442 ASSERT(NT_SUCCESS(Status));
443
444 /* Allocate the restricted SID */
445 Status = RtlAllocateAndInitializeSid(&NtAuthority,
446 1, SECURITY_RESTRICTED_CODE_RID,
447 0, 0, 0, 0, 0, 0, 0,
448 &RestrictedSid);
449 ASSERT(NT_SUCCESS(Status));
450
451 /* Allocate one ACL with 3 ACEs each for one SID */
452 AclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) +
453 RtlLengthSid(SystemSid) +
454 RtlLengthSid(RestrictedSid) +
455 RtlLengthSid(WorldSid);
456 *Dacl = RtlAllocateHeap(CsrHeap, 0, AclLength);
457 ASSERT(*Dacl != NULL);
458
459 /* Set the correct header fields */
460 Status = RtlCreateAcl(*Dacl, AclLength, ACL_REVISION2);
461 ASSERT(NT_SUCCESS(Status));
462
463 /* Give the appropriate rights to each SID */
464 /* FIXME: Should check SessionId/ProtectionMode */
465 Status = RtlAddAccessAllowedAce(*Dacl, ACL_REVISION2, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY | READ_CONTROL, WorldSid);
466 ASSERT(NT_SUCCESS(Status));
467 Status = RtlAddAccessAllowedAce(*Dacl, ACL_REVISION2, DIRECTORY_ALL_ACCESS, SystemSid);
468 ASSERT(NT_SUCCESS(Status));
469 Status = RtlAddAccessAllowedAce(*Dacl, ACL_REVISION2, DIRECTORY_TRAVERSE, RestrictedSid);
470 ASSERT(NT_SUCCESS(Status));
471
472 /* Now allocate the restricted DACL */
473 *RestrictedDacl = RtlAllocateHeap(CsrHeap, 0, AclLength);
474 ASSERT(*RestrictedDacl != NULL);
475
476 /* Initialize it */
477 Status = RtlCreateAcl(*RestrictedDacl, AclLength, ACL_REVISION2);
478 ASSERT(NT_SUCCESS(Status));
479
480 /* And add the same ACEs as before */
481 /* FIXME: Not really fully correct */
482 Status = RtlAddAccessAllowedAce(*RestrictedDacl, ACL_REVISION2, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY | READ_CONTROL, WorldSid);
483 ASSERT(NT_SUCCESS(Status));
484 Status = RtlAddAccessAllowedAce(*RestrictedDacl, ACL_REVISION2, DIRECTORY_ALL_ACCESS, SystemSid);
485 ASSERT(NT_SUCCESS(Status));
486 Status = RtlAddAccessAllowedAce(*RestrictedDacl, ACL_REVISION2, DIRECTORY_TRAVERSE, RestrictedSid);
487 ASSERT(NT_SUCCESS(Status));
488
489 /* The SIDs are captured, can free them now */
490 RtlFreeHeap(CsrHeap, 0, SystemSid);
491 RtlFreeHeap(CsrHeap, 0, WorldSid);
492 RtlFreeHeap(CsrHeap, 0, RestrictedSid);
493 return Status;
494 }
495
496 NTSTATUS WINAPI
497 CsrpHandleConnectionRequest(PPORT_MESSAGE Request)
498 {
499 NTSTATUS Status;
500 HANDLE ServerPort = NULL;//, ServerThread = NULL;
501 PCSR_PROCESS ProcessData = NULL;
502 REMOTE_PORT_VIEW RemotePortView;
503 // CLIENT_ID ClientId;
504 BOOLEAN AllowConnection = FALSE;
505 PCSR_CONNECTION_INFO ConnectInfo;
506 ServerPort = NULL;
507
508 DPRINT("CSR: %s: Handling: %p\n", __FUNCTION__, Request);
509
510 ConnectInfo = (PCSR_CONNECTION_INFO)(Request + 1);
511
512 /* Save the process ID */
513 RtlZeroMemory(ConnectInfo, sizeof(CSR_CONNECTION_INFO));
514
515 CsrLockProcessByClientId(Request->ClientId.UniqueProcess, &ProcessData);
516 if (!ProcessData)
517 {
518 DPRINT1("CSRSRV: Unknown process: %lx. Will be rejecting connection\n",
519 Request->ClientId.UniqueProcess);
520 }
521
522 if ((ProcessData) && (ProcessData != CsrRootProcess))
523 {
524 /* Attach the Shared Section */
525 Status = CsrSrvAttachSharedSection(ProcessData, ConnectInfo);
526 if (NT_SUCCESS(Status))
527 {
528 DPRINT("Connection ok\n");
529 AllowConnection = TRUE;
530 }
531 else
532 {
533 DPRINT1("Shared section map failed: %lx\n", Status);
534 }
535 }
536 else if (ProcessData == CsrRootProcess)
537 {
538 AllowConnection = TRUE;
539 }
540
541 /* Release the process */
542 if (ProcessData) CsrUnlockProcess(ProcessData);
543
544 /* Setup the Port View Structure */
545 RemotePortView.Length = sizeof(REMOTE_PORT_VIEW);
546 RemotePortView.ViewSize = 0;
547 RemotePortView.ViewBase = NULL;
548
549 /* Save the Process ID */
550 ConnectInfo->ProcessId = NtCurrentTeb()->ClientId.UniqueProcess;
551
552 Status = NtAcceptConnectPort(&ServerPort,
553 AllowConnection ? UlongToPtr(ProcessData->SequenceNumber) : 0,
554 Request,
555 AllowConnection,
556 NULL,
557 &RemotePortView);
558 if (!NT_SUCCESS(Status))
559 {
560 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status);
561 }
562 else if (AllowConnection)
563 {
564 if (CsrDebug & 2)
565 {
566 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
567 Request->ClientId.UniqueProcess,
568 Request->ClientId.UniqueThread,
569 RemotePortView.ViewBase,
570 RemotePortView.ViewSize);
571 }
572
573 /* Set some Port Data in the Process */
574 ProcessData->ClientPort = ServerPort;
575 ProcessData->ClientViewBase = (ULONG_PTR)RemotePortView.ViewBase;
576 ProcessData->ClientViewBounds = (ULONG_PTR)((ULONG_PTR)RemotePortView.ViewBase +
577 (ULONG_PTR)RemotePortView.ViewSize);
578
579 /* Complete the connection */
580 Status = NtCompleteConnectPort(ServerPort);
581 if (!NT_SUCCESS(Status))
582 {
583 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status);
584 }
585 }
586 else
587 {
588 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
589 Request->ClientId.UniqueProcess,
590 Request->ClientId.UniqueThread);
591 }
592
593 return Status;
594 }
595
596 /*++
597 * @name CsrConnectToUser
598 * @implemented NT4
599 *
600 * The CsrConnectToUser connects to the User subsystem.
601 *
602 * @param None
603 *
604 * @return A pointer to the CSR Thread
605 *
606 * @remarks None.
607 *
608 *--*/
609 PCSR_THREAD
610 NTAPI
611 CsrConnectToUser(VOID)
612 {
613 PTEB Teb = NtCurrentTeb();
614 PCSR_THREAD CsrThread;
615 #if 0
616 NTSTATUS Status;
617 ANSI_STRING DllName;
618 UNICODE_STRING TempName;
619 HANDLE hUser32;
620 STRING StartupName;
621
622 /* Check if we didn't already find it */
623 if (!CsrClientThreadSetup)
624 {
625 /* Get the DLL Handle for user32.dll */
626 RtlInitAnsiString(&DllName, "user32");
627 RtlAnsiStringToUnicodeString(&TempName, &DllName, TRUE);
628 Status = LdrGetDllHandle(NULL,
629 NULL,
630 &TempName,
631 &hUser32);
632 RtlFreeUnicodeString(&TempName);
633
634 /* If we got teh handle, get the Client Thread Startup Entrypoint */
635 if (NT_SUCCESS(Status))
636 {
637 RtlInitAnsiString(&StartupName,"ClientThreadSetup");
638 Status = LdrGetProcedureAddress(hUser32,
639 &StartupName,
640 0,
641 (PVOID)&CsrClientThreadSetup);
642 }
643 }
644
645 /* Connect to user32 */
646 CsrClientThreadSetup();
647 #endif
648 /* Save pointer to this thread in TEB */
649 CsrThread = CsrLocateThreadInProcess(NULL, &Teb->ClientId);
650 if (CsrThread) Teb->CsrClientThread = CsrThread;
651
652 /* Return it */
653 return CsrThread;
654 }
655
656 /*++
657 * @name CsrpCheckRequestThreads
658 *
659 * The CsrpCheckRequestThreads routine checks if there are no more threads
660 * to handle CSR API Requests, and creates a new thread if possible, to
661 * avoid starvation.
662 *
663 * @param None.
664 *
665 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
666 * if a new thread couldn't be created.
667 *
668 * @remarks None.
669 *
670 *--*/
671 NTSTATUS
672 NTAPI
673 CsrpCheckRequestThreads(VOID)
674 {
675 HANDLE hThread;
676 CLIENT_ID ClientId;
677 NTSTATUS Status;
678
679 /* Decrease the count, and see if we're out */
680 if (!(_InterlockedDecrement(&CsrpStaticThreadCount)))
681 {
682 /* Check if we've still got space for a Dynamic Thread */
683 if (CsrpDynamicThreadTotal < CsrMaxApiRequestThreads)
684 {
685 /* Create a new dynamic thread */
686 Status = RtlCreateUserThread(NtCurrentProcess(),
687 NULL,
688 TRUE,
689 0,
690 0,
691 0,
692 (PVOID)ClientConnectionThread,//CsrApiRequestThread,
693 NULL,
694 &hThread,
695 &ClientId);
696 /* Check success */
697 if (NT_SUCCESS(Status))
698 {
699 /* Increase the thread counts */
700 _InterlockedIncrement(&CsrpStaticThreadCount);
701 _InterlockedIncrement(&CsrpDynamicThreadTotal);
702
703 /* Add a new server thread */
704 if (CsrAddStaticServerThread(hThread,
705 &ClientId,
706 CsrThreadIsServerThread))
707 {
708 /* Activate it */
709 NtResumeThread(hThread, NULL);
710 }
711 else
712 {
713 /* Failed to create a new static thread */
714 _InterlockedDecrement(&CsrpStaticThreadCount);
715 _InterlockedDecrement(&CsrpDynamicThreadTotal);
716
717 /* Terminate it */
718 DPRINT1("Failing\n");
719 NtTerminateThread(hThread, 0);
720 NtClose(hThread);
721
722 /* Return */
723 return STATUS_UNSUCCESSFUL;
724 }
725 }
726 }
727 }
728
729 /* Success */
730 return STATUS_SUCCESS;
731 }
732
733 VOID
734 WINAPI
735 ClientConnectionThread(IN PVOID Parameter)
736 {
737 PTEB Teb = NtCurrentTeb();
738 LARGE_INTEGER TimeOut;
739 NTSTATUS Status;
740 BYTE RawRequest[LPC_MAX_DATA_LENGTH];
741 PCSR_API_MESSAGE Request = (PCSR_API_MESSAGE)RawRequest;
742 PCSR_API_MESSAGE Reply;
743 PCSR_PROCESS CsrProcess;
744 PCSR_THREAD ServerThread, CsrThread;
745 ULONG MessageType;
746 HANDLE ReplyPort;
747 PDBGKM_MSG DebugMessage;
748 PHARDERROR_MSG HardErrorMsg;
749 PCLIENT_DIED_MSG ClientDiedMsg;
750 DPRINT("CSR: %s called\n", __FUNCTION__);
751
752 /* Setup LPC loop port and message */
753 Reply = NULL;
754 ReplyPort = CsrApiPort;
755
756 /* Connect to user32 */
757 while (!CsrConnectToUser())
758 {
759 /* Set up the timeout for the connect (30 seconds) */
760 TimeOut.QuadPart = -30 * 1000 * 1000 * 10;
761
762 /* Keep trying until we get a response */
763 Teb->Win32ClientInfo[0] = 0;
764 NtDelayExecution(FALSE, &TimeOut);
765 }
766
767 /* Get our thread */
768 ServerThread = Teb->CsrClientThread;
769
770 /* If we got an event... */
771 if (Parameter)
772 {
773 /* Set it, to let stuff waiting on us load */
774 Status = NtSetEvent((HANDLE)Parameter, NULL);
775 ASSERT(NT_SUCCESS(Status));
776
777 /* Increase the Thread Counts */
778 _InterlockedIncrement(&CsrpStaticThreadCount);
779 _InterlockedIncrement(&CsrpDynamicThreadTotal);
780 }
781
782 /* Now start the loop */
783 while (TRUE)
784 {
785 /* Make sure the real CID is set */
786 Teb->RealClientId = Teb->ClientId;
787
788 /* Debug check */
789 if (Teb->CountOfOwnedCriticalSections)
790 {
791 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
792 Teb->CountOfOwnedCriticalSections);
793 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
794 Request, Reply);
795 DbgBreakPoint();
796 }
797
798 /* Send the reply and wait for a new request */
799 DPRINT("Replying to: %lx (%lx)\n", ReplyPort, CsrApiPort);
800 Status = NtReplyWaitReceivePort(ReplyPort,
801 0,
802 &Reply->Header,
803 &Request->Header);
804 /* Check if we didn't get success */
805 if (Status != STATUS_SUCCESS)
806 {
807 /* Was it a failure or another success code? */
808 if (!NT_SUCCESS(Status))
809 {
810 /* Check for specific status cases */
811 if ((Status != STATUS_INVALID_CID) &&
812 (Status != STATUS_UNSUCCESSFUL) &&
813 ((Status == STATUS_INVALID_HANDLE) || (ReplyPort == CsrApiPort)))
814 {
815 /* Notify the debugger */
816 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status);
817 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort, CsrApiPort);
818 }
819
820 /* We failed big time, so start out fresh */
821 Reply = NULL;
822 ReplyPort = CsrApiPort;
823 DPRINT1("failed: %lx\n", Status);
824 continue;
825 }
826 else
827 {
828 /* A bizare "success" code, just try again */
829 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status);
830 continue;
831 }
832 }
833
834 /* Use whatever Client ID we got */
835 Teb->RealClientId = Request->Header.ClientId;
836
837 /* Get the Message Type */
838 MessageType = Request->Header.u2.s2.Type;
839
840 /* Handle connection requests */
841 if (MessageType == LPC_CONNECTION_REQUEST)
842 {
843 /* Handle the Connection Request */
844 DPRINT("Accepting new connection\n");
845 CsrpHandleConnectionRequest((PPORT_MESSAGE)Request);
846 Reply = NULL;
847 ReplyPort = CsrApiPort;
848 continue;
849 }
850
851 /* It's some other kind of request. Get the lock for the lookup */
852 CsrAcquireProcessLock();
853
854 /* Now do the lookup to get the CSR_THREAD */
855 CsrThread = CsrLocateThreadByClientId(&CsrProcess,
856 &Request->Header.ClientId);
857
858 /* Did we find a thread? */
859 if (!CsrThread)
860 {
861 /* This wasn't a CSR Thread, release lock */
862 CsrReleaseProcessLock();
863
864 /* If this was an exception, handle it */
865 if (MessageType == LPC_EXCEPTION)
866 {
867 DPRINT1("Exception from unknown thread, just continue\n");
868 Reply = Request;
869 ReplyPort = CsrApiPort;
870 Reply->Status = DBG_CONTINUE;
871 }
872 else if (MessageType == LPC_PORT_CLOSED ||
873 MessageType == LPC_CLIENT_DIED)
874 {
875 /* The Client or Port are gone, loop again */
876 DPRINT("Death from unknown thread, just continue\n");
877 Reply = NULL;
878 ReplyPort = CsrApiPort;
879 }
880 else if (MessageType == LPC_ERROR_EVENT)
881 {
882 /* If it's a hard error, handle this too */
883 DPRINT1("Hard error from unknown thread, call handlers\n");
884 HandleHardError:
885 HardErrorMsg = (PHARDERROR_MSG)Request;
886
887 /* Default it to unhandled */
888 HardErrorMsg->Response = ResponseNotHandled;
889
890 /* Check if there are free api threads */
891 CsrpCheckRequestThreads();
892 if (CsrpStaticThreadCount)
893 {
894 CsrHandleHardError(CsrThread, (PHARDERROR_MSG)Request);
895 }
896
897 /* If the response was 0xFFFFFFFF, we'll ignore it */
898 if (HardErrorMsg->Response == 0xFFFFFFFF)
899 {
900 Reply = NULL;
901 ReplyPort = CsrApiPort;
902 }
903 else
904 {
905 if (CsrThread) CsrDereferenceThread(CsrThread);
906 Reply = Request;
907 ReplyPort = CsrApiPort;
908 }
909 }
910 else if (MessageType == LPC_REQUEST)
911 {
912 /* This is an API Message coming from a non-CSR Thread */
913 DPRINT1("No thread found for request %lx and clientID %lx.%lx\n",
914 Request->ApiNumber & 0xFFFF,
915 Request->Header.ClientId.UniqueProcess,
916 Request->Header.ClientId.UniqueThread);
917 Reply = Request;
918 ReplyPort = CsrApiPort;
919 Reply->Status = STATUS_ILLEGAL_FUNCTION;
920 }
921 else if (MessageType == LPC_DATAGRAM)
922 {
923 DPRINT1("Kernel datagram: not yet supported\n");
924 Reply = NULL;
925 ReplyPort = CsrApiPort;
926 }
927 else
928 {
929 /* Some other ignored message type */
930 Reply = NULL;
931 ReplyPort = CsrApiPort;
932 }
933
934 /* Keep going */
935 continue;
936 }
937
938 /* We have a valid thread, was this an LPC Request? */
939 if (MessageType != LPC_REQUEST)
940 {
941 /* It's not an API, check if the client died */
942 if (MessageType == LPC_CLIENT_DIED)
943 {
944 /* Get the information and check if it matches our thread */
945 ClientDiedMsg = (PCLIENT_DIED_MSG)Request;
946 if (ClientDiedMsg->CreateTime.QuadPart == CsrThread->CreateTime.QuadPart)
947 {
948 /* Reference the thread */
949 CsrLockedReferenceThread(CsrThread);
950
951 /* Destroy the thread in the API Message */
952 CsrDestroyThread(&Request->Header.ClientId);
953
954 /* Check if the thread was actually ourselves */
955 if (CsrProcess->ThreadCount == 1)
956 {
957 /* Kill the process manually here */
958 DPRINT1("Last thread\n");
959 CsrDestroyProcess(&CsrThread->ClientId, 0);
960 }
961
962 /* Remove our extra reference */
963 CsrLockedDereferenceThread(CsrThread);
964 }
965
966 /* Release the lock and keep looping */
967 CsrReleaseProcessLock();
968 Reply = NULL;
969 ReplyPort = CsrApiPort;
970 continue;
971 }
972
973 /* Reference the thread and release the lock */
974 CsrLockedReferenceThread(CsrThread);
975 CsrReleaseProcessLock();
976
977 /* If this was an exception, handle it */
978 if (MessageType == LPC_EXCEPTION)
979 {
980 /* Kill the process */
981 DPRINT1("Exception in %lx.%lx. Killing...\n",
982 Request->Header.ClientId.UniqueProcess,
983 Request->Header.ClientId.UniqueThread);
984 NtTerminateProcess(CsrProcess->ProcessHandle, STATUS_ABANDONED);
985
986 /* Destroy it from CSR */
987 CsrDestroyProcess(&Request->Header.ClientId, STATUS_ABANDONED);
988
989 /* Return a Debug Message */
990 DebugMessage = (PDBGKM_MSG)Request;
991 DebugMessage->ReturnedStatus = DBG_CONTINUE;
992 Reply = Request;
993 ReplyPort = CsrApiPort;
994
995 /* Remove our extra reference */
996 CsrDereferenceThread(CsrThread);
997 }
998 else if (MessageType == LPC_ERROR_EVENT)
999 {
1000 DPRINT1("Hard error from known CSR thread... handling\n");
1001 goto HandleHardError;
1002 }
1003 else
1004 {
1005 /* Something else */
1006 DPRINT1("Unhandled message type: %lx\n", MessageType);
1007 CsrDereferenceThread(CsrThread);
1008 Reply = NULL;
1009 }
1010
1011 /* Keep looping */
1012 continue;
1013 }
1014
1015 /* We got an API Request */
1016 CsrLockedReferenceThread(CsrThread);
1017 CsrReleaseProcessLock();
1018
1019 /* Assume success */
1020 Reply = Request;
1021 Request->Status = STATUS_SUCCESS;
1022
1023 /* Now we reply to a particular client */
1024 ReplyPort = CsrThread->Process->ClientPort;
1025
1026 DPRINT("CSR: Got CSR API: %x [Message Origin: %x]\n",
1027 Request->ApiNumber,
1028 Request->Header.ClientId.UniqueThread);
1029
1030 /* Validation complete, start SEH */
1031 _SEH2_TRY
1032 {
1033 ULONG ReplyCode;
1034
1035 /* Make sure we have enough threads */
1036 CsrpCheckRequestThreads();
1037
1038 /* Set the client thread pointer */
1039 NtCurrentTeb()->CsrClientThread = CsrThread;
1040
1041 /* Call the Handler */
1042 CsrApiCallHandler(Request, &ReplyCode);
1043
1044 /* Increase the static thread count */
1045 _InterlockedIncrement(&CsrpStaticThreadCount);
1046
1047 /* Restore the server thread */
1048 NtCurrentTeb()->CsrClientThread = ServerThread;
1049
1050 /* Check if this is a dead client now */
1051 if (Request->ApiNumber == 0xBABE)
1052 {
1053 /* Reply to the death message */
1054 NtReplyPort(ReplyPort, &Reply->Header);
1055
1056 /* Reply back to the API port now */
1057 ReplyPort = CsrApiPort;
1058 Reply = NULL;
1059
1060 /* Drop the reference */
1061 CsrDereferenceThread(CsrThread);
1062 }
1063 else
1064 {
1065 /* Drop the reference */
1066 CsrDereferenceThread(CsrThread);
1067 }
1068 }
1069 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
1070 {
1071 Reply = NULL;
1072 ReplyPort = CsrApiPort;
1073 }
1074 _SEH2_END;
1075 }
1076
1077 /* Close the port and exit the thread */
1078 // NtClose(ServerPort);
1079
1080 DPRINT1("CSR: %s done\n", __FUNCTION__);
1081 /* We're out of the loop for some reason, terminate! */
1082 NtTerminateThread(NtCurrentThread(), Status);
1083 //return Status;
1084 }
1085
1086 /*++
1087 * @name CsrReleaseCapturedArguments
1088 * @implemented NT5.1
1089 *
1090 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1091 * that was previously captured with CsrCaptureArguments.
1092 *
1093 * @param ApiMessage
1094 * Pointer to the CSR API Message containing the Capture Buffer
1095 * that needs to be released.
1096 *
1097 * @return None.
1098 *
1099 * @remarks None.
1100 *
1101 *--*/
1102 VOID
1103 NTAPI
1104 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage)
1105 {
1106 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer, LocalCaptureBuffer;
1107 SIZE_T BufferDistance;
1108 ULONG PointerCount;
1109 ULONG_PTR **PointerOffsets, *CurrentPointer;
1110
1111 /* Get the capture buffers */
1112 RemoteCaptureBuffer = ApiMessage->CsrCaptureData;
1113 LocalCaptureBuffer = RemoteCaptureBuffer->PreviousCaptureBuffer;
1114
1115 /* Free the previous one */
1116 RemoteCaptureBuffer->PreviousCaptureBuffer = NULL;
1117
1118 /* Find out the difference between the two buffers */
1119 BufferDistance = (ULONG_PTR)LocalCaptureBuffer - (ULONG_PTR)RemoteCaptureBuffer;
1120
1121 /* Save the pointer count and offset pointer */
1122 PointerCount = RemoteCaptureBuffer->PointerCount;
1123 PointerOffsets = (ULONG_PTR**)(RemoteCaptureBuffer + 1);
1124
1125 /* Start the loop */
1126 while (PointerCount)
1127 {
1128 /* Get the current pointer */
1129 CurrentPointer = *PointerOffsets++;
1130 if (CurrentPointer)
1131 {
1132 /* Add it to the CSR Message structure */
1133 CurrentPointer += (ULONG_PTR)ApiMessage;
1134
1135 /* Modify the pointer to take into account its new position */
1136 *CurrentPointer += BufferDistance;
1137 }
1138
1139 /* Move to the next Pointer */
1140 PointerCount--;
1141 }
1142
1143 /* Copy the data back */
1144 RtlMoveMemory(LocalCaptureBuffer, RemoteCaptureBuffer, RemoteCaptureBuffer->Size);
1145
1146 /* Free our allocated buffer */
1147 RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
1148 }
1149
1150 /* EOF */