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