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