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