6be1bbd3aad66cb7a876a945bcb0edf220b55069
[reactos.git] / subsystems / win32 / csrsrv / init.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSR SubSystem
4 * FILE: subsystems/win32/csrss/csrsrv/init.c
5 * PURPOSE: CSR Server DLL Initialization
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * ReactOS Portable Systems Group
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "srv.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* DATA ***********************************************************************/
18
19 HANDLE CsrHeap = (HANDLE) 0;
20 HANDLE CsrObjectDirectory = (HANDLE) 0;
21 UNICODE_STRING CsrDirectoryName;
22 UNICODE_STRING CsrSbApiPortName;
23 HANDLE CsrSbApiPort = 0;
24 PCSR_THREAD CsrSbApiRequestThreadPtr;
25 HANDLE CsrSmApiPort;
26 HANDLE hSbApiPort = (HANDLE) 0;
27 HANDLE CsrApiPort = (HANDLE) 0;
28 ULONG CsrDebug = 0;//0xFFFFFFFF;
29 ULONG CsrMaxApiRequestThreads;
30 ULONG CsrTotalPerProcessDataLength;
31 ULONG SessionId;
32 HANDLE BNOLinksDirectory;
33 HANDLE SessionObjectDirectory;
34 HANDLE DosDevicesDirectory;
35 HANDLE CsrInitializationEvent;
36 SYSTEM_BASIC_INFORMATION CsrNtSysInfo;
37
38 /* PRIVATE FUNCTIONS **********************************************************/
39
40 VOID
41 CallHardError(IN PCSR_THREAD ThreadData,
42 IN PHARDERROR_MSG HardErrorMessage)
43 {
44 ULONG i;
45 PCSR_SERVER_DLL ServerDll;
46
47 DPRINT("CSR: %s called\n", __FUNCTION__);
48
49 /* Notify the Server DLLs */
50 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
51 {
52 /* Get the current Server DLL */
53 ServerDll = CsrLoadedServerDll[i];
54
55 /* Make sure it's valid and that it has callback */
56 if ((ServerDll) && (ServerDll->HardErrorCallback))
57 {
58 ServerDll->HardErrorCallback(ThreadData, HardErrorMessage);
59 }
60 }
61 }
62
63 #if 0
64 NTSTATUS
65 CallProcessCreated(IN PCSR_PROCESS SourceProcessData,
66 IN PCSR_PROCESS TargetProcessData)
67 {
68 NTSTATUS Status = STATUS_SUCCESS;
69 ULONG i;
70 PCSR_SERVER_DLL ServerDll;
71
72 DPRINT("CSR: %s called\n", __FUNCTION__);
73
74 /* Notify the Server DLLs */
75 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
76 {
77 /* Get the current Server DLL */
78 ServerDll = CsrLoadedServerDll[i];
79
80 /* Make sure it's valid and that it has callback */
81 if ((ServerDll) && (ServerDll->NewProcessCallback))
82 {
83 Status = ServerDll->NewProcessCallback(SourceProcessData, TargetProcessData);
84 }
85 }
86
87 return Status;
88 }
89 #endif
90
91 CSRSS_API_DEFINITION NativeDefinitions[] =
92 {
93 CSRSS_DEFINE_API(REGISTER_SERVICES_PROCESS, SrvRegisterServicesProcess), // winsrv.dll
94 };
95
96 /* === INIT ROUTINES === */
97
98 /*++
99 * @name CsrSetProcessSecurity
100 *
101 * The CsrSetProcessSecurity routine protects access to the CSRSS process
102 * from unauthorized tampering.
103 *
104 * @param None.
105 *
106 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
107 * otherwise.
108 *
109 * @remarks None.
110 *
111 *--*/
112 NTSTATUS
113 NTAPI
114 CsrSetProcessSecurity(VOID)
115 {
116 NTSTATUS Status;
117 HANDLE hToken, hProcess = NtCurrentProcess();
118 ULONG Length;
119 PTOKEN_USER TokenInfo = NULL;
120 PSECURITY_DESCRIPTOR ProcSd = NULL;
121 PACL Dacl;
122 PSID UserSid;
123
124 /* Open our token */
125 Status = NtOpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
126 if (!NT_SUCCESS(Status)) goto Quickie;
127
128 /* Get the Token User Length */
129 NtQueryInformationToken(hToken, TokenUser, NULL, 0, &Length);
130
131 /* Allocate space for it */
132 TokenInfo = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Length);
133 if (!TokenInfo)
134 {
135 Status = STATUS_NO_MEMORY;
136 goto Quickie;
137 }
138
139 /* Now query the data */
140 Status = NtQueryInformationToken(hToken, TokenUser, TokenInfo, Length, &Length);
141 NtClose(hToken);
142 if (!NT_SUCCESS(Status)) goto Quickie;
143
144 /* Now check the SID Length */
145 UserSid = TokenInfo->User.Sid;
146 Length = RtlLengthSid(UserSid) + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
147
148 /* Allocate a buffer for the Security Descriptor, with SID and DACL */
149 ProcSd = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, SECURITY_DESCRIPTOR_MIN_LENGTH + Length);
150 if (!ProcSd)
151 {
152 Status = STATUS_NO_MEMORY;
153 goto Quickie;
154 }
155
156 /* Set the pointer to the DACL */
157 Dacl = (PACL)((ULONG_PTR)ProcSd + SECURITY_DESCRIPTOR_MIN_LENGTH);
158
159 /* Now create the SD itself */
160 Status = RtlCreateSecurityDescriptor(ProcSd, SECURITY_DESCRIPTOR_REVISION);
161 if (!NT_SUCCESS(Status))
162 {
163 DPRINT1("CSRSS: SD creation failed - status = %lx\n", Status);
164 goto Quickie;
165 }
166
167 /* Create the DACL for it*/
168 Status = RtlCreateAcl(Dacl, Length, ACL_REVISION2);
169 if (!NT_SUCCESS(Status))
170 {
171 DPRINT1("CSRSS: DACL creation failed - status = %lx\n", Status);
172 goto Quickie;
173 }
174
175 /* Create the ACE */
176 Status = RtlAddAccessAllowedAce(Dacl,
177 ACL_REVISION,
178 PROCESS_VM_READ | PROCESS_VM_WRITE |
179 PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE |
180 PROCESS_TERMINATE | PROCESS_SUSPEND_RESUME |
181 PROCESS_QUERY_INFORMATION | READ_CONTROL,
182 UserSid);
183 if (!NT_SUCCESS(Status))
184 {
185 DPRINT1("CSRSS: ACE creation failed - status = %lx\n", Status);
186 goto Quickie;
187 }
188
189 /* Clear the DACL in the SD */
190 Status = RtlSetDaclSecurityDescriptor(ProcSd, TRUE, Dacl, FALSE);
191 if (!NT_SUCCESS(Status))
192 {
193 DPRINT1("CSRSS: set DACL failed - status = %lx\n", Status);
194 goto Quickie;
195 }
196
197 /* Write the SD into the Process */
198 Status = NtSetSecurityObject(hProcess, DACL_SECURITY_INFORMATION, ProcSd);
199 if (!NT_SUCCESS(Status))
200 {
201 DPRINT1("CSRSS: set process DACL failed - status = %lx\n", Status);
202 goto Quickie;
203 }
204
205 /* Free the memory and return */
206 Quickie:
207 if (ProcSd) RtlFreeHeap(CsrHeap, 0, ProcSd);
208 RtlFreeHeap(CsrHeap, 0, TokenInfo);
209 return Status;
210 }
211
212 /*++
213 * @name CsrSetDirectorySecurity
214 *
215 * The CsrSetDirectorySecurity routine sets the security descriptor for the
216 * specified Object Directory.
217 *
218 * @param ObjectDirectory
219 * Handle fo the Object Directory to protect.
220 *
221 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
222 * otherwise.
223 *
224 * @remarks None.
225 *
226 *--*/
227 NTSTATUS
228 NTAPI
229 CsrSetDirectorySecurity(IN HANDLE ObjectDirectory)
230 {
231 /* FIXME: Implement */
232 return STATUS_SUCCESS;
233 }
234
235 /*++
236 * @name GetDosDevicesProtection
237 *
238 * The GetDosDevicesProtection creates a security descriptor for the DOS Devices
239 * Object Directory.
240 *
241 * @param DosDevicesSd
242 * Pointer to the Security Descriptor to return.
243 *
244 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
245 * otherwise.
246 *
247 * @remarks Depending on the DOS Devices Protection Mode (set in the registry),
248 * regular users may or may not have full access to the directory.
249 *
250 *--*/
251 NTSTATUS
252 NTAPI
253 GetDosDevicesProtection(OUT PSECURITY_DESCRIPTOR DosDevicesSd)
254 {
255 SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
256 SID_IDENTIFIER_AUTHORITY CreatorAuthority = {SECURITY_CREATOR_SID_AUTHORITY};
257 SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
258 PSID WorldSid, CreatorSid, AdminSid, SystemSid;
259 UCHAR KeyValueBuffer[0x40];
260 PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
261 UNICODE_STRING KeyName;
262 ULONG ProtectionMode = 0;
263 OBJECT_ATTRIBUTES ObjectAttributes;
264 PACL Dacl;
265 PACCESS_ALLOWED_ACE Ace;
266 HANDLE hKey;
267 NTSTATUS Status;
268 ULONG ResultLength, SidLength, AclLength;
269
270 /* Create the SD */
271 Status = RtlCreateSecurityDescriptor(DosDevicesSd, SECURITY_DESCRIPTOR_REVISION);
272 ASSERT(NT_SUCCESS(Status));
273
274 /* Initialize the System SID */
275 Status = RtlAllocateAndInitializeSid(&NtSidAuthority, 1,
276 SECURITY_LOCAL_SYSTEM_RID,
277 0, 0, 0, 0, 0, 0, 0,
278 &SystemSid);
279 ASSERT(NT_SUCCESS(Status));
280
281 /* Initialize the World SID */
282 Status = RtlAllocateAndInitializeSid(&WorldAuthority, 1,
283 SECURITY_WORLD_RID,
284 0, 0, 0, 0, 0, 0, 0,
285 &WorldSid);
286 ASSERT(NT_SUCCESS(Status));
287
288 /* Initialize the Admin SID */
289 Status = RtlAllocateAndInitializeSid(&NtSidAuthority, 2,
290 SECURITY_BUILTIN_DOMAIN_RID,
291 DOMAIN_ALIAS_RID_ADMINS,
292 0, 0, 0, 0, 0, 0,
293 &AdminSid);
294 ASSERT(NT_SUCCESS(Status));
295
296 /* Initialize the Creator SID */
297 Status = RtlAllocateAndInitializeSid(&CreatorAuthority, 1,
298 SECURITY_CREATOR_OWNER_RID,
299 0, 0, 0, 0, 0, 0, 0,
300 &CreatorSid);
301 ASSERT(NT_SUCCESS(Status));
302
303 /* Open the Session Manager Key */
304 RtlInitUnicodeString(&KeyName, SM_REG_KEY);
305 InitializeObjectAttributes(&ObjectAttributes,
306 &KeyName,
307 OBJ_CASE_INSENSITIVE,
308 NULL,
309 NULL);
310 Status = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
311 if (NT_SUCCESS(Status))
312 {
313 /* Read the key value */
314 RtlInitUnicodeString(&KeyName, L"ProtectionMode");
315 Status = NtQueryValueKey(hKey,
316 &KeyName,
317 KeyValuePartialInformation,
318 KeyValueBuffer,
319 sizeof(KeyValueBuffer),
320 &ResultLength);
321
322 /* Make sure it's what we expect it to be */
323 KeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
324 if ((NT_SUCCESS(Status)) && (KeyValuePartialInfo->Type == REG_DWORD) &&
325 (*(PULONG)KeyValuePartialInfo->Data))
326 {
327 /* Save the Protection Mode */
328 ProtectionMode = *(PULONG)KeyValuePartialInfo->Data;
329 }
330
331 /* Close the handle */
332 NtClose(hKey);
333 }
334
335 /* Check the Protection Mode */
336 if (ProtectionMode & 3)
337 {
338 /* Calculate SID Lengths */
339 SidLength = RtlLengthSid(CreatorSid) + RtlLengthSid(SystemSid) +
340 RtlLengthSid(AdminSid);
341 AclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + SidLength;
342
343 /* Allocate memory for the DACL */
344 Dacl = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, AclLength);
345 ASSERT(Dacl != NULL);
346
347 /* Build the ACL and add 3 ACEs */
348 Status = RtlCreateAcl(Dacl, AclLength, ACL_REVISION2);
349 ASSERT(NT_SUCCESS(Status));
350 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, SystemSid);
351 ASSERT(NT_SUCCESS(Status));
352 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, AdminSid);
353 ASSERT(NT_SUCCESS(Status));
354 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, CreatorSid);
355 ASSERT(NT_SUCCESS(Status));
356
357 /* Edit the ACEs to make them inheritable */
358 Status = RtlGetAce(Dacl, 0, (PVOID*)&Ace);
359 ASSERT(NT_SUCCESS(Status));
360 Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
361 Status = RtlGetAce(Dacl, 1, (PVOID*)&Ace);
362 ASSERT(NT_SUCCESS(Status));
363 Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
364 Status = RtlGetAce(Dacl, 2, (PVOID*)&Ace);
365 ASSERT(NT_SUCCESS(Status));
366 Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
367
368 /* Set this DACL with the SD */
369 Status = RtlSetDaclSecurityDescriptor(DosDevicesSd, TRUE, Dacl, FALSE);
370 ASSERT(NT_SUCCESS(Status));
371 goto Quickie;
372 }
373 else
374 {
375 /* Calculate SID Lengths */
376 SidLength = RtlLengthSid(WorldSid) + RtlLengthSid(SystemSid);
377 AclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + SidLength;
378
379 /* Allocate memory for the DACL */
380 Dacl = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, AclLength);
381 ASSERT(Dacl != NULL);
382
383 /* Build the ACL and add 3 ACEs */
384 Status = RtlCreateAcl(Dacl, AclLength, ACL_REVISION2);
385 ASSERT(NT_SUCCESS(Status));
386 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE, WorldSid);
387 ASSERT(NT_SUCCESS(Status));
388 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, SystemSid);
389 ASSERT(NT_SUCCESS(Status));
390 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, WorldSid);
391 ASSERT(NT_SUCCESS(Status));
392
393 /* Edit the last ACE to make it inheritable */
394 Status = RtlGetAce(Dacl, 2, (PVOID*)&Ace);
395 ASSERT(NT_SUCCESS(Status));
396 Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE;
397
398 /* Set this DACL with the SD */
399 Status = RtlSetDaclSecurityDescriptor(DosDevicesSd, TRUE, Dacl, FALSE);
400 ASSERT(NT_SUCCESS(Status));
401 goto Quickie;
402 }
403
404 /* FIXME: failure cases! Fail: */
405 /* Free the memory */
406 RtlFreeHeap(CsrHeap, 0, Dacl);
407
408 /* FIXME: semi-failure cases! Quickie: */
409 Quickie:
410 /* Free the SIDs */
411 RtlFreeSid(SystemSid);
412 RtlFreeSid(WorldSid);
413 RtlFreeSid(AdminSid);
414 RtlFreeSid(CreatorSid);
415
416 /* Return */
417 return Status;
418 }
419
420 /*++
421 * @name FreeDosDevicesProtection
422 *
423 * The FreeDosDevicesProtection frees the security descriptor that was created
424 * by GetDosDevicesProtection
425 *
426 * @param DosDevicesSd
427 * Pointer to the security descriptor to free.
428
429 * @return None.
430 *
431 * @remarks None.
432 *
433 *--*/
434 VOID
435 NTAPI
436 FreeDosDevicesProtection(IN PSECURITY_DESCRIPTOR DosDevicesSd)
437 {
438 PACL Dacl;
439 BOOLEAN Present, Default;
440 NTSTATUS Status;
441
442 /* Get the DACL corresponding to this SD */
443 Status = RtlGetDaclSecurityDescriptor(DosDevicesSd, &Present, &Dacl, &Default);
444 ASSERT(NT_SUCCESS(Status));
445 ASSERT(Present);
446 ASSERT(Dacl != NULL);
447
448 /* Free it */
449 if ((NT_SUCCESS(Status)) && (Dacl)) RtlFreeHeap(CsrHeap, 0, Dacl);
450 }
451
452 /*++
453 * @name CsrCreateSessionObjectDirectory
454 *
455 * The CsrCreateSessionObjectDirectory routine creates the BaseNamedObjects,
456 * Session and Dos Devices directories for the specified session.
457 *
458 * @param Session
459 * Session ID for which to create the directories.
460 *
461 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
462 * otherwise.
463 *
464 * @remarks None.
465 *
466 *--*/
467 NTSTATUS
468 NTAPI
469 CsrCreateSessionObjectDirectory(IN ULONG Session)
470 {
471 WCHAR SessionBuffer[512], BnoBuffer[512];
472 UNICODE_STRING SessionString, BnoString;
473 OBJECT_ATTRIBUTES ObjectAttributes;
474 HANDLE BnoHandle;
475 SECURITY_DESCRIPTOR DosDevicesSd;
476 NTSTATUS Status;
477
478 /* Generate the Session BNOLINKS Directory name */
479 swprintf(SessionBuffer, L"%ws\\BNOLINKS", SESSION_ROOT);
480 RtlInitUnicodeString(&SessionString, SessionBuffer);
481
482 /* Create it */
483 InitializeObjectAttributes(&ObjectAttributes,
484 &SessionString,
485 OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
486 NULL,
487 NULL);
488 Status = NtCreateDirectoryObject(&BNOLinksDirectory,
489 DIRECTORY_ALL_ACCESS,
490 &ObjectAttributes);
491 if (!NT_SUCCESS(Status))
492 {
493 DPRINT1("CSRSS: NtCreateDirectoryObject failed in "
494 "CsrCreateSessionObjectDirectory - status = %lx\n", Status);
495 return Status;
496 }
497
498 /* Now add the Session ID */
499 swprintf(SessionBuffer, L"%ld", Session);
500 RtlInitUnicodeString(&SessionString, SessionBuffer);
501
502 /* Check if this is the first Session */
503 if (Session)
504 {
505 /* Not the first, so the name will be slighly more complex */
506 swprintf(BnoBuffer, L"%ws\\%ld\\BaseNamedObjects", SESSION_ROOT, Session);
507 RtlInitUnicodeString(&BnoString, BnoBuffer);
508 }
509 else
510 {
511 /* Use the direct name */
512 RtlInitUnicodeString(&BnoString, L"\\BaseNamedObjects");
513 }
514
515 /* Create the symlink */
516 InitializeObjectAttributes(&ObjectAttributes,
517 &SessionString,
518 OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
519 BNOLinksDirectory,
520 NULL);
521 Status = NtCreateSymbolicLinkObject(&BnoHandle,
522 SYMBOLIC_LINK_ALL_ACCESS,
523 &ObjectAttributes,
524 &BnoString);
525 if (!NT_SUCCESS(Status))
526 {
527 DPRINT1("CSRSS: NtCreateSymbolicLinkObject failed in "
528 "CsrCreateSessionObjectDirectory - status = %lx\n", Status);
529 return Status;
530 }
531
532 /* Create the \DosDevices Security Descriptor */
533 Status = GetDosDevicesProtection(&DosDevicesSd);
534 if (!NT_SUCCESS(Status)) return Status;
535
536 /* Now create a directory for this session */
537 swprintf(SessionBuffer, L"%ws\\%ld", SESSION_ROOT, Session);
538 RtlInitUnicodeString(&SessionString, SessionBuffer);
539
540 /* Create the directory */
541 InitializeObjectAttributes(&ObjectAttributes,
542 &SessionString,
543 OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
544 0,
545 &DosDevicesSd);
546 Status = NtCreateDirectoryObject(&SessionObjectDirectory,
547 DIRECTORY_ALL_ACCESS,
548 &ObjectAttributes);
549 if (!NT_SUCCESS(Status))
550 {
551 DPRINT1("CSRSS: NtCreateDirectoryObject failed in "
552 "CsrCreateSessionObjectDirectory - status = %lx\n", Status);
553 FreeDosDevicesProtection(&DosDevicesSd);
554 return Status;
555 }
556
557 /* Next, create a directory for this session's DOS Devices */
558 RtlInitUnicodeString(&SessionString, L"DosDevices");
559 InitializeObjectAttributes(&ObjectAttributes,
560 &SessionString,
561 OBJ_CASE_INSENSITIVE,
562 SessionObjectDirectory,
563 &DosDevicesSd);
564 Status = NtCreateDirectoryObject(&DosDevicesDirectory,
565 DIRECTORY_ALL_ACCESS,
566 &ObjectAttributes);
567 if (!NT_SUCCESS(Status))
568 {
569 DPRINT1("CSRSS: NtCreateDirectoryObject failed in "
570 "CsrCreateSessionObjectDirectory - status = %lx\n", Status);
571 }
572
573 /* Release the Security Descriptor */
574 FreeDosDevicesProtection(&DosDevicesSd);
575
576 /* Return */
577 return Status;
578 }
579
580 /*++
581 * @name CsrParseServerCommandLine
582 *
583 * The CsrParseServerCommandLine routine parses the CSRSS command-line in the
584 * registry and performs operations for each entry found.
585 *
586 * @param ArgumentCount
587 * Number of arguments on the command line.
588 *
589 * @param Arguments
590 * Array of arguments.
591 *
592 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
593 * otherwise.
594 *
595 * @remarks None.
596 *
597 *--*/
598 NTSTATUS
599 FASTCALL
600 CsrParseServerCommandLine(IN ULONG ArgumentCount,
601 IN PCHAR Arguments[])
602 {
603 NTSTATUS Status;
604 PCHAR ParameterName = NULL, ParameterValue = NULL, EntryPoint, ServerString;
605 ULONG i, DllIndex;
606 ANSI_STRING AnsiString;
607 OBJECT_ATTRIBUTES ObjectAttributes;
608
609 /* Set the Defaults */
610 CsrTotalPerProcessDataLength = 0;
611 CsrObjectDirectory = NULL;
612 CsrMaxApiRequestThreads = 16;
613
614 /* Save our Session ID, and create a Directory for it */
615 SessionId = NtCurrentPeb()->SessionId;
616 Status = CsrCreateSessionObjectDirectory(SessionId);
617 if (!NT_SUCCESS(Status))
618 {
619 DPRINT1("CSRSS: CsrCreateSessionObjectDirectory failed (%lx)\n",
620 Status);
621
622 /* It's not fatal if the session ID isn't zero */
623 if (SessionId) return Status;
624 ASSERT(NT_SUCCESS(Status));
625 }
626
627 /* Loop through every argument */
628 for (i = 1; i < ArgumentCount; i++)
629 {
630 /* Split Name and Value */
631 ParameterName = Arguments[i];
632 ParameterValue = NULL;
633 ParameterValue = strchr(ParameterName, '=');
634 if (ParameterValue) *ParameterValue++ = ANSI_NULL;
635 DPRINT1("Name=%s, Value=%s\n", ParameterName, ParameterValue);
636
637 /* Check for Object Directory */
638 if (_stricmp(ParameterName, "ObjectDirectory") == 0)
639 {
640 /* Check if a session ID is specified */
641 if (SessionId)
642 {
643 DPRINT1("Sessions not yet implemented\n");
644 ASSERT(SessionId);
645 }
646
647 /* Initialize the directory name */
648 RtlInitAnsiString(&AnsiString, ParameterValue);
649 Status = RtlAnsiStringToUnicodeString(&CsrDirectoryName,
650 &AnsiString,
651 TRUE);
652 ASSERT(NT_SUCCESS(Status) || SessionId != 0);
653 if (!NT_SUCCESS(Status)) return Status;
654
655 /* Create it */
656 InitializeObjectAttributes(&ObjectAttributes,
657 &CsrDirectoryName,
658 OBJ_OPENIF | OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
659 NULL,
660 NULL);
661 Status = NtCreateDirectoryObject(&CsrObjectDirectory,
662 DIRECTORY_ALL_ACCESS,
663 &ObjectAttributes);
664 if (!NT_SUCCESS(Status)) return Status;
665
666 /* Secure it */
667 Status = CsrSetDirectorySecurity(CsrObjectDirectory);
668 if (!NT_SUCCESS(Status)) return Status;
669 }
670 else if (_stricmp(ParameterName, "SubSystemType") == 0)
671 {
672 /* Ignored */
673 }
674 else if (_stricmp(ParameterName, "MaxRequestThreads") == 0)
675 {
676 Status = RtlCharToInteger(ParameterValue,
677 0,
678 &CsrMaxApiRequestThreads);
679 }
680 else if (_stricmp(ParameterName, "RequestThreads") == 0)
681 {
682 /* Ignored */
683 Status = STATUS_SUCCESS;
684 }
685 else if (_stricmp(ParameterName, "ProfileControl") == 0)
686 {
687 /* Ignored */
688 }
689 else if (_stricmp(ParameterName, "SharedSection") == 0)
690 {
691 /* Create the Section */
692 Status = CsrSrvCreateSharedSection(ParameterValue);
693 if (!NT_SUCCESS(Status))
694 {
695 DPRINT1("CSRSS: *** Invalid syntax for %s=%s (Status == %X)\n",
696 ParameterName, ParameterValue, Status);
697 return Status;
698 }
699
700 /* Load us */
701 Status = CsrLoadServerDll("CSRSS" /* "CSRSRV" */, NULL, CSRSRV_SERVERDLL_INDEX);
702 }
703 else if (_stricmp(ParameterName, "ServerDLL") == 0)
704 {
705 /* Loop the command line */
706 EntryPoint = NULL;
707 Status = STATUS_INVALID_PARAMETER;
708 ServerString = ParameterValue;
709 while (*ServerString)
710 {
711 /* Check for the Entry Point */
712 if ((*ServerString == ':') && (!EntryPoint))
713 {
714 /* Found it. Add a nullchar and save it */
715 *ServerString++ = ANSI_NULL;
716 EntryPoint = ServerString;
717 }
718
719 /* Check for the Dll Index */
720 if (*ServerString++ == ',') break;
721 }
722
723 /* Did we find something to load? */
724 if (!*ServerString)
725 {
726 DPRINT1("CSRSS: *** Invalid syntax for ServerDll=%s (Status == %X)\n",
727 ParameterValue, Status);
728 return Status;
729 }
730
731 /* Convert it to a ULONG */
732 Status = RtlCharToInteger(ServerString, 10, &DllIndex);
733
734 /* Add a null char if it was valid */
735 if (NT_SUCCESS(Status)) ServerString[-1] = ANSI_NULL;
736
737 /* Load it */
738 if (CsrDebug & 1) DPRINT1("CSRSS: Loading ServerDll=%s:%s\n", ParameterValue, EntryPoint);
739 Status = CsrLoadServerDll(ParameterValue, EntryPoint, DllIndex);
740 if (!NT_SUCCESS(Status))
741 {
742 DPRINT1("CSRSS: *** Failed loading ServerDll=%s (Status == 0x%x)\n",
743 ParameterValue, Status);
744 return Status;
745 }
746 }
747 else if (_stricmp(ParameterName, "Windows") == 0)
748 {
749 /* Ignored */
750 // Check whether we want to start in pure GUI or pure CLI.
751 }
752 else
753 {
754 /* Invalid parameter on the command line */
755 Status = STATUS_INVALID_PARAMETER;
756 }
757 }
758
759 /* Return status */
760 return Status;
761 }
762
763 /*++
764 * @name CsrCreateLocalSystemSD
765 *
766 * The CsrCreateLocalSystemSD routine creates a Security Descriptor for
767 * the local account with PORT_ALL_ACCESS.
768 *
769 * @param LocalSystemSd
770 * Pointer to a pointer to the security descriptor to create.
771 *
772 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
773 * otherwise.
774 *
775 * @remarks None.
776 *
777 *--*/
778 NTSTATUS
779 NTAPI
780 CsrCreateLocalSystemSD(OUT PSECURITY_DESCRIPTOR *LocalSystemSd)
781 {
782 SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY};
783 PSID SystemSid;
784 ULONG Length;
785 PSECURITY_DESCRIPTOR SystemSd;
786 PACL Dacl;
787 NTSTATUS Status;
788
789 /* Initialize the System SID */
790 RtlAllocateAndInitializeSid(&NtSidAuthority, 1,
791 SECURITY_LOCAL_SYSTEM_RID,
792 0, 0, 0, 0, 0, 0, 0,
793 &SystemSid);
794
795 /* Get the length of the SID */
796 Length = RtlLengthSid(SystemSid) + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
797
798 /* Allocate a buffer for the Security Descriptor, with SID and DACL */
799 SystemSd = RtlAllocateHeap(CsrHeap, 0, SECURITY_DESCRIPTOR_MIN_LENGTH + Length);
800
801 /* Set the pointer to the DACL */
802 Dacl = (PACL)((ULONG_PTR)SystemSd + SECURITY_DESCRIPTOR_MIN_LENGTH);
803
804 /* Now create the SD itself */
805 Status = RtlCreateSecurityDescriptor(SystemSd, SECURITY_DESCRIPTOR_REVISION);
806 if (!NT_SUCCESS(Status))
807 {
808 /* Fail */
809 RtlFreeHeap(CsrHeap, 0, SystemSd);
810 return Status;
811 }
812
813 /* Create the DACL for it */
814 RtlCreateAcl(Dacl, Length, ACL_REVISION2);
815
816 /* Create the ACE */
817 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, PORT_ALL_ACCESS, SystemSid);
818 if (!NT_SUCCESS(Status))
819 {
820 /* Fail */
821 RtlFreeHeap(CsrHeap, 0, SystemSd);
822 return Status;
823 }
824
825 /* Clear the DACL in the SD */
826 Status = RtlSetDaclSecurityDescriptor(SystemSd, TRUE, Dacl, FALSE);
827 if (!NT_SUCCESS(Status))
828 {
829 /* Fail */
830 RtlFreeHeap(CsrHeap, 0, SystemSd);
831 return Status;
832 }
833
834 /* Free the SID and return*/
835 RtlFreeSid(SystemSid);
836 *LocalSystemSd = SystemSd;
837 return Status;
838 }
839
840 /*++
841 * @name CsrSbApiPortInitialize
842 *
843 * The CsrSbApiPortInitialize routine initializes the LPC Port used for
844 * communications with the Session Manager (SM) and initializes the static
845 * thread that will handle connection requests and APIs.
846 *
847 * @param None
848 *
849 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
850 * otherwise.
851 *
852 * @remarks None.
853 *
854 *--*/
855 NTSTATUS
856 NTAPI
857 CsrSbApiPortInitialize(VOID)
858 {
859 ULONG Size;
860 PSECURITY_DESCRIPTOR PortSd;
861 OBJECT_ATTRIBUTES ObjectAttributes;
862 NTSTATUS Status;
863 HANDLE hRequestThread;
864 CLIENT_ID ClientId;
865
866 /* Calculate how much space we'll need for the Port Name */
867 Size = CsrDirectoryName.Length + sizeof(SB_PORT_NAME) + sizeof(WCHAR);
868
869 /* Create the buffer for it */
870 CsrSbApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
871 if (!CsrSbApiPortName.Buffer) return STATUS_NO_MEMORY;
872
873 /* Setup the rest of the empty string */
874 CsrSbApiPortName.Length = 0;
875 CsrSbApiPortName.MaximumLength = (USHORT)Size;
876
877 /* Now append the full port name */
878 RtlAppendUnicodeStringToString(&CsrSbApiPortName, &CsrDirectoryName);
879 RtlAppendUnicodeToString(&CsrSbApiPortName, UNICODE_PATH_SEP);
880 RtlAppendUnicodeToString(&CsrSbApiPortName, SB_PORT_NAME);
881 if (CsrDebug & 2) DPRINT1("CSRSS: Creating %wZ port and associated thread\n", &CsrSbApiPortName);
882
883 /* Create Security Descriptor for this Port */
884 Status = CsrCreateLocalSystemSD(&PortSd);
885 if (!NT_SUCCESS(Status)) return Status;
886
887 /* Initialize the Attributes */
888 InitializeObjectAttributes(&ObjectAttributes,
889 &CsrSbApiPortName,
890 0,
891 NULL,
892 PortSd);
893
894 /* Create the Port Object */
895 Status = NtCreatePort(&CsrSbApiPort,
896 &ObjectAttributes,
897 sizeof(SB_CONNECTION_INFO),
898 sizeof(SB_API_MSG),
899 32 * sizeof(SB_API_MSG));
900 if (PortSd) RtlFreeHeap(CsrHeap, 0, PortSd);
901
902 if (NT_SUCCESS(Status))
903 {
904 /* Create the Thread to handle the API Requests */
905 Status = RtlCreateUserThread(NtCurrentProcess(),
906 NULL,
907 TRUE,
908 0,
909 0,
910 0,
911 (PVOID)CsrSbApiRequestThread,
912 NULL,
913 &hRequestThread,
914 &ClientId);
915 if (NT_SUCCESS(Status))
916 {
917 /* Add it as a Static Server Thread */
918 CsrSbApiRequestThreadPtr = CsrAddStaticServerThread(hRequestThread,
919 &ClientId,
920 0);
921
922 /* Activate it */
923 Status = NtResumeThread(hRequestThread, NULL);
924 }
925 }
926
927 return Status;
928 }
929
930
931
932 /* PUBLIC FUNCTIONS ***********************************************************/
933
934 /*++
935 * @name CsrServerInitialization
936 * @implemented NT4
937 *
938 * The CsrServerInitialization routine is the native (not Server) entrypoint
939 * of this Server DLL. It serves as the entrypoint for csrss.
940 *
941 * @param ArgumentCount
942 * Number of arguments on the command line.
943 *
944 * @param Arguments
945 * Array of arguments from the command line.
946 *
947 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
948 * otherwise.
949 *
950 * @remarks None.
951 *
952 *--*/
953 NTSTATUS
954 NTAPI
955 CsrServerInitialization(IN ULONG ArgumentCount,
956 IN PCHAR Arguments[])
957 {
958 NTSTATUS Status = STATUS_SUCCESS;
959 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
960
961 /* Create the Init Event */
962 Status = NtCreateEvent(&CsrInitializationEvent,
963 EVENT_ALL_ACCESS,
964 NULL,
965 SynchronizationEvent,
966 FALSE);
967 if (!NT_SUCCESS(Status))
968 {
969 DPRINT1("CSRSRV:%s: NtCreateEvent failed (Status=%08lx)\n",
970 __FUNCTION__, Status);
971 return Status;
972 }
973
974 /* Cache System Basic Information so we don't always request it */
975 Status = NtQuerySystemInformation(SystemBasicInformation,
976 &CsrNtSysInfo,
977 sizeof(SYSTEM_BASIC_INFORMATION),
978 NULL);
979 if (!NT_SUCCESS(Status))
980 {
981 DPRINT1("CSRSRV:%s: NtQuerySystemInformation failed (Status=%08lx)\n",
982 __FUNCTION__, Status);
983 return Status;
984 }
985
986 /* Save our Heap */
987 CsrHeap = RtlGetProcessHeap();
988
989 /* Set our Security Descriptor to protect the process */
990 Status = CsrSetProcessSecurity();
991 if (!NT_SUCCESS(Status))
992 {
993 DPRINT1("CSRSRV:%s: CsrSetProcessSecurity failed (Status=%08lx)\n",
994 __FUNCTION__, Status);
995 return Status;
996 }
997
998 /* Set up Session Support */
999 Status = CsrInitializeNtSessionList();
1000 if (!NT_SUCCESS(Status))
1001 {
1002 DPRINT1("CSRSRV:%s: CsrInitializeSessions failed (Status=%08lx)\n",
1003 __FUNCTION__, Status);
1004 return Status;
1005 }
1006
1007 /* Set up Process Support */
1008 Status = CsrInitializeProcessStructure();
1009 if (!NT_SUCCESS(Status))
1010 {
1011 DPRINT1("CSRSRV:%s: CsrInitializeProcessStructure failed (Status=%08lx)\n",
1012 __FUNCTION__, Status);
1013 return Status;
1014 }
1015
1016 /* Parse the command line */
1017 Status = CsrParseServerCommandLine(ArgumentCount, Arguments);
1018 if (!NT_SUCCESS(Status))
1019 {
1020 DPRINT1("CSRSRV:%s: CsrParseServerCommandLine failed (Status=%08lx)\n",
1021 __FUNCTION__, Status);
1022 return Status;
1023 }
1024
1025 #if 0
1026 Status = CsrApiRegisterDefinitions(NativeDefinitions);
1027 if (!NT_SUCCESS(Status))
1028 {
1029 DPRINT1("CSRSRV failed in %s with status %lx\n", "CsrApiRegisterDefinitions", Status);
1030 }
1031 #endif
1032
1033 /* Now initialize our API Port */
1034 Status = CsrApiPortInitialize();
1035 if (!NT_SUCCESS(Status))
1036 {
1037 DPRINT1("CSRSRV:%s: CsrApiPortInitialize failed (Status=%08lx)\n",
1038 __FUNCTION__, Status);
1039 return Status;
1040 }
1041
1042 /* Initialize the API Port for SM communication */
1043 Status = CsrSbApiPortInitialize();
1044 if (!NT_SUCCESS(Status))
1045 {
1046 DPRINT1("CSRSRV:%s: CsrSbApiPortInitialize failed (Status=%08lx)\n",
1047 __FUNCTION__, Status);
1048 return Status;
1049 }
1050
1051 /* We're all set! Connect to SM! */
1052 Status = SmConnectToSm(&CsrSbApiPortName,
1053 CsrSbApiPort,
1054 IMAGE_SUBSYSTEM_WINDOWS_GUI,
1055 &CsrSmApiPort);
1056 if (!NT_SUCCESS(Status))
1057 {
1058 DPRINT1("CSRSRV:%s: SmConnectToSm failed (Status=%08lx)\n",
1059 __FUNCTION__, Status);
1060 return Status;
1061 }
1062
1063 /* Finito! Signal the event */
1064 Status = NtSetEvent(CsrInitializationEvent, NULL);
1065 if (!NT_SUCCESS(Status))
1066 {
1067 DPRINT1("CSRSRV:%s: NtSetEvent failed (Status=%08lx)\n",
1068 __FUNCTION__, Status);
1069 return Status;
1070 }
1071
1072 /* Close the event handle now */
1073 NtClose(CsrInitializationEvent);
1074
1075 /* Have us handle Hard Errors */
1076 Status = NtSetDefaultHardErrorPort(CsrApiPort);
1077 if (!NT_SUCCESS(Status))
1078 {
1079 DPRINT1("CSRSRV:%s: NtSetDefaultHardErrorPort failed (Status=%08lx)\n",
1080 __FUNCTION__, Status);
1081 return Status;
1082 }
1083
1084 /* Return status */
1085 return Status;
1086 }
1087
1088 /*++
1089 * @name CsrPopulateDosDevices
1090 * @unimplemented NT5.1
1091 *
1092 * The CsrPopulateDosDevices routine uses the DOS Device Map from the Kernel
1093 * to populate the Dos Devices Object Directory for the session.
1094 *
1095 * @param None.
1096 *
1097 * @return None.
1098 *
1099 * @remarks None.
1100 *
1101 *--*/
1102 VOID
1103 NTAPI
1104 CsrPopulateDosDevices(VOID)
1105 {
1106 DPRINT1("Deprecated API\n");
1107 return;
1108 }
1109
1110 BOOL
1111 NTAPI
1112 DllMain(IN HANDLE hDll,
1113 IN DWORD dwReason,
1114 IN LPVOID lpReserved)
1115 {
1116 /* We don't do much */
1117 UNREFERENCED_PARAMETER(hDll);
1118 UNREFERENCED_PARAMETER(dwReason);
1119 UNREFERENCED_PARAMETER(lpReserved);
1120
1121 return TRUE;
1122 }
1123
1124 /* EOF */