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