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