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