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