xref: /reactos/ntoskrnl/ob/obname.c (revision 3ad38f29)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS Kernel
3c2c66affSColin Finck  * LICENSE:         GPL - See COPYING in the top level directory
4c2c66affSColin Finck  * FILE:            ntoskrnl/ob/obname.c
5c2c66affSColin Finck  * PURPOSE:         Manages all functions related to the Object Manager name-
6c2c66affSColin Finck  *                  space, such as finding objects or querying their names.
7c2c66affSColin Finck  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
8c2c66affSColin Finck  *                  Eric Kohl
9c2c66affSColin Finck  *                  Thomas Weidenmueller (w3seek@reactos.org)
10c2c66affSColin Finck  */
11c2c66affSColin Finck 
12c2c66affSColin Finck /* INCLUDES ******************************************************************/
13c2c66affSColin Finck 
14c2c66affSColin Finck #include <ntoskrnl.h>
15c2c66affSColin Finck #define NDEBUG
16c2c66affSColin Finck #include <debug.h>
17c2c66affSColin Finck 
18c2c66affSColin Finck BOOLEAN ObpCaseInsensitive = TRUE;
19c2c66affSColin Finck POBJECT_DIRECTORY ObpRootDirectoryObject;
20c2c66affSColin Finck POBJECT_DIRECTORY ObpTypeDirectoryObject;
21c2c66affSColin Finck 
22c2c66affSColin Finck /* DOS Device Prefix \??\ and \?? */
23c2c66affSColin Finck ALIGNEDNAME ObpDosDevicesShortNamePrefix = {{L'\\',L'?',L'?',L'\\'}};
24c2c66affSColin Finck ALIGNEDNAME ObpDosDevicesShortNameRoot = {{L'\\',L'?',L'?',L'\0'}};
25c2c66affSColin Finck UNICODE_STRING ObpDosDevicesShortName =
26c2c66affSColin Finck {
27c2c66affSColin Finck     sizeof(ObpDosDevicesShortNamePrefix),
28c2c66affSColin Finck     sizeof(ObpDosDevicesShortNamePrefix),
29c2c66affSColin Finck     (PWSTR)&ObpDosDevicesShortNamePrefix
30c2c66affSColin Finck };
31c2c66affSColin Finck 
32b9423f07SPierre Schweitzer WCHAR ObpUnsecureGlobalNamesBuffer[128] = {0};
33b9423f07SPierre Schweitzer ULONG ObpUnsecureGlobalNamesLength = sizeof(ObpUnsecureGlobalNamesBuffer);
34b9423f07SPierre Schweitzer 
35c2c66affSColin Finck /* PRIVATE FUNCTIONS *********************************************************/
36c2c66affSColin Finck 
375c7ce447SVictor Perevertkin CODE_SEG("INIT")
38c2c66affSColin Finck NTSTATUS
39c2c66affSColin Finck NTAPI
4095d303bfSPierre Schweitzer ObpGetDosDevicesProtection(OUT PSECURITY_DESCRIPTOR SecurityDescriptor)
41c2c66affSColin Finck {
42c2c66affSColin Finck     PACL Dacl;
4395d303bfSPierre Schweitzer     ULONG AclSize;
441b42731dSPierre Schweitzer     NTSTATUS Status;
4595d303bfSPierre Schweitzer 
4695d303bfSPierre Schweitzer     /* Initialize the SD */
471b42731dSPierre Schweitzer     Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
481b42731dSPierre Schweitzer     ASSERT(NT_SUCCESS(Status));
49c2c66affSColin Finck 
5033f524c6SPierre Schweitzer     if (ObpProtectionMode & 1)
5133f524c6SPierre Schweitzer     {
52c2c66affSColin Finck         AclSize = sizeof(ACL) +
53c2c66affSColin Finck                   sizeof(ACE) + RtlLengthSid(SeWorldSid) +
54c2c66affSColin Finck                   sizeof(ACE) + RtlLengthSid(SeLocalSystemSid) +
55c2c66affSColin Finck                   sizeof(ACE) + RtlLengthSid(SeWorldSid) +
56c2c66affSColin Finck                   sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid) +
57c2c66affSColin Finck                   sizeof(ACE) + RtlLengthSid(SeLocalSystemSid) +
58c2c66affSColin Finck                   sizeof(ACE) + RtlLengthSid(SeCreatorOwnerSid);
59c2c66affSColin Finck 
6095d303bfSPierre Schweitzer         /* Allocate the ACL */
6195d303bfSPierre Schweitzer         Dacl = ExAllocatePoolWithTag(PagedPool, AclSize, 'lcaD');
6295d303bfSPierre Schweitzer         if (Dacl == NULL)
63c2c66affSColin Finck         {
64c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
65c2c66affSColin Finck         }
66c2c66affSColin Finck 
67c2c66affSColin Finck         /* Initialize the DACL */
681b42731dSPierre Schweitzer         Status = RtlCreateAcl(Dacl, AclSize, ACL_REVISION);
691b42731dSPierre Schweitzer         ASSERT(NT_SUCCESS(Status));
70c2c66affSColin Finck 
71c2c66affSColin Finck         /* Add the ACEs */
721b42731dSPierre Schweitzer         Status = RtlAddAccessAllowedAce(Dacl,
73c2c66affSColin Finck                                         ACL_REVISION,
74c2c66affSColin Finck                                         GENERIC_READ | GENERIC_EXECUTE,
75c2c66affSColin Finck                                         SeWorldSid);
761b42731dSPierre Schweitzer         ASSERT(NT_SUCCESS(Status));
77c2c66affSColin Finck 
781b42731dSPierre Schweitzer         Status = RtlAddAccessAllowedAce(Dacl,
79c2c66affSColin Finck                                         ACL_REVISION,
80c2c66affSColin Finck                                         GENERIC_ALL,
81c2c66affSColin Finck                                         SeLocalSystemSid);
821b42731dSPierre Schweitzer         ASSERT(NT_SUCCESS(Status));
83c2c66affSColin Finck 
841b42731dSPierre Schweitzer         Status = RtlAddAccessAllowedAceEx(Dacl,
85c2c66affSColin Finck                                           ACL_REVISION,
86c2c66affSColin Finck                                           INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
87c2c66affSColin Finck                                           GENERIC_EXECUTE,
88c2c66affSColin Finck                                           SeWorldSid);
891b42731dSPierre Schweitzer         ASSERT(NT_SUCCESS(Status));
90c2c66affSColin Finck 
911b42731dSPierre Schweitzer         Status = RtlAddAccessAllowedAceEx(Dacl,
92c2c66affSColin Finck                                           ACL_REVISION,
93c2c66affSColin Finck                                           INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
94c2c66affSColin Finck                                           GENERIC_ALL,
95c2c66affSColin Finck                                           SeAliasAdminsSid);
961b42731dSPierre Schweitzer         ASSERT(NT_SUCCESS(Status));
97c2c66affSColin Finck 
981b42731dSPierre Schweitzer         Status = RtlAddAccessAllowedAceEx(Dacl,
99c2c66affSColin Finck                                           ACL_REVISION,
100c2c66affSColin Finck                                           INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
101c2c66affSColin Finck                                           GENERIC_ALL,
102c2c66affSColin Finck                                           SeLocalSystemSid);
1031b42731dSPierre Schweitzer         ASSERT(NT_SUCCESS(Status));
104c2c66affSColin Finck 
1051b42731dSPierre Schweitzer         Status = RtlAddAccessAllowedAceEx(Dacl,
106c2c66affSColin Finck                                           ACL_REVISION,
107c2c66affSColin Finck                                           INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
108c2c66affSColin Finck                                           GENERIC_ALL,
109c2c66affSColin Finck                                           SeCreatorOwnerSid);
1101b42731dSPierre Schweitzer         ASSERT(NT_SUCCESS(Status));
11133f524c6SPierre Schweitzer     }
11233f524c6SPierre Schweitzer     else
11333f524c6SPierre Schweitzer     {
11433f524c6SPierre Schweitzer         AclSize = sizeof(ACL) +
11533f524c6SPierre Schweitzer                   sizeof(ACE) + RtlLengthSid(SeLocalSystemSid) +
11633f524c6SPierre Schweitzer                   sizeof(ACE) + RtlLengthSid(SeWorldSid) +
11733f524c6SPierre Schweitzer                   sizeof(ACE) + RtlLengthSid(SeLocalSystemSid);
11833f524c6SPierre Schweitzer 
11995d303bfSPierre Schweitzer         /* Allocate the ACL */
12095d303bfSPierre Schweitzer         Dacl = ExAllocatePoolWithTag(PagedPool, AclSize, 'lcaD');
12195d303bfSPierre Schweitzer         if (Dacl == NULL)
12233f524c6SPierre Schweitzer         {
12333f524c6SPierre Schweitzer             return STATUS_INSUFFICIENT_RESOURCES;
12433f524c6SPierre Schweitzer         }
12533f524c6SPierre Schweitzer 
12633f524c6SPierre Schweitzer         /* Initialize the DACL */
1271b42731dSPierre Schweitzer         Status = RtlCreateAcl(Dacl, AclSize, ACL_REVISION);
1281b42731dSPierre Schweitzer         ASSERT(NT_SUCCESS(Status));
12933f524c6SPierre Schweitzer 
13033f524c6SPierre Schweitzer         /* Add the ACEs */
1311b42731dSPierre Schweitzer         Status = RtlAddAccessAllowedAce(Dacl,
13233f524c6SPierre Schweitzer                                         ACL_REVISION,
13333f524c6SPierre Schweitzer                                         GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE,
13433f524c6SPierre Schweitzer                                         SeWorldSid);
1351b42731dSPierre Schweitzer         ASSERT(NT_SUCCESS(Status));
13633f524c6SPierre Schweitzer 
1371b42731dSPierre Schweitzer         Status = RtlAddAccessAllowedAce(Dacl,
13833f524c6SPierre Schweitzer                                         ACL_REVISION,
13933f524c6SPierre Schweitzer                                         GENERIC_ALL,
14033f524c6SPierre Schweitzer                                         SeLocalSystemSid);
1411b42731dSPierre Schweitzer         ASSERT(NT_SUCCESS(Status));
14233f524c6SPierre Schweitzer 
1431b42731dSPierre Schweitzer         Status = RtlAddAccessAllowedAceEx(Dacl,
14433f524c6SPierre Schweitzer                                           ACL_REVISION,
14533f524c6SPierre Schweitzer                                           INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
14633f524c6SPierre Schweitzer                                           GENERIC_ALL,
14733f524c6SPierre Schweitzer                                           SeWorldSid);
1481b42731dSPierre Schweitzer         ASSERT(NT_SUCCESS(Status));
14933f524c6SPierre Schweitzer     }
150c2c66affSColin Finck 
151c2c66affSColin Finck     /* Attach the DACL to the SD */
1521b42731dSPierre Schweitzer     Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE, Dacl, FALSE);
1531b42731dSPierre Schweitzer     ASSERT(NT_SUCCESS(Status));
154c2c66affSColin Finck 
15595d303bfSPierre Schweitzer     return STATUS_SUCCESS;
156c2c66affSColin Finck }
157c2c66affSColin Finck 
1585c7ce447SVictor Perevertkin CODE_SEG("INIT")
1598f655f94SPierre Schweitzer VOID
1608f655f94SPierre Schweitzer NTAPI
1618f655f94SPierre Schweitzer ObpFreeDosDevicesProtection(OUT PSECURITY_DESCRIPTOR SecurityDescriptor)
1628f655f94SPierre Schweitzer {
1638f655f94SPierre Schweitzer     PACL Dacl;
1648f655f94SPierre Schweitzer     NTSTATUS Status;
1658f655f94SPierre Schweitzer     BOOLEAN DaclPresent, DaclDefaulted;
1668f655f94SPierre Schweitzer 
1678f655f94SPierre Schweitzer     Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor, &DaclPresent, &Dacl, &DaclDefaulted);
1688f655f94SPierre Schweitzer     ASSERT(NT_SUCCESS(Status));
1698f655f94SPierre Schweitzer     ASSERT(DaclPresent);
1708f655f94SPierre Schweitzer     ASSERT(Dacl != NULL);
1718f655f94SPierre Schweitzer     ExFreePoolWithTag(Dacl, 'lcaD');
1728f655f94SPierre Schweitzer }
1738f655f94SPierre Schweitzer 
1745c7ce447SVictor Perevertkin CODE_SEG("INIT")
175c2c66affSColin Finck NTSTATUS
176c2c66affSColin Finck NTAPI
177c2c66affSColin Finck ObpCreateDosDevicesDirectory(VOID)
178c2c66affSColin Finck {
179c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
180c2c66affSColin Finck     UNICODE_STRING RootName, TargetName, LinkName;
181c2c66affSColin Finck     HANDLE Handle, SymHandle;
18295d303bfSPierre Schweitzer     SECURITY_DESCRIPTOR DosDevicesSD;
183c2c66affSColin Finck     NTSTATUS Status;
184c2c66affSColin Finck 
1857898b2eaSPierre Schweitzer     /*
1867898b2eaSPierre Schweitzer      * Enable LUID mappings only if not explicitely disabled
1877898b2eaSPierre Schweitzer      * and if protection mode is set
1887898b2eaSPierre Schweitzer      */
1897898b2eaSPierre Schweitzer     if (ObpProtectionMode == 0 || ObpLUIDDeviceMapsDisabled != 0)
1907898b2eaSPierre Schweitzer         ObpLUIDDeviceMapsEnabled = 0;
19133604e01SPierre Schweitzer     else
19233604e01SPierre Schweitzer         ObpLUIDDeviceMapsEnabled = 1;
1937898b2eaSPierre Schweitzer 
194c2c66affSColin Finck     /* Create a custom security descriptor for the global DosDevices directory */
19595d303bfSPierre Schweitzer     Status = ObpGetDosDevicesProtection(&DosDevicesSD);
196c2c66affSColin Finck     if (!NT_SUCCESS(Status))
197c2c66affSColin Finck         return Status;
198c2c66affSColin Finck 
199c2c66affSColin Finck     /* Create the global DosDevices directory \?? */
200c2c66affSColin Finck     RtlInitUnicodeString(&RootName, L"\\GLOBAL??");
201c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
202c2c66affSColin Finck                                &RootName,
203c2c66affSColin Finck                                OBJ_PERMANENT,
204c2c66affSColin Finck                                NULL,
20595d303bfSPierre Schweitzer                                &DosDevicesSD);
206c2c66affSColin Finck     Status = NtCreateDirectoryObject(&Handle,
207c2c66affSColin Finck                                      DIRECTORY_ALL_ACCESS,
208c2c66affSColin Finck                                      &ObjectAttributes);
209fe6c7f05SPierre Schweitzer     if (!NT_SUCCESS(Status))
210fe6c7f05SPierre Schweitzer         goto done;
211c2c66affSColin Finck 
212c2c66affSColin Finck     /* Create the system device map */
213933dddebSPierre Schweitzer     Status = ObSetDeviceMap(NULL, Handle);
214c2c66affSColin Finck     if (!NT_SUCCESS(Status))
215fe6c7f05SPierre Schweitzer         goto done;
216c2c66affSColin Finck 
217c2c66affSColin Finck     /*
218c2c66affSColin Finck      * Initialize the \??\GLOBALROOT symbolic link
219c2c66affSColin Finck      * pointing to the root directory \ .
220c2c66affSColin Finck      */
221c2c66affSColin Finck     RtlInitUnicodeString(&LinkName, L"GLOBALROOT");
222c2c66affSColin Finck     RtlInitUnicodeString(&TargetName, L"");
223c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
224c2c66affSColin Finck                                &LinkName,
225c2c66affSColin Finck                                OBJ_PERMANENT,
226c2c66affSColin Finck                                Handle,
227fe6c7f05SPierre Schweitzer                                &DosDevicesSD);
228c2c66affSColin Finck     Status = NtCreateSymbolicLinkObject(&SymHandle,
229c2c66affSColin Finck                                         SYMBOLIC_LINK_ALL_ACCESS,
230c2c66affSColin Finck                                         &ObjectAttributes,
231c2c66affSColin Finck                                         &TargetName);
232c2c66affSColin Finck     if (NT_SUCCESS(Status)) NtClose(SymHandle);
233c2c66affSColin Finck 
234c2c66affSColin Finck     /*
235c2c66affSColin Finck      * Initialize the \??\Global symbolic link pointing to the global
236c2c66affSColin Finck      * DosDevices directory \?? . It is used to access the global \??
237c2c66affSColin Finck      * by user-mode components which, by default, use a per-session
238c2c66affSColin Finck      * DosDevices directory.
239c2c66affSColin Finck      */
240c2c66affSColin Finck     RtlInitUnicodeString(&LinkName, L"Global");
241c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
242c2c66affSColin Finck                                &LinkName,
243c2c66affSColin Finck                                OBJ_PERMANENT,
244c2c66affSColin Finck                                Handle,
245fe6c7f05SPierre Schweitzer                                &DosDevicesSD);
246c2c66affSColin Finck     Status = NtCreateSymbolicLinkObject(&SymHandle,
247c2c66affSColin Finck                                         SYMBOLIC_LINK_ALL_ACCESS,
248c2c66affSColin Finck                                         &ObjectAttributes,
249c2c66affSColin Finck                                         &RootName);
250c2c66affSColin Finck     if (NT_SUCCESS(Status)) NtClose(SymHandle);
251c2c66affSColin Finck 
252c2c66affSColin Finck     /* Close the directory handle */
253c2c66affSColin Finck     NtClose(Handle);
254fe6c7f05SPierre Schweitzer     if (!NT_SUCCESS(Status))
255fe6c7f05SPierre Schweitzer         goto done;
256c2c66affSColin Finck 
257c2c66affSColin Finck     /*
258c2c66affSColin Finck      * Initialize the \DosDevices symbolic link pointing to the global
259c2c66affSColin Finck      * DosDevices directory \?? , for backward compatibility with
260c2c66affSColin Finck      * Windows NT-2000 systems.
261c2c66affSColin Finck      */
262*3ad38f29SJérôme Gardou     RtlInitUnicodeString(&LinkName, L"\\DosDevices");
263c2c66affSColin Finck     RtlInitUnicodeString(&RootName, (PCWSTR)&ObpDosDevicesShortNameRoot);
264c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
265c2c66affSColin Finck                                &LinkName,
266c2c66affSColin Finck                                OBJ_PERMANENT,
267c2c66affSColin Finck                                NULL,
268fe6c7f05SPierre Schweitzer                                &DosDevicesSD);
269c2c66affSColin Finck     Status = NtCreateSymbolicLinkObject(&SymHandle,
270c2c66affSColin Finck                                         SYMBOLIC_LINK_ALL_ACCESS,
271c2c66affSColin Finck                                         &ObjectAttributes,
272c2c66affSColin Finck                                         &RootName);
273c2c66affSColin Finck     if (NT_SUCCESS(Status)) NtClose(SymHandle);
274c2c66affSColin Finck 
275fe6c7f05SPierre Schweitzer done:
2768f655f94SPierre Schweitzer     ObpFreeDosDevicesProtection(&DosDevicesSD);
277fe6c7f05SPierre Schweitzer 
278c2c66affSColin Finck     /* Return status */
279c2c66affSColin Finck     return Status;
280c2c66affSColin Finck }
281c2c66affSColin Finck 
282c2c66affSColin Finck /*++
283c2c66affSColin Finck * @name ObpDeleteNameCheck
284c2c66affSColin Finck *
285c2c66affSColin Finck *     The ObpDeleteNameCheck routine checks if a named object should be
286c2c66affSColin Finck *     removed from the object directory namespace.
287c2c66affSColin Finck *
288c2c66affSColin Finck * @param Object
289c2c66affSColin Finck *        Pointer to the object to check for possible removal.
290c2c66affSColin Finck *
291c2c66affSColin Finck * @return None.
292c2c66affSColin Finck *
293c2c66affSColin Finck * @remarks An object is removed if the following 4 criteria are met:
294c2c66affSColin Finck *          1) The object has 0 handles open
295c2c66affSColin Finck *          2) The object is in the directory namespace and has a name
296c2c66affSColin Finck *          3) The object is not permanent
297c2c66affSColin Finck *
298c2c66affSColin Finck *--*/
299c2c66affSColin Finck VOID
300c2c66affSColin Finck NTAPI
301c2c66affSColin Finck ObpDeleteNameCheck(IN PVOID Object)
302c2c66affSColin Finck {
303c2c66affSColin Finck     POBJECT_HEADER ObjectHeader;
304c2c66affSColin Finck     OBP_LOOKUP_CONTEXT Context;
305c2c66affSColin Finck     POBJECT_HEADER_NAME_INFO ObjectNameInfo;
306c2c66affSColin Finck     POBJECT_TYPE ObjectType;
307c2c66affSColin Finck     PVOID Directory = NULL;
308c2c66affSColin Finck 
309c2c66affSColin Finck     /* Get object structures */
310c2c66affSColin Finck     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
311c2c66affSColin Finck     ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
312c2c66affSColin Finck     ObjectType = ObjectHeader->Type;
313c2c66affSColin Finck 
314c2c66affSColin Finck     /*
315c2c66affSColin Finck      * Check if the handle count is 0, if the object is named,
316c2c66affSColin Finck      * and if the object isn't a permanent object.
317c2c66affSColin Finck      */
318c2c66affSColin Finck     if (!(ObjectHeader->HandleCount) &&
319c2c66affSColin Finck          (ObjectNameInfo) &&
320c2c66affSColin Finck          (ObjectNameInfo->Name.Length) &&
321c2c66affSColin Finck          (ObjectNameInfo->Directory) &&
322c2c66affSColin Finck          !(ObjectHeader->Flags & OB_FLAG_PERMANENT))
323c2c66affSColin Finck     {
324c2c66affSColin Finck         /* Setup a lookup context */
325c2c66affSColin Finck         ObpInitializeLookupContext(&Context);
326c2c66affSColin Finck 
327c2c66affSColin Finck         /* Lock the directory */
328c2c66affSColin Finck         ObpAcquireDirectoryLockExclusive(ObjectNameInfo->Directory, &Context);
329c2c66affSColin Finck 
330c2c66affSColin Finck         /* Do the lookup */
331c2c66affSColin Finck         Object = ObpLookupEntryDirectory(ObjectNameInfo->Directory,
332c2c66affSColin Finck                                          &ObjectNameInfo->Name,
333c2c66affSColin Finck                                          0,
334c2c66affSColin Finck                                          FALSE,
335c2c66affSColin Finck                                          &Context);
336c2c66affSColin Finck         if (Object)
337c2c66affSColin Finck         {
338c2c66affSColin Finck             /* Lock the object */
339c2c66affSColin Finck             ObpAcquireObjectLock(ObjectHeader);
340c2c66affSColin Finck 
341c2c66affSColin Finck             /* Make sure we can still delete the object */
342c2c66affSColin Finck             if (!(ObjectHeader->HandleCount) &&
343c2c66affSColin Finck                 !(ObjectHeader->Flags & OB_FLAG_PERMANENT))
344c2c66affSColin Finck             {
345c2c66affSColin Finck                 /* First delete it from the directory */
346c2c66affSColin Finck                 ObpDeleteEntryDirectory(&Context);
347c2c66affSColin Finck 
348c2c66affSColin Finck                 /* Check if this is a symbolic link */
3492c909db2STimo Kreuzer                 if (ObjectType == ObpSymbolicLinkObjectType)
350c2c66affSColin Finck                 {
351c2c66affSColin Finck                     /* Remove internal name */
352c2c66affSColin Finck                     ObpDeleteSymbolicLinkName(Object);
353c2c66affSColin Finck                 }
354c2c66affSColin Finck 
355c2c66affSColin Finck                 /* Check if the kernel exclusive is set */
356c2c66affSColin Finck                 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
357c2c66affSColin Finck                 if ((ObjectNameInfo) &&
358c2c66affSColin Finck                     (ObjectNameInfo->QueryReferences & OB_FLAG_KERNEL_EXCLUSIVE))
359c2c66affSColin Finck                 {
360c2c66affSColin Finck                     /* Remove protection flag */
361c2c66affSColin Finck                     InterlockedExchangeAdd((PLONG)&ObjectNameInfo->QueryReferences,
362c2c66affSColin Finck                                            -OB_FLAG_KERNEL_EXCLUSIVE);
363c2c66affSColin Finck                 }
364c2c66affSColin Finck 
365c2c66affSColin Finck                 /* Get the directory */
366c2c66affSColin Finck                 Directory = ObjectNameInfo->Directory;
367c2c66affSColin Finck             }
368c2c66affSColin Finck 
369c2c66affSColin Finck             /* Release the lock */
370c2c66affSColin Finck             ObpReleaseObjectLock(ObjectHeader);
371c2c66affSColin Finck         }
372c2c66affSColin Finck 
373c2c66affSColin Finck         /* Cleanup after lookup */
374c2c66affSColin Finck         ObpReleaseLookupContext(&Context);
375c2c66affSColin Finck 
376c2c66affSColin Finck         /* Remove another query reference since we added one on top */
377c2c66affSColin Finck         ObpDereferenceNameInfo(ObjectNameInfo);
378c2c66affSColin Finck 
379c2c66affSColin Finck         /* Check if we were inserted in a directory */
380c2c66affSColin Finck         if (Directory)
381c2c66affSColin Finck         {
382c2c66affSColin Finck             /* We were, so first remove the extra reference we had added */
383c2c66affSColin Finck             ObpDereferenceNameInfo(ObjectNameInfo);
384c2c66affSColin Finck 
385c2c66affSColin Finck             /* Now dereference the object as well */
386c2c66affSColin Finck             ObDereferenceObject(Object);
387c2c66affSColin Finck         }
388c2c66affSColin Finck     }
389c2c66affSColin Finck     else
390c2c66affSColin Finck     {
391c2c66affSColin Finck         /* Remove the reference we added */
392c2c66affSColin Finck         ObpDereferenceNameInfo(ObjectNameInfo);
393c2c66affSColin Finck     }
394c2c66affSColin Finck }
395c2c66affSColin Finck 
3960f363535SPierre Schweitzer BOOLEAN
3970f363535SPierre Schweitzer NTAPI
3980f363535SPierre Schweitzer ObpIsUnsecureName(IN PUNICODE_STRING ObjectName,
3990f363535SPierre Schweitzer                   IN BOOLEAN CaseInSensitive)
4000f363535SPierre Schweitzer {
4010f363535SPierre Schweitzer     BOOLEAN Unsecure;
4020f363535SPierre Schweitzer     PWSTR UnsecureBuffer;
4030f363535SPierre Schweitzer     UNICODE_STRING UnsecureName;
4040f363535SPierre Schweitzer 
4050f363535SPierre Schweitzer     /* No unsecure names known, quit */
4060f363535SPierre Schweitzer     if (ObpUnsecureGlobalNamesBuffer[0] == UNICODE_NULL)
4070f363535SPierre Schweitzer     {
4080f363535SPierre Schweitzer         return FALSE;
4090f363535SPierre Schweitzer     }
4100f363535SPierre Schweitzer 
4110f363535SPierre Schweitzer     /* By default, we have a secure name */
4120f363535SPierre Schweitzer     Unsecure = FALSE;
4130f363535SPierre Schweitzer     /* We will browse the whole string */
4140f363535SPierre Schweitzer     UnsecureBuffer = &ObpUnsecureGlobalNamesBuffer[0];
4150f363535SPierre Schweitzer     while (TRUE)
4160f363535SPierre Schweitzer     {
4170f363535SPierre Schweitzer         /* Initialize the unicode string */
4180f363535SPierre Schweitzer         RtlInitUnicodeString(&UnsecureName, UnsecureBuffer);
4190f363535SPierre Schweitzer         /* We're at the end of the multisz string! */
4200f363535SPierre Schweitzer         if (UnsecureName.Length == 0)
4210f363535SPierre Schweitzer         {
4220f363535SPierre Schweitzer             break;
4230f363535SPierre Schweitzer         }
4240f363535SPierre Schweitzer 
4250f363535SPierre Schweitzer         /*
4260f363535SPierre Schweitzer          * Does the unsecure name prefix the object name?
4270f363535SPierre Schweitzer          * If so, that's an unsecure name, and return so
4280f363535SPierre Schweitzer          */
4290f363535SPierre Schweitzer         if (RtlPrefixUnicodeString(&UnsecureName, ObjectName, CaseInSensitive))
4300f363535SPierre Schweitzer         {
4310f363535SPierre Schweitzer             Unsecure = TRUE;
4320f363535SPierre Schweitzer             break;
4330f363535SPierre Schweitzer         }
4340f363535SPierre Schweitzer 
4350f363535SPierre Schweitzer         /*
4360f363535SPierre Schweitzer          * Move to the next string. As a reminder, ObpUnsecureGlobalNamesBuffer is
4370f363535SPierre Schweitzer          * a multisz, so we move the string next to the current UNICODE_NULL char
4380f363535SPierre Schweitzer          */
4390f363535SPierre Schweitzer         UnsecureBuffer = (PWSTR)((ULONG_PTR)UnsecureBuffer + UnsecureName.Length + sizeof(UNICODE_NULL));
4400f363535SPierre Schweitzer     }
4410f363535SPierre Schweitzer 
4420f363535SPierre Schweitzer     /* Return our findings */
4430f363535SPierre Schweitzer     return Unsecure;
4440f363535SPierre Schweitzer }
4450f363535SPierre Schweitzer 
446c2c66affSColin Finck NTSTATUS
447c2c66affSColin Finck NTAPI
448c2c66affSColin Finck ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL,
449c2c66affSColin Finck                     IN OUT PUNICODE_STRING ObjectName,
450c2c66affSColin Finck                     IN ULONG Attributes,
451c2c66affSColin Finck                     IN POBJECT_TYPE ObjectType,
452c2c66affSColin Finck                     IN KPROCESSOR_MODE AccessMode,
453c2c66affSColin Finck                     IN OUT PVOID ParseContext,
454c2c66affSColin Finck                     IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
455c2c66affSColin Finck                     IN PVOID InsertObject OPTIONAL,
456c2c66affSColin Finck                     IN OUT PACCESS_STATE AccessState,
457c2c66affSColin Finck                     OUT POBP_LOOKUP_CONTEXT LookupContext,
458c2c66affSColin Finck                     OUT PVOID *FoundObject)
459c2c66affSColin Finck {
460c2c66affSColin Finck     PVOID Object;
461c2c66affSColin Finck     POBJECT_HEADER ObjectHeader;
462c2c66affSColin Finck     UNICODE_STRING ComponentName, RemainingName;
463c2c66affSColin Finck     BOOLEAN Reparse = FALSE, SymLink = FALSE;
464c2c66affSColin Finck     POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory;
465c2c66affSColin Finck     POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL;
466c2c66affSColin Finck     KIRQL CalloutIrql;
467c2c66affSColin Finck     OB_PARSE_METHOD ParseRoutine;
468c2c66affSColin Finck     NTSTATUS Status;
469c2c66affSColin Finck     KPROCESSOR_MODE AccessCheckMode;
470c2c66affSColin Finck     PWCHAR NewName;
471c2c66affSColin Finck     POBJECT_HEADER_NAME_INFO ObjectNameInfo;
472c2c66affSColin Finck     ULONG MaxReparse = 30;
473f13b6e02SPierre Schweitzer     PDEVICE_MAP DeviceMap = NULL;
474f13b6e02SPierre Schweitzer     UNICODE_STRING LocalName;
475c2c66affSColin Finck     PAGED_CODE();
476c2c66affSColin Finck     OBTRACE(OB_NAMESPACE_DEBUG,
477c2c66affSColin Finck             "%s - Finding Object: %wZ. Expecting: %p\n",
478c2c66affSColin Finck             __FUNCTION__,
479c2c66affSColin Finck             ObjectName,
480c2c66affSColin Finck             InsertObject);
481c2c66affSColin Finck 
482c2c66affSColin Finck     /* Initialize starting state */
483c2c66affSColin Finck     ObpInitializeLookupContext(LookupContext);
484c2c66affSColin Finck     *FoundObject = NULL;
485c2c66affSColin Finck     Status = STATUS_SUCCESS;
486c2c66affSColin Finck     Object = NULL;
487c2c66affSColin Finck 
488c2c66affSColin Finck     /* Check if case-insensitivity is checked */
489c2c66affSColin Finck     if (ObpCaseInsensitive)
490c2c66affSColin Finck     {
491c2c66affSColin Finck         /* Check if the object type requests this */
492c2c66affSColin Finck         if (!(ObjectType) || (ObjectType->TypeInfo.CaseInsensitive))
493c2c66affSColin Finck         {
494c2c66affSColin Finck             /* Add the flag to disable case sensitivity */
495c2c66affSColin Finck             Attributes |= OBJ_CASE_INSENSITIVE;
496c2c66affSColin Finck         }
497c2c66affSColin Finck     }
498c2c66affSColin Finck 
499c2c66affSColin Finck     /* Check if this is a access checks are being forced */
500c2c66affSColin Finck     AccessCheckMode = (Attributes & OBJ_FORCE_ACCESS_CHECK) ?
501c2c66affSColin Finck                        UserMode : AccessMode;
502c2c66affSColin Finck 
503c2c66affSColin Finck     /* Check if we got a Root Directory */
504c2c66affSColin Finck     if (RootHandle)
505c2c66affSColin Finck     {
506c2c66affSColin Finck         /* We did. Reference it */
507c2c66affSColin Finck         Status = ObReferenceObjectByHandle(RootHandle,
508c2c66affSColin Finck                                            0,
509c2c66affSColin Finck                                            NULL,
510c2c66affSColin Finck                                            AccessMode,
511c2c66affSColin Finck                                            (PVOID*)&RootDirectory,
512c2c66affSColin Finck                                            NULL);
513c2c66affSColin Finck         if (!NT_SUCCESS(Status)) return Status;
514c2c66affSColin Finck 
515c2c66affSColin Finck         /* Get the header */
516c2c66affSColin Finck         ObjectHeader = OBJECT_TO_OBJECT_HEADER(RootDirectory);
517c2c66affSColin Finck 
518c2c66affSColin Finck         /* The name cannot start with a separator, unless this is a file */
519c2c66affSColin Finck         if ((ObjectName->Buffer) &&
520c2c66affSColin Finck             (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) &&
521c2c66affSColin Finck             (ObjectHeader->Type != IoFileObjectType))
522c2c66affSColin Finck         {
523c2c66affSColin Finck             /* The syntax is bad, so fail this request */
524c2c66affSColin Finck             ObDereferenceObject(RootDirectory);
525c2c66affSColin Finck             return STATUS_OBJECT_PATH_SYNTAX_BAD;
526c2c66affSColin Finck         }
527c2c66affSColin Finck 
528c2c66affSColin Finck         /* Don't parse a Directory */
5292c909db2STimo Kreuzer         if (ObjectHeader->Type != ObpDirectoryObjectType)
530c2c66affSColin Finck         {
531c2c66affSColin Finck             /* Make sure the Object Type has a parse routine */
532c2c66affSColin Finck             ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure;
533c2c66affSColin Finck             if (!ParseRoutine)
534c2c66affSColin Finck             {
535c2c66affSColin Finck                 /* We can't parse a name if we don't have a parse routine */
536c2c66affSColin Finck                 ObDereferenceObject(RootDirectory);
537c2c66affSColin Finck                 return STATUS_INVALID_HANDLE;
538c2c66affSColin Finck             }
539c2c66affSColin Finck 
540c2c66affSColin Finck             /* Set default parse count */
541c2c66affSColin Finck             MaxReparse = 30;
542c2c66affSColin Finck 
543c2c66affSColin Finck             /* Now parse */
544c2c66affSColin Finck             while (TRUE)
545c2c66affSColin Finck             {
546c2c66affSColin Finck                 /* Start with the full name */
547c2c66affSColin Finck                 RemainingName = *ObjectName;
548c2c66affSColin Finck 
549c2c66affSColin Finck                 /* Call the Parse Procedure */
550c2c66affSColin Finck                 ObpCalloutStart(&CalloutIrql);
551c2c66affSColin Finck                 Status = ParseRoutine(RootDirectory,
552c2c66affSColin Finck                                       ObjectType,
553c2c66affSColin Finck                                       AccessState,
554c2c66affSColin Finck                                       AccessCheckMode,
555c2c66affSColin Finck                                       Attributes,
556c2c66affSColin Finck                                       ObjectName,
557c2c66affSColin Finck                                       &RemainingName,
558c2c66affSColin Finck                                       ParseContext,
559c2c66affSColin Finck                                       SecurityQos,
560c2c66affSColin Finck                                       &Object);
561c2c66affSColin Finck                 ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
562c2c66affSColin Finck 
563c2c66affSColin Finck                 /* Check for success or failure, so not reparse */
564c2c66affSColin Finck                 if ((Status != STATUS_REPARSE) &&
565c2c66affSColin Finck                     (Status != STATUS_REPARSE_OBJECT))
566c2c66affSColin Finck                 {
567c2c66affSColin Finck                     /* Check for failure */
568c2c66affSColin Finck                     if (!NT_SUCCESS(Status))
569c2c66affSColin Finck                     {
570c2c66affSColin Finck                         /* Parse routine might not have cleared this, do it */
571c2c66affSColin Finck                         Object = NULL;
572c2c66affSColin Finck                     }
573c2c66affSColin Finck                     else if (!Object)
574c2c66affSColin Finck                     {
575c2c66affSColin Finck                         /* Modify status to reflect failure inside Ob */
576c2c66affSColin Finck                         Status = STATUS_OBJECT_NAME_NOT_FOUND;
577c2c66affSColin Finck                     }
578c2c66affSColin Finck 
579c2c66affSColin Finck                     /* We're done, return the status and object */
580c2c66affSColin Finck                     *FoundObject = Object;
581c2c66affSColin Finck                     ObDereferenceObject(RootDirectory);
582c2c66affSColin Finck                     return Status;
583c2c66affSColin Finck                 }
584c2c66affSColin Finck                 else if ((!ObjectName->Length) ||
585c2c66affSColin Finck                          (!ObjectName->Buffer) ||
586c2c66affSColin Finck                          (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
587c2c66affSColin Finck                 {
588c2c66affSColin Finck                     /* Reparsed to the root directory, so start over */
589c2c66affSColin Finck                     ObDereferenceObject(RootDirectory);
590c2c66affSColin Finck                     RootDirectory = ObpRootDirectoryObject;
591c2c66affSColin Finck 
592c2c66affSColin Finck                     /* Don't use this anymore, since we're starting at root */
593c2c66affSColin Finck                     RootHandle = NULL;
594c2c66affSColin Finck                     goto ParseFromRoot;
595c2c66affSColin Finck                 }
596c2c66affSColin Finck                 else if (--MaxReparse)
597c2c66affSColin Finck                 {
598c2c66affSColin Finck                     /* Try reparsing again */
599c2c66affSColin Finck                     continue;
600c2c66affSColin Finck                 }
601c2c66affSColin Finck                 else
602c2c66affSColin Finck                 {
603c2c66affSColin Finck                     /* Reparsed too many times */
604c2c66affSColin Finck                     ObDereferenceObject(RootDirectory);
605c2c66affSColin Finck 
606c2c66affSColin Finck                     /* Return the object and normalized status */
607c2c66affSColin Finck                     *FoundObject = Object;
608c2c66affSColin Finck                     if (!Object) Status = STATUS_OBJECT_NAME_NOT_FOUND;
609c2c66affSColin Finck                     return Status;
610c2c66affSColin Finck                 }
611c2c66affSColin Finck             }
612c2c66affSColin Finck         }
613c2c66affSColin Finck         else if (!(ObjectName->Length) || !(ObjectName->Buffer))
614c2c66affSColin Finck         {
615c2c66affSColin Finck             /* Just return the Root Directory if we didn't get a name */
616c2c66affSColin Finck             Status = ObReferenceObjectByPointer(RootDirectory,
617c2c66affSColin Finck                                                 0,
618c2c66affSColin Finck                                                 ObjectType,
619c2c66affSColin Finck                                                 AccessMode);
620c2c66affSColin Finck             if (NT_SUCCESS(Status)) Object = RootDirectory;
621c2c66affSColin Finck 
622c2c66affSColin Finck             /* Remove the first reference we added and return the object */
623c2c66affSColin Finck             ObDereferenceObject(RootDirectory);
624c2c66affSColin Finck             *FoundObject = Object;
625c2c66affSColin Finck             return Status;
626c2c66affSColin Finck         }
627f13b6e02SPierre Schweitzer 
628f13b6e02SPierre Schweitzer         LocalName = *ObjectName;
629c2c66affSColin Finck     }
630c2c66affSColin Finck     else
631c2c66affSColin Finck     {
632c2c66affSColin Finck         /* We did not get a Root Directory, so use the root */
633c2c66affSColin Finck         RootDirectory = ObpRootDirectoryObject;
634c2c66affSColin Finck 
635c2c66affSColin Finck         /* It must start with a path separator */
636c2c66affSColin Finck         if (!(ObjectName->Length) ||
637c2c66affSColin Finck             !(ObjectName->Buffer) ||
638c2c66affSColin Finck             (ObjectName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR))
639c2c66affSColin Finck         {
640c2c66affSColin Finck             /* This name is invalid, so fail */
641c2c66affSColin Finck             return STATUS_OBJECT_PATH_SYNTAX_BAD;
642c2c66affSColin Finck         }
643c2c66affSColin Finck 
644c2c66affSColin Finck         /* Check if the name is only the path separator */
645c2c66affSColin Finck         if (ObjectName->Length == sizeof(OBJ_NAME_PATH_SEPARATOR))
646c2c66affSColin Finck         {
647c2c66affSColin Finck             /* So the caller only wants the root directory; do we have one? */
648c2c66affSColin Finck             if (!RootDirectory)
649c2c66affSColin Finck             {
650c2c66affSColin Finck                 /* This must be the first time we're creating it... right? */
651c2c66affSColin Finck                 if (InsertObject)
652c2c66affSColin Finck                 {
653c2c66affSColin Finck                     /* Yes, so return it to ObInsert so that it can create it */
654c2c66affSColin Finck                     Status = ObReferenceObjectByPointer(InsertObject,
655c2c66affSColin Finck                                                         0,
656c2c66affSColin Finck                                                         ObjectType,
657c2c66affSColin Finck                                                         AccessMode);
658c2c66affSColin Finck                     if (NT_SUCCESS(Status)) *FoundObject = InsertObject;
659c2c66affSColin Finck                     return Status;
660c2c66affSColin Finck                 }
661c2c66affSColin Finck                 else
662c2c66affSColin Finck                 {
663c2c66affSColin Finck                     /* This should never really happen */
664c2c66affSColin Finck                     ASSERT(FALSE);
665c2c66affSColin Finck                     return STATUS_INVALID_PARAMETER;
666c2c66affSColin Finck                 }
667c2c66affSColin Finck             }
668c2c66affSColin Finck             else
669c2c66affSColin Finck             {
670c2c66affSColin Finck                 /* We do have the root directory, so just return it */
671c2c66affSColin Finck                 Status = ObReferenceObjectByPointer(RootDirectory,
672c2c66affSColin Finck                                                     0,
673c2c66affSColin Finck                                                     ObjectType,
674c2c66affSColin Finck                                                     AccessMode);
675c2c66affSColin Finck                 if (NT_SUCCESS(Status)) *FoundObject = RootDirectory;
676c2c66affSColin Finck                 return Status;
677c2c66affSColin Finck             }
678c2c66affSColin Finck         }
679c2c66affSColin Finck         else
680c2c66affSColin Finck         {
681c2c66affSColin Finck ParseFromRoot:
682f13b6e02SPierre Schweitzer             LocalName = *ObjectName;
683f13b6e02SPierre Schweitzer 
684f13b6e02SPierre Schweitzer             /* Deference the device map if we already have one */
685f13b6e02SPierre Schweitzer             if (DeviceMap != NULL)
686f13b6e02SPierre Schweitzer             {
687f13b6e02SPierre Schweitzer                 ObfDereferenceDeviceMap(DeviceMap);
688f13b6e02SPierre Schweitzer                 DeviceMap = NULL;
689f13b6e02SPierre Schweitzer             }
690c2c66affSColin Finck 
691c2c66affSColin Finck             /* Check if this is a possible DOS name */
692c2c66affSColin Finck             if (!((ULONG_PTR)(ObjectName->Buffer) & 7))
693c2c66affSColin Finck             {
694c2c66affSColin Finck                 /*
695c2c66affSColin Finck                  * This could be one. Does it match the prefix?
696c2c66affSColin Finck                  * Note that as an optimization, the match is done as 64-bit
697c2c66affSColin Finck                  * compare since the prefix is "\??\" which is exactly 8 bytes.
698c2c66affSColin Finck                  *
699c2c66affSColin Finck                  * In the second branch, we test for "\??" which is also valid.
700c2c66affSColin Finck                  * This time, we use a 32-bit compare followed by a Unicode
701c2c66affSColin Finck                  * character compare (16-bit), since the sum is 6 bytes.
702c2c66affSColin Finck                  */
703c2c66affSColin Finck                 if ((ObjectName->Length >= ObpDosDevicesShortName.Length) &&
704c2c66affSColin Finck                     (*(PULONGLONG)(ObjectName->Buffer) ==
705c2c66affSColin Finck                      ObpDosDevicesShortNamePrefix.Alignment.QuadPart))
706c2c66affSColin Finck                 {
707f13b6e02SPierre Schweitzer                     DeviceMap = ObpReferenceDeviceMap();
708f13b6e02SPierre Schweitzer                     /* We have a local mapping, drop the ?? prefix */
709f13b6e02SPierre Schweitzer                     if (DeviceMap != NULL && DeviceMap->DosDevicesDirectory != NULL)
710f13b6e02SPierre Schweitzer                     {
711f13b6e02SPierre Schweitzer                         LocalName.Length -= ObpDosDevicesShortName.Length;
712f13b6e02SPierre Schweitzer                         LocalName.MaximumLength -= ObpDosDevicesShortName.Length;
713f13b6e02SPierre Schweitzer                         LocalName.Buffer += (ObpDosDevicesShortName.Length / sizeof(WCHAR));
714f13b6e02SPierre Schweitzer 
715f13b6e02SPierre Schweitzer                         /* We'll browse that local directory */
716f13b6e02SPierre Schweitzer                         Directory = DeviceMap->DosDevicesDirectory;
717f13b6e02SPierre Schweitzer                     }
718c2c66affSColin Finck                 }
719c2c66affSColin Finck                 else if ((ObjectName->Length == ObpDosDevicesShortName.Length -
720c2c66affSColin Finck                                                 sizeof(WCHAR)) &&
721c2c66affSColin Finck                          (*(PULONG)(ObjectName->Buffer) ==
722c2c66affSColin Finck                           ObpDosDevicesShortNameRoot.Alignment.LowPart) &&
723c2c66affSColin Finck                          (*((PWCHAR)(ObjectName->Buffer) + 2) ==
724c2c66affSColin Finck                           (WCHAR)(ObpDosDevicesShortNameRoot.Alignment.HighPart)))
725c2c66affSColin Finck                 {
726f13b6e02SPierre Schweitzer                     DeviceMap = ObpReferenceDeviceMap();
727f13b6e02SPierre Schweitzer 
728f13b6e02SPierre Schweitzer                     /* Caller is looking for the directory itself */
729f13b6e02SPierre Schweitzer                     if (DeviceMap != NULL && DeviceMap->DosDevicesDirectory != NULL)
730f13b6e02SPierre Schweitzer                     {
731f13b6e02SPierre Schweitzer                         Status = ObReferenceObjectByPointer(DeviceMap->DosDevicesDirectory,
732f13b6e02SPierre Schweitzer                                                             0,
733f13b6e02SPierre Schweitzer                                                             ObjectType,
734f13b6e02SPierre Schweitzer                                                             AccessMode);
735f13b6e02SPierre Schweitzer                         if (NT_SUCCESS(Status))
736f13b6e02SPierre Schweitzer                         {
737f13b6e02SPierre Schweitzer                             *FoundObject = DeviceMap->DosDevicesDirectory;
738f13b6e02SPierre Schweitzer                         }
739f13b6e02SPierre Schweitzer 
740f13b6e02SPierre Schweitzer                         ObfDereferenceDeviceMap(DeviceMap);
741f13b6e02SPierre Schweitzer                         return Status;
742f13b6e02SPierre Schweitzer                     }
743c2c66affSColin Finck                 }
744c2c66affSColin Finck             }
745c2c66affSColin Finck         }
746c2c66affSColin Finck     }
747c2c66affSColin Finck 
748c2c66affSColin Finck     /* Check if we were reparsing a symbolic link */
749c2c66affSColin Finck     if (!SymLink)
750c2c66affSColin Finck     {
751c2c66affSColin Finck         /* Allow reparse */
752c2c66affSColin Finck         Reparse = TRUE;
753c2c66affSColin Finck         MaxReparse = 30;
754c2c66affSColin Finck     }
755c2c66affSColin Finck 
756c2c66affSColin Finck     /* Reparse */
757c2c66affSColin Finck     while (Reparse && MaxReparse)
758c2c66affSColin Finck     {
759c2c66affSColin Finck         /* Get the name */
760f13b6e02SPierre Schweitzer         RemainingName = LocalName;
761c2c66affSColin Finck 
762c2c66affSColin Finck         /* Disable reparsing again */
763c2c66affSColin Finck         Reparse = FALSE;
764c2c66affSColin Finck 
765c2c66affSColin Finck         /* Start parse loop */
766c2c66affSColin Finck         while (TRUE)
767c2c66affSColin Finck         {
768c2c66affSColin Finck             /* Clear object */
769c2c66affSColin Finck             Object = NULL;
770c2c66affSColin Finck 
771c2c66affSColin Finck             /* Check if the name starts with a path separator */
772c2c66affSColin Finck             if ((RemainingName.Length) &&
773c2c66affSColin Finck                 (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
774c2c66affSColin Finck             {
775c2c66affSColin Finck                 /* Skip the path separator */
776c2c66affSColin Finck                 RemainingName.Buffer++;
777c2c66affSColin Finck                 RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
778c2c66affSColin Finck             }
779c2c66affSColin Finck 
780c2c66affSColin Finck             /* Find the next Part Name */
781c2c66affSColin Finck             ComponentName = RemainingName;
782c2c66affSColin Finck             while (RemainingName.Length)
783c2c66affSColin Finck             {
784c2c66affSColin Finck                 /* Break if we found the \ ending */
785c2c66affSColin Finck                 if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break;
786c2c66affSColin Finck 
787c2c66affSColin Finck                 /* Move on */
788c2c66affSColin Finck                 RemainingName.Buffer++;
789c2c66affSColin Finck                 RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
790c2c66affSColin Finck             }
791c2c66affSColin Finck 
792c2c66affSColin Finck             /* Get its size and make sure it's valid */
793c2c66affSColin Finck             ComponentName.Length -= RemainingName.Length;
794c2c66affSColin Finck             if (!ComponentName.Length)
795c2c66affSColin Finck             {
796c2c66affSColin Finck                 /* Invalid size, fail */
797c2c66affSColin Finck                 Status = STATUS_OBJECT_NAME_INVALID;
798c2c66affSColin Finck                 break;
799c2c66affSColin Finck             }
800c2c66affSColin Finck 
801c2c66affSColin Finck             /* Check if we're in the root */
802c2c66affSColin Finck             if (!Directory) Directory = RootDirectory;
803c2c66affSColin Finck 
804c2c66affSColin Finck             /* Check if this is a user-mode call that needs to traverse */
805c2c66affSColin Finck             if ((AccessCheckMode != KernelMode) &&
806c2c66affSColin Finck                 !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
807c2c66affSColin Finck             {
808c2c66affSColin Finck                 /* We shouldn't have referenced a directory yet */
809c2c66affSColin Finck                 ASSERT(ReferencedDirectory == NULL);
810c2c66affSColin Finck 
811c2c66affSColin Finck                 /* Reference the directory */
812c2c66affSColin Finck                 ObReferenceObject(Directory);
813c2c66affSColin Finck                 ReferencedDirectory = Directory;
814c2c66affSColin Finck 
815c2c66affSColin Finck                 /* Check if we have a parent directory */
816c2c66affSColin Finck                 if (ParentDirectory)
817c2c66affSColin Finck                 {
818c2c66affSColin Finck                     /* Check for traverse access */
819c2c66affSColin Finck                     if (!ObpCheckTraverseAccess(ParentDirectory,
820c2c66affSColin Finck                                                 DIRECTORY_TRAVERSE,
821c2c66affSColin Finck                                                 AccessState,
822c2c66affSColin Finck                                                 FALSE,
823c2c66affSColin Finck                                                 AccessCheckMode,
824c2c66affSColin Finck                                                 &Status))
825c2c66affSColin Finck                     {
826c2c66affSColin Finck                         /* We don't have it, fail */
827c2c66affSColin Finck                         break;
828c2c66affSColin Finck                     }
829c2c66affSColin Finck                 }
830c2c66affSColin Finck             }
831c2c66affSColin Finck 
832c2c66affSColin Finck             /* Check if we don't have a remaining name yet */
833c2c66affSColin Finck             if (!RemainingName.Length)
834c2c66affSColin Finck             {
835c2c66affSColin Finck                 /* Check if we don't have a referenced directory yet */
836c2c66affSColin Finck                 if (!ReferencedDirectory)
837c2c66affSColin Finck                 {
838c2c66affSColin Finck                     /* Reference it */
839c2c66affSColin Finck                     ObReferenceObject(Directory);
840c2c66affSColin Finck                     ReferencedDirectory = Directory;
841c2c66affSColin Finck                 }
842c2c66affSColin Finck 
843c2c66affSColin Finck                 /* Check if we are inserting an object */
844c2c66affSColin Finck                 if (InsertObject)
845c2c66affSColin Finck                 {
846c2c66affSColin Finck                     /* Lock the directory */
847c2c66affSColin Finck                     ObpAcquireDirectoryLockExclusive(Directory, LookupContext);
848c2c66affSColin Finck                 }
849c2c66affSColin Finck             }
850c2c66affSColin Finck 
851c2c66affSColin Finck             /* Do the lookup */
852c2c66affSColin Finck             Object = ObpLookupEntryDirectory(Directory,
853c2c66affSColin Finck                                              &ComponentName,
854c2c66affSColin Finck                                              Attributes,
855c2c66affSColin Finck                                              InsertObject ? FALSE : TRUE,
856c2c66affSColin Finck                                              LookupContext);
857c2c66affSColin Finck             if (!Object)
858c2c66affSColin Finck             {
859c2c66affSColin Finck                 /* We didn't find it... do we still have a path? */
860c2c66affSColin Finck                 if (RemainingName.Length)
861c2c66affSColin Finck                 {
862c2c66affSColin Finck                     /* Then tell the caller the path wasn't found */
863c2c66affSColin Finck                     Status = STATUS_OBJECT_PATH_NOT_FOUND;
864c2c66affSColin Finck                     break;
865c2c66affSColin Finck                 }
866c2c66affSColin Finck                 else if (!InsertObject)
867c2c66affSColin Finck                 {
868c2c66affSColin Finck                     /* Otherwise, we have a path, but the name isn't valid */
869c2c66affSColin Finck                     Status = STATUS_OBJECT_NAME_NOT_FOUND;
870c2c66affSColin Finck                     break;
871c2c66affSColin Finck                 }
872c2c66affSColin Finck 
873c2c66affSColin Finck                 /* Check create access for the object */
874c2c66affSColin Finck                 if (!ObCheckCreateObjectAccess(Directory,
8752c909db2STimo Kreuzer                                                ObjectType == ObpDirectoryObjectType ?
876c2c66affSColin Finck                                                DIRECTORY_CREATE_SUBDIRECTORY :
877c2c66affSColin Finck                                                DIRECTORY_CREATE_OBJECT,
878c2c66affSColin Finck                                                AccessState,
879c2c66affSColin Finck                                                &ComponentName,
880c2c66affSColin Finck                                                FALSE,
881c2c66affSColin Finck                                                AccessCheckMode,
882c2c66affSColin Finck                                                &Status))
883c2c66affSColin Finck                 {
884c2c66affSColin Finck                     /* We don't have create access, fail */
885c2c66affSColin Finck                     break;
886c2c66affSColin Finck                 }
887c2c66affSColin Finck 
888c2c66affSColin Finck                 /* Get the object header */
889c2c66affSColin Finck                 ObjectHeader = OBJECT_TO_OBJECT_HEADER(InsertObject);
890c2c66affSColin Finck 
8919c603718SPierre Schweitzer                 /*
8929c603718SPierre Schweitzer                  * Deny object creation if:
8939c603718SPierre Schweitzer                  * That's a section object or a symbolic link
8949c603718SPierre Schweitzer                  * Which isn't in the same section that root directory
8959c603718SPierre Schweitzer                  * That doesn't have the SeCreateGlobalPrivilege
8969c603718SPierre Schweitzer                  * And that is not a known unsecure name
8979c603718SPierre Schweitzer                  */
8989c603718SPierre Schweitzer                 if (RootDirectory->SessionId != -1)
8999c603718SPierre Schweitzer                 {
9009c603718SPierre Schweitzer                     if (ObjectHeader->Type == MmSectionObjectType ||
9019c603718SPierre Schweitzer                         ObjectHeader->Type == ObpSymbolicLinkObjectType)
9029c603718SPierre Schweitzer                     {
9039c603718SPierre Schweitzer                         if (RootDirectory->SessionId != PsGetCurrentProcessSessionId() &&
9049c603718SPierre Schweitzer                             !SeSinglePrivilegeCheck(SeCreateGlobalPrivilege, AccessCheckMode) &&
9059c603718SPierre Schweitzer                             !ObpIsUnsecureName(&ComponentName, BooleanFlagOn(Attributes, OBJ_CASE_INSENSITIVE)))
9069c603718SPierre Schweitzer                         {
9079c603718SPierre Schweitzer                             Status = STATUS_ACCESS_DENIED;
9089c603718SPierre Schweitzer                             break;
9099c603718SPierre Schweitzer                         }
9109c603718SPierre Schweitzer                     }
9119c603718SPierre Schweitzer                 }
912c2c66affSColin Finck 
913c2c66affSColin Finck                 /* Create Object Name */
914c2c66affSColin Finck                 NewName = ExAllocatePoolWithTag(PagedPool,
915c2c66affSColin Finck                                                 ComponentName.Length,
916c2c66affSColin Finck                                                 OB_NAME_TAG);
917c2c66affSColin Finck                 if (!(NewName) ||
918c2c66affSColin Finck                     !(ObpInsertEntryDirectory(Directory,
919c2c66affSColin Finck                                               LookupContext,
920c2c66affSColin Finck                                               ObjectHeader)))
921c2c66affSColin Finck                 {
922c2c66affSColin Finck                     /* Either couldn't allocate the name, or insert failed */
923c2c66affSColin Finck                     if (NewName) ExFreePoolWithTag(NewName, OB_NAME_TAG);
924c2c66affSColin Finck 
925c2c66affSColin Finck                     /* Fail due to memory reasons */
926c2c66affSColin Finck                     Status = STATUS_INSUFFICIENT_RESOURCES;
927c2c66affSColin Finck                     break;
928c2c66affSColin Finck                 }
929c2c66affSColin Finck 
930c2c66affSColin Finck                 /* Reference newly to be inserted object */
931c2c66affSColin Finck                 ObReferenceObject(InsertObject);
932c2c66affSColin Finck 
933c2c66affSColin Finck                 /* Get the name information */
934c2c66affSColin Finck                 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
935c2c66affSColin Finck 
936c2c66affSColin Finck                 /* Reference the directory */
937c2c66affSColin Finck                 ObReferenceObject(Directory);
938c2c66affSColin Finck 
939c2c66affSColin Finck                 /* Copy the Name */
940c2c66affSColin Finck                 RtlCopyMemory(NewName,
941c2c66affSColin Finck                               ComponentName.Buffer,
942c2c66affSColin Finck                               ComponentName.Length);
943c2c66affSColin Finck 
944c2c66affSColin Finck                 /* Check if we had an old name */
945c2c66affSColin Finck                 if (ObjectNameInfo->Name.Buffer)
946c2c66affSColin Finck                 {
947c2c66affSColin Finck                     /* Free it */
948c2c66affSColin Finck                     ExFreePoolWithTag(ObjectNameInfo->Name.Buffer, OB_NAME_TAG);
949c2c66affSColin Finck                 }
950c2c66affSColin Finck 
951c2c66affSColin Finck                 /* Write new one */
952c2c66affSColin Finck                 ObjectNameInfo->Name.Buffer = NewName;
953c2c66affSColin Finck                 ObjectNameInfo->Name.Length = ComponentName.Length;
954c2c66affSColin Finck                 ObjectNameInfo->Name.MaximumLength = ComponentName.Length;
955c2c66affSColin Finck 
956c2c66affSColin Finck                 /* Return Status and the Expected Object */
957c2c66affSColin Finck                 Status = STATUS_SUCCESS;
958c2c66affSColin Finck                 Object = InsertObject;
959c2c66affSColin Finck 
960c2c66affSColin Finck                 /* Get out of here */
961c2c66affSColin Finck                 break;
962c2c66affSColin Finck             }
963c2c66affSColin Finck 
964c2c66affSColin Finck ReparseObject:
965c2c66affSColin Finck             /* We found it, so now get its header */
966c2c66affSColin Finck             ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
967c2c66affSColin Finck 
968c2c66affSColin Finck             /*
969c2c66affSColin Finck              * Check for a parse Procedure, but don't bother to parse for an insert
970c2c66affSColin Finck              * unless it's a Symbolic Link, in which case we MUST parse
971c2c66affSColin Finck              */
972c2c66affSColin Finck             ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure;
973c2c66affSColin Finck             if ((ParseRoutine) &&
974c2c66affSColin Finck                 (!(InsertObject) || (ParseRoutine == ObpParseSymbolicLink)))
975c2c66affSColin Finck             {
976c2c66affSColin Finck                 /* Use the Root Directory next time */
977c2c66affSColin Finck                 Directory = NULL;
978c2c66affSColin Finck 
979c2c66affSColin Finck                 /* Increment the pointer count */
980ff7cc6f3STimo Kreuzer                 InterlockedExchangeAddSizeT(&ObjectHeader->PointerCount, 1);
981c2c66affSColin Finck 
982c2c66affSColin Finck                 /* Cleanup from the first lookup */
983c2c66affSColin Finck                 ObpReleaseLookupContext(LookupContext);
984c2c66affSColin Finck 
985c2c66affSColin Finck                 /* Check if we have a referenced directory */
986c2c66affSColin Finck                 if (ReferencedDirectory)
987c2c66affSColin Finck                 {
988c2c66affSColin Finck                     /* We do, dereference it */
989c2c66affSColin Finck                     ObDereferenceObject(ReferencedDirectory);
990c2c66affSColin Finck                     ReferencedDirectory = NULL;
991c2c66affSColin Finck                 }
992c2c66affSColin Finck 
993c2c66affSColin Finck                 /* Check if we have a referenced parent directory */
994c2c66affSColin Finck                 if (ReferencedParentDirectory)
995c2c66affSColin Finck                 {
996c2c66affSColin Finck                     /* We do, dereference it */
997c2c66affSColin Finck                     ObDereferenceObject(ReferencedParentDirectory);
998c2c66affSColin Finck                     ReferencedParentDirectory = NULL;
999c2c66affSColin Finck                 }
1000c2c66affSColin Finck 
1001c2c66affSColin Finck                 /* Call the Parse Procedure */
1002c2c66affSColin Finck                 ObpCalloutStart(&CalloutIrql);
1003c2c66affSColin Finck                 Status = ParseRoutine(Object,
1004c2c66affSColin Finck                                       ObjectType,
1005c2c66affSColin Finck                                       AccessState,
1006c2c66affSColin Finck                                       AccessCheckMode,
1007c2c66affSColin Finck                                       Attributes,
1008c2c66affSColin Finck                                       ObjectName,
1009c2c66affSColin Finck                                       &RemainingName,
1010c2c66affSColin Finck                                       ParseContext,
1011c2c66affSColin Finck                                       SecurityQos,
1012c2c66affSColin Finck                                       &Object);
1013c2c66affSColin Finck                 ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
1014c2c66affSColin Finck 
1015c2c66affSColin Finck                 /* Remove our extra reference */
1016c2c66affSColin Finck                 ObDereferenceObject(&ObjectHeader->Body);
1017c2c66affSColin Finck 
1018c2c66affSColin Finck                 /* Check if we have to reparse */
1019c2c66affSColin Finck                 if ((Status == STATUS_REPARSE) ||
1020c2c66affSColin Finck                     (Status == STATUS_REPARSE_OBJECT))
1021c2c66affSColin Finck                 {
1022c2c66affSColin Finck                     /* Reparse again */
1023c2c66affSColin Finck                     Reparse = TRUE;
1024c2c66affSColin Finck                     --MaxReparse;
1025c2c66affSColin Finck                     if (MaxReparse == 0)
1026c2c66affSColin Finck                     {
1027c2c66affSColin Finck                         Object = NULL;
1028c2c66affSColin Finck                         break;
1029c2c66affSColin Finck                     }
1030c2c66affSColin Finck 
1031c2c66affSColin Finck                     /* Start over from root if we got sent back there */
1032c2c66affSColin Finck                     if ((Status == STATUS_REPARSE_OBJECT) ||
1033c2c66affSColin Finck                         (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
1034c2c66affSColin Finck                     {
1035c2c66affSColin Finck                         /* Check if we got a root directory */
1036c2c66affSColin Finck                         if (RootHandle)
1037c2c66affSColin Finck                         {
1038c2c66affSColin Finck                             /* Stop using it, because we have a new directory now */
1039c2c66affSColin Finck                             ObDereferenceObject(RootDirectory);
1040c2c66affSColin Finck                             RootHandle = NULL;
1041c2c66affSColin Finck                         }
1042c2c66affSColin Finck 
1043c2c66affSColin Finck                         /* Start at Root */
1044c2c66affSColin Finck                         ParentDirectory = NULL;
1045c2c66affSColin Finck                         RootDirectory = ObpRootDirectoryObject;
1046c2c66affSColin Finck 
1047c2c66affSColin Finck                         /* Check for reparse status */
1048c2c66affSColin Finck                         if (Status == STATUS_REPARSE_OBJECT)
1049c2c66affSColin Finck                         {
1050c2c66affSColin Finck                             /* Don't reparse again */
1051c2c66affSColin Finck                             Reparse = FALSE;
1052c2c66affSColin Finck 
1053c2c66affSColin Finck                             /* Did we actually get an object to which to reparse? */
1054c2c66affSColin Finck                             if (!Object)
1055c2c66affSColin Finck                             {
1056c2c66affSColin Finck                                 /* We didn't, so set a failure status */
1057c2c66affSColin Finck                                 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1058c2c66affSColin Finck                             }
1059c2c66affSColin Finck                             else
1060c2c66affSColin Finck                             {
1061c2c66affSColin Finck                                 /* We did, so we're free to parse the new object */
1062c2c66affSColin Finck                                 goto ReparseObject;
1063c2c66affSColin Finck                             }
1064c2c66affSColin Finck                         }
1065c2c66affSColin Finck                         else
1066c2c66affSColin Finck                         {
1067c2c66affSColin Finck                             /* This is a symbolic link */
1068c2c66affSColin Finck                             SymLink = TRUE;
1069c2c66affSColin Finck                             goto ParseFromRoot;
1070c2c66affSColin Finck                         }
1071c2c66affSColin Finck                     }
1072c2c66affSColin Finck                     else if (RootDirectory == ObpRootDirectoryObject)
1073c2c66affSColin Finck                     {
1074c2c66affSColin Finck                         /* We got STATUS_REPARSE but are at the Root Directory */
1075c2c66affSColin Finck                         Object = NULL;
1076c2c66affSColin Finck                         Status = STATUS_OBJECT_NAME_NOT_FOUND;
1077c2c66affSColin Finck                         Reparse = FALSE;
1078c2c66affSColin Finck                     }
1079c2c66affSColin Finck                 }
1080c2c66affSColin Finck                 else if (!NT_SUCCESS(Status))
1081c2c66affSColin Finck                 {
1082c2c66affSColin Finck                     /* Total failure */
1083c2c66affSColin Finck                     Object = NULL;
1084c2c66affSColin Finck                 }
1085c2c66affSColin Finck                 else if (!Object)
1086c2c66affSColin Finck                 {
1087c2c66affSColin Finck                     /* We didn't reparse but we didn't find the Object Either */
1088c2c66affSColin Finck                     Status = STATUS_OBJECT_NAME_NOT_FOUND;
1089c2c66affSColin Finck                 }
1090c2c66affSColin Finck 
1091c2c66affSColin Finck                 /* Break out of the loop */
1092c2c66affSColin Finck                 break;
1093c2c66affSColin Finck             }
1094c2c66affSColin Finck             else
1095c2c66affSColin Finck             {
1096c2c66affSColin Finck                 /* No parse routine...do we still have a remaining name? */
1097c2c66affSColin Finck                 if (!RemainingName.Length)
1098c2c66affSColin Finck                 {
1099c2c66affSColin Finck                     /* Are we creating an object? */
1100c2c66affSColin Finck                     if (!InsertObject)
1101c2c66affSColin Finck                     {
1102c2c66affSColin Finck                         /* Check if this is a user-mode call that needs to traverse */
1103c2c66affSColin Finck                         if ((AccessCheckMode != KernelMode) &&
1104c2c66affSColin Finck                             !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
1105c2c66affSColin Finck                         {
1106c2c66affSColin Finck                             /* Check if we can get it */
1107c2c66affSColin Finck                             if (!ObpCheckTraverseAccess(Directory,
1108c2c66affSColin Finck                                                         DIRECTORY_TRAVERSE,
1109c2c66affSColin Finck                                                         AccessState,
1110c2c66affSColin Finck                                                         FALSE,
1111c2c66affSColin Finck                                                         AccessCheckMode,
1112c2c66affSColin Finck                                                         &Status))
1113c2c66affSColin Finck                             {
1114c2c66affSColin Finck                                 /* We don't have access, fail */
1115c2c66affSColin Finck                                 Object = NULL;
1116c2c66affSColin Finck                                 break;
1117c2c66affSColin Finck                             }
1118c2c66affSColin Finck                         }
1119c2c66affSColin Finck 
1120c2c66affSColin Finck                         /* Reference the Object */
1121c2c66affSColin Finck                         Status = ObReferenceObjectByPointer(Object,
1122c2c66affSColin Finck                                                             0,
1123c2c66affSColin Finck                                                             ObjectType,
1124c2c66affSColin Finck                                                             AccessMode);
1125c2c66affSColin Finck                         if (!NT_SUCCESS(Status)) Object = NULL;
1126c2c66affSColin Finck                     }
1127c2c66affSColin Finck 
1128c2c66affSColin Finck                     /* And get out of the reparse loop */
1129c2c66affSColin Finck                     break;
1130c2c66affSColin Finck                 }
1131c2c66affSColin Finck                 else
1132c2c66affSColin Finck                 {
1133c2c66affSColin Finck                     /* We still have a name; check if this is a directory object */
11342c909db2STimo Kreuzer                     if (ObjectHeader->Type == ObpDirectoryObjectType)
1135c2c66affSColin Finck                     {
1136c2c66affSColin Finck                         /* Check if we have a referenced parent directory */
1137c2c66affSColin Finck                         if (ReferencedParentDirectory)
1138c2c66affSColin Finck                         {
1139c2c66affSColin Finck                             /* Dereference it */
1140c2c66affSColin Finck                             ObDereferenceObject(ReferencedParentDirectory);
1141c2c66affSColin Finck                         }
1142c2c66affSColin Finck 
1143c2c66affSColin Finck                         /* Restart the lookup from this directory */
1144c2c66affSColin Finck                         ReferencedParentDirectory = ReferencedDirectory;
1145c2c66affSColin Finck                         ParentDirectory = Directory;
1146c2c66affSColin Finck                         Directory = Object;
1147c2c66affSColin Finck                         ReferencedDirectory = NULL;
1148c2c66affSColin Finck                     }
1149c2c66affSColin Finck                     else
1150c2c66affSColin Finck                     {
1151c2c66affSColin Finck                         /* We still have a name, but no parse routine for it */
1152c2c66affSColin Finck                         Status = STATUS_OBJECT_TYPE_MISMATCH;
1153c2c66affSColin Finck                         Object = NULL;
1154c2c66affSColin Finck                         break;
1155c2c66affSColin Finck                     }
1156c2c66affSColin Finck                 }
1157c2c66affSColin Finck             }
1158c2c66affSColin Finck         }
1159c2c66affSColin Finck     }
1160c2c66affSColin Finck 
1161c2c66affSColin Finck     /* Check if we failed */
1162c2c66affSColin Finck     if (!NT_SUCCESS(Status))
1163c2c66affSColin Finck     {
1164c2c66affSColin Finck         /* Cleanup after lookup */
1165c2c66affSColin Finck         ObpReleaseLookupContext(LookupContext);
1166c2c66affSColin Finck     }
1167c2c66affSColin Finck 
1168c2c66affSColin Finck     /* Check if we have a device map and dereference it if so */
1169f13b6e02SPierre Schweitzer     if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
1170c2c66affSColin Finck 
1171c2c66affSColin Finck     /* Check if we have a referenced directory and dereference it if so */
1172c2c66affSColin Finck     if (ReferencedDirectory) ObDereferenceObject(ReferencedDirectory);
1173c2c66affSColin Finck 
1174c2c66affSColin Finck     /* Check if we have a referenced parent directory */
1175c2c66affSColin Finck     if (ReferencedParentDirectory)
1176c2c66affSColin Finck     {
1177c2c66affSColin Finck         /* We do, dereference it */
1178c2c66affSColin Finck         ObDereferenceObject(ReferencedParentDirectory);
1179c2c66affSColin Finck     }
1180c2c66affSColin Finck 
1181c2c66affSColin Finck     /* Set the found object and check if we got one */
1182c2c66affSColin Finck     *FoundObject = Object;
1183c2c66affSColin Finck     if (!Object)
1184c2c66affSColin Finck     {
1185c2c66affSColin Finck         /* Nothing was found. Did we reparse or get success? */
1186c2c66affSColin Finck         if ((Status == STATUS_REPARSE) || (NT_SUCCESS(Status)))
1187c2c66affSColin Finck         {
1188c2c66affSColin Finck             /* Set correct failure */
1189c2c66affSColin Finck             Status = STATUS_OBJECT_NAME_NOT_FOUND;
1190c2c66affSColin Finck         }
1191c2c66affSColin Finck     }
1192c2c66affSColin Finck 
1193c2c66affSColin Finck     /* Check if we had a root directory */
1194c2c66affSColin Finck     if (RootHandle) ObDereferenceObject(RootDirectory);
1195c2c66affSColin Finck 
1196c2c66affSColin Finck     /* Return status to caller */
1197c2c66affSColin Finck     OBTRACE(OB_NAMESPACE_DEBUG,
1198c2c66affSColin Finck             "%s - Found Object: %p. Expected: %p\n",
1199c2c66affSColin Finck             __FUNCTION__,
1200c2c66affSColin Finck             *FoundObject,
1201c2c66affSColin Finck             InsertObject);
1202c2c66affSColin Finck     return Status;
1203c2c66affSColin Finck }
1204c2c66affSColin Finck 
1205c2c66affSColin Finck /* PUBLIC FUNCTIONS *********************************************************/
1206c2c66affSColin Finck 
1207c2c66affSColin Finck NTSTATUS
1208c2c66affSColin Finck NTAPI
1209c2c66affSColin Finck ObQueryNameString(IN PVOID Object,
1210c2c66affSColin Finck                   OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1211c2c66affSColin Finck                   IN ULONG Length,
1212c2c66affSColin Finck                   OUT PULONG ReturnLength)
1213c2c66affSColin Finck {
1214c2c66affSColin Finck     POBJECT_HEADER_NAME_INFO LocalInfo;
1215c2c66affSColin Finck     POBJECT_HEADER ObjectHeader;
1216c2c66affSColin Finck     POBJECT_DIRECTORY ParentDirectory;
1217c2c66affSColin Finck     ULONG NameSize;
1218c2c66affSColin Finck     PWCH ObjectName;
1219c2c66affSColin Finck     BOOLEAN ObjectIsNamed;
1220c2c66affSColin Finck     NTSTATUS Status = STATUS_SUCCESS;
1221c2c66affSColin Finck 
1222c2c66affSColin Finck     /* Get the Kernel Meta-Structures */
1223c2c66affSColin Finck     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1224c2c66affSColin Finck     LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
1225c2c66affSColin Finck 
1226c2c66affSColin Finck     /* Check if a Query Name Procedure is available */
1227c2c66affSColin Finck     if (ObjectHeader->Type->TypeInfo.QueryNameProcedure)
1228c2c66affSColin Finck     {
1229c2c66affSColin Finck         /* Call the procedure inside SEH */
1230c2c66affSColin Finck         ObjectIsNamed = ((LocalInfo) && (LocalInfo->Name.Length > 0));
1231c2c66affSColin Finck 
1232c2c66affSColin Finck         _SEH2_TRY
1233c2c66affSColin Finck         {
1234c2c66affSColin Finck             Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object,
1235c2c66affSColin Finck                                                                ObjectIsNamed,
1236c2c66affSColin Finck                                                                ObjectNameInfo,
1237c2c66affSColin Finck                                                                Length,
1238c2c66affSColin Finck                                                                ReturnLength,
1239c2c66affSColin Finck                                                                KernelMode);
1240c2c66affSColin Finck         }
1241c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1242c2c66affSColin Finck         {
1243c2c66affSColin Finck             /* Return the exception code */
1244c2c66affSColin Finck             Status = _SEH2_GetExceptionCode();
1245c2c66affSColin Finck         }
1246c2c66affSColin Finck         _SEH2_END;
1247c2c66affSColin Finck 
1248c2c66affSColin Finck         return Status;
1249c2c66affSColin Finck     }
1250c2c66affSColin Finck 
1251c2c66affSColin Finck     /* Check if the object doesn't even have a name */
1252c2c66affSColin Finck     if (!(LocalInfo) || !(LocalInfo->Name.Buffer))
1253c2c66affSColin Finck     {
1254c2c66affSColin Finck         Status = STATUS_SUCCESS;
1255c2c66affSColin Finck 
1256c2c66affSColin Finck         _SEH2_TRY
1257c2c66affSColin Finck         {
1258c2c66affSColin Finck             /* We're returning the name structure */
1259c2c66affSColin Finck             *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
1260c2c66affSColin Finck 
1261c2c66affSColin Finck             /* Check if we were given enough space */
1262c2c66affSColin Finck             if (*ReturnLength > Length)
1263c2c66affSColin Finck             {
1264c2c66affSColin Finck                 Status = STATUS_INFO_LENGTH_MISMATCH;
1265c2c66affSColin Finck             }
1266c2c66affSColin Finck             else
1267c2c66affSColin Finck             {
1268c2c66affSColin Finck                 /* Return an empty buffer */
1269c2c66affSColin Finck                 RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0);
1270c2c66affSColin Finck             }
1271c2c66affSColin Finck         }
1272c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1273c2c66affSColin Finck         {
1274c2c66affSColin Finck             /* Return the exception code */
1275c2c66affSColin Finck             Status = _SEH2_GetExceptionCode();
1276c2c66affSColin Finck         }
1277c2c66affSColin Finck         _SEH2_END;
1278c2c66affSColin Finck 
1279c2c66affSColin Finck         return Status;
1280c2c66affSColin Finck     }
1281c2c66affSColin Finck 
1282c2c66affSColin Finck     /*
1283c2c66affSColin Finck      * Find the size needed for the name. We won't do
1284c2c66affSColin Finck      * this during the Name Creation loop because we want
1285c2c66affSColin Finck      * to let the caller know that the buffer isn't big
1286c2c66affSColin Finck      * enough right at the beginning, not work our way through
1287c2c66affSColin Finck      * and find out at the end
1288c2c66affSColin Finck      */
1289c2c66affSColin Finck     _SEH2_TRY
1290c2c66affSColin Finck     {
1291c2c66affSColin Finck         if (Object == ObpRootDirectoryObject)
1292c2c66affSColin Finck         {
1293c2c66affSColin Finck             /* Size of the '\' string */
1294c2c66affSColin Finck             NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR);
1295c2c66affSColin Finck         }
1296c2c66affSColin Finck         else
1297c2c66affSColin Finck         {
1298c2c66affSColin Finck             /* Get the Object Directory and add name of Object */
1299c2c66affSColin Finck             ParentDirectory = LocalInfo->Directory;
1300c2c66affSColin Finck             NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length;
1301c2c66affSColin Finck 
1302c2c66affSColin Finck             /* Loop inside the directory to get the top-most one (meaning root) */
1303c2c66affSColin Finck             while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory))
1304c2c66affSColin Finck             {
1305c2c66affSColin Finck                 /* Get the Name Information */
1306c2c66affSColin Finck                 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
1307c2c66affSColin Finck                     OBJECT_TO_OBJECT_HEADER(ParentDirectory));
1308c2c66affSColin Finck 
1309c2c66affSColin Finck                 /* Add the size of the Directory Name */
1310c2c66affSColin Finck                 if (LocalInfo && LocalInfo->Directory)
1311c2c66affSColin Finck                 {
1312c2c66affSColin Finck                     /* Size of the '\' string + Directory Name */
1313c2c66affSColin Finck                     NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) +
1314c2c66affSColin Finck                                 LocalInfo->Name.Length;
1315c2c66affSColin Finck 
1316c2c66affSColin Finck                     /* Move to next parent Directory */
1317c2c66affSColin Finck                     ParentDirectory = LocalInfo->Directory;
1318c2c66affSColin Finck                 }
1319c2c66affSColin Finck                 else
1320c2c66affSColin Finck                 {
1321c2c66affSColin Finck                     /* Directory with no name. We append "...\" */
1322c2c66affSColin Finck                     NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR);
1323c2c66affSColin Finck                     break;
1324c2c66affSColin Finck                 }
1325c2c66affSColin Finck             }
1326c2c66affSColin Finck         }
1327c2c66affSColin Finck 
1328c2c66affSColin Finck         /* Finally, add the name of the structure and the null char */
1329c2c66affSColin Finck         *ReturnLength = NameSize +
1330c2c66affSColin Finck                         sizeof(OBJECT_NAME_INFORMATION) +
1331c2c66affSColin Finck                         sizeof(UNICODE_NULL);
1332c2c66affSColin Finck 
1333c2c66affSColin Finck         /* Check if we were given enough space */
1334c2c66affSColin Finck         if (*ReturnLength > Length) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH);
1335c2c66affSColin Finck 
1336c2c66affSColin Finck         /*
1337c2c66affSColin Finck         * Now we will actually create the name. We work backwards because
1338c2c66affSColin Finck         * it's easier to start off from the Name we have and walk up the
1339c2c66affSColin Finck         * parent directories. We use the same logic as Name Length calculation.
1340c2c66affSColin Finck         */
1341c2c66affSColin Finck         LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
1342c2c66affSColin Finck         ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength);
1343c2c66affSColin Finck         *--ObjectName = UNICODE_NULL;
1344c2c66affSColin Finck 
1345c2c66affSColin Finck         /* Check if the object is actually the Root directory */
1346c2c66affSColin Finck         if (Object == ObpRootDirectoryObject)
1347c2c66affSColin Finck         {
1348c2c66affSColin Finck             /* This is already the Root Directory, return "\\" */
1349c2c66affSColin Finck             *--ObjectName = OBJ_NAME_PATH_SEPARATOR;
1350c2c66affSColin Finck             ObjectNameInfo->Name.Length = (USHORT)NameSize;
1351c2c66affSColin Finck             ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize +
1352c2c66affSColin Finck                                                           sizeof(UNICODE_NULL));
1353c2c66affSColin Finck             ObjectNameInfo->Name.Buffer = ObjectName;
1354c2c66affSColin Finck             Status = STATUS_SUCCESS;
1355c2c66affSColin Finck         }
1356c2c66affSColin Finck         else
1357c2c66affSColin Finck         {
1358c2c66affSColin Finck             /* Start by adding the Object's Name */
1359c2c66affSColin Finck             ObjectName = (PWCH)((ULONG_PTR)ObjectName -
1360c2c66affSColin Finck                                            LocalInfo->Name.Length);
1361c2c66affSColin Finck             RtlCopyMemory(ObjectName,
1362c2c66affSColin Finck                           LocalInfo->Name.Buffer,
1363c2c66affSColin Finck                           LocalInfo->Name.Length);
1364c2c66affSColin Finck 
1365c2c66affSColin Finck             /* Now parse the Parent directories until we reach the top */
1366c2c66affSColin Finck             ParentDirectory = LocalInfo->Directory;
1367c2c66affSColin Finck             while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory))
1368c2c66affSColin Finck             {
1369c2c66affSColin Finck                 /* Get the name information */
1370c2c66affSColin Finck                 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
1371c2c66affSColin Finck                     OBJECT_TO_OBJECT_HEADER(ParentDirectory));
1372c2c66affSColin Finck 
1373c2c66affSColin Finck                 /* Add the "\" */
1374c2c66affSColin Finck                 *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR;
1375c2c66affSColin Finck 
1376c2c66affSColin Finck                 /* Add the Parent Directory's Name */
1377c2c66affSColin Finck                 if (LocalInfo && LocalInfo->Name.Buffer)
1378c2c66affSColin Finck                 {
1379c2c66affSColin Finck                     /* Add the name */
1380c2c66affSColin Finck                     ObjectName = (PWCH)((ULONG_PTR)ObjectName -
1381c2c66affSColin Finck                                                    LocalInfo->Name.Length);
1382c2c66affSColin Finck                     RtlCopyMemory(ObjectName,
1383c2c66affSColin Finck                                   LocalInfo->Name.Buffer,
1384c2c66affSColin Finck                                   LocalInfo->Name.Length);
1385c2c66affSColin Finck 
1386c2c66affSColin Finck                     /* Move to next parent */
1387c2c66affSColin Finck                     ParentDirectory = LocalInfo->Directory;
1388c2c66affSColin Finck                 }
1389c2c66affSColin Finck                 else
1390c2c66affSColin Finck                 {
1391c2c66affSColin Finck                     /* Directory without a name, we add "..." */
1392c2c66affSColin Finck                     ObjectName = (PWCH)((ULONG_PTR)ObjectName -
1393c2c66affSColin Finck                                                    sizeof(L"...") +
1394c2c66affSColin Finck                                                    sizeof(UNICODE_NULL));
1395c2c66affSColin Finck                     RtlCopyMemory(ObjectName, L"...", sizeof(L"..."));
1396c2c66affSColin Finck                     break;
1397c2c66affSColin Finck                 }
1398c2c66affSColin Finck             }
1399c2c66affSColin Finck 
1400c2c66affSColin Finck             /* Add Root Directory Name */
1401c2c66affSColin Finck             *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR;
1402c2c66affSColin Finck             ObjectNameInfo->Name.Length = (USHORT)NameSize;
1403c2c66affSColin Finck             ObjectNameInfo->Name.MaximumLength =
1404c2c66affSColin Finck                 (USHORT)(NameSize + sizeof(UNICODE_NULL));
1405c2c66affSColin Finck             ObjectNameInfo->Name.Buffer = ObjectName;
1406c2c66affSColin Finck         }
1407c2c66affSColin Finck     }
1408c2c66affSColin Finck     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1409c2c66affSColin Finck     {
1410c2c66affSColin Finck         /* Return the exception code */
1411c2c66affSColin Finck         Status = _SEH2_GetExceptionCode();
1412c2c66affSColin Finck     }
1413c2c66affSColin Finck     _SEH2_END;
1414c2c66affSColin Finck 
1415c2c66affSColin Finck     /* Return success */
1416c2c66affSColin Finck     return Status;
1417c2c66affSColin Finck }
1418c2c66affSColin Finck 
1419c2c66affSColin Finck /* EOF */
1420