xref: /reactos/ntoskrnl/ob/obname.c (revision ff7cc6f3)
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 
32c2c66affSColin Finck /* PRIVATE FUNCTIONS *********************************************************/
33c2c66affSColin Finck 
34c2c66affSColin Finck NTSTATUS
35c2c66affSColin Finck NTAPI
36c2c66affSColin Finck INIT_FUNCTION
37c2c66affSColin Finck ObpCreateGlobalDosDevicesSD(OUT PSECURITY_DESCRIPTOR *SecurityDescriptor)
38c2c66affSColin Finck {
39c2c66affSColin Finck     PSECURITY_DESCRIPTOR Sd = NULL;
40c2c66affSColin Finck     PACL Dacl;
41c2c66affSColin Finck     ULONG AclSize, SdSize;
42c2c66affSColin Finck     NTSTATUS Status;
43c2c66affSColin Finck 
44c2c66affSColin Finck     AclSize = sizeof(ACL) +
45c2c66affSColin Finck               sizeof(ACE) + RtlLengthSid(SeWorldSid) +
46c2c66affSColin Finck               sizeof(ACE) + RtlLengthSid(SeLocalSystemSid) +
47c2c66affSColin Finck               sizeof(ACE) + RtlLengthSid(SeWorldSid) +
48c2c66affSColin Finck               sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid) +
49c2c66affSColin Finck               sizeof(ACE) + RtlLengthSid(SeLocalSystemSid) +
50c2c66affSColin Finck               sizeof(ACE) + RtlLengthSid(SeCreatorOwnerSid);
51c2c66affSColin Finck 
52c2c66affSColin Finck     SdSize = sizeof(SECURITY_DESCRIPTOR) + AclSize;
53c2c66affSColin Finck 
54c2c66affSColin Finck     /* Allocate the SD and ACL */
55c2c66affSColin Finck     Sd = ExAllocatePoolWithTag(PagedPool, SdSize, TAG_SD);
56c2c66affSColin Finck     if (Sd == NULL)
57c2c66affSColin Finck     {
58c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
59c2c66affSColin Finck     }
60c2c66affSColin Finck 
61c2c66affSColin Finck     /* Initialize the SD */
62c2c66affSColin Finck     Status = RtlCreateSecurityDescriptor(Sd,
63c2c66affSColin Finck                                          SECURITY_DESCRIPTOR_REVISION);
64c2c66affSColin Finck     if (!NT_SUCCESS(Status))
65c2c66affSColin Finck         return Status;
66c2c66affSColin Finck 
67c2c66affSColin Finck     Dacl = (PACL)((INT_PTR)Sd + sizeof(SECURITY_DESCRIPTOR));
68c2c66affSColin Finck 
69c2c66affSColin Finck     /* Initialize the DACL */
70c2c66affSColin Finck     RtlCreateAcl(Dacl, AclSize, ACL_REVISION);
71c2c66affSColin Finck 
72c2c66affSColin Finck     /* Add the ACEs */
73c2c66affSColin Finck     RtlAddAccessAllowedAce(Dacl,
74c2c66affSColin Finck                            ACL_REVISION,
75c2c66affSColin Finck                            GENERIC_READ | GENERIC_EXECUTE,
76c2c66affSColin Finck                            SeWorldSid);
77c2c66affSColin Finck 
78c2c66affSColin Finck     RtlAddAccessAllowedAce(Dacl,
79c2c66affSColin Finck                            ACL_REVISION,
80c2c66affSColin Finck                            GENERIC_ALL,
81c2c66affSColin Finck                            SeLocalSystemSid);
82c2c66affSColin Finck 
83c2c66affSColin Finck     RtlAddAccessAllowedAceEx(Dacl,
84c2c66affSColin Finck                              ACL_REVISION,
85c2c66affSColin Finck                              INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
86c2c66affSColin Finck                              GENERIC_EXECUTE,
87c2c66affSColin Finck                              SeWorldSid);
88c2c66affSColin Finck 
89c2c66affSColin Finck     RtlAddAccessAllowedAceEx(Dacl,
90c2c66affSColin Finck                              ACL_REVISION,
91c2c66affSColin Finck                              INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
92c2c66affSColin Finck                              GENERIC_ALL,
93c2c66affSColin Finck                              SeAliasAdminsSid);
94c2c66affSColin Finck 
95c2c66affSColin Finck     RtlAddAccessAllowedAceEx(Dacl,
96c2c66affSColin Finck                              ACL_REVISION,
97c2c66affSColin Finck                              INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
98c2c66affSColin Finck                              GENERIC_ALL,
99c2c66affSColin Finck                              SeLocalSystemSid);
100c2c66affSColin Finck 
101c2c66affSColin Finck     RtlAddAccessAllowedAceEx(Dacl,
102c2c66affSColin Finck                              ACL_REVISION,
103c2c66affSColin Finck                              INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
104c2c66affSColin Finck                              GENERIC_ALL,
105c2c66affSColin Finck                              SeCreatorOwnerSid);
106c2c66affSColin Finck 
107c2c66affSColin Finck     /* Attach the DACL to the SD */
108c2c66affSColin Finck     Status = RtlSetDaclSecurityDescriptor(Sd,
109c2c66affSColin Finck                                           TRUE,
110c2c66affSColin Finck                                           Dacl,
111c2c66affSColin Finck                                           FALSE);
112c2c66affSColin Finck     if (!NT_SUCCESS(Status))
113c2c66affSColin Finck         goto done;
114c2c66affSColin Finck 
115c2c66affSColin Finck     *SecurityDescriptor = Sd;
116c2c66affSColin Finck 
117c2c66affSColin Finck done:
118c2c66affSColin Finck     if (!NT_SUCCESS(Status))
119c2c66affSColin Finck     {
120c2c66affSColin Finck         if (Sd != NULL)
121c2c66affSColin Finck             ExFreePoolWithTag(Sd, TAG_SD);
122c2c66affSColin Finck     }
123c2c66affSColin Finck 
124c2c66affSColin Finck     return Status;
125c2c66affSColin Finck }
126c2c66affSColin Finck 
127c2c66affSColin Finck NTSTATUS
128c2c66affSColin Finck NTAPI
129c2c66affSColin Finck INIT_FUNCTION
130c2c66affSColin Finck ObpCreateDosDevicesDirectory(VOID)
131c2c66affSColin Finck {
132c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
133c2c66affSColin Finck     UNICODE_STRING RootName, TargetName, LinkName;
134c2c66affSColin Finck     HANDLE Handle, SymHandle;
135c2c66affSColin Finck     PSECURITY_DESCRIPTOR DosDevicesSD = NULL;
136c2c66affSColin Finck     NTSTATUS Status;
137c2c66affSColin Finck 
138c2c66affSColin Finck     /* Create a custom security descriptor for the global DosDevices directory */
139c2c66affSColin Finck     Status = ObpCreateGlobalDosDevicesSD(&DosDevicesSD);
140c2c66affSColin Finck     if (!NT_SUCCESS(Status))
141c2c66affSColin Finck         return Status;
142c2c66affSColin Finck 
143c2c66affSColin Finck     /* Create the global DosDevices directory \?? */
144c2c66affSColin Finck     RtlInitUnicodeString(&RootName, L"\\GLOBAL??");
145c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
146c2c66affSColin Finck                                &RootName,
147c2c66affSColin Finck                                OBJ_PERMANENT,
148c2c66affSColin Finck                                NULL,
149c2c66affSColin Finck                                DosDevicesSD);
150c2c66affSColin Finck     Status = NtCreateDirectoryObject(&Handle,
151c2c66affSColin Finck                                      DIRECTORY_ALL_ACCESS,
152c2c66affSColin Finck                                      &ObjectAttributes);
153c2c66affSColin Finck     ExFreePoolWithTag(DosDevicesSD, TAG_SD);
154c2c66affSColin Finck     if (!NT_SUCCESS(Status)) return Status;
155c2c66affSColin Finck 
156c2c66affSColin Finck     /* Create the system device map */
157c2c66affSColin Finck     Status = ObpCreateDeviceMap(Handle);
158c2c66affSColin Finck     if (!NT_SUCCESS(Status))
159c2c66affSColin Finck         return Status;
160c2c66affSColin Finck 
161c2c66affSColin Finck     /*********************************************\
162c2c66affSColin Finck     |*** HACK until we support device mappings ***|
163c2c66affSColin Finck     |*** Add a symlink \??\ <--> \GLOBAL??\    ***|
164c2c66affSColin Finck     \*********************************************/
165c2c66affSColin Finck     RtlInitUnicodeString(&LinkName, L"\\??");
166c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
167c2c66affSColin Finck                                &LinkName,
168c2c66affSColin Finck                                OBJ_PERMANENT,
169c2c66affSColin Finck                                NULL,
170c2c66affSColin Finck                                NULL);
171c2c66affSColin Finck     Status = NtCreateSymbolicLinkObject(&SymHandle,
172c2c66affSColin Finck                                         SYMBOLIC_LINK_ALL_ACCESS,
173c2c66affSColin Finck                                         &ObjectAttributes,
174c2c66affSColin Finck                                         &RootName);
175c2c66affSColin Finck     if (NT_SUCCESS(Status)) NtClose(SymHandle);
176c2c66affSColin Finck     /*********************************************\
177c2c66affSColin Finck     \*********************************************/
178c2c66affSColin Finck 
179c2c66affSColin Finck     // FIXME: Create a device mapping for the global \?? directory
180c2c66affSColin Finck 
181c2c66affSColin Finck     /*
182c2c66affSColin Finck      * Initialize the \??\GLOBALROOT symbolic link
183c2c66affSColin Finck      * pointing to the root directory \ .
184c2c66affSColin Finck      */
185c2c66affSColin Finck     RtlInitUnicodeString(&LinkName, L"GLOBALROOT");
186c2c66affSColin Finck     RtlInitUnicodeString(&TargetName, L"");
187c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
188c2c66affSColin Finck                                &LinkName,
189c2c66affSColin Finck                                OBJ_PERMANENT,
190c2c66affSColin Finck                                Handle,
191c2c66affSColin Finck                                NULL);
192c2c66affSColin Finck     Status = NtCreateSymbolicLinkObject(&SymHandle,
193c2c66affSColin Finck                                         SYMBOLIC_LINK_ALL_ACCESS,
194c2c66affSColin Finck                                         &ObjectAttributes,
195c2c66affSColin Finck                                         &TargetName);
196c2c66affSColin Finck     if (NT_SUCCESS(Status)) NtClose(SymHandle);
197c2c66affSColin Finck 
198c2c66affSColin Finck     /*
199c2c66affSColin Finck      * Initialize the \??\Global symbolic link pointing to the global
200c2c66affSColin Finck      * DosDevices directory \?? . It is used to access the global \??
201c2c66affSColin Finck      * by user-mode components which, by default, use a per-session
202c2c66affSColin Finck      * DosDevices directory.
203c2c66affSColin Finck      */
204c2c66affSColin Finck     RtlInitUnicodeString(&LinkName, L"Global");
205c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
206c2c66affSColin Finck                                &LinkName,
207c2c66affSColin Finck                                OBJ_PERMANENT,
208c2c66affSColin Finck                                Handle,
209c2c66affSColin Finck                                NULL);
210c2c66affSColin Finck     Status = NtCreateSymbolicLinkObject(&SymHandle,
211c2c66affSColin Finck                                         SYMBOLIC_LINK_ALL_ACCESS,
212c2c66affSColin Finck                                         &ObjectAttributes,
213c2c66affSColin Finck                                         &RootName);
214c2c66affSColin Finck     if (NT_SUCCESS(Status)) NtClose(SymHandle);
215c2c66affSColin Finck 
216c2c66affSColin Finck     /* Close the directory handle */
217c2c66affSColin Finck     NtClose(Handle);
218c2c66affSColin Finck     if (!NT_SUCCESS(Status)) return Status;
219c2c66affSColin Finck 
220c2c66affSColin Finck     /*
221c2c66affSColin Finck      * Initialize the \DosDevices symbolic link pointing to the global
222c2c66affSColin Finck      * DosDevices directory \?? , for backward compatibility with
223c2c66affSColin Finck      * Windows NT-2000 systems.
224c2c66affSColin Finck      */
225c2c66affSColin Finck     RtlCreateUnicodeString(&LinkName, L"\\DosDevices");
226c2c66affSColin Finck     RtlInitUnicodeString(&RootName, (PCWSTR)&ObpDosDevicesShortNameRoot);
227c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
228c2c66affSColin Finck                                &LinkName,
229c2c66affSColin Finck                                OBJ_PERMANENT,
230c2c66affSColin Finck                                NULL,
231c2c66affSColin Finck                                NULL);
232c2c66affSColin Finck     Status = NtCreateSymbolicLinkObject(&SymHandle,
233c2c66affSColin Finck                                         SYMBOLIC_LINK_ALL_ACCESS,
234c2c66affSColin Finck                                         &ObjectAttributes,
235c2c66affSColin Finck                                         &RootName);
236c2c66affSColin Finck     if (NT_SUCCESS(Status)) NtClose(SymHandle);
237c2c66affSColin Finck 
238c2c66affSColin Finck     /* Return status */
239c2c66affSColin Finck     return Status;
240c2c66affSColin Finck }
241c2c66affSColin Finck 
242c2c66affSColin Finck /*++
243c2c66affSColin Finck * @name ObpDeleteNameCheck
244c2c66affSColin Finck *
245c2c66affSColin Finck *     The ObpDeleteNameCheck routine checks if a named object should be
246c2c66affSColin Finck *     removed from the object directory namespace.
247c2c66affSColin Finck *
248c2c66affSColin Finck * @param Object
249c2c66affSColin Finck *        Pointer to the object to check for possible removal.
250c2c66affSColin Finck *
251c2c66affSColin Finck * @return None.
252c2c66affSColin Finck *
253c2c66affSColin Finck * @remarks An object is removed if the following 4 criteria are met:
254c2c66affSColin Finck *          1) The object has 0 handles open
255c2c66affSColin Finck *          2) The object is in the directory namespace and has a name
256c2c66affSColin Finck *          3) The object is not permanent
257c2c66affSColin Finck *
258c2c66affSColin Finck *--*/
259c2c66affSColin Finck VOID
260c2c66affSColin Finck NTAPI
261c2c66affSColin Finck ObpDeleteNameCheck(IN PVOID Object)
262c2c66affSColin Finck {
263c2c66affSColin Finck     POBJECT_HEADER ObjectHeader;
264c2c66affSColin Finck     OBP_LOOKUP_CONTEXT Context;
265c2c66affSColin Finck     POBJECT_HEADER_NAME_INFO ObjectNameInfo;
266c2c66affSColin Finck     POBJECT_TYPE ObjectType;
267c2c66affSColin Finck     PVOID Directory = NULL;
268c2c66affSColin Finck 
269c2c66affSColin Finck     /* Get object structures */
270c2c66affSColin Finck     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
271c2c66affSColin Finck     ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
272c2c66affSColin Finck     ObjectType = ObjectHeader->Type;
273c2c66affSColin Finck 
274c2c66affSColin Finck     /*
275c2c66affSColin Finck      * Check if the handle count is 0, if the object is named,
276c2c66affSColin Finck      * and if the object isn't a permanent object.
277c2c66affSColin Finck      */
278c2c66affSColin Finck     if (!(ObjectHeader->HandleCount) &&
279c2c66affSColin Finck          (ObjectNameInfo) &&
280c2c66affSColin Finck          (ObjectNameInfo->Name.Length) &&
281c2c66affSColin Finck          (ObjectNameInfo->Directory) &&
282c2c66affSColin Finck          !(ObjectHeader->Flags & OB_FLAG_PERMANENT))
283c2c66affSColin Finck     {
284c2c66affSColin Finck         /* Setup a lookup context */
285c2c66affSColin Finck         ObpInitializeLookupContext(&Context);
286c2c66affSColin Finck 
287c2c66affSColin Finck         /* Lock the directory */
288c2c66affSColin Finck         ObpAcquireDirectoryLockExclusive(ObjectNameInfo->Directory, &Context);
289c2c66affSColin Finck 
290c2c66affSColin Finck         /* Do the lookup */
291c2c66affSColin Finck         Object = ObpLookupEntryDirectory(ObjectNameInfo->Directory,
292c2c66affSColin Finck                                          &ObjectNameInfo->Name,
293c2c66affSColin Finck                                          0,
294c2c66affSColin Finck                                          FALSE,
295c2c66affSColin Finck                                          &Context);
296c2c66affSColin Finck         if (Object)
297c2c66affSColin Finck         {
298c2c66affSColin Finck             /* Lock the object */
299c2c66affSColin Finck             ObpAcquireObjectLock(ObjectHeader);
300c2c66affSColin Finck 
301c2c66affSColin Finck             /* Make sure we can still delete the object */
302c2c66affSColin Finck             if (!(ObjectHeader->HandleCount) &&
303c2c66affSColin Finck                 !(ObjectHeader->Flags & OB_FLAG_PERMANENT))
304c2c66affSColin Finck             {
305c2c66affSColin Finck                 /* First delete it from the directory */
306c2c66affSColin Finck                 ObpDeleteEntryDirectory(&Context);
307c2c66affSColin Finck 
308c2c66affSColin Finck                 /* Check if this is a symbolic link */
309c2c66affSColin Finck                 if (ObjectType == ObSymbolicLinkType)
310c2c66affSColin Finck                 {
311c2c66affSColin Finck                     /* Remove internal name */
312c2c66affSColin Finck                     ObpDeleteSymbolicLinkName(Object);
313c2c66affSColin Finck                 }
314c2c66affSColin Finck 
315c2c66affSColin Finck                 /* Check if the kernel exclusive is set */
316c2c66affSColin Finck                 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
317c2c66affSColin Finck                 if ((ObjectNameInfo) &&
318c2c66affSColin Finck                     (ObjectNameInfo->QueryReferences & OB_FLAG_KERNEL_EXCLUSIVE))
319c2c66affSColin Finck                 {
320c2c66affSColin Finck                     /* Remove protection flag */
321c2c66affSColin Finck                     InterlockedExchangeAdd((PLONG)&ObjectNameInfo->QueryReferences,
322c2c66affSColin Finck                                            -OB_FLAG_KERNEL_EXCLUSIVE);
323c2c66affSColin Finck                 }
324c2c66affSColin Finck 
325c2c66affSColin Finck                 /* Get the directory */
326c2c66affSColin Finck                 Directory = ObjectNameInfo->Directory;
327c2c66affSColin Finck             }
328c2c66affSColin Finck 
329c2c66affSColin Finck             /* Release the lock */
330c2c66affSColin Finck             ObpReleaseObjectLock(ObjectHeader);
331c2c66affSColin Finck         }
332c2c66affSColin Finck 
333c2c66affSColin Finck         /* Cleanup after lookup */
334c2c66affSColin Finck         ObpReleaseLookupContext(&Context);
335c2c66affSColin Finck 
336c2c66affSColin Finck         /* Remove another query reference since we added one on top */
337c2c66affSColin Finck         ObpDereferenceNameInfo(ObjectNameInfo);
338c2c66affSColin Finck 
339c2c66affSColin Finck         /* Check if we were inserted in a directory */
340c2c66affSColin Finck         if (Directory)
341c2c66affSColin Finck         {
342c2c66affSColin Finck             /* We were, so first remove the extra reference we had added */
343c2c66affSColin Finck             ObpDereferenceNameInfo(ObjectNameInfo);
344c2c66affSColin Finck 
345c2c66affSColin Finck             /* Now dereference the object as well */
346c2c66affSColin Finck             ObDereferenceObject(Object);
347c2c66affSColin Finck         }
348c2c66affSColin Finck     }
349c2c66affSColin Finck     else
350c2c66affSColin Finck     {
351c2c66affSColin Finck         /* Remove the reference we added */
352c2c66affSColin Finck         ObpDereferenceNameInfo(ObjectNameInfo);
353c2c66affSColin Finck     }
354c2c66affSColin Finck }
355c2c66affSColin Finck 
356c2c66affSColin Finck NTSTATUS
357c2c66affSColin Finck NTAPI
358c2c66affSColin Finck ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL,
359c2c66affSColin Finck                     IN OUT PUNICODE_STRING ObjectName,
360c2c66affSColin Finck                     IN ULONG Attributes,
361c2c66affSColin Finck                     IN POBJECT_TYPE ObjectType,
362c2c66affSColin Finck                     IN KPROCESSOR_MODE AccessMode,
363c2c66affSColin Finck                     IN OUT PVOID ParseContext,
364c2c66affSColin Finck                     IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
365c2c66affSColin Finck                     IN PVOID InsertObject OPTIONAL,
366c2c66affSColin Finck                     IN OUT PACCESS_STATE AccessState,
367c2c66affSColin Finck                     OUT POBP_LOOKUP_CONTEXT LookupContext,
368c2c66affSColin Finck                     OUT PVOID *FoundObject)
369c2c66affSColin Finck {
370c2c66affSColin Finck     PVOID Object;
371c2c66affSColin Finck     POBJECT_HEADER ObjectHeader;
372c2c66affSColin Finck     UNICODE_STRING ComponentName, RemainingName;
373c2c66affSColin Finck     BOOLEAN Reparse = FALSE, SymLink = FALSE;
374c2c66affSColin Finck     POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory;
375c2c66affSColin Finck     POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL;
376c2c66affSColin Finck     KIRQL CalloutIrql;
377c2c66affSColin Finck     OB_PARSE_METHOD ParseRoutine;
378c2c66affSColin Finck     NTSTATUS Status;
379c2c66affSColin Finck     KPROCESSOR_MODE AccessCheckMode;
380c2c66affSColin Finck     PWCHAR NewName;
381c2c66affSColin Finck     POBJECT_HEADER_NAME_INFO ObjectNameInfo;
382c2c66affSColin Finck     ULONG MaxReparse = 30;
383c2c66affSColin Finck     PAGED_CODE();
384c2c66affSColin Finck     OBTRACE(OB_NAMESPACE_DEBUG,
385c2c66affSColin Finck             "%s - Finding Object: %wZ. Expecting: %p\n",
386c2c66affSColin Finck             __FUNCTION__,
387c2c66affSColin Finck             ObjectName,
388c2c66affSColin Finck             InsertObject);
389c2c66affSColin Finck 
390c2c66affSColin Finck     /* Initialize starting state */
391c2c66affSColin Finck     ObpInitializeLookupContext(LookupContext);
392c2c66affSColin Finck     *FoundObject = NULL;
393c2c66affSColin Finck     Status = STATUS_SUCCESS;
394c2c66affSColin Finck     Object = NULL;
395c2c66affSColin Finck 
396c2c66affSColin Finck     /* Check if case-insensitivity is checked */
397c2c66affSColin Finck     if (ObpCaseInsensitive)
398c2c66affSColin Finck     {
399c2c66affSColin Finck         /* Check if the object type requests this */
400c2c66affSColin Finck         if (!(ObjectType) || (ObjectType->TypeInfo.CaseInsensitive))
401c2c66affSColin Finck         {
402c2c66affSColin Finck             /* Add the flag to disable case sensitivity */
403c2c66affSColin Finck             Attributes |= OBJ_CASE_INSENSITIVE;
404c2c66affSColin Finck         }
405c2c66affSColin Finck     }
406c2c66affSColin Finck 
407c2c66affSColin Finck     /* Check if this is a access checks are being forced */
408c2c66affSColin Finck     AccessCheckMode = (Attributes & OBJ_FORCE_ACCESS_CHECK) ?
409c2c66affSColin Finck                        UserMode : AccessMode;
410c2c66affSColin Finck 
411c2c66affSColin Finck     /* Check if we got a Root Directory */
412c2c66affSColin Finck     if (RootHandle)
413c2c66affSColin Finck     {
414c2c66affSColin Finck         /* We did. Reference it */
415c2c66affSColin Finck         Status = ObReferenceObjectByHandle(RootHandle,
416c2c66affSColin Finck                                            0,
417c2c66affSColin Finck                                            NULL,
418c2c66affSColin Finck                                            AccessMode,
419c2c66affSColin Finck                                            (PVOID*)&RootDirectory,
420c2c66affSColin Finck                                            NULL);
421c2c66affSColin Finck         if (!NT_SUCCESS(Status)) return Status;
422c2c66affSColin Finck 
423c2c66affSColin Finck         /* Get the header */
424c2c66affSColin Finck         ObjectHeader = OBJECT_TO_OBJECT_HEADER(RootDirectory);
425c2c66affSColin Finck 
426c2c66affSColin Finck         /* The name cannot start with a separator, unless this is a file */
427c2c66affSColin Finck         if ((ObjectName->Buffer) &&
428c2c66affSColin Finck             (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) &&
429c2c66affSColin Finck             (ObjectHeader->Type != IoFileObjectType))
430c2c66affSColin Finck         {
431c2c66affSColin Finck             /* The syntax is bad, so fail this request */
432c2c66affSColin Finck             ObDereferenceObject(RootDirectory);
433c2c66affSColin Finck             return STATUS_OBJECT_PATH_SYNTAX_BAD;
434c2c66affSColin Finck         }
435c2c66affSColin Finck 
436c2c66affSColin Finck         /* Don't parse a Directory */
437c2c66affSColin Finck         if (ObjectHeader->Type != ObDirectoryType)
438c2c66affSColin Finck         {
439c2c66affSColin Finck             /* Make sure the Object Type has a parse routine */
440c2c66affSColin Finck             ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure;
441c2c66affSColin Finck             if (!ParseRoutine)
442c2c66affSColin Finck             {
443c2c66affSColin Finck                 /* We can't parse a name if we don't have a parse routine */
444c2c66affSColin Finck                 ObDereferenceObject(RootDirectory);
445c2c66affSColin Finck                 return STATUS_INVALID_HANDLE;
446c2c66affSColin Finck             }
447c2c66affSColin Finck 
448c2c66affSColin Finck             /* Set default parse count */
449c2c66affSColin Finck             MaxReparse = 30;
450c2c66affSColin Finck 
451c2c66affSColin Finck             /* Now parse */
452c2c66affSColin Finck             while (TRUE)
453c2c66affSColin Finck             {
454c2c66affSColin Finck                 /* Start with the full name */
455c2c66affSColin Finck                 RemainingName = *ObjectName;
456c2c66affSColin Finck 
457c2c66affSColin Finck                 /* Call the Parse Procedure */
458c2c66affSColin Finck                 ObpCalloutStart(&CalloutIrql);
459c2c66affSColin Finck                 Status = ParseRoutine(RootDirectory,
460c2c66affSColin Finck                                       ObjectType,
461c2c66affSColin Finck                                       AccessState,
462c2c66affSColin Finck                                       AccessCheckMode,
463c2c66affSColin Finck                                       Attributes,
464c2c66affSColin Finck                                       ObjectName,
465c2c66affSColin Finck                                       &RemainingName,
466c2c66affSColin Finck                                       ParseContext,
467c2c66affSColin Finck                                       SecurityQos,
468c2c66affSColin Finck                                       &Object);
469c2c66affSColin Finck                 ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
470c2c66affSColin Finck 
471c2c66affSColin Finck                 /* Check for success or failure, so not reparse */
472c2c66affSColin Finck                 if ((Status != STATUS_REPARSE) &&
473c2c66affSColin Finck                     (Status != STATUS_REPARSE_OBJECT))
474c2c66affSColin Finck                 {
475c2c66affSColin Finck                     /* Check for failure */
476c2c66affSColin Finck                     if (!NT_SUCCESS(Status))
477c2c66affSColin Finck                     {
478c2c66affSColin Finck                         /* Parse routine might not have cleared this, do it */
479c2c66affSColin Finck                         Object = NULL;
480c2c66affSColin Finck                     }
481c2c66affSColin Finck                     else if (!Object)
482c2c66affSColin Finck                     {
483c2c66affSColin Finck                         /* Modify status to reflect failure inside Ob */
484c2c66affSColin Finck                         Status = STATUS_OBJECT_NAME_NOT_FOUND;
485c2c66affSColin Finck                     }
486c2c66affSColin Finck 
487c2c66affSColin Finck                     /* We're done, return the status and object */
488c2c66affSColin Finck                     *FoundObject = Object;
489c2c66affSColin Finck                     ObDereferenceObject(RootDirectory);
490c2c66affSColin Finck                     return Status;
491c2c66affSColin Finck                 }
492c2c66affSColin Finck                 else if ((!ObjectName->Length) ||
493c2c66affSColin Finck                          (!ObjectName->Buffer) ||
494c2c66affSColin Finck                          (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
495c2c66affSColin Finck                 {
496c2c66affSColin Finck                     /* Reparsed to the root directory, so start over */
497c2c66affSColin Finck                     ObDereferenceObject(RootDirectory);
498c2c66affSColin Finck                     RootDirectory = ObpRootDirectoryObject;
499c2c66affSColin Finck 
500c2c66affSColin Finck                     /* Don't use this anymore, since we're starting at root */
501c2c66affSColin Finck                     RootHandle = NULL;
502c2c66affSColin Finck                     goto ParseFromRoot;
503c2c66affSColin Finck                 }
504c2c66affSColin Finck                 else if (--MaxReparse)
505c2c66affSColin Finck                 {
506c2c66affSColin Finck                     /* Try reparsing again */
507c2c66affSColin Finck                     continue;
508c2c66affSColin Finck                 }
509c2c66affSColin Finck                 else
510c2c66affSColin Finck                 {
511c2c66affSColin Finck                     /* Reparsed too many times */
512c2c66affSColin Finck                     ObDereferenceObject(RootDirectory);
513c2c66affSColin Finck 
514c2c66affSColin Finck                     /* Return the object and normalized status */
515c2c66affSColin Finck                     *FoundObject = Object;
516c2c66affSColin Finck                     if (!Object) Status = STATUS_OBJECT_NAME_NOT_FOUND;
517c2c66affSColin Finck                     return Status;
518c2c66affSColin Finck                 }
519c2c66affSColin Finck             }
520c2c66affSColin Finck         }
521c2c66affSColin Finck         else if (!(ObjectName->Length) || !(ObjectName->Buffer))
522c2c66affSColin Finck         {
523c2c66affSColin Finck             /* Just return the Root Directory if we didn't get a name */
524c2c66affSColin Finck             Status = ObReferenceObjectByPointer(RootDirectory,
525c2c66affSColin Finck                                                 0,
526c2c66affSColin Finck                                                 ObjectType,
527c2c66affSColin Finck                                                 AccessMode);
528c2c66affSColin Finck             if (NT_SUCCESS(Status)) Object = RootDirectory;
529c2c66affSColin Finck 
530c2c66affSColin Finck             /* Remove the first reference we added and return the object */
531c2c66affSColin Finck             ObDereferenceObject(RootDirectory);
532c2c66affSColin Finck             *FoundObject = Object;
533c2c66affSColin Finck             return Status;
534c2c66affSColin Finck         }
535c2c66affSColin Finck     }
536c2c66affSColin Finck     else
537c2c66affSColin Finck     {
538c2c66affSColin Finck         /* We did not get a Root Directory, so use the root */
539c2c66affSColin Finck         RootDirectory = ObpRootDirectoryObject;
540c2c66affSColin Finck 
541c2c66affSColin Finck         /* It must start with a path separator */
542c2c66affSColin Finck         if (!(ObjectName->Length) ||
543c2c66affSColin Finck             !(ObjectName->Buffer) ||
544c2c66affSColin Finck             (ObjectName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR))
545c2c66affSColin Finck         {
546c2c66affSColin Finck             /* This name is invalid, so fail */
547c2c66affSColin Finck             return STATUS_OBJECT_PATH_SYNTAX_BAD;
548c2c66affSColin Finck         }
549c2c66affSColin Finck 
550c2c66affSColin Finck         /* Check if the name is only the path separator */
551c2c66affSColin Finck         if (ObjectName->Length == sizeof(OBJ_NAME_PATH_SEPARATOR))
552c2c66affSColin Finck         {
553c2c66affSColin Finck             /* So the caller only wants the root directory; do we have one? */
554c2c66affSColin Finck             if (!RootDirectory)
555c2c66affSColin Finck             {
556c2c66affSColin Finck                 /* This must be the first time we're creating it... right? */
557c2c66affSColin Finck                 if (InsertObject)
558c2c66affSColin Finck                 {
559c2c66affSColin Finck                     /* Yes, so return it to ObInsert so that it can create it */
560c2c66affSColin Finck                     Status = ObReferenceObjectByPointer(InsertObject,
561c2c66affSColin Finck                                                         0,
562c2c66affSColin Finck                                                         ObjectType,
563c2c66affSColin Finck                                                         AccessMode);
564c2c66affSColin Finck                     if (NT_SUCCESS(Status)) *FoundObject = InsertObject;
565c2c66affSColin Finck                     return Status;
566c2c66affSColin Finck                 }
567c2c66affSColin Finck                 else
568c2c66affSColin Finck                 {
569c2c66affSColin Finck                     /* This should never really happen */
570c2c66affSColin Finck                     ASSERT(FALSE);
571c2c66affSColin Finck                     return STATUS_INVALID_PARAMETER;
572c2c66affSColin Finck                 }
573c2c66affSColin Finck             }
574c2c66affSColin Finck             else
575c2c66affSColin Finck             {
576c2c66affSColin Finck                 /* We do have the root directory, so just return it */
577c2c66affSColin Finck                 Status = ObReferenceObjectByPointer(RootDirectory,
578c2c66affSColin Finck                                                     0,
579c2c66affSColin Finck                                                     ObjectType,
580c2c66affSColin Finck                                                     AccessMode);
581c2c66affSColin Finck                 if (NT_SUCCESS(Status)) *FoundObject = RootDirectory;
582c2c66affSColin Finck                 return Status;
583c2c66affSColin Finck             }
584c2c66affSColin Finck         }
585c2c66affSColin Finck         else
586c2c66affSColin Finck         {
587c2c66affSColin Finck ParseFromRoot:
588c2c66affSColin Finck             /* FIXME: Check if we have a device map */
589c2c66affSColin Finck 
590c2c66affSColin Finck             /* Check if this is a possible DOS name */
591c2c66affSColin Finck             if (!((ULONG_PTR)(ObjectName->Buffer) & 7))
592c2c66affSColin Finck             {
593c2c66affSColin Finck                 /*
594c2c66affSColin Finck                  * This could be one. Does it match the prefix?
595c2c66affSColin Finck                  * Note that as an optimization, the match is done as 64-bit
596c2c66affSColin Finck                  * compare since the prefix is "\??\" which is exactly 8 bytes.
597c2c66affSColin Finck                  *
598c2c66affSColin Finck                  * In the second branch, we test for "\??" which is also valid.
599c2c66affSColin Finck                  * This time, we use a 32-bit compare followed by a Unicode
600c2c66affSColin Finck                  * character compare (16-bit), since the sum is 6 bytes.
601c2c66affSColin Finck                  */
602c2c66affSColin Finck                 if ((ObjectName->Length >= ObpDosDevicesShortName.Length) &&
603c2c66affSColin Finck                     (*(PULONGLONG)(ObjectName->Buffer) ==
604c2c66affSColin Finck                      ObpDosDevicesShortNamePrefix.Alignment.QuadPart))
605c2c66affSColin Finck                 {
606c2c66affSColin Finck                     /* FIXME! */
607c2c66affSColin Finck                 }
608c2c66affSColin Finck                 else if ((ObjectName->Length == ObpDosDevicesShortName.Length -
609c2c66affSColin Finck                                                 sizeof(WCHAR)) &&
610c2c66affSColin Finck                          (*(PULONG)(ObjectName->Buffer) ==
611c2c66affSColin Finck                           ObpDosDevicesShortNameRoot.Alignment.LowPart) &&
612c2c66affSColin Finck                          (*((PWCHAR)(ObjectName->Buffer) + 2) ==
613c2c66affSColin Finck                           (WCHAR)(ObpDosDevicesShortNameRoot.Alignment.HighPart)))
614c2c66affSColin Finck                 {
615c2c66affSColin Finck                     /* FIXME! */
616c2c66affSColin Finck                 }
617c2c66affSColin Finck             }
618c2c66affSColin Finck         }
619c2c66affSColin Finck     }
620c2c66affSColin Finck 
621c2c66affSColin Finck     /* Check if we were reparsing a symbolic link */
622c2c66affSColin Finck     if (!SymLink)
623c2c66affSColin Finck     {
624c2c66affSColin Finck         /* Allow reparse */
625c2c66affSColin Finck         Reparse = TRUE;
626c2c66affSColin Finck         MaxReparse = 30;
627c2c66affSColin Finck     }
628c2c66affSColin Finck 
629c2c66affSColin Finck     /* Reparse */
630c2c66affSColin Finck     while (Reparse && MaxReparse)
631c2c66affSColin Finck     {
632c2c66affSColin Finck         /* Get the name */
633c2c66affSColin Finck         RemainingName = *ObjectName;
634c2c66affSColin Finck 
635c2c66affSColin Finck         /* Disable reparsing again */
636c2c66affSColin Finck         Reparse = FALSE;
637c2c66affSColin Finck 
638c2c66affSColin Finck         /* Start parse loop */
639c2c66affSColin Finck         while (TRUE)
640c2c66affSColin Finck         {
641c2c66affSColin Finck             /* Clear object */
642c2c66affSColin Finck             Object = NULL;
643c2c66affSColin Finck 
644c2c66affSColin Finck             /* Check if the name starts with a path separator */
645c2c66affSColin Finck             if ((RemainingName.Length) &&
646c2c66affSColin Finck                 (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
647c2c66affSColin Finck             {
648c2c66affSColin Finck                 /* Skip the path separator */
649c2c66affSColin Finck                 RemainingName.Buffer++;
650c2c66affSColin Finck                 RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
651c2c66affSColin Finck             }
652c2c66affSColin Finck 
653c2c66affSColin Finck             /* Find the next Part Name */
654c2c66affSColin Finck             ComponentName = RemainingName;
655c2c66affSColin Finck             while (RemainingName.Length)
656c2c66affSColin Finck             {
657c2c66affSColin Finck                 /* Break if we found the \ ending */
658c2c66affSColin Finck                 if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break;
659c2c66affSColin Finck 
660c2c66affSColin Finck                 /* Move on */
661c2c66affSColin Finck                 RemainingName.Buffer++;
662c2c66affSColin Finck                 RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR);
663c2c66affSColin Finck             }
664c2c66affSColin Finck 
665c2c66affSColin Finck             /* Get its size and make sure it's valid */
666c2c66affSColin Finck             ComponentName.Length -= RemainingName.Length;
667c2c66affSColin Finck             if (!ComponentName.Length)
668c2c66affSColin Finck             {
669c2c66affSColin Finck                 /* Invalid size, fail */
670c2c66affSColin Finck                 Status = STATUS_OBJECT_NAME_INVALID;
671c2c66affSColin Finck                 break;
672c2c66affSColin Finck             }
673c2c66affSColin Finck 
674c2c66affSColin Finck             /* Check if we're in the root */
675c2c66affSColin Finck             if (!Directory) Directory = RootDirectory;
676c2c66affSColin Finck 
677c2c66affSColin Finck             /* Check if this is a user-mode call that needs to traverse */
678c2c66affSColin Finck             if ((AccessCheckMode != KernelMode) &&
679c2c66affSColin Finck                 !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
680c2c66affSColin Finck             {
681c2c66affSColin Finck                 /* We shouldn't have referenced a directory yet */
682c2c66affSColin Finck                 ASSERT(ReferencedDirectory == NULL);
683c2c66affSColin Finck 
684c2c66affSColin Finck                 /* Reference the directory */
685c2c66affSColin Finck                 ObReferenceObject(Directory);
686c2c66affSColin Finck                 ReferencedDirectory = Directory;
687c2c66affSColin Finck 
688c2c66affSColin Finck                 /* Check if we have a parent directory */
689c2c66affSColin Finck                 if (ParentDirectory)
690c2c66affSColin Finck                 {
691c2c66affSColin Finck                     /* Check for traverse access */
692c2c66affSColin Finck                     if (!ObpCheckTraverseAccess(ParentDirectory,
693c2c66affSColin Finck                                                 DIRECTORY_TRAVERSE,
694c2c66affSColin Finck                                                 AccessState,
695c2c66affSColin Finck                                                 FALSE,
696c2c66affSColin Finck                                                 AccessCheckMode,
697c2c66affSColin Finck                                                 &Status))
698c2c66affSColin Finck                     {
699c2c66affSColin Finck                         /* We don't have it, fail */
700c2c66affSColin Finck                         break;
701c2c66affSColin Finck                     }
702c2c66affSColin Finck                 }
703c2c66affSColin Finck             }
704c2c66affSColin Finck 
705c2c66affSColin Finck             /* Check if we don't have a remaining name yet */
706c2c66affSColin Finck             if (!RemainingName.Length)
707c2c66affSColin Finck             {
708c2c66affSColin Finck                 /* Check if we don't have a referenced directory yet */
709c2c66affSColin Finck                 if (!ReferencedDirectory)
710c2c66affSColin Finck                 {
711c2c66affSColin Finck                     /* Reference it */
712c2c66affSColin Finck                     ObReferenceObject(Directory);
713c2c66affSColin Finck                     ReferencedDirectory = Directory;
714c2c66affSColin Finck                 }
715c2c66affSColin Finck 
716c2c66affSColin Finck                 /* Check if we are inserting an object */
717c2c66affSColin Finck                 if (InsertObject)
718c2c66affSColin Finck                 {
719c2c66affSColin Finck                     /* Lock the directory */
720c2c66affSColin Finck                     ObpAcquireDirectoryLockExclusive(Directory, LookupContext);
721c2c66affSColin Finck                 }
722c2c66affSColin Finck             }
723c2c66affSColin Finck 
724c2c66affSColin Finck             /* Do the lookup */
725c2c66affSColin Finck             Object = ObpLookupEntryDirectory(Directory,
726c2c66affSColin Finck                                              &ComponentName,
727c2c66affSColin Finck                                              Attributes,
728c2c66affSColin Finck                                              InsertObject ? FALSE : TRUE,
729c2c66affSColin Finck                                              LookupContext);
730c2c66affSColin Finck             if (!Object)
731c2c66affSColin Finck             {
732c2c66affSColin Finck                 /* We didn't find it... do we still have a path? */
733c2c66affSColin Finck                 if (RemainingName.Length)
734c2c66affSColin Finck                 {
735c2c66affSColin Finck                     /* Then tell the caller the path wasn't found */
736c2c66affSColin Finck                     Status = STATUS_OBJECT_PATH_NOT_FOUND;
737c2c66affSColin Finck                     break;
738c2c66affSColin Finck                 }
739c2c66affSColin Finck                 else if (!InsertObject)
740c2c66affSColin Finck                 {
741c2c66affSColin Finck                     /* Otherwise, we have a path, but the name isn't valid */
742c2c66affSColin Finck                     Status = STATUS_OBJECT_NAME_NOT_FOUND;
743c2c66affSColin Finck                     break;
744c2c66affSColin Finck                 }
745c2c66affSColin Finck 
746c2c66affSColin Finck                 /* Check create access for the object */
747c2c66affSColin Finck                 if (!ObCheckCreateObjectAccess(Directory,
748c2c66affSColin Finck                                                ObjectType == ObDirectoryType ?
749c2c66affSColin Finck                                                DIRECTORY_CREATE_SUBDIRECTORY :
750c2c66affSColin Finck                                                DIRECTORY_CREATE_OBJECT,
751c2c66affSColin Finck                                                AccessState,
752c2c66affSColin Finck                                                &ComponentName,
753c2c66affSColin Finck                                                FALSE,
754c2c66affSColin Finck                                                AccessCheckMode,
755c2c66affSColin Finck                                                &Status))
756c2c66affSColin Finck                 {
757c2c66affSColin Finck                     /* We don't have create access, fail */
758c2c66affSColin Finck                     break;
759c2c66affSColin Finck                 }
760c2c66affSColin Finck 
761c2c66affSColin Finck                 /* Get the object header */
762c2c66affSColin Finck                 ObjectHeader = OBJECT_TO_OBJECT_HEADER(InsertObject);
763c2c66affSColin Finck 
764c2c66affSColin Finck                 /* FIXME: Check if this is a Section Object or Sym Link */
765c2c66affSColin Finck                 /* FIXME: If it is, then check if this isn't session 0 */
766c2c66affSColin Finck                 /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */
767c2c66affSColin Finck                 /* FIXME: If privilege isn't there, check for unsecure name */
768c2c66affSColin Finck                 /* FIXME: If it isn't a known unsecure name, then fail */
769c2c66affSColin Finck 
770c2c66affSColin Finck                 /* Create Object Name */
771c2c66affSColin Finck                 NewName = ExAllocatePoolWithTag(PagedPool,
772c2c66affSColin Finck                                                 ComponentName.Length,
773c2c66affSColin Finck                                                 OB_NAME_TAG);
774c2c66affSColin Finck                 if (!(NewName) ||
775c2c66affSColin Finck                     !(ObpInsertEntryDirectory(Directory,
776c2c66affSColin Finck                                               LookupContext,
777c2c66affSColin Finck                                               ObjectHeader)))
778c2c66affSColin Finck                 {
779c2c66affSColin Finck                     /* Either couldn't allocate the name, or insert failed */
780c2c66affSColin Finck                     if (NewName) ExFreePoolWithTag(NewName, OB_NAME_TAG);
781c2c66affSColin Finck 
782c2c66affSColin Finck                     /* Fail due to memory reasons */
783c2c66affSColin Finck                     Status = STATUS_INSUFFICIENT_RESOURCES;
784c2c66affSColin Finck                     break;
785c2c66affSColin Finck                 }
786c2c66affSColin Finck 
787c2c66affSColin Finck                 /* Reference newly to be inserted object */
788c2c66affSColin Finck                 ObReferenceObject(InsertObject);
789c2c66affSColin Finck 
790c2c66affSColin Finck                 /* Get the name information */
791c2c66affSColin Finck                 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
792c2c66affSColin Finck 
793c2c66affSColin Finck                 /* Reference the directory */
794c2c66affSColin Finck                 ObReferenceObject(Directory);
795c2c66affSColin Finck 
796c2c66affSColin Finck                 /* Copy the Name */
797c2c66affSColin Finck                 RtlCopyMemory(NewName,
798c2c66affSColin Finck                               ComponentName.Buffer,
799c2c66affSColin Finck                               ComponentName.Length);
800c2c66affSColin Finck 
801c2c66affSColin Finck                 /* Check if we had an old name */
802c2c66affSColin Finck                 if (ObjectNameInfo->Name.Buffer)
803c2c66affSColin Finck                 {
804c2c66affSColin Finck                     /* Free it */
805c2c66affSColin Finck                     ExFreePoolWithTag(ObjectNameInfo->Name.Buffer, OB_NAME_TAG);
806c2c66affSColin Finck                 }
807c2c66affSColin Finck 
808c2c66affSColin Finck                 /* Write new one */
809c2c66affSColin Finck                 ObjectNameInfo->Name.Buffer = NewName;
810c2c66affSColin Finck                 ObjectNameInfo->Name.Length = ComponentName.Length;
811c2c66affSColin Finck                 ObjectNameInfo->Name.MaximumLength = ComponentName.Length;
812c2c66affSColin Finck 
813c2c66affSColin Finck                 /* Return Status and the Expected Object */
814c2c66affSColin Finck                 Status = STATUS_SUCCESS;
815c2c66affSColin Finck                 Object = InsertObject;
816c2c66affSColin Finck 
817c2c66affSColin Finck                 /* Get out of here */
818c2c66affSColin Finck                 break;
819c2c66affSColin Finck             }
820c2c66affSColin Finck 
821c2c66affSColin Finck ReparseObject:
822c2c66affSColin Finck             /* We found it, so now get its header */
823c2c66affSColin Finck             ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
824c2c66affSColin Finck 
825c2c66affSColin Finck             /*
826c2c66affSColin Finck              * Check for a parse Procedure, but don't bother to parse for an insert
827c2c66affSColin Finck              * unless it's a Symbolic Link, in which case we MUST parse
828c2c66affSColin Finck              */
829c2c66affSColin Finck             ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure;
830c2c66affSColin Finck             if ((ParseRoutine) &&
831c2c66affSColin Finck                 (!(InsertObject) || (ParseRoutine == ObpParseSymbolicLink)))
832c2c66affSColin Finck             {
833c2c66affSColin Finck                 /* Use the Root Directory next time */
834c2c66affSColin Finck                 Directory = NULL;
835c2c66affSColin Finck 
836c2c66affSColin Finck                 /* Increment the pointer count */
837*ff7cc6f3STimo Kreuzer                 InterlockedExchangeAddSizeT(&ObjectHeader->PointerCount, 1);
838c2c66affSColin Finck 
839c2c66affSColin Finck                 /* Cleanup from the first lookup */
840c2c66affSColin Finck                 ObpReleaseLookupContext(LookupContext);
841c2c66affSColin Finck 
842c2c66affSColin Finck                 /* Check if we have a referenced directory */
843c2c66affSColin Finck                 if (ReferencedDirectory)
844c2c66affSColin Finck                 {
845c2c66affSColin Finck                     /* We do, dereference it */
846c2c66affSColin Finck                     ObDereferenceObject(ReferencedDirectory);
847c2c66affSColin Finck                     ReferencedDirectory = NULL;
848c2c66affSColin Finck                 }
849c2c66affSColin Finck 
850c2c66affSColin Finck                 /* Check if we have a referenced parent directory */
851c2c66affSColin Finck                 if (ReferencedParentDirectory)
852c2c66affSColin Finck                 {
853c2c66affSColin Finck                     /* We do, dereference it */
854c2c66affSColin Finck                     ObDereferenceObject(ReferencedParentDirectory);
855c2c66affSColin Finck                     ReferencedParentDirectory = NULL;
856c2c66affSColin Finck                 }
857c2c66affSColin Finck 
858c2c66affSColin Finck                 /* Call the Parse Procedure */
859c2c66affSColin Finck                 ObpCalloutStart(&CalloutIrql);
860c2c66affSColin Finck                 Status = ParseRoutine(Object,
861c2c66affSColin Finck                                       ObjectType,
862c2c66affSColin Finck                                       AccessState,
863c2c66affSColin Finck                                       AccessCheckMode,
864c2c66affSColin Finck                                       Attributes,
865c2c66affSColin Finck                                       ObjectName,
866c2c66affSColin Finck                                       &RemainingName,
867c2c66affSColin Finck                                       ParseContext,
868c2c66affSColin Finck                                       SecurityQos,
869c2c66affSColin Finck                                       &Object);
870c2c66affSColin Finck                 ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object);
871c2c66affSColin Finck 
872c2c66affSColin Finck                 /* Remove our extra reference */
873c2c66affSColin Finck                 ObDereferenceObject(&ObjectHeader->Body);
874c2c66affSColin Finck 
875c2c66affSColin Finck                 /* Check if we have to reparse */
876c2c66affSColin Finck                 if ((Status == STATUS_REPARSE) ||
877c2c66affSColin Finck                     (Status == STATUS_REPARSE_OBJECT))
878c2c66affSColin Finck                 {
879c2c66affSColin Finck                     /* Reparse again */
880c2c66affSColin Finck                     Reparse = TRUE;
881c2c66affSColin Finck                     --MaxReparse;
882c2c66affSColin Finck                     if (MaxReparse == 0)
883c2c66affSColin Finck                     {
884c2c66affSColin Finck                         Object = NULL;
885c2c66affSColin Finck                         break;
886c2c66affSColin Finck                     }
887c2c66affSColin Finck 
888c2c66affSColin Finck                     /* Start over from root if we got sent back there */
889c2c66affSColin Finck                     if ((Status == STATUS_REPARSE_OBJECT) ||
890c2c66affSColin Finck                         (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR))
891c2c66affSColin Finck                     {
892c2c66affSColin Finck                         /* Check if we got a root directory */
893c2c66affSColin Finck                         if (RootHandle)
894c2c66affSColin Finck                         {
895c2c66affSColin Finck                             /* Stop using it, because we have a new directory now */
896c2c66affSColin Finck                             ObDereferenceObject(RootDirectory);
897c2c66affSColin Finck                             RootHandle = NULL;
898c2c66affSColin Finck                         }
899c2c66affSColin Finck 
900c2c66affSColin Finck                         /* Start at Root */
901c2c66affSColin Finck                         ParentDirectory = NULL;
902c2c66affSColin Finck                         RootDirectory = ObpRootDirectoryObject;
903c2c66affSColin Finck 
904c2c66affSColin Finck                         /* Check for reparse status */
905c2c66affSColin Finck                         if (Status == STATUS_REPARSE_OBJECT)
906c2c66affSColin Finck                         {
907c2c66affSColin Finck                             /* Don't reparse again */
908c2c66affSColin Finck                             Reparse = FALSE;
909c2c66affSColin Finck 
910c2c66affSColin Finck                             /* Did we actually get an object to which to reparse? */
911c2c66affSColin Finck                             if (!Object)
912c2c66affSColin Finck                             {
913c2c66affSColin Finck                                 /* We didn't, so set a failure status */
914c2c66affSColin Finck                                 Status = STATUS_OBJECT_NAME_NOT_FOUND;
915c2c66affSColin Finck                             }
916c2c66affSColin Finck                             else
917c2c66affSColin Finck                             {
918c2c66affSColin Finck                                 /* We did, so we're free to parse the new object */
919c2c66affSColin Finck                                 goto ReparseObject;
920c2c66affSColin Finck                             }
921c2c66affSColin Finck                         }
922c2c66affSColin Finck                         else
923c2c66affSColin Finck                         {
924c2c66affSColin Finck                             /* This is a symbolic link */
925c2c66affSColin Finck                             SymLink = TRUE;
926c2c66affSColin Finck                             goto ParseFromRoot;
927c2c66affSColin Finck                         }
928c2c66affSColin Finck                     }
929c2c66affSColin Finck                     else if (RootDirectory == ObpRootDirectoryObject)
930c2c66affSColin Finck                     {
931c2c66affSColin Finck                         /* We got STATUS_REPARSE but are at the Root Directory */
932c2c66affSColin Finck                         Object = NULL;
933c2c66affSColin Finck                         Status = STATUS_OBJECT_NAME_NOT_FOUND;
934c2c66affSColin Finck                         Reparse = FALSE;
935c2c66affSColin Finck                     }
936c2c66affSColin Finck                 }
937c2c66affSColin Finck                 else if (!NT_SUCCESS(Status))
938c2c66affSColin Finck                 {
939c2c66affSColin Finck                     /* Total failure */
940c2c66affSColin Finck                     Object = NULL;
941c2c66affSColin Finck                 }
942c2c66affSColin Finck                 else if (!Object)
943c2c66affSColin Finck                 {
944c2c66affSColin Finck                     /* We didn't reparse but we didn't find the Object Either */
945c2c66affSColin Finck                     Status = STATUS_OBJECT_NAME_NOT_FOUND;
946c2c66affSColin Finck                 }
947c2c66affSColin Finck 
948c2c66affSColin Finck                 /* Break out of the loop */
949c2c66affSColin Finck                 break;
950c2c66affSColin Finck             }
951c2c66affSColin Finck             else
952c2c66affSColin Finck             {
953c2c66affSColin Finck                 /* No parse routine...do we still have a remaining name? */
954c2c66affSColin Finck                 if (!RemainingName.Length)
955c2c66affSColin Finck                 {
956c2c66affSColin Finck                     /* Are we creating an object? */
957c2c66affSColin Finck                     if (!InsertObject)
958c2c66affSColin Finck                     {
959c2c66affSColin Finck                         /* Check if this is a user-mode call that needs to traverse */
960c2c66affSColin Finck                         if ((AccessCheckMode != KernelMode) &&
961c2c66affSColin Finck                             !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE))
962c2c66affSColin Finck                         {
963c2c66affSColin Finck                             /* Check if we can get it */
964c2c66affSColin Finck                             if (!ObpCheckTraverseAccess(Directory,
965c2c66affSColin Finck                                                         DIRECTORY_TRAVERSE,
966c2c66affSColin Finck                                                         AccessState,
967c2c66affSColin Finck                                                         FALSE,
968c2c66affSColin Finck                                                         AccessCheckMode,
969c2c66affSColin Finck                                                         &Status))
970c2c66affSColin Finck                             {
971c2c66affSColin Finck                                 /* We don't have access, fail */
972c2c66affSColin Finck                                 Object = NULL;
973c2c66affSColin Finck                                 break;
974c2c66affSColin Finck                             }
975c2c66affSColin Finck                         }
976c2c66affSColin Finck 
977c2c66affSColin Finck                         /* Reference the Object */
978c2c66affSColin Finck                         Status = ObReferenceObjectByPointer(Object,
979c2c66affSColin Finck                                                             0,
980c2c66affSColin Finck                                                             ObjectType,
981c2c66affSColin Finck                                                             AccessMode);
982c2c66affSColin Finck                         if (!NT_SUCCESS(Status)) Object = NULL;
983c2c66affSColin Finck                     }
984c2c66affSColin Finck 
985c2c66affSColin Finck                     /* And get out of the reparse loop */
986c2c66affSColin Finck                     break;
987c2c66affSColin Finck                 }
988c2c66affSColin Finck                 else
989c2c66affSColin Finck                 {
990c2c66affSColin Finck                     /* We still have a name; check if this is a directory object */
991c2c66affSColin Finck                     if (ObjectHeader->Type == ObDirectoryType)
992c2c66affSColin Finck                     {
993c2c66affSColin Finck                         /* Check if we have a referenced parent directory */
994c2c66affSColin Finck                         if (ReferencedParentDirectory)
995c2c66affSColin Finck                         {
996c2c66affSColin Finck                             /* Dereference it */
997c2c66affSColin Finck                             ObDereferenceObject(ReferencedParentDirectory);
998c2c66affSColin Finck                         }
999c2c66affSColin Finck 
1000c2c66affSColin Finck                         /* Restart the lookup from this directory */
1001c2c66affSColin Finck                         ReferencedParentDirectory = ReferencedDirectory;
1002c2c66affSColin Finck                         ParentDirectory = Directory;
1003c2c66affSColin Finck                         Directory = Object;
1004c2c66affSColin Finck                         ReferencedDirectory = NULL;
1005c2c66affSColin Finck                     }
1006c2c66affSColin Finck                     else
1007c2c66affSColin Finck                     {
1008c2c66affSColin Finck                         /* We still have a name, but no parse routine for it */
1009c2c66affSColin Finck                         Status = STATUS_OBJECT_TYPE_MISMATCH;
1010c2c66affSColin Finck                         Object = NULL;
1011c2c66affSColin Finck                         break;
1012c2c66affSColin Finck                     }
1013c2c66affSColin Finck                 }
1014c2c66affSColin Finck             }
1015c2c66affSColin Finck         }
1016c2c66affSColin Finck     }
1017c2c66affSColin Finck 
1018c2c66affSColin Finck     /* Check if we failed */
1019c2c66affSColin Finck     if (!NT_SUCCESS(Status))
1020c2c66affSColin Finck     {
1021c2c66affSColin Finck         /* Cleanup after lookup */
1022c2c66affSColin Finck         ObpReleaseLookupContext(LookupContext);
1023c2c66affSColin Finck     }
1024c2c66affSColin Finck 
1025c2c66affSColin Finck     /* Check if we have a device map and dereference it if so */
1026c2c66affSColin Finck     //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap);
1027c2c66affSColin Finck 
1028c2c66affSColin Finck     /* Check if we have a referenced directory and dereference it if so */
1029c2c66affSColin Finck     if (ReferencedDirectory) ObDereferenceObject(ReferencedDirectory);
1030c2c66affSColin Finck 
1031c2c66affSColin Finck     /* Check if we have a referenced parent directory */
1032c2c66affSColin Finck     if (ReferencedParentDirectory)
1033c2c66affSColin Finck     {
1034c2c66affSColin Finck         /* We do, dereference it */
1035c2c66affSColin Finck         ObDereferenceObject(ReferencedParentDirectory);
1036c2c66affSColin Finck     }
1037c2c66affSColin Finck 
1038c2c66affSColin Finck     /* Set the found object and check if we got one */
1039c2c66affSColin Finck     *FoundObject = Object;
1040c2c66affSColin Finck     if (!Object)
1041c2c66affSColin Finck     {
1042c2c66affSColin Finck         /* Nothing was found. Did we reparse or get success? */
1043c2c66affSColin Finck         if ((Status == STATUS_REPARSE) || (NT_SUCCESS(Status)))
1044c2c66affSColin Finck         {
1045c2c66affSColin Finck             /* Set correct failure */
1046c2c66affSColin Finck             Status = STATUS_OBJECT_NAME_NOT_FOUND;
1047c2c66affSColin Finck         }
1048c2c66affSColin Finck     }
1049c2c66affSColin Finck 
1050c2c66affSColin Finck     /* Check if we had a root directory */
1051c2c66affSColin Finck     if (RootHandle) ObDereferenceObject(RootDirectory);
1052c2c66affSColin Finck 
1053c2c66affSColin Finck     /* Return status to caller */
1054c2c66affSColin Finck     OBTRACE(OB_NAMESPACE_DEBUG,
1055c2c66affSColin Finck             "%s - Found Object: %p. Expected: %p\n",
1056c2c66affSColin Finck             __FUNCTION__,
1057c2c66affSColin Finck             *FoundObject,
1058c2c66affSColin Finck             InsertObject);
1059c2c66affSColin Finck     return Status;
1060c2c66affSColin Finck }
1061c2c66affSColin Finck 
1062c2c66affSColin Finck /* PUBLIC FUNCTIONS *********************************************************/
1063c2c66affSColin Finck 
1064c2c66affSColin Finck NTSTATUS
1065c2c66affSColin Finck NTAPI
1066c2c66affSColin Finck ObQueryNameString(IN PVOID Object,
1067c2c66affSColin Finck                   OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1068c2c66affSColin Finck                   IN ULONG Length,
1069c2c66affSColin Finck                   OUT PULONG ReturnLength)
1070c2c66affSColin Finck {
1071c2c66affSColin Finck     POBJECT_HEADER_NAME_INFO LocalInfo;
1072c2c66affSColin Finck     POBJECT_HEADER ObjectHeader;
1073c2c66affSColin Finck     POBJECT_DIRECTORY ParentDirectory;
1074c2c66affSColin Finck     ULONG NameSize;
1075c2c66affSColin Finck     PWCH ObjectName;
1076c2c66affSColin Finck     BOOLEAN ObjectIsNamed;
1077c2c66affSColin Finck     NTSTATUS Status = STATUS_SUCCESS;
1078c2c66affSColin Finck 
1079c2c66affSColin Finck     /* Get the Kernel Meta-Structures */
1080c2c66affSColin Finck     ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
1081c2c66affSColin Finck     LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
1082c2c66affSColin Finck 
1083c2c66affSColin Finck     /* Check if a Query Name Procedure is available */
1084c2c66affSColin Finck     if (ObjectHeader->Type->TypeInfo.QueryNameProcedure)
1085c2c66affSColin Finck     {
1086c2c66affSColin Finck         /* Call the procedure inside SEH */
1087c2c66affSColin Finck         ObjectIsNamed = ((LocalInfo) && (LocalInfo->Name.Length > 0));
1088c2c66affSColin Finck 
1089c2c66affSColin Finck         _SEH2_TRY
1090c2c66affSColin Finck         {
1091c2c66affSColin Finck             Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object,
1092c2c66affSColin Finck                                                                ObjectIsNamed,
1093c2c66affSColin Finck                                                                ObjectNameInfo,
1094c2c66affSColin Finck                                                                Length,
1095c2c66affSColin Finck                                                                ReturnLength,
1096c2c66affSColin Finck                                                                KernelMode);
1097c2c66affSColin Finck         }
1098c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1099c2c66affSColin Finck         {
1100c2c66affSColin Finck             /* Return the exception code */
1101c2c66affSColin Finck             Status = _SEH2_GetExceptionCode();
1102c2c66affSColin Finck         }
1103c2c66affSColin Finck         _SEH2_END;
1104c2c66affSColin Finck 
1105c2c66affSColin Finck         return Status;
1106c2c66affSColin Finck     }
1107c2c66affSColin Finck 
1108c2c66affSColin Finck     /* Check if the object doesn't even have a name */
1109c2c66affSColin Finck     if (!(LocalInfo) || !(LocalInfo->Name.Buffer))
1110c2c66affSColin Finck     {
1111c2c66affSColin Finck         Status = STATUS_SUCCESS;
1112c2c66affSColin Finck 
1113c2c66affSColin Finck         _SEH2_TRY
1114c2c66affSColin Finck         {
1115c2c66affSColin Finck             /* We're returning the name structure */
1116c2c66affSColin Finck             *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
1117c2c66affSColin Finck 
1118c2c66affSColin Finck             /* Check if we were given enough space */
1119c2c66affSColin Finck             if (*ReturnLength > Length)
1120c2c66affSColin Finck             {
1121c2c66affSColin Finck                 Status = STATUS_INFO_LENGTH_MISMATCH;
1122c2c66affSColin Finck             }
1123c2c66affSColin Finck             else
1124c2c66affSColin Finck             {
1125c2c66affSColin Finck                 /* Return an empty buffer */
1126c2c66affSColin Finck                 RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0);
1127c2c66affSColin Finck             }
1128c2c66affSColin Finck         }
1129c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1130c2c66affSColin Finck         {
1131c2c66affSColin Finck             /* Return the exception code */
1132c2c66affSColin Finck             Status = _SEH2_GetExceptionCode();
1133c2c66affSColin Finck         }
1134c2c66affSColin Finck         _SEH2_END;
1135c2c66affSColin Finck 
1136c2c66affSColin Finck         return Status;
1137c2c66affSColin Finck     }
1138c2c66affSColin Finck 
1139c2c66affSColin Finck     /*
1140c2c66affSColin Finck      * Find the size needed for the name. We won't do
1141c2c66affSColin Finck      * this during the Name Creation loop because we want
1142c2c66affSColin Finck      * to let the caller know that the buffer isn't big
1143c2c66affSColin Finck      * enough right at the beginning, not work our way through
1144c2c66affSColin Finck      * and find out at the end
1145c2c66affSColin Finck      */
1146c2c66affSColin Finck     _SEH2_TRY
1147c2c66affSColin Finck     {
1148c2c66affSColin Finck         if (Object == ObpRootDirectoryObject)
1149c2c66affSColin Finck         {
1150c2c66affSColin Finck             /* Size of the '\' string */
1151c2c66affSColin Finck             NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR);
1152c2c66affSColin Finck         }
1153c2c66affSColin Finck         else
1154c2c66affSColin Finck         {
1155c2c66affSColin Finck             /* Get the Object Directory and add name of Object */
1156c2c66affSColin Finck             ParentDirectory = LocalInfo->Directory;
1157c2c66affSColin Finck             NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length;
1158c2c66affSColin Finck 
1159c2c66affSColin Finck             /* Loop inside the directory to get the top-most one (meaning root) */
1160c2c66affSColin Finck             while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory))
1161c2c66affSColin Finck             {
1162c2c66affSColin Finck                 /* Get the Name Information */
1163c2c66affSColin Finck                 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
1164c2c66affSColin Finck                     OBJECT_TO_OBJECT_HEADER(ParentDirectory));
1165c2c66affSColin Finck 
1166c2c66affSColin Finck                 /* Add the size of the Directory Name */
1167c2c66affSColin Finck                 if (LocalInfo && LocalInfo->Directory)
1168c2c66affSColin Finck                 {
1169c2c66affSColin Finck                     /* Size of the '\' string + Directory Name */
1170c2c66affSColin Finck                     NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) +
1171c2c66affSColin Finck                                 LocalInfo->Name.Length;
1172c2c66affSColin Finck 
1173c2c66affSColin Finck                     /* Move to next parent Directory */
1174c2c66affSColin Finck                     ParentDirectory = LocalInfo->Directory;
1175c2c66affSColin Finck                 }
1176c2c66affSColin Finck                 else
1177c2c66affSColin Finck                 {
1178c2c66affSColin Finck                     /* Directory with no name. We append "...\" */
1179c2c66affSColin Finck                     NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR);
1180c2c66affSColin Finck                     break;
1181c2c66affSColin Finck                 }
1182c2c66affSColin Finck             }
1183c2c66affSColin Finck         }
1184c2c66affSColin Finck 
1185c2c66affSColin Finck         /* Finally, add the name of the structure and the null char */
1186c2c66affSColin Finck         *ReturnLength = NameSize +
1187c2c66affSColin Finck                         sizeof(OBJECT_NAME_INFORMATION) +
1188c2c66affSColin Finck                         sizeof(UNICODE_NULL);
1189c2c66affSColin Finck 
1190c2c66affSColin Finck         /* Check if we were given enough space */
1191c2c66affSColin Finck         if (*ReturnLength > Length) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH);
1192c2c66affSColin Finck 
1193c2c66affSColin Finck         /*
1194c2c66affSColin Finck         * Now we will actually create the name. We work backwards because
1195c2c66affSColin Finck         * it's easier to start off from the Name we have and walk up the
1196c2c66affSColin Finck         * parent directories. We use the same logic as Name Length calculation.
1197c2c66affSColin Finck         */
1198c2c66affSColin Finck         LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
1199c2c66affSColin Finck         ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength);
1200c2c66affSColin Finck         *--ObjectName = UNICODE_NULL;
1201c2c66affSColin Finck 
1202c2c66affSColin Finck         /* Check if the object is actually the Root directory */
1203c2c66affSColin Finck         if (Object == ObpRootDirectoryObject)
1204c2c66affSColin Finck         {
1205c2c66affSColin Finck             /* This is already the Root Directory, return "\\" */
1206c2c66affSColin Finck             *--ObjectName = OBJ_NAME_PATH_SEPARATOR;
1207c2c66affSColin Finck             ObjectNameInfo->Name.Length = (USHORT)NameSize;
1208c2c66affSColin Finck             ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize +
1209c2c66affSColin Finck                                                           sizeof(UNICODE_NULL));
1210c2c66affSColin Finck             ObjectNameInfo->Name.Buffer = ObjectName;
1211c2c66affSColin Finck             Status = STATUS_SUCCESS;
1212c2c66affSColin Finck         }
1213c2c66affSColin Finck         else
1214c2c66affSColin Finck         {
1215c2c66affSColin Finck             /* Start by adding the Object's Name */
1216c2c66affSColin Finck             ObjectName = (PWCH)((ULONG_PTR)ObjectName -
1217c2c66affSColin Finck                                            LocalInfo->Name.Length);
1218c2c66affSColin Finck             RtlCopyMemory(ObjectName,
1219c2c66affSColin Finck                           LocalInfo->Name.Buffer,
1220c2c66affSColin Finck                           LocalInfo->Name.Length);
1221c2c66affSColin Finck 
1222c2c66affSColin Finck             /* Now parse the Parent directories until we reach the top */
1223c2c66affSColin Finck             ParentDirectory = LocalInfo->Directory;
1224c2c66affSColin Finck             while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory))
1225c2c66affSColin Finck             {
1226c2c66affSColin Finck                 /* Get the name information */
1227c2c66affSColin Finck                 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(
1228c2c66affSColin Finck                     OBJECT_TO_OBJECT_HEADER(ParentDirectory));
1229c2c66affSColin Finck 
1230c2c66affSColin Finck                 /* Add the "\" */
1231c2c66affSColin Finck                 *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR;
1232c2c66affSColin Finck 
1233c2c66affSColin Finck                 /* Add the Parent Directory's Name */
1234c2c66affSColin Finck                 if (LocalInfo && LocalInfo->Name.Buffer)
1235c2c66affSColin Finck                 {
1236c2c66affSColin Finck                     /* Add the name */
1237c2c66affSColin Finck                     ObjectName = (PWCH)((ULONG_PTR)ObjectName -
1238c2c66affSColin Finck                                                    LocalInfo->Name.Length);
1239c2c66affSColin Finck                     RtlCopyMemory(ObjectName,
1240c2c66affSColin Finck                                   LocalInfo->Name.Buffer,
1241c2c66affSColin Finck                                   LocalInfo->Name.Length);
1242c2c66affSColin Finck 
1243c2c66affSColin Finck                     /* Move to next parent */
1244c2c66affSColin Finck                     ParentDirectory = LocalInfo->Directory;
1245c2c66affSColin Finck                 }
1246c2c66affSColin Finck                 else
1247c2c66affSColin Finck                 {
1248c2c66affSColin Finck                     /* Directory without a name, we add "..." */
1249c2c66affSColin Finck                     ObjectName = (PWCH)((ULONG_PTR)ObjectName -
1250c2c66affSColin Finck                                                    sizeof(L"...") +
1251c2c66affSColin Finck                                                    sizeof(UNICODE_NULL));
1252c2c66affSColin Finck                     RtlCopyMemory(ObjectName, L"...", sizeof(L"..."));
1253c2c66affSColin Finck                     break;
1254c2c66affSColin Finck                 }
1255c2c66affSColin Finck             }
1256c2c66affSColin Finck 
1257c2c66affSColin Finck             /* Add Root Directory Name */
1258c2c66affSColin Finck             *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR;
1259c2c66affSColin Finck             ObjectNameInfo->Name.Length = (USHORT)NameSize;
1260c2c66affSColin Finck             ObjectNameInfo->Name.MaximumLength =
1261c2c66affSColin Finck                 (USHORT)(NameSize + sizeof(UNICODE_NULL));
1262c2c66affSColin Finck             ObjectNameInfo->Name.Buffer = ObjectName;
1263c2c66affSColin Finck         }
1264c2c66affSColin Finck     }
1265c2c66affSColin Finck     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1266c2c66affSColin Finck     {
1267c2c66affSColin Finck         /* Return the exception code */
1268c2c66affSColin Finck         Status = _SEH2_GetExceptionCode();
1269c2c66affSColin Finck     }
1270c2c66affSColin Finck     _SEH2_END;
1271c2c66affSColin Finck 
1272c2c66affSColin Finck     /* Return success */
1273c2c66affSColin Finck     return Status;
1274c2c66affSColin Finck }
1275c2c66affSColin Finck 
1276c2c66affSColin Finck /* EOF */
1277