VOID NTAPI BaseInitializeStaticServerData(IN PCSR_SERVER_DLL LoadedServerDll) { NTSTATUS Status; BOOLEAN Success; WCHAR Buffer[MAX_PATH]; PWCHAR HeapBuffer; UNICODE_STRING SystemRootString; UNICODE_STRING UnexpandedSystemRootString = RTL_CONSTANT_STRING(L"%SystemRoot%"); UNICODE_STRING BaseSrvCSDString; UNICODE_STRING BaseSrvWindowsDirectory; UNICODE_STRING BaseSrvWindowsSystemDirectory; UNICODE_STRING BnoString; OBJECT_ATTRIBUTES ObjectAttributes; ULONG SessionId; HANDLE BaseSrvNamedObjectDirectory; HANDLE BaseSrvRestrictedObjectDirectory; PACL BnoDacl, BnoRestrictedDacl; PSECURITY_DESCRIPTOR BnoSd; HANDLE SymHandle; UNICODE_STRING DirectoryName, SymlinkName; ULONG LuidEnabled; RTL_QUERY_REGISTRY_TABLE BaseServerRegistryConfigurationTable[2] = { { NULL, RTL_QUERY_REGISTRY_DIRECT, L"CSDVersion", &BaseSrvCSDString, REG_NONE, NULL, 0 }, {0} }; /* Initialize the memory */ BaseSrvHeap = RtlGetProcessHeap(); // Initialize our own heap. BaseSrvSharedHeap = LoadedServerDll->SharedSection; // Get the CSR shared heap. /* Get the session ID */ SessionId = NtCurrentPeb()->SessionId; /* Get the Windows directory */ RtlInitEmptyUnicodeString(&SystemRootString, Buffer, sizeof(Buffer)); Status = RtlExpandEnvironmentStrings_U(NULL, &UnexpandedSystemRootString, &SystemRootString, NULL); ASSERT(NT_SUCCESS(Status)); /* Create the base directory */ Buffer[SystemRootString.Length / sizeof(WCHAR)] = UNICODE_NULL; Success = RtlCreateUnicodeString(&BaseSrvWindowsDirectory, SystemRootString.Buffer); ASSERT(Success); /* Create the system directory */ wcscat(SystemRootString.Buffer, L"\\System32"); Success = RtlCreateUnicodeString(&BaseSrvWindowsSystemDirectory, SystemRootString.Buffer); ASSERT(Success); /* Create the kernel32 path */ wcscat(SystemRootString.Buffer, L"\\kernel32.dll"); Success = RtlCreateUnicodeString(&BaseSrvKernel32DllPath, SystemRootString.Buffer); ASSERT(Success); /* FIXME: Check Session ID */ wcscpy(Buffer, L"\\BaseNamedObjects"); RtlInitUnicodeString(&BnoString, Buffer); /* Allocate the server data */ BaseStaticServerData = RtlAllocateHeap(BaseSrvSharedHeap, HEAP_ZERO_MEMORY, sizeof(BASE_STATIC_SERVER_DATA)); ASSERT(BaseStaticServerData != NULL); /* Process timezone information */ BaseStaticServerData->TermsrvClientTimeZoneId = TIME_ZONE_ID_INVALID; BaseStaticServerData->TermsrvClientTimeZoneChangeNum = 0; Status = NtQuerySystemInformation(SystemTimeOfDayInformation, &BaseStaticServerData->TimeOfDay, sizeof(BaseStaticServerData->TimeOfDay), NULL); ASSERT(NT_SUCCESS(Status)); /* Make a shared heap copy of the Windows directory */ BaseStaticServerData->WindowsDirectory = BaseSrvWindowsDirectory; HeapBuffer = RtlAllocateHeap(BaseSrvSharedHeap, 0, BaseSrvWindowsDirectory.MaximumLength); ASSERT(HeapBuffer); RtlCopyMemory(HeapBuffer, BaseStaticServerData->WindowsDirectory.Buffer, BaseSrvWindowsDirectory.MaximumLength); BaseStaticServerData->WindowsDirectory.Buffer = HeapBuffer; /* Make a shared heap copy of the System directory */ BaseStaticServerData->WindowsSystemDirectory = BaseSrvWindowsSystemDirectory; HeapBuffer = RtlAllocateHeap(BaseSrvSharedHeap, 0, BaseSrvWindowsSystemDirectory.MaximumLength); ASSERT(HeapBuffer); RtlCopyMemory(HeapBuffer, BaseStaticServerData->WindowsSystemDirectory.Buffer, BaseSrvWindowsSystemDirectory.MaximumLength); BaseStaticServerData->WindowsSystemDirectory.Buffer = HeapBuffer; /* This string is not used */ RtlInitEmptyUnicodeString(&BaseStaticServerData->WindowsSys32x86Directory, NULL, 0); /* Make a shared heap copy of the BNO directory */ BaseStaticServerData->NamedObjectDirectory = BnoString; BaseStaticServerData->NamedObjectDirectory.MaximumLength = BnoString.Length + sizeof(UNICODE_NULL); HeapBuffer = RtlAllocateHeap(BaseSrvSharedHeap, 0, BaseStaticServerData->NamedObjectDirectory.MaximumLength); ASSERT(HeapBuffer); RtlCopyMemory(HeapBuffer, BaseStaticServerData->NamedObjectDirectory.Buffer, BaseStaticServerData->NamedObjectDirectory.MaximumLength); BaseStaticServerData->NamedObjectDirectory.Buffer = HeapBuffer; /* * Confirmed that in Windows, CSDNumber and RCNumber are actually Length * and MaximumLength of the CSD String, since the same UNICODE_STRING is * being queried twice, the first time as a ULONG! * * Somehow, in Windows this doesn't cause a buffer overflow, but it might * in ReactOS, so this code is disabled until someone figures out WTF. */ BaseStaticServerData->CSDNumber = 0; BaseStaticServerData->RCNumber = 0; /* Initialize the CSD string and query its value from the registry */ RtlInitEmptyUnicodeString(&BaseSrvCSDString, Buffer, sizeof(Buffer)); Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, L"", BaseServerRegistryConfigurationTable, NULL, NULL); if (NT_SUCCESS(Status)) { /* Copy into the shared buffer */ wcsncpy(BaseStaticServerData->CSDVersion, BaseSrvCSDString.Buffer, BaseSrvCSDString.Length / sizeof(WCHAR)); } else { /* NULL-terminate to indicate nothing is there */ BaseStaticServerData->CSDVersion[0] = UNICODE_NULL; } /* Cache the system information */ Status = NtQuerySystemInformation(SystemBasicInformation, &BaseStaticServerData->SysInfo, sizeof(BaseStaticServerData->SysInfo), NULL); ASSERT(NT_SUCCESS(Status)); /* Setup the ini file mappings */ Status = BaseSrvInitializeIniFileMappings(BaseStaticServerData); ASSERT(NT_SUCCESS(Status)); /* FIXME: Should query the registry for these */ BaseStaticServerData->DefaultSeparateVDM = FALSE; BaseStaticServerData->IsWowTaskReady = FALSE; /* Allocate a security descriptor and create it */ BnoSd = RtlAllocateHeap(BaseSrvHeap, 0, 1024); ASSERT(BnoSd); Status = RtlCreateSecurityDescriptor(BnoSd, SECURITY_DESCRIPTOR_REVISION); ASSERT(NT_SUCCESS(Status)); /* Create the BNO and \Restricted DACLs */ Status = CreateBaseAcls(&BnoDacl, &BnoRestrictedDacl); ASSERT(NT_SUCCESS(Status)); /* Set the BNO DACL as active for now */ Status = RtlSetDaclSecurityDescriptor(BnoSd, TRUE, BnoDacl, FALSE); ASSERT(NT_SUCCESS(Status)); /* Create the BNO directory */ RtlInitUnicodeString(&BnoString, L"\\BaseNamedObjects"); InitializeObjectAttributes(&ObjectAttributes, &BnoString, OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, NULL, BnoSd); Status = NtCreateDirectoryObject(&BaseSrvNamedObjectDirectory, DIRECTORY_ALL_ACCESS, &ObjectAttributes); ASSERT(NT_SUCCESS(Status)); /* Check if we are session 0 */ if (SessionId == 0) { /* Mark this as a session 0 directory */ Status = NtSetInformationObject(BaseSrvNamedObjectDirectory, ObjectSessionInformation, NULL, 0); ASSERT(NT_SUCCESS(Status)); } /* Check if LUID device maps are enabled */ Status = NtQueryInformationProcess(NtCurrentProcess(), ProcessLUIDDeviceMapsEnabled, &LuidEnabled, sizeof(LuidEnabled), NULL); ASSERT(NT_SUCCESS(Status)); BaseStaticServerData->LUIDDeviceMapsEnabled = (BOOLEAN)LuidEnabled; if (!BaseStaticServerData->LUIDDeviceMapsEnabled) { /* Make Global point back to BNO */ RtlInitUnicodeString(&DirectoryName, L"Global"); RtlInitUnicodeString(&SymlinkName, L"\\BaseNamedObjects"); InitializeObjectAttributes(&ObjectAttributes, &DirectoryName, OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, BaseSrvNamedObjectDirectory, BnoSd); Status = NtCreateSymbolicLinkObject(&SymHandle, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes, &SymlinkName); if ((NT_SUCCESS(Status)) && SessionId == 0) NtClose(SymHandle); /* Make local point back to \Sessions\x\BNO */ RtlInitUnicodeString(&DirectoryName, L"Local"); ASSERT(SessionId == 0); InitializeObjectAttributes(&ObjectAttributes, &DirectoryName, OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, BaseSrvNamedObjectDirectory, BnoSd); Status = NtCreateSymbolicLinkObject(&SymHandle, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes, &SymlinkName); if ((NT_SUCCESS(Status)) && SessionId == 0) NtClose(SymHandle); /* Make Session point back to BNOLINKS */ RtlInitUnicodeString(&DirectoryName, L"Session"); RtlInitUnicodeString(&SymlinkName, L"\\Sessions\\BNOLINKS"); InitializeObjectAttributes(&ObjectAttributes, &DirectoryName, OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, BaseSrvNamedObjectDirectory, BnoSd); Status = NtCreateSymbolicLinkObject(&SymHandle, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes, &SymlinkName); if ((NT_SUCCESS(Status)) && SessionId == 0) NtClose(SymHandle); /* Create the BNO\Restricted directory and set the restricted DACL */ RtlInitUnicodeString(&DirectoryName, L"Restricted"); Status = RtlSetDaclSecurityDescriptor(BnoSd, TRUE, BnoRestrictedDacl, FALSE); ASSERT(NT_SUCCESS(Status)); InitializeObjectAttributes(&ObjectAttributes, &DirectoryName, OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, BaseSrvNamedObjectDirectory, BnoSd); Status = NtCreateDirectoryObject(&BaseSrvRestrictedObjectDirectory, DIRECTORY_ALL_ACCESS, &ObjectAttributes); ASSERT(NT_SUCCESS(Status)); } /* Initialize NLS */ BaseSrvNLSInit(BaseStaticServerData); /* Finally, set the pointer */ LoadedServerDll->SharedSection = BaseStaticServerData; }
NTSTATUS NTAPI INIT_FUNCTION IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock, OUT PANSI_STRING NtBootPath) { OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status; CHAR Buffer[256], AnsiBuffer[256]; WCHAR ArcNameBuffer[64]; ANSI_STRING TargetString, ArcString, TempString; UNICODE_STRING LinkName, TargetName, ArcName; HANDLE LinkHandle; /* Create the Unicode name for the current ARC boot device */ sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName); RtlInitAnsiString(&TargetString, Buffer); Status = RtlAnsiStringToUnicodeString(&TargetName, &TargetString, TRUE); if (!NT_SUCCESS(Status)) return FALSE; /* Initialize the attributes and open the link */ InitializeObjectAttributes(&ObjectAttributes, &TargetName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) { /* We failed, free the string */ RtlFreeUnicodeString(&TargetName); return FALSE; } /* Query the current \\SystemRoot */ ArcName.Buffer = ArcNameBuffer; ArcName.Length = 0; ArcName.MaximumLength = sizeof(ArcNameBuffer); Status = NtQuerySymbolicLinkObject(LinkHandle, &ArcName, NULL); if (!NT_SUCCESS(Status)) { /* We failed, free the string */ RtlFreeUnicodeString(&TargetName); return FALSE; } /* Convert it to Ansi */ ArcString.Buffer = AnsiBuffer; ArcString.Length = 0; ArcString.MaximumLength = sizeof(AnsiBuffer); Status = RtlUnicodeStringToAnsiString(&ArcString, &ArcName, FALSE); AnsiBuffer[ArcString.Length] = ANSI_NULL; /* Close the link handle and free the name */ ObCloseHandle(LinkHandle, KernelMode); RtlFreeUnicodeString(&TargetName); /* Setup the system root name again */ RtlInitAnsiString(&TempString, "\\SystemRoot"); Status = RtlAnsiStringToUnicodeString(&LinkName, &TempString, TRUE); if (!NT_SUCCESS(Status)) return FALSE; /* Open the symbolic link for it */ InitializeObjectAttributes(&ObjectAttributes, &LinkName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) return FALSE; /* Destroy it */ NtMakeTemporaryObject(LinkHandle); ObCloseHandle(LinkHandle, KernelMode); /* Now create the new name for it */ sprintf(Buffer, "%s%s", ArcString.Buffer, LoaderBlock->NtBootPathName); /* Copy it into the passed parameter and null-terminate it */ RtlCopyString(NtBootPath, &ArcString); Buffer[strlen(Buffer) - 1] = ANSI_NULL; /* Setup the Unicode-name for the new symbolic link value */ RtlInitAnsiString(&TargetString, Buffer); InitializeObjectAttributes(&ObjectAttributes, &LinkName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL); Status = RtlAnsiStringToUnicodeString(&ArcName, &TargetString, TRUE); if (!NT_SUCCESS(Status)) return FALSE; /* Create it */ Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &ObjectAttributes, &ArcName); /* Free all the strings and close the handle and return success */ RtlFreeUnicodeString(&ArcName); RtlFreeUnicodeString(&LinkName); ObCloseHandle(LinkHandle, KernelMode); return TRUE; }
HANDLE SymlinkCreateTests(OUT PHANDLE OddLink) { NTSTATUS Status; HANDLE LinkHandle; UNICODE_STRING TargetName = RTL_CONSTANT_STRING(L"\\"); UNICODE_STRING TargetName2 = RTL_CONSTANT_STRING(L"\\"); UNICODE_STRING TargetName3 = RTL_CONSTANT_STRING(L"\\"); UNICODE_STRING TargetName4 = RTL_CONSTANT_STRING(L"\\"); UNICODE_STRING TargetName5 = RTL_CONSTANT_STRING(L"\\"); UNICODE_STRING OkName = RTL_CONSTANT_STRING(L"\\OddLink"); UNICODE_STRING OkName2 = RTL_CONSTANT_STRING(L"\\TestLink"); // // Test1: Empty Attributes // { OBJECT_ATTRIBUTES Test1 = RTL_INIT_OBJECT_ATTRIBUTES(NULL, 0); Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &Test1, &TargetName); TEST_ASSERT(NT_SUCCESS(Status)); } // // Test2: No Attributes // { POBJECT_ATTRIBUTES Test2 = NULL; Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, Test2, &TargetName); TEST_ASSERT(NT_SUCCESS(Status)); } // // Test3: Attributes with an empty name // { UNICODE_STRING TestName1 = {0, 0, NULL}; OBJECT_ATTRIBUTES Test3 = RTL_INIT_OBJECT_ATTRIBUTES(&TestName1, 0); Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &Test3, &TargetName); TEST_ASSERT(NT_SUCCESS(Status)); } // // Test4: Attributes with an invalid name // { UNICODE_STRING TestName2 = {10, 12, UlongToPtr(0x81000000)}; OBJECT_ATTRIBUTES Test4 = RTL_INIT_OBJECT_ATTRIBUTES(&TestName2, 0); Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &Test4, &TargetName); TEST_ASSERT(Status == STATUS_ACCESS_VIOLATION); } // // Test5: Target with an odd name len // { UNICODE_STRING OddName = RTL_CONSTANT_STRING(L"\\TestLink"); OBJECT_ATTRIBUTES Test5 = RTL_INIT_OBJECT_ATTRIBUTES(&OkName, 0); TargetName3.Length--; Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &Test5, &TargetName3); TEST_ASSERT(Status == STATUS_INVALID_PARAMETER); } // // Test6: Target with an emtpy name len // { OBJECT_ATTRIBUTES Test5 = RTL_INIT_OBJECT_ATTRIBUTES(&OkName, 0); TargetName4.MaximumLength = 0; Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &Test5, &TargetName4); TEST_ASSERT(Status == STATUS_INVALID_PARAMETER); } // // Test7: Target with an name len larger then maxlen // { OBJECT_ATTRIBUTES Test6 = RTL_INIT_OBJECT_ATTRIBUTES(&OkName, 0); TargetName5.Length = TargetName5.MaximumLength + 2; Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &Test6, &TargetName5); TEST_ASSERT(Status == STATUS_INVALID_PARAMETER); } // // Test5: Target with an odd name maxlen // { OBJECT_ATTRIBUTES Test5 = RTL_INIT_OBJECT_ATTRIBUTES(&OkName, 0); TargetName2.MaximumLength--; TEST_ASSERT(TargetName2.MaximumLength % sizeof(WCHAR)); Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &Test5, &TargetName2); *OddLink = LinkHandle; TEST_ASSERT(NT_SUCCESS(Status)); TEST_ASSERT(TargetName2.MaximumLength % sizeof(WCHAR)); } // // Test6: collission // { OBJECT_ATTRIBUTES Test6 = RTL_INIT_OBJECT_ATTRIBUTES(&OkName, 0); TargetName2.MaximumLength++; Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &Test6, &TargetName2); TEST_ASSERT(Status == STATUS_OBJECT_NAME_COLLISION); } // // Test7: OK! // { OBJECT_ATTRIBUTES Test7 = RTL_INIT_OBJECT_ATTRIBUTES(&OkName2, 0); Status = NtCreateSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_ALL_ACCESS, &Test7, &TargetName2); TEST_ASSERT(NT_SUCCESS(Status)); } // // Return the last valid handle // return LinkHandle; };