/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Base API Server DLL * FILE: subsystems/win/basesrv/init.c * PURPOSE: Initialization * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr) */ /* INCLUDES *******************************************************************/ #include "basesrv.h" #include "api.h" #define NDEBUG #include /* GLOBALS ********************************************************************/ HANDLE BaseSrvDllInstance = NULL; /* Memory */ HANDLE BaseSrvHeap = NULL; // Our own heap. HANDLE BaseSrvSharedHeap = NULL; // Shared heap with CSR. (CsrSrvSharedSectionHeap) PBASE_STATIC_SERVER_DATA BaseStaticServerData = NULL; // Data that we can share amongst processes. Initialized inside BaseSrvSharedHeap. // Windows Server 2003 table from http://j00ru.vexillium.org/csrss_list/api_list.html#Windows_2k3 PCSR_API_ROUTINE BaseServerApiDispatchTable[BasepMaxApiNumber - BASESRV_FIRST_API_NUMBER] = { BaseSrvCreateProcess, BaseSrvCreateThread, BaseSrvGetTempFile, BaseSrvExitProcess, // BaseSrvDebugProcess, // BaseSrvCheckVDM, // BaseSrvUpdateVDMEntry, // BaseSrvGetNextVDMCommand, // BaseSrvExitVDM, // BaseSrvIsFirstVDM, // BaseSrvGetVDMExitCode, // BaseSrvSetReenterCount, BaseSrvSetProcessShutdownParam, BaseSrvGetProcessShutdownParam, // BaseSrvNlsSetUserInfo, // BaseSrvNlsSetMultipleUserInfo, // BaseSrvNlsCreateSection, // BaseSrvSetVDMCurDirs, // BaseSrvGetVDMCurDirs, // BaseSrvBatNotification, // BaseSrvRegisterWowExec, BaseSrvSoundSentryNotification, // BaseSrvRefreshIniFileMapping, BaseSrvDefineDosDevice, // BaseSrvSetTermsrvAppInstallMode, // BaseSrvNlsUpdateCacheCount, // BaseSrvSetTermsrvClientTimeZone, // BaseSrvSxsCreateActivationContext, // BaseSrvRegisterThread, // BaseSrvNlsGetUserInfo, }; BOOLEAN BaseServerApiServerValidTable[BasepMaxApiNumber - BASESRV_FIRST_API_NUMBER] = { TRUE, // BaseSrvCreateProcess TRUE, // BaseSrvCreateThread TRUE, // BaseSrvGetTempFile FALSE, // BaseSrvExitProcess // FALSE, // BaseSrvDebugProcess // TRUE, // BaseSrvCheckVDM // TRUE, // BaseSrvUpdateVDMEntry // TRUE, // BaseSrvGetNextVDMCommand // TRUE, // BaseSrvExitVDM // TRUE, // BaseSrvIsFirstVDM // TRUE, // BaseSrvGetVDMExitCode // TRUE, // BaseSrvSetReenterCount TRUE, // BaseSrvSetProcessShutdownParam TRUE, // BaseSrvGetProcessShutdownParam // TRUE, // BaseSrvNlsSetUserInfo // TRUE, // BaseSrvNlsSetMultipleUserInfo // TRUE, // BaseSrvNlsCreateSection // TRUE, // BaseSrvSetVDMCurDirs // TRUE, // BaseSrvGetVDMCurDirs // TRUE, // BaseSrvBatNotification // TRUE, // BaseSrvRegisterWowExec TRUE, // BaseSrvSoundSentryNotification // TRUE, // BaseSrvRefreshIniFileMapping TRUE, // BaseSrvDefineDosDevice // FALSE, // BaseSrvSetTermsrvAppInstallMode // FALSE, // BaseSrvNlsUpdateCacheCount // FALSE, // BaseSrvSetTermsrvClientTimeZone // FALSE, // BaseSrvSxsCreateActivationContext // FALSE, // BaseSrvRegisterThread // FALSE, // BaseSrvNlsGetUserInfo }; PCHAR BaseServerApiNameTable[BasepMaxApiNumber - BASESRV_FIRST_API_NUMBER] = { "BaseCreateProcess", "BaseCreateThread", "BaseGetTempFile", "BaseExitProcess", // "BaseDebugProcess", // "BaseCheckVDM", // "BaseUpdateVDMEntry", // "BaseGetNextVDMCommand", // "BaseExitVDM", // "BaseIsFirstVDM", // "BaseGetVDMExitCode", // "BaseSetReenterCount", "BaseSetProcessShutdownParam", "BaseGetProcessShutdownParam", // "BaseNlsSetUserInfo", // "BaseNlsSetMultipleUserInfo", // "BaseNlsCreateSection", // "BaseSetVDMCurDirs", // "BaseGetVDMCurDirs", // "BaseBatNotification", // "BaseRegisterWowExec", "BaseSoundSentryNotification", // "BaseRefreshIniFileMapping", "BaseDefineDosDevice", // "BaseSetTermsrvAppInstallMode", // "BaseNlsUpdateCacheCount", // "BaseSetTermsrvClientTimeZone", // "BaseSxsCreateActivationContext", // "BaseRegisterThread", // "BaseNlsGetUserInfo", }; /* FUNCTIONS ******************************************************************/ NTSTATUS NTAPI CreateBaseAcls(OUT PACL* Dacl, OUT PACL* RestrictedDacl) { PSID SystemSid, WorldSid, RestrictedSid; SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; NTSTATUS Status; // UCHAR KeyValueBuffer[0x40]; // PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo; // UNICODE_STRING KeyName; // ULONG ProtectionMode = 0; ULONG AclLength; // , ResultLength; // HANDLE hKey; // OBJECT_ATTRIBUTES ObjectAttributes; /* Open the Session Manager Key */ /* RtlInitUnicodeString(&KeyName, SM_REG_KEY); InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes); if (NT_SUCCESS(Status)) { /\* Read the key value *\/ RtlInitUnicodeString(&KeyName, L"ProtectionMode"); Status = NtQueryValueKey(hKey, &KeyName, KeyValuePartialInformation, KeyValueBuffer, sizeof(KeyValueBuffer), &ResultLength); /\* Make sure it's what we expect it to be *\/ KeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer; if ((NT_SUCCESS(Status)) && (KeyValuePartialInfo->Type == REG_DWORD) && (*(PULONG)KeyValuePartialInfo->Data)) { /\* Save the Protection Mode *\/ // ProtectionMode = *(PULONG)KeyValuePartialInfo->Data; } /\* Close the handle *\/ NtClose(hKey); } */ /* Allocate the System SID */ Status = RtlAllocateAndInitializeSid(&NtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &SystemSid); ASSERT(NT_SUCCESS(Status)); /* Allocate the World SID */ Status = RtlAllocateAndInitializeSid(&WorldAuthority, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &WorldSid); ASSERT(NT_SUCCESS(Status)); /* Allocate the restricted SID */ Status = RtlAllocateAndInitializeSid(&NtAuthority, 1, SECURITY_RESTRICTED_CODE_RID, 0, 0, 0, 0, 0, 0, 0, &RestrictedSid); ASSERT(NT_SUCCESS(Status)); /* Allocate one ACL with 3 ACEs each for one SID */ AclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(SystemSid) + RtlLengthSid(WorldSid) + RtlLengthSid(RestrictedSid); *Dacl = RtlAllocateHeap(BaseSrvHeap, 0, AclLength); ASSERT(*Dacl != NULL); /* Set the correct header fields */ Status = RtlCreateAcl(*Dacl, AclLength, ACL_REVISION2); ASSERT(NT_SUCCESS(Status)); /* Give the appropriate rights to each SID */ /* FIXME: Should check SessionId/ProtectionMode */ Status = RtlAddAccessAllowedAce(*Dacl, ACL_REVISION2, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY | READ_CONTROL, WorldSid); ASSERT(NT_SUCCESS(Status)); Status = RtlAddAccessAllowedAce(*Dacl, ACL_REVISION2, DIRECTORY_ALL_ACCESS, SystemSid); ASSERT(NT_SUCCESS(Status)); Status = RtlAddAccessAllowedAce(*Dacl, ACL_REVISION2, DIRECTORY_TRAVERSE, RestrictedSid); ASSERT(NT_SUCCESS(Status)); /* Now allocate the restricted DACL */ *RestrictedDacl = RtlAllocateHeap(BaseSrvHeap, 0, AclLength); ASSERT(*RestrictedDacl != NULL); /* Initialize it */ Status = RtlCreateAcl(*RestrictedDacl, AclLength, ACL_REVISION2); ASSERT(NT_SUCCESS(Status)); /* And add the same ACEs as before */ /* FIXME: Not really fully correct */ Status = RtlAddAccessAllowedAce(*RestrictedDacl, ACL_REVISION2, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY | READ_CONTROL, WorldSid); ASSERT(NT_SUCCESS(Status)); Status = RtlAddAccessAllowedAce(*RestrictedDacl, ACL_REVISION2, DIRECTORY_ALL_ACCESS, SystemSid); ASSERT(NT_SUCCESS(Status)); Status = RtlAddAccessAllowedAce(*RestrictedDacl, ACL_REVISION2, DIRECTORY_TRAVERSE, RestrictedSid); ASSERT(NT_SUCCESS(Status)); /* The SIDs are captured, can free them now */ RtlFreeSid(RestrictedSid); RtlFreeSid(WorldSid); RtlFreeSid(SystemSid); return Status; } VOID NTAPI BaseInitializeStaticServerData(IN PCSR_SERVER_DLL LoadedServerDll) { NTSTATUS Status; 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; Status = RtlCreateUnicodeString(&BaseSrvWindowsDirectory, SystemRootString.Buffer); ASSERT(NT_SUCCESS(Status)); /* Create the system directory */ wcscat(SystemRootString.Buffer, L"\\System32"); Status = RtlCreateUnicodeString(&BaseSrvWindowsSystemDirectory, SystemRootString.Buffer); ASSERT(NT_SUCCESS(Status)); /* 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)); /* 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 = 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)); } /* Finally, set the pointer */ LoadedServerDll->SharedSection = BaseStaticServerData; } CSR_SERVER_DLL_INIT(ServerDllInitialization) { /* Setup the DLL Object */ LoadedServerDll->ApiBase = BASESRV_FIRST_API_NUMBER; // ApiNumberBase LoadedServerDll->HighestApiSupported = BasepMaxApiNumber; // MaxApiNumber LoadedServerDll->DispatchTable = BaseServerApiDispatchTable; LoadedServerDll->ValidTable = BaseServerApiServerValidTable; LoadedServerDll->NameTable = BaseServerApiNameTable; LoadedServerDll->SizeOfProcessData = 0; LoadedServerDll->ConnectCallback = NULL; LoadedServerDll->DisconnectCallback = NULL; LoadedServerDll->ShutdownProcessCallback = NULL; BaseSrvDllInstance = LoadedServerDll->ServerHandle; BaseInitializeStaticServerData(LoadedServerDll); /* Initialize DOS devices management */ BaseInitDefineDosDevice(); /* All done */ return STATUS_SUCCESS; } BOOL NTAPI DllMain(IN HINSTANCE hInstanceDll, IN DWORD dwReason, IN LPVOID lpReserved) { UNREFERENCED_PARAMETER(hInstanceDll); UNREFERENCED_PARAMETER(dwReason); UNREFERENCED_PARAMETER(lpReserved); if (DLL_PROCESS_DETACH == dwReason) { BaseCleanupDefineDosDevice(); } return TRUE; } /* EOF */