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