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