xref: /reactos/subsystems/win/basesrv/init.c (revision d0fad527)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Base API Server DLL
4  * FILE:            subsystems/win/basesrv/init.c
5  * PURPOSE:         Initialization
6  * PROGRAMMERS:     Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "basesrv.h"
12 #include "vdm.h"
13 
14 #include <winreg.h>
15 
16 #define NDEBUG
17 #include <debug.h>
18 
19 #include "api.h"
20 
21 /* GLOBALS ********************************************************************/
22 
23 HANDLE BaseSrvDllInstance = NULL;
24 extern UNICODE_STRING BaseSrvKernel32DllPath;
25 
26 /* Memory */
27 HANDLE BaseSrvHeap = NULL;          // Our own heap.
28 HANDLE BaseSrvSharedHeap = NULL;    // Shared heap with CSR. (CsrSrvSharedSectionHeap)
29 PBASE_STATIC_SERVER_DATA BaseStaticServerData = NULL;   // Data that we can share amongst processes. Initialized inside BaseSrvSharedHeap.
30 
31 PINIFILE_MAPPING BaseSrvIniFileMapping;
32 
33 // Windows Server 2003 table from http://j00ru.vexillium.org/csrss_list/api_list.html#Windows_2k3
34 PCSR_API_ROUTINE BaseServerApiDispatchTable[BasepMaxApiNumber - BASESRV_FIRST_API_NUMBER] =
35 {
36     BaseSrvCreateProcess,
37     BaseSrvCreateThread,
38     BaseSrvGetTempFile,
39     BaseSrvExitProcess,
40     BaseSrvDebugProcess,
41     BaseSrvCheckVDM,
42     BaseSrvUpdateVDMEntry,
43     BaseSrvGetNextVDMCommand,
44     BaseSrvExitVDM,
45     BaseSrvIsFirstVDM,
46     BaseSrvGetVDMExitCode,
47     BaseSrvSetReenterCount,
48     BaseSrvSetProcessShutdownParam,
49     BaseSrvGetProcessShutdownParam,
50     BaseSrvNlsSetUserInfo,
51     BaseSrvNlsSetMultipleUserInfo,
52     BaseSrvNlsCreateSection,
53     BaseSrvSetVDMCurDirs,
54     BaseSrvGetVDMCurDirs,
55     BaseSrvBatNotification,
56     BaseSrvRegisterWowExec,
57     BaseSrvSoundSentryNotification,
58     BaseSrvRefreshIniFileMapping,
59     BaseSrvDefineDosDevice,
60     BaseSrvSetTermsrvAppInstallMode,
61     BaseSrvNlsUpdateCacheCount,
62     BaseSrvSetTermsrvClientTimeZone,
63     BaseSrvSxsCreateActivationContext,
64     BaseSrvUnknown,
65     BaseSrvRegisterThread,
66     BaseSrvNlsGetUserInfo,
67 };
68 
69 BOOLEAN BaseServerApiServerValidTable[BasepMaxApiNumber - BASESRV_FIRST_API_NUMBER] =
70 {
71     TRUE,   // BaseSrvCreateProcess
72     TRUE,   // BaseSrvCreateThread
73     TRUE,   // BaseSrvGetTempFile
74     FALSE,  // BaseSrvExitProcess
75     FALSE,  // BaseSrvDebugProcess
76     TRUE,   // BaseSrvCheckVDM
77     TRUE,   // BaseSrvUpdateVDMEntry
78     TRUE,   // BaseSrvGetNextVDMCommand
79     TRUE,   // BaseSrvExitVDM
80     TRUE,   // BaseSrvIsFirstVDM
81     TRUE,   // BaseSrvGetVDMExitCode
82     TRUE,   // BaseSrvSetReenterCount
83     TRUE,   // BaseSrvSetProcessShutdownParam
84     TRUE,   // BaseSrvGetProcessShutdownParam
85     TRUE,   // BaseSrvNlsSetUserInfo
86     TRUE,   // BaseSrvNlsSetMultipleUserInfo
87     TRUE,   // BaseSrvNlsCreateSection
88     TRUE,   // BaseSrvSetVDMCurDirs
89     TRUE,   // BaseSrvGetVDMCurDirs
90     TRUE,   // BaseSrvBatNotification
91     TRUE,   // BaseSrvRegisterWowExec
92     TRUE,   // BaseSrvSoundSentryNotification
93     TRUE,   // BaseSrvRefreshIniFileMapping
94     TRUE,   // BaseSrvDefineDosDevice
95     TRUE,   // BaseSrvSetTermsrvAppInstallMode
96     TRUE,   // BaseSrvNlsUpdateCacheCount
97     TRUE,   // BaseSrvSetTermsrvClientTimeZone
98     TRUE,   // BaseSrvSxsCreateActivationContext
99     TRUE,   // BaseSrvUnknown
100     TRUE,   // BaseSrvRegisterThread
101     TRUE,   // BaseSrvNlsGetUserInfo
102 };
103 
104 /*
105  * On Windows Server 2003, CSR Servers contain
106  * the API Names Table only in Debug Builds.
107  */
108 #ifdef CSR_DBG
109 PCHAR BaseServerApiNameTable[BasepMaxApiNumber - BASESRV_FIRST_API_NUMBER] =
110 {
111     "BaseCreateProcess",
112     "BaseCreateThread",
113     "BaseGetTempFile",
114     "BaseExitProcess",
115     "BaseDebugProcess",
116     "BaseCheckVDM",
117     "BaseUpdateVDMEntry",
118     "BaseGetNextVDMCommand",
119     "BaseExitVDM",
120     "BaseIsFirstVDM",
121     "BaseGetVDMExitCode",
122     "BaseSetReenterCount",
123     "BaseSetProcessShutdownParam",
124     "BaseGetProcessShutdownParam",
125     "BaseNlsSetUserInfo",
126     "BaseNlsSetMultipleUserInfo",
127     "BaseNlsCreateSection",
128     "BaseSetVDMCurDirs",
129     "BaseGetVDMCurDirs",
130     "BaseBatNotification",
131     "BaseRegisterWowExec",
132     "BaseSoundSentryNotification",
133     "BaseRefreshIniFileMapping",
134     "BaseDefineDosDevice",
135     "BaseSetTermsrvAppInstallMode",
136     "BaseNlsUpdateCacheCount",
137     "BaseSetTermsrvClientTimeZone",
138     "BaseSxsCreateActivationContext",
139     "BaseUnknown",
140     "BaseRegisterThread",
141     "BaseNlsGetUserInfo",
142 };
143 #endif
144 
145 /* FUNCTIONS ******************************************************************/
146 
147 NTSTATUS
148 NTAPI
149 BaseSrvInitializeIniFileMappings(IN PBASE_STATIC_SERVER_DATA StaticServerData)
150 {
151     /* Allocate the mapping blob */
152     BaseSrvIniFileMapping = RtlAllocateHeap(BaseSrvSharedHeap,
153                                             HEAP_ZERO_MEMORY,
154                                             sizeof(*BaseSrvIniFileMapping));
155     if (BaseSrvIniFileMapping == NULL)
156     {
157         DPRINT1("BASESRV: Unable to allocate memory in shared heap for IniFileMapping\n");
158         return STATUS_NO_MEMORY;
159     }
160 
161     /* Set it*/
162     StaticServerData->IniFileMapping = BaseSrvIniFileMapping;
163 
164     /* FIXME: Do the work to initialize the mappings */
165     return STATUS_SUCCESS;
166 }
167 
168 NTSTATUS
169 NTAPI
170 CreateBaseAcls(OUT PACL* Dacl,
171                OUT PACL* RestrictedDacl)
172 {
173     PSID SystemSid, WorldSid, RestrictedSid;
174     SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
175     SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
176     NTSTATUS Status;
177 #if 0 // Unused code
178     UCHAR KeyValueBuffer[0x40];
179     PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
180     UNICODE_STRING KeyName;
181     ULONG ProtectionMode = 0;
182 #endif
183     ULONG AclLength;
184 #if 0 // Unused code
185     ULONG ResultLength;
186     HANDLE hKey;
187     OBJECT_ATTRIBUTES ObjectAttributes;
188 
189     /* Open the Session Manager Key */
190     RtlInitUnicodeString(&KeyName, SM_REG_KEY);
191     InitializeObjectAttributes(&ObjectAttributes,
192                                &KeyName,
193                                OBJ_CASE_INSENSITIVE,
194                                NULL,
195                                NULL);
196     Status = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
197     if (NT_SUCCESS(Status))
198     {
199         /* Read the key value */
200         RtlInitUnicodeString(&KeyName, L"ProtectionMode");
201         Status = NtQueryValueKey(hKey,
202                                  &KeyName,
203                                  KeyValuePartialInformation,
204                                  KeyValueBuffer,
205                                  sizeof(KeyValueBuffer),
206                                  &ResultLength);
207 
208         /* Make sure it's what we expect it to be */
209         KeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
210         if ((NT_SUCCESS(Status)) && (KeyValuePartialInfo->Type == REG_DWORD) &&
211             (*(PULONG)KeyValuePartialInfo->Data))
212         {
213             /* Save the Protection Mode */
214             ProtectionMode = *(PULONG)KeyValuePartialInfo->Data;
215         }
216 
217         /* Close the handle */
218         NtClose(hKey);
219     }
220 #endif
221 
222     /* Allocate the System SID */
223     Status = RtlAllocateAndInitializeSid(&NtAuthority,
224                                          1, SECURITY_LOCAL_SYSTEM_RID,
225                                          0, 0, 0, 0, 0, 0, 0,
226                                          &SystemSid);
227     ASSERT(NT_SUCCESS(Status));
228 
229     /* Allocate the World SID */
230     Status = RtlAllocateAndInitializeSid(&WorldAuthority,
231                                          1, SECURITY_WORLD_RID,
232                                          0, 0, 0, 0, 0, 0, 0,
233                                          &WorldSid);
234     ASSERT(NT_SUCCESS(Status));
235 
236     /* Allocate the restricted SID */
237     Status = RtlAllocateAndInitializeSid(&NtAuthority,
238                                          1, SECURITY_RESTRICTED_CODE_RID,
239                                          0, 0, 0, 0, 0, 0, 0,
240                                          &RestrictedSid);
241     ASSERT(NT_SUCCESS(Status));
242 
243     /* Allocate one ACL with 3 ACEs each for one SID */
244     AclLength = sizeof(ACL) + 3 * sizeof(ACCESS_ALLOWED_ACE) +
245                     RtlLengthSid(SystemSid) +
246                     RtlLengthSid(WorldSid)  +
247                     RtlLengthSid(RestrictedSid);
248     *Dacl = RtlAllocateHeap(BaseSrvHeap, 0, AclLength);
249     ASSERT(*Dacl != NULL);
250 
251     /* Set the correct header fields */
252     Status = RtlCreateAcl(*Dacl, AclLength, ACL_REVISION2);
253     ASSERT(NT_SUCCESS(Status));
254 
255     /* Give the appropriate rights to each SID */
256     /* FIXME: Should check SessionId/ProtectionMode */
257     Status = RtlAddAccessAllowedAce(*Dacl, ACL_REVISION2, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY | READ_CONTROL, WorldSid);
258     ASSERT(NT_SUCCESS(Status));
259     Status = RtlAddAccessAllowedAce(*Dacl, ACL_REVISION2, DIRECTORY_ALL_ACCESS, SystemSid);
260     ASSERT(NT_SUCCESS(Status));
261     Status = RtlAddAccessAllowedAce(*Dacl, ACL_REVISION2, DIRECTORY_TRAVERSE, RestrictedSid);
262     ASSERT(NT_SUCCESS(Status));
263 
264     /* Now allocate the restricted DACL */
265     *RestrictedDacl = RtlAllocateHeap(BaseSrvHeap, 0, AclLength);
266     ASSERT(*RestrictedDacl != NULL);
267 
268     /* Initialize it */
269     Status = RtlCreateAcl(*RestrictedDacl, AclLength, ACL_REVISION2);
270     ASSERT(NT_SUCCESS(Status));
271 
272     /* And add the same ACEs as before */
273     /* FIXME: Not really fully correct */
274     Status = RtlAddAccessAllowedAce(*RestrictedDacl, ACL_REVISION2, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY | READ_CONTROL, WorldSid);
275     ASSERT(NT_SUCCESS(Status));
276     Status = RtlAddAccessAllowedAce(*RestrictedDacl, ACL_REVISION2, DIRECTORY_ALL_ACCESS, SystemSid);
277     ASSERT(NT_SUCCESS(Status));
278     Status = RtlAddAccessAllowedAce(*RestrictedDacl, ACL_REVISION2, DIRECTORY_TRAVERSE, RestrictedSid);
279     ASSERT(NT_SUCCESS(Status));
280 
281     /* The SIDs are captured, can free them now */
282     RtlFreeSid(RestrictedSid);
283     RtlFreeSid(WorldSid);
284     RtlFreeSid(SystemSid);
285     return Status;
286 }
287 
288 VOID
289 NTAPI
290 BaseInitializeStaticServerData(IN PCSR_SERVER_DLL LoadedServerDll)
291 {
292     NTSTATUS Status;
293     BOOLEAN Success;
294     WCHAR Buffer[MAX_PATH];
295     PWCHAR HeapBuffer;
296     UNICODE_STRING SystemRootString;
297     UNICODE_STRING UnexpandedSystemRootString = RTL_CONSTANT_STRING(L"%SystemRoot%");
298     UNICODE_STRING BaseSrvCSDString;
299     UNICODE_STRING BaseSrvWindowsDirectory;
300     UNICODE_STRING BaseSrvWindowsSystemDirectory;
301     UNICODE_STRING BnoString;
302     OBJECT_ATTRIBUTES ObjectAttributes;
303     ULONG SessionId;
304     HANDLE BaseSrvNamedObjectDirectory;
305     HANDLE BaseSrvRestrictedObjectDirectory;
306     PACL BnoDacl, BnoRestrictedDacl;
307     PSECURITY_DESCRIPTOR BnoSd;
308     HANDLE SymHandle;
309     UNICODE_STRING DirectoryName, SymlinkName;
310     ULONG LuidEnabled;
311     RTL_QUERY_REGISTRY_TABLE BaseServerRegistryConfigurationTable[2] =
312     {
313         {
314             NULL,
315             RTL_QUERY_REGISTRY_DIRECT,
316             L"CSDVersion",
317             &BaseSrvCSDString,
318             REG_NONE, NULL, 0
319         },
320 
321         {0}
322     };
323 
324     /* Initialize the memory */
325     BaseSrvHeap = RtlGetProcessHeap();                  // Initialize our own heap.
326     BaseSrvSharedHeap = LoadedServerDll->SharedSection; // Get the CSR shared heap.
327 
328     /* Get the session ID */
329     SessionId = NtCurrentPeb()->SessionId;
330 
331     /* Get the Windows directory */
332     RtlInitEmptyUnicodeString(&SystemRootString, Buffer, sizeof(Buffer));
333     Status = RtlExpandEnvironmentStrings_U(NULL,
334                                            &UnexpandedSystemRootString,
335                                            &SystemRootString,
336                                            NULL);
337     ASSERT(NT_SUCCESS(Status));
338 
339     /* Create the base directory */
340     Buffer[SystemRootString.Length / sizeof(WCHAR)] = UNICODE_NULL;
341     Success = RtlCreateUnicodeString(&BaseSrvWindowsDirectory,
342                                      SystemRootString.Buffer);
343     ASSERT(Success);
344 
345     /* Create the system directory */
346     wcscat(SystemRootString.Buffer, L"\\System32");
347     Success = RtlCreateUnicodeString(&BaseSrvWindowsSystemDirectory,
348                                      SystemRootString.Buffer);
349     ASSERT(Success);
350 
351     /* Create the kernel32 path */
352     wcscat(SystemRootString.Buffer, L"\\kernel32.dll");
353     Success = RtlCreateUnicodeString(&BaseSrvKernel32DllPath,
354                                      SystemRootString.Buffer);
355     ASSERT(Success);
356 
357     /* FIXME: Check Session ID */
358     wcscpy(Buffer, L"\\BaseNamedObjects");
359     RtlInitUnicodeString(&BnoString, Buffer);
360 
361     /* Allocate the server data */
362     BaseStaticServerData = RtlAllocateHeap(BaseSrvSharedHeap,
363                                            HEAP_ZERO_MEMORY,
364                                            sizeof(BASE_STATIC_SERVER_DATA));
365     ASSERT(BaseStaticServerData != NULL);
366 
367     /* Process timezone information */
368     BaseStaticServerData->TermsrvClientTimeZoneId = TIME_ZONE_ID_INVALID;
369     BaseStaticServerData->TermsrvClientTimeZoneChangeNum = 0;
370     Status = NtQuerySystemInformation(SystemTimeOfDayInformation,
371                                       &BaseStaticServerData->TimeOfDay,
372                                       sizeof(BaseStaticServerData->TimeOfDay),
373                                       NULL);
374     ASSERT(NT_SUCCESS(Status));
375 
376     /* Make a shared heap copy of the Windows directory */
377     BaseStaticServerData->WindowsDirectory = BaseSrvWindowsDirectory;
378     HeapBuffer = RtlAllocateHeap(BaseSrvSharedHeap,
379                                  0,
380                                  BaseSrvWindowsDirectory.MaximumLength);
381     ASSERT(HeapBuffer);
382     RtlCopyMemory(HeapBuffer,
383                   BaseStaticServerData->WindowsDirectory.Buffer,
384                   BaseSrvWindowsDirectory.MaximumLength);
385     BaseStaticServerData->WindowsDirectory.Buffer = HeapBuffer;
386 
387     /* Make a shared heap copy of the System directory */
388     BaseStaticServerData->WindowsSystemDirectory = BaseSrvWindowsSystemDirectory;
389     HeapBuffer = RtlAllocateHeap(BaseSrvSharedHeap,
390                                  0,
391                                  BaseSrvWindowsSystemDirectory.MaximumLength);
392     ASSERT(HeapBuffer);
393     RtlCopyMemory(HeapBuffer,
394                   BaseStaticServerData->WindowsSystemDirectory.Buffer,
395                   BaseSrvWindowsSystemDirectory.MaximumLength);
396     BaseStaticServerData->WindowsSystemDirectory.Buffer = HeapBuffer;
397 
398     /* This string is not used */
399     RtlInitEmptyUnicodeString(&BaseStaticServerData->WindowsSys32x86Directory,
400                               NULL,
401                               0);
402 
403     /* Make a shared heap copy of the BNO directory */
404     BaseStaticServerData->NamedObjectDirectory = BnoString;
405     BaseStaticServerData->NamedObjectDirectory.MaximumLength = BnoString.Length +
406                                                                sizeof(UNICODE_NULL);
407     HeapBuffer = RtlAllocateHeap(BaseSrvSharedHeap,
408                                  0,
409                                  BaseStaticServerData->NamedObjectDirectory.MaximumLength);
410     ASSERT(HeapBuffer);
411     RtlCopyMemory(HeapBuffer,
412                   BaseStaticServerData->NamedObjectDirectory.Buffer,
413                   BaseStaticServerData->NamedObjectDirectory.MaximumLength);
414     BaseStaticServerData->NamedObjectDirectory.Buffer = HeapBuffer;
415 
416     /*
417      * Confirmed that in Windows, CSDNumber and RCNumber are actually Length
418      * and MaximumLength of the CSD String, since the same UNICODE_STRING is
419      * being queried twice, the first time as a ULONG!
420      *
421      * Somehow, in Windows this doesn't cause a buffer overflow, but it might
422      * in ReactOS, so this code is disabled until someone figures out WTF.
423      */
424     BaseStaticServerData->CSDNumber = 0;
425     BaseStaticServerData->RCNumber = 0;
426 
427     /* Initialize the CSD string and query its value from the registry */
428     RtlInitEmptyUnicodeString(&BaseSrvCSDString, Buffer, sizeof(Buffer));
429     Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
430                                     L"",
431                                     BaseServerRegistryConfigurationTable,
432                                     NULL,
433                                     NULL);
434     if (NT_SUCCESS(Status))
435     {
436         /* Copy into the shared buffer */
437         wcsncpy(BaseStaticServerData->CSDVersion,
438                 BaseSrvCSDString.Buffer,
439                 BaseSrvCSDString.Length / sizeof(WCHAR));
440     }
441     else
442     {
443         /* NULL-terminate to indicate nothing is there */
444         BaseStaticServerData->CSDVersion[0] = UNICODE_NULL;
445     }
446 
447     /* Cache the system information */
448     Status = NtQuerySystemInformation(SystemBasicInformation,
449                                       &BaseStaticServerData->SysInfo,
450                                       sizeof(BaseStaticServerData->SysInfo),
451                                       NULL);
452     ASSERT(NT_SUCCESS(Status));
453 
454     /* Setup the ini file mappings */
455     Status = BaseSrvInitializeIniFileMappings(BaseStaticServerData);
456     ASSERT(NT_SUCCESS(Status));
457 
458     /* FIXME: Should query the registry for these */
459     BaseStaticServerData->DefaultSeparateVDM = FALSE;
460     BaseStaticServerData->IsWowTaskReady = FALSE;
461 
462     /* Allocate a security descriptor and create it */
463     BnoSd = RtlAllocateHeap(BaseSrvHeap, 0, 1024);
464     ASSERT(BnoSd);
465     Status = RtlCreateSecurityDescriptor(BnoSd, SECURITY_DESCRIPTOR_REVISION);
466     ASSERT(NT_SUCCESS(Status));
467 
468     /* Create the BNO and \Restricted DACLs */
469     Status = CreateBaseAcls(&BnoDacl, &BnoRestrictedDacl);
470     ASSERT(NT_SUCCESS(Status));
471 
472     /* Set the BNO DACL as active for now */
473     Status = RtlSetDaclSecurityDescriptor(BnoSd, TRUE, BnoDacl, FALSE);
474     ASSERT(NT_SUCCESS(Status));
475 
476     /* Create the BNO directory */
477     RtlInitUnicodeString(&BnoString, L"\\BaseNamedObjects");
478     InitializeObjectAttributes(&ObjectAttributes,
479                                &BnoString,
480                                OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
481                                NULL,
482                                BnoSd);
483     Status = NtCreateDirectoryObject(&BaseSrvNamedObjectDirectory,
484                                      DIRECTORY_ALL_ACCESS,
485                                      &ObjectAttributes);
486     ASSERT(NT_SUCCESS(Status));
487 
488     /* Check if we are session 0 */
489     if (SessionId == 0)
490     {
491         /* Mark this as a session 0 directory */
492         Status = NtSetInformationObject(BaseSrvNamedObjectDirectory,
493                                         ObjectSessionInformation,
494                                         NULL,
495                                         0);
496         ASSERT(NT_SUCCESS(Status));
497     }
498 
499     /* Check if LUID device maps are enabled */
500     Status = NtQueryInformationProcess(NtCurrentProcess(),
501                                        ProcessLUIDDeviceMapsEnabled,
502                                        &LuidEnabled,
503                                        sizeof(LuidEnabled),
504                                        NULL);
505     ASSERT(NT_SUCCESS(Status));
506     BaseStaticServerData->LUIDDeviceMapsEnabled = (BOOLEAN)LuidEnabled;
507     if (!BaseStaticServerData->LUIDDeviceMapsEnabled)
508     {
509         /* Make Global point back to BNO */
510         RtlInitUnicodeString(&DirectoryName, L"Global");
511         RtlInitUnicodeString(&SymlinkName, L"\\BaseNamedObjects");
512         InitializeObjectAttributes(&ObjectAttributes,
513                                    &DirectoryName,
514                                    OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
515                                    BaseSrvNamedObjectDirectory,
516                                    BnoSd);
517         Status = NtCreateSymbolicLinkObject(&SymHandle,
518                                             SYMBOLIC_LINK_ALL_ACCESS,
519                                             &ObjectAttributes,
520                                             &SymlinkName);
521         if ((NT_SUCCESS(Status)) && SessionId == 0) NtClose(SymHandle);
522 
523         /* Make local point back to \Sessions\x\BNO */
524         RtlInitUnicodeString(&DirectoryName, L"Local");
525         ASSERT(SessionId == 0);
526         InitializeObjectAttributes(&ObjectAttributes,
527                                    &DirectoryName,
528                                    OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
529                                    BaseSrvNamedObjectDirectory,
530                                    BnoSd);
531         Status = NtCreateSymbolicLinkObject(&SymHandle,
532                                             SYMBOLIC_LINK_ALL_ACCESS,
533                                             &ObjectAttributes,
534                                             &SymlinkName);
535         if ((NT_SUCCESS(Status)) && SessionId == 0) NtClose(SymHandle);
536 
537         /* Make Session point back to BNOLINKS */
538         RtlInitUnicodeString(&DirectoryName, L"Session");
539         RtlInitUnicodeString(&SymlinkName, L"\\Sessions\\BNOLINKS");
540         InitializeObjectAttributes(&ObjectAttributes,
541                                    &DirectoryName,
542                                    OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
543                                    BaseSrvNamedObjectDirectory,
544                                    BnoSd);
545         Status = NtCreateSymbolicLinkObject(&SymHandle,
546                                             SYMBOLIC_LINK_ALL_ACCESS,
547                                             &ObjectAttributes,
548                                             &SymlinkName);
549         if ((NT_SUCCESS(Status)) && SessionId == 0) NtClose(SymHandle);
550 
551         /* Create the BNO\Restricted directory and set the restricted DACL */
552         RtlInitUnicodeString(&DirectoryName, L"Restricted");
553         Status = RtlSetDaclSecurityDescriptor(BnoSd, TRUE, BnoRestrictedDacl, FALSE);
554         ASSERT(NT_SUCCESS(Status));
555         InitializeObjectAttributes(&ObjectAttributes,
556                                    &DirectoryName,
557                                    OBJ_OPENIF | OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
558                                    BaseSrvNamedObjectDirectory,
559                                    BnoSd);
560         Status = NtCreateDirectoryObject(&BaseSrvRestrictedObjectDirectory,
561                                          DIRECTORY_ALL_ACCESS,
562                                          &ObjectAttributes);
563         ASSERT(NT_SUCCESS(Status));
564     }
565 
566     /* Initialize NLS */
567     BaseSrvNLSInit(BaseStaticServerData);
568 
569     /* Finally, set the pointer */
570     LoadedServerDll->SharedSection = BaseStaticServerData;
571 }
572 
573 VOID
574 NTAPI
575 BaseSrvDisconnect(PCSR_PROCESS Process)
576 {
577     /* Cleanup the VDM console records */
578     BaseSrvCleanupVdmRecords(HandleToUlong(Process->ClientId.UniqueProcess));
579 }
580 
581 CSR_SERVER_DLL_INIT(ServerDllInitialization)
582 {
583     /* Setup the DLL Object */
584     LoadedServerDll->ApiBase = BASESRV_FIRST_API_NUMBER;
585     LoadedServerDll->HighestApiSupported = BasepMaxApiNumber;
586     LoadedServerDll->DispatchTable = BaseServerApiDispatchTable;
587     LoadedServerDll->ValidTable = BaseServerApiServerValidTable;
588 #ifdef CSR_DBG
589     LoadedServerDll->NameTable = BaseServerApiNameTable;
590 #endif
591     LoadedServerDll->SizeOfProcessData = 0;
592     LoadedServerDll->ConnectCallback = NULL;
593     LoadedServerDll->DisconnectCallback = BaseSrvDisconnect;
594     LoadedServerDll->ShutdownProcessCallback = NULL;
595 
596     BaseSrvDllInstance = LoadedServerDll->ServerHandle;
597 
598     BaseInitializeStaticServerData(LoadedServerDll);
599 
600     /* Initialize DOS devices management */
601     BaseInitDefineDosDevice();
602 
603     /* Initialize VDM support */
604     BaseInitializeVDM();
605 
606     /* All done */
607     return STATUS_SUCCESS;
608 }
609 
610 BOOL
611 NTAPI
612 DllMain(IN HINSTANCE hInstanceDll,
613         IN DWORD dwReason,
614         IN LPVOID lpReserved)
615 {
616     UNREFERENCED_PARAMETER(hInstanceDll);
617     UNREFERENCED_PARAMETER(dwReason);
618     UNREFERENCED_PARAMETER(lpReserved);
619 
620     if (DLL_PROCESS_DETACH == dwReason)
621     {
622         BaseCleanupDefineDosDevice();
623     }
624 
625     return TRUE;
626 }
627 
628 /* EOF */
629