xref: /reactos/subsystems/csr/csrsrv/init.c (revision bcbfcd22)
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