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