/*++ Copyright (c) Microsoft Corporation Module Name: baseinit.c Abstract: This module implements Win32 base initialization Author: Mark Lucovsky (markl) 26-Sep-1990 Revision History: --*/ #include "basedll.h" ULONG BaseDllTag; BOOLEAN BaseRunningInServerProcess; UINT_PTR SystemRangeStart; #if defined(_WIN64) || defined(BUILD_WOW6432) SYSTEM_BASIC_INFORMATION SysInfo; SYSTEM_PROCESSOR_INFORMATION NativeProcessorInfo; #endif WCHAR BaseDefaultPathBuffer[ 3072 ]; extern const WCHAR PsapiDllString[] = L"psapi.dll"; UNICODE_STRING BaseDefaultPath; UNICODE_STRING BaseDefaultPathAppend; PWSTR BaseCSDVersion; WORD BaseCSDNumber; WORD BaseRCNumber; UNICODE_STRING BaseUnicodeCommandLine; ANSI_STRING BaseAnsiCommandLine; LPSTARTUPINFOA BaseAnsiStartupInfo; PBASE_STATIC_SERVER_DATA BaseStaticServerData; ULONG BaseIniFileUpdateCount; RTL_CRITICAL_SECTION gcsAppCert; LIST_ENTRY BasepAppCertDllsList; RTL_CRITICAL_SECTION gcsAppCompat; PTERMSRVFORMATOBJECTNAME gpTermsrvFormatObjectName; PTERMSRVGETCOMPUTERNAME gpTermsrvGetComputerName; PTERMSRVADJUSTPHYMEMLIMITS gpTermsrvAdjustPhyMemLimits; PTERMSRVGETWINDOWSDIRECTORYA gpTermsrvGetWindowsDirectoryA; PTERMSRVGETWINDOWSDIRECTORYW gpTermsrvGetWindowsDirectoryW; PTERMSRVCONVERTSYSROOTTOUSERDIR gpTermsrvConvertSysRootToUserDir; PTERMSRVBUILDINIFILENAME gpTermsrvBuildIniFileName; PTERMSRVCORINIFILE gpTermsrvCORIniFile; PTERMSRVUPDATEALLUSERMENU gpTermsrvUpdateAllUserMenu; PGETTERMSRCOMPATFLAGS gpGetTermsrCompatFlags; PTERMSRVBUILDSYSINIPATH gpTermsrvBuildSysIniPath; PTERMSRVCOPYINIFILE gpTermsrvCopyIniFile; PTERMSRVGETSTRING gpTermsrvGetString; PTERMSRVLOGINSTALLINIFILE gpTermsrvLogInstallIniFile; HANDLE BaseDllHandle; HANDLE BaseNamedObjectDirectory; PVOID BaseHeap; RTL_HANDLE_TABLE BaseHeapHandleTable; UNICODE_STRING BaseWindowsDirectory; UNICODE_STRING BaseWindowsSystemDirectory; UNICODE_STRING BaseDllDirectory = { 0, 0, NULL }; RTL_CRITICAL_SECTION BaseDllDirectoryLock; RTL_CRITICAL_SECTION BaseLZSemTable; #ifdef WX86 UNICODE_STRING BaseWindowsSys32x86Directory; #endif // // Dispatch functions for Oem/Ansi sensitive conversions // NTSTATUS (*Basep8BitStringToUnicodeString)( PUNICODE_STRING DestinationString, PANSI_STRING SourceString, BOOLEAN AllocateDestinationString ) = RtlAnsiStringToUnicodeString; NTSTATUS (*BasepUnicodeStringTo8BitString)( PANSI_STRING DestinationString, PUNICODE_STRING SourceString, BOOLEAN AllocateDestinationString ) = RtlUnicodeStringToAnsiString; ULONG (*BasepUnicodeStringTo8BitSize)( PUNICODE_STRING UnicodeString ) = BasepUnicodeStringToAnsiSize; ULONG (*Basep8BitStringToUnicodeSize)( PANSI_STRING AnsiString ) = BasepAnsiStringToUnicodeSize; VOID WINAPI SetFileApisToOEM( VOID ) { Basep8BitStringToUnicodeString = RtlOemStringToUnicodeString; BasepUnicodeStringTo8BitString = RtlUnicodeStringToOemString; BasepUnicodeStringTo8BitSize = BasepUnicodeStringToOemSize; Basep8BitStringToUnicodeSize = BasepOemStringToUnicodeSize; } VOID WINAPI SetFileApisToANSI( VOID ) { Basep8BitStringToUnicodeString = RtlAnsiStringToUnicodeString; BasepUnicodeStringTo8BitString = RtlUnicodeStringToAnsiString; BasepUnicodeStringTo8BitSize = BasepUnicodeStringToAnsiSize; Basep8BitStringToUnicodeSize = BasepAnsiStringToUnicodeSize; } BOOL WINAPI AreFileApisANSI( VOID ) { return Basep8BitStringToUnicodeString == RtlAnsiStringToUnicodeString; } BOOLEAN ConDllInitialize( IN ULONG Reason, IN PWSTR pObjectDirectory OPTIONAL ); BOOLEAN NlsDllInitialize( IN PVOID DllHandle, IN ULONG Reason, IN PBASE_STATIC_SERVER_DATA BaseStaticServerData ); VOID NlsThreadCleanup( VOID); #if DBG VOID WINAPI AssertDelayLoadFailureMapsAreSorted ( VOID ); #endif extern const UNICODE_STRING BasePathVariableName = RTL_CONSTANT_STRING(L"PATH"); extern const UNICODE_STRING BaseUserProfileVariableName = RTL_CONSTANT_STRING(L"USERPROFILE"); extern const UNICODE_STRING BaseTmpVariableName = RTL_CONSTANT_STRING(L"TMP"); extern const UNICODE_STRING BaseTempVariableName = RTL_CONSTANT_STRING(L"TEMP"); extern const UNICODE_STRING BaseDotVariableName = RTL_CONSTANT_STRING(L"."); extern const UNICODE_STRING BaseDotTmpSuffixName = RTL_CONSTANT_STRING(L".tmp"); extern const UNICODE_STRING BaseDotComSuffixName = RTL_CONSTANT_STRING(L".com"); extern const UNICODE_STRING BaseDotPifSuffixName = RTL_CONSTANT_STRING(L".pif"); extern const UNICODE_STRING BaseDotExeSuffixName = RTL_CONSTANT_STRING(L".exe"); extern const UNICODE_STRING BaseConsoleInput = RTL_CONSTANT_STRING(L"CONIN$"); extern const UNICODE_STRING BaseConsoleOutput = RTL_CONSTANT_STRING(L"CONOUT$"); extern const UNICODE_STRING BaseConsoleGeneric = RTL_CONSTANT_STRING(L"CON"); BOOLEAN BaseDllInitialize( IN PVOID DllHandle, IN ULONG Reason, IN PCONTEXT Context OPTIONAL ) /*++ Routine Description: This function implements Win32 base dll initialization. It's primary purpose is to create the Base heap. Arguments: DllHandle - Saved in BaseDllHandle global variable Context - Not Used Return Value: STATUS_SUCCESS --*/ { BOOLEAN Success; NTSTATUS Status; PPEB Peb; LPWSTR p, p1; BOOLEAN ServerProcess; HANDLE hNlsCacheMutant; USHORT Size; #if !defined(BUILD_WOW6432) ULONG SizeMutant; #endif WCHAR szSessionDir[MAX_SESSION_PATH]; Peb = NtCurrentPeb(); SessionId = Peb->SessionId; BaseDllHandle = DllHandle; Success = TRUE; switch ( Reason ) { case DLL_PROCESS_ATTACH: Basep8BitStringToUnicodeString = RtlAnsiStringToUnicodeString; RtlSetThreadPoolStartFunc( BaseCreateThreadPoolThread, BaseExitThreadPoolThread ); LdrSetDllManifestProber(&BasepProbeForDllManifest); BaseDllTag = RtlCreateTagHeap( RtlProcessHeap(), 0, L"BASEDLL!", L"TMP\0" L"BACKUP\0" L"INI\0" L"FIND\0" L"GMEM\0" L"LMEM\0" L"ENV\0" L"RES\0" L"VDM\0" ); BaseIniFileUpdateCount = 0; BaseDllInitializeMemoryManager(); BaseDefaultPath.Length = 0; BaseDefaultPath.MaximumLength = 0; BaseDefaultPath.Buffer = NULL; // // Connect to BASESRV.DLL in the server process // #if !defined(BUILD_WOW6432) SizeMutant = sizeof(hNlsCacheMutant); #endif if ( SessionId == 0 ) { // // Console Session // wcscpy(szSessionDir, WINSS_OBJECT_DIRECTORY_NAME); } else { swprintf(szSessionDir,L"%ws\\%ld%ws",SESSION_ROOT,SessionId,WINSS_OBJECT_DIRECTORY_NAME); } #if defined(BUILD_WOW6432) || defined(_WIN64) Status = NtQuerySystemInformation(SystemBasicInformation, &SysInfo, sizeof(SYSTEM_BASIC_INFORMATION), NULL ); if (!NT_SUCCESS(Status)) { return FALSE; } Status = RtlGetNativeSystemInformation( SystemProcessorInformation, &NativeProcessorInfo, sizeof(SYSTEM_PROCESSOR_INFORMATION), NULL ); if (!NT_SUCCESS(Status)) { return FALSE; } #endif #if defined(BUILD_WOW6432) Status = CsrBaseClientConnectToServer(szSessionDir, &hNlsCacheMutant, &ServerProcess ); #else Status = CsrClientConnectToServer( szSessionDir, BASESRV_SERVERDLL_INDEX, &hNlsCacheMutant, &SizeMutant, &ServerProcess ); #endif if (!NT_SUCCESS( Status )) { return FALSE; } BaseStaticServerData = BASE_SHARED_SERVER_DATA; if (!ServerProcess) { CsrNewThread(); BaseRunningInServerProcess = FALSE; } else { BaseRunningInServerProcess = TRUE; } BaseCSDVersion = BaseStaticServerData->CSDVersion; BaseCSDNumber = BaseStaticServerData->CSDNumber; BaseRCNumber = BaseStaticServerData->RCNumber; if ((BaseCSDVersion) && (!Peb->CSDVersion.Buffer)) { RtlInitUnicodeString(&Peb->CSDVersion, BaseCSDVersion); } BASE_SERVER_STR_TO_LOCAL_STR(&BaseWindowsDirectory, &BaseStaticServerData->WindowsDirectory); BASE_SERVER_STR_TO_LOCAL_STR(&BaseWindowsSystemDirectory, &BaseStaticServerData->WindowsSystemDirectory); #ifdef WX86 BASE_SERVER_STR_TO_LOCAL_STR(&BaseWindowsSys32x86Directory, &BaseStaticServerData->WindowsSys32x86Directory); #endif BaseUnicodeCommandLine = Peb->ProcessParameters->CommandLine; Status = RtlUnicodeStringToAnsiString( &BaseAnsiCommandLine, &BaseUnicodeCommandLine, TRUE ); if ( !NT_SUCCESS(Status) ){ BaseAnsiCommandLine.Buffer = NULL; BaseAnsiCommandLine.Length = 0; BaseAnsiCommandLine.MaximumLength = 0; } p = BaseDefaultPathBuffer; p1 = BaseWindowsSystemDirectory.Buffer; while( *p = *p1++) { p++; } *p++ = L';'; #ifdef WX86 // // Wx86 system dir follows 32 bit system dir // p1 = BaseWindowsSys32x86Directory.Buffer; while( *p = *p1++) { p++; } *p++ = L';'; #endif // // 16bit system directory follows 32bit system directory // p1 = BaseWindowsDirectory.Buffer; while( *p = *p1++) { p++; } p1 = L"\\system"; while( *p = *p1++) { p++; } *p++ = L';'; p1 = BaseWindowsDirectory.Buffer; while( *p = *p1++) { p++; } *p++ = L';'; if (IsTerminalServer()) { WCHAR TermSrvWindowsPath[MAX_PATH]; SIZE_T TermSrvWindowsPathLength = 0; NTSTATUS TermSrvWindowsPathStatus; TermSrvWindowsPathStatus = GetPerUserWindowsDirectory( TermSrvWindowsPath, RTL_NUMBER_OF(TermSrvWindowsPath), &TermSrvWindowsPathLength ); if (NT_SUCCESS(TermSrvWindowsPathStatus) && TermSrvWindowsPathLength != 0 ) { RtlCopyMemory(p, TermSrvWindowsPath, (TermSrvWindowsPathLength * sizeof(p[0]))); p += TermSrvWindowsPathLength; *p++ = L';'; } } *p = UNICODE_NULL; BaseDefaultPath.Buffer = BaseDefaultPathBuffer; BaseDefaultPath.Length = (USHORT)((ULONG_PTR)p - (ULONG_PTR)BaseDefaultPathBuffer); BaseDefaultPath.MaximumLength = sizeof( BaseDefaultPathBuffer ); BaseDefaultPathAppend.Buffer = p; BaseDefaultPathAppend.Length = 0; BaseDefaultPathAppend.MaximumLength = (USHORT) (BaseDefaultPath.MaximumLength - BaseDefaultPath.Length); if (!NT_SUCCESS(RtlInitializeCriticalSection(&BaseDllDirectoryLock))) { return FALSE; } if (!NT_SUCCESS(RtlInitializeCriticalSection(&BaseLZSemTable))) { return FALSE; } BaseDllInitializeIniFileMappings( BaseStaticServerData ); if ( Peb->ProcessParameters ) { if ( Peb->ProcessParameters->Flags & RTL_USER_PROC_PROFILE_USER ) { LoadLibraryW(PsapiDllString); } if (Peb->ProcessParameters->DebugFlags) { DbgBreakPoint(); } } // // call the NLS API initialization routine // if ( !NlsDllInitialize( DllHandle, Reason, BaseStaticServerData ) ) { return FALSE; } // // call the console initialization routine // if ( !ConDllInitialize(Reason,szSessionDir) ) { return FALSE; } InitializeListHead( &BasepAppCertDllsList ); if (!NT_SUCCESS(RtlInitializeCriticalSection(&gcsAppCert))) { return FALSE; } if (!NT_SUCCESS(RtlInitializeCriticalSection(&gcsAppCompat))) { return(FALSE); } #if DBG AssertDelayLoadFailureMapsAreSorted (); #endif break; case DLL_PROCESS_DETACH: // // Make sure any open registry keys are closed. // if (BaseIniFileUpdateCount != 0) { WriteProfileStringW( NULL, NULL, NULL ); } break; case DLL_THREAD_ATTACH: // // call the console initialization routine // if ( !ConDllInitialize(Reason,NULL) ) { return FALSE; } break; case DLL_THREAD_DETACH: // // Delete the thread NLS cache, if exists. // NlsThreadCleanup(); break; default: break; } return Success; } NTSTATUS NTAPI BaseProcessInitPostImport() /* Routine Description: Called by the ntdll process initialization code after all of the import tables for the static imports of the EXE have been processed, but before any DLL_PROCESS_ATTACHes are sent with the exception of kernel32.dll's. Needed for the terminal server app compat hooks. */ { NTSTATUS Status = STATUS_INTERNAL_ERROR; // // Intialize TerminalServer(Hydra) hook function pointers for app compatibility // if (IsTerminalServer()) { Status = BasepInitializeTermsrvFpns(); if (!NT_SUCCESS(Status)) { goto Exit; } } Status = STATUS_SUCCESS; Exit: return Status; } HANDLE BaseGetNamedObjectDirectory( VOID ) { OBJECT_ATTRIBUTES Obja; NTSTATUS Status; const static UNICODE_STRING RestrictedObjectDirectory = RTL_CONSTANT_STRING(L"Restricted"); ACCESS_MASK DirAccess = DIRECTORY_ALL_ACCESS & ~(DELETE | WRITE_DAC | WRITE_OWNER); HANDLE hRootNamedObject; HANDLE BaseHandle; HANDLE Token, NewToken; if ( BaseNamedObjectDirectory != NULL) { return BaseNamedObjectDirectory; } if (NtCurrentTeb()->IsImpersonating) { // // If we're impersonating, save the impersonation token, and // revert to self for the duration of the directory creation. // Status = NtOpenThreadToken(NtCurrentThread(), TOKEN_IMPERSONATE, TRUE, &Token); if (! NT_SUCCESS(Status)) { return BaseNamedObjectDirectory; } NewToken = NULL; Status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, (PVOID) &NewToken, (ULONG) sizeof(NewToken)); if (! NT_SUCCESS(Status)) { NtClose(Token); return BaseNamedObjectDirectory; } } else { Token = NULL; } RtlAcquirePebLock(); if ( !BaseNamedObjectDirectory ) { BASE_READ_REMOTE_STR_TEMP(TempStr); InitializeObjectAttributes( &Obja, BASE_READ_REMOTE_STR(BaseStaticServerData->NamedObjectDirectory, TempStr), OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenDirectoryObject( &BaseHandle, DirAccess, &Obja ); // if the intial open failed, try again with just traverse, and // open the restricted subdirectory if ( !NT_SUCCESS(Status) ) { Status = NtOpenDirectoryObject( &hRootNamedObject, DIRECTORY_TRAVERSE, &Obja ); if ( NT_SUCCESS(Status) ) { InitializeObjectAttributes( &Obja, (PUNICODE_STRING)&RestrictedObjectDirectory, OBJ_CASE_INSENSITIVE, hRootNamedObject, NULL ); Status = NtOpenDirectoryObject( &BaseHandle, DirAccess, &Obja ); NtClose( hRootNamedObject ); } } if ( NT_SUCCESS(Status) ) { BaseNamedObjectDirectory = BaseHandle; } } RtlReleasePebLock(); if (Token) { NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, (PVOID) &Token, (ULONG) sizeof(Token)); NtClose(Token); } return BaseNamedObjectDirectory; }