/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Base API Server DLL * FILE: subsystems/win/basesrv/init.c * PURPOSE: Initialization * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Hermes Belusca-Maito (hermes.belusca@sfr.fr) */ /* INCLUDES *******************************************************************/ #include "basesrv.h" #include "vdm.h" #include #define NDEBUG #include #include "api.h" /* GLOBALS ********************************************************************/ HANDLE BaseSrvDllInstance = NULL; extern UNICODE_STRING BaseSrvKernel32DllPath; /* 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. PINIFILE_MAPPING BaseSrvIniFileMapping; // 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, BaseSrvDebugProcess, 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 TRUE, // BaseSrvSetTermsrvAppInstallMode TRUE, // BaseSrvNlsUpdateCacheCount TRUE, // BaseSrvSetTermsrvClientTimeZone TRUE, // BaseSrvSxsCreateActivationContext FALSE, // BaseSrvDebugProcess TRUE, // BaseSrvRegisterThread TRUE, // BaseSrvNlsGetUserInfo }; /* * On Windows Server 2003, CSR Servers contain * the API Names Table only in Debug Builds. */ #ifdef CSR_DBG 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", "BaseSrvDebugProcessStop", "BaseRegisterThread", "BaseNlsGetUserInfo", }; #endif /* FUNCTIONS ******************************************************************/ NTSTATUS NTAPI BaseSrvInitializeIniFileMappings(IN PBASE_STATIC_SERVER_DATA StaticServerData) { /* Allocate the mapping blob */ BaseSrvIniFileMapping = RtlAllocateHeap(BaseSrvSharedHeap, HEAP_ZERO_MEMORY, sizeof(*BaseSrvIniFileMapping)); if (BaseSrvIniFileMapping == NULL) { DPRINT1("BASESRV: Unable to allocate memory in shared heap for IniFileMapping\n"); return STATUS_NO_MEMORY; } /* Set it*/ StaticServerData->IniFileMapping = BaseSrvIniFileMapping; /* FIXME: Do the work to initialize the mappings */ return STATUS_SUCCESS; } 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; #if 0 // Unused code UCHAR KeyValueBuffer[0x40]; PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo; UNICODE_STRING KeyName; ULONG ProtectionMode = 0; #endif ULONG AclLength; #if 0 // Unused code ULONG 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); } #endif /* 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; 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 { /* Indicate nothing is there */ BaseSrvCSDString.Length = 0; } /* NULL-terminate */ BaseStaticServerData->CSDVersion[BaseSrvCSDString.Length / sizeof(WCHAR)] = 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 BaseClientConnectRoutine(IN PCSR_PROCESS CsrProcess, IN OUT PVOID ConnectionInfo, IN OUT PULONG ConnectionInfoLength) { PBASESRV_API_CONNECTINFO ConnectInfo = (PBASESRV_API_CONNECTINFO)ConnectionInfo; if ( ConnectionInfo == NULL || ConnectionInfoLength == NULL || *ConnectionInfoLength != sizeof(*ConnectInfo) ) { DPRINT1("BASESRV: Connection failed - ConnectionInfo = 0x%p ; ConnectionInfoLength = 0x%p (%lu), expected %lu\n", ConnectionInfo, ConnectionInfoLength, ConnectionInfoLength ? *ConnectionInfoLength : (ULONG)-1, sizeof(*ConnectInfo)); return STATUS_INVALID_PARAMETER; } /* Do the NLS connection */ return BaseSrvNlsConnect(CsrProcess, ConnectionInfo, ConnectionInfoLength); } VOID NTAPI BaseClientDisconnectRoutine(IN PCSR_PROCESS CsrProcess) { /* Cleanup VDM resources */ BaseSrvCleanupVDMResources(CsrProcess); } CSR_SERVER_DLL_INIT(ServerDllInitialization) { /* Setup the DLL Object */ LoadedServerDll->ApiBase = BASESRV_FIRST_API_NUMBER; LoadedServerDll->HighestApiSupported = BasepMaxApiNumber; LoadedServerDll->DispatchTable = BaseServerApiDispatchTable; LoadedServerDll->ValidTable = BaseServerApiServerValidTable; #ifdef CSR_DBG LoadedServerDll->NameTable = BaseServerApiNameTable; #endif LoadedServerDll->SizeOfProcessData = 0; LoadedServerDll->ConnectCallback = BaseClientConnectRoutine; LoadedServerDll->DisconnectCallback = BaseClientDisconnectRoutine; LoadedServerDll->ShutdownProcessCallback = NULL; BaseSrvDllInstance = LoadedServerDll->ServerHandle; BaseInitializeStaticServerData(LoadedServerDll); /* Initialize DOS devices management */ BaseInitDefineDosDevice(); /* Initialize VDM support */ BaseInitializeVDM(); /* 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 */