Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenobname.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ob/obname.c 00005 * PURPOSE: Manages all functions related to the Object Manager name- 00006 * space, such as finding objects or querying their names. 00007 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00008 * Eric Kohl 00009 * Thomas Weidenmueller (w3seek@reactos.org) 00010 */ 00011 00012 /* INCLUDES ******************************************************************/ 00013 00014 #include <ntoskrnl.h> 00015 #define NDEBUG 00016 #include <debug.h> 00017 00018 BOOLEAN ObpCaseInsensitive = TRUE; 00019 POBJECT_DIRECTORY ObpRootDirectoryObject; 00020 POBJECT_DIRECTORY ObpTypeDirectoryObject; 00021 00022 /* DOS Device Prefix \??\ and \?? */ 00023 ALIGNEDNAME ObpDosDevicesShortNamePrefix = {{L'\\',L'?',L'?',L'\\'}}; 00024 ALIGNEDNAME ObpDosDevicesShortNameRoot = {{L'\\',L'?',L'?',L'\0'}}; 00025 UNICODE_STRING ObpDosDevicesShortName = 00026 { 00027 sizeof(ObpDosDevicesShortNamePrefix), 00028 sizeof(ObpDosDevicesShortNamePrefix), 00029 (PWSTR)&ObpDosDevicesShortNamePrefix 00030 }; 00031 00032 /* PRIVATE FUNCTIONS *********************************************************/ 00033 00034 NTSTATUS 00035 NTAPI 00036 INIT_FUNCTION 00037 ObpCreateDosDevicesDirectory(VOID) 00038 { 00039 OBJECT_ATTRIBUTES ObjectAttributes; 00040 UNICODE_STRING Name, LinkName; 00041 HANDLE Handle, SymHandle; 00042 NTSTATUS Status; 00043 00044 /* Create the '\??' directory */ 00045 RtlInitUnicodeString(&Name, L"\\??"); 00046 InitializeObjectAttributes(&ObjectAttributes, 00047 &Name, 00048 OBJ_PERMANENT, 00049 NULL, 00050 NULL); 00051 Status = NtCreateDirectoryObject(&Handle, 00052 DIRECTORY_ALL_ACCESS, 00053 &ObjectAttributes); 00054 if (!NT_SUCCESS(Status)) return FALSE; 00055 00056 /* Initialize the GLOBALROOT path */ 00057 RtlInitUnicodeString(&LinkName, L"GLOBALROOT"); 00058 RtlInitUnicodeString(&Name, L""); 00059 InitializeObjectAttributes(&ObjectAttributes, 00060 &LinkName, 00061 OBJ_PERMANENT, 00062 Handle, 00063 NULL); 00064 Status = NtCreateSymbolicLinkObject(&SymHandle, 00065 SYMBOLIC_LINK_ALL_ACCESS, 00066 &ObjectAttributes, 00067 &Name); 00068 if (NT_SUCCESS(Status)) NtClose(SymHandle); 00069 00070 /* Link \??\Global to \?? */ 00071 RtlInitUnicodeString(&LinkName, L"Global"); 00072 RtlInitUnicodeString(&Name, L"\\??"); 00073 InitializeObjectAttributes(&ObjectAttributes, 00074 &LinkName, 00075 OBJ_PERMANENT, 00076 Handle, 00077 NULL); 00078 Status = NtCreateSymbolicLinkObject(&SymHandle, 00079 SYMBOLIC_LINK_ALL_ACCESS, 00080 &ObjectAttributes, 00081 &Name); 00082 if (NT_SUCCESS(Status)) NtClose(SymHandle); 00083 00084 /* Close the directory handle */ 00085 NtClose(Handle); 00086 if (!NT_SUCCESS(Status)) return Status; 00087 00088 /* Create link from '\DosDevices' to '\??' directory */ 00089 RtlCreateUnicodeString(&LinkName, L"\\DosDevices"); 00090 InitializeObjectAttributes(&ObjectAttributes, 00091 &LinkName, 00092 OBJ_PERMANENT, 00093 NULL, 00094 NULL); 00095 Status = NtCreateSymbolicLinkObject(&SymHandle, 00096 SYMBOLIC_LINK_ALL_ACCESS, 00097 &ObjectAttributes, 00098 &Name); 00099 if (NT_SUCCESS(Status)) NtClose(SymHandle); 00100 00101 /* FIXME: Hack Hack! */ 00102 ObSystemDeviceMap = ExAllocatePoolWithTag(NonPagedPool, 00103 sizeof(*ObSystemDeviceMap), 00104 'mDbO'); 00105 if (!ObSystemDeviceMap) return STATUS_INSUFFICIENT_RESOURCES; 00106 RtlZeroMemory(ObSystemDeviceMap, sizeof(*ObSystemDeviceMap)); 00107 00108 /* Return status */ 00109 return Status; 00110 } 00111 00112 VOID 00113 NTAPI 00114 ObDereferenceDeviceMap(IN PEPROCESS Process) 00115 { 00116 PDEVICE_MAP DeviceMap; 00117 00118 /* Get the pointer to this process devicemap and reset it 00119 holding devicemap lock */ 00120 KeAcquireGuardedMutex(&ObpDeviceMapLock); 00121 DeviceMap = Process->DeviceMap; 00122 Process->DeviceMap = NULL; 00123 KeReleaseGuardedMutex(&ObpDeviceMapLock); 00124 00125 /* Continue only if there is a devicemap to dereference */ 00126 if (DeviceMap) 00127 { 00128 KeAcquireGuardedMutex(&ObpDeviceMapLock); 00129 00130 /* Delete the device map link and dereference it */ 00131 if (--DeviceMap->ReferenceCount) 00132 { 00133 /* Nobody is referencing it anymore, unlink the DOS directory */ 00134 DeviceMap->DosDevicesDirectory->DeviceMap = NULL; 00135 00136 /* Release the devicemap lock */ 00137 KeReleaseGuardedMutex(&ObpDeviceMapLock); 00138 00139 /* Dereference the DOS Devices Directory and free the Device Map */ 00140 ObDereferenceObject(DeviceMap->DosDevicesDirectory); 00141 ExFreePool(DeviceMap); 00142 } 00143 else 00144 { 00145 /* Release the devicemap lock */ 00146 KeReleaseGuardedMutex(&ObpDeviceMapLock); 00147 } 00148 } 00149 } 00150 00151 VOID 00152 NTAPI 00153 ObInheritDeviceMap(IN PEPROCESS Parent, 00154 IN PEPROCESS Process) 00155 { 00156 /* FIXME: Devicemap Support */ 00157 } 00158 00159 /*++ 00160 * @name ObpDeleteNameCheck 00161 * 00162 * The ObpDeleteNameCheck routine checks if a named object should be 00163 * removed from the object directory namespace. 00164 * 00165 * @param Object 00166 * Pointer to the object to check for possible removal. 00167 * 00168 * @return None. 00169 * 00170 * @remarks An object is removed if the following 4 criteria are met: 00171 * 1) The object has 0 handles open 00172 * 2) The object is in the directory namespace and has a name 00173 * 3) The object is not permanent 00174 * 00175 *--*/ 00176 VOID 00177 NTAPI 00178 ObpDeleteNameCheck(IN PVOID Object) 00179 { 00180 POBJECT_HEADER ObjectHeader; 00181 OBP_LOOKUP_CONTEXT Context; 00182 POBJECT_HEADER_NAME_INFO ObjectNameInfo; 00183 POBJECT_TYPE ObjectType; 00184 PVOID Directory = NULL; 00185 00186 /* Get object structures */ 00187 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 00188 ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader); 00189 ObjectType = ObjectHeader->Type; 00190 00191 /* 00192 * Check if the handle count is 0, if the object is named, 00193 * and if the object isn't a permanent object. 00194 */ 00195 if (!(ObjectHeader->HandleCount) && 00196 (ObjectNameInfo) && 00197 (ObjectNameInfo->Name.Length) && 00198 (ObjectNameInfo->Directory) && 00199 !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) 00200 { 00201 /* Setup a lookup context */ 00202 ObpInitializeLookupContext(&Context); 00203 00204 /* Lock the directory */ 00205 ObpAcquireDirectoryLockExclusive(ObjectNameInfo->Directory, &Context); 00206 00207 /* Do the lookup */ 00208 Object = ObpLookupEntryDirectory(ObjectNameInfo->Directory, 00209 &ObjectNameInfo->Name, 00210 0, 00211 FALSE, 00212 &Context); 00213 if (Object) 00214 { 00215 /* Lock the object */ 00216 ObpAcquireObjectLock(ObjectHeader); 00217 00218 /* Make sure we can still delete the object */ 00219 if (!(ObjectHeader->HandleCount) && 00220 !(ObjectHeader->Flags & OB_FLAG_PERMANENT)) 00221 { 00222 /* First delete it from the directory */ 00223 ObpDeleteEntryDirectory(&Context); 00224 00225 /* Check if this is a symbolic link */ 00226 if (ObjectType == ObSymbolicLinkType) 00227 { 00228 /* Remove internal name */ 00229 ObpDeleteSymbolicLinkName(Object); 00230 } 00231 00232 /* Check if the magic protection flag is set */ 00233 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 00234 if ((ObjectNameInfo) && 00235 (ObjectNameInfo->QueryReferences & 0x40000000)) 00236 { 00237 /* Remove protection flag */ 00238 InterlockedExchangeAdd((PLONG)&ObjectNameInfo->QueryReferences, 00239 -0x40000000); 00240 } 00241 00242 /* Get the directory */ 00243 Directory = ObjectNameInfo->Directory; 00244 } 00245 00246 /* Release the lock */ 00247 ObpReleaseObjectLock(ObjectHeader); 00248 } 00249 00250 /* Cleanup after lookup */ 00251 ObpReleaseLookupContext(&Context); 00252 00253 /* Remove another query reference since we added one on top */ 00254 ObpDereferenceNameInfo(ObjectNameInfo); 00255 00256 /* Check if we were inserted in a directory */ 00257 if (Directory) 00258 { 00259 /* We were, so first remove the extra reference we had added */ 00260 ObpDereferenceNameInfo(ObjectNameInfo); 00261 00262 /* Now dereference the object as well */ 00263 ObDereferenceObject(Object); 00264 } 00265 } 00266 else 00267 { 00268 /* Remove the reference we added */ 00269 ObpDereferenceNameInfo(ObjectNameInfo); 00270 } 00271 } 00272 00273 NTSTATUS 00274 NTAPI 00275 ObpLookupObjectName(IN HANDLE RootHandle OPTIONAL, 00276 IN PUNICODE_STRING ObjectName, 00277 IN ULONG Attributes, 00278 IN POBJECT_TYPE ObjectType, 00279 IN KPROCESSOR_MODE AccessMode, 00280 IN OUT PVOID ParseContext, 00281 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, 00282 IN PVOID InsertObject OPTIONAL, 00283 IN OUT PACCESS_STATE AccessState, 00284 OUT POBP_LOOKUP_CONTEXT LookupContext, 00285 OUT PVOID *FoundObject) 00286 { 00287 PVOID Object; 00288 POBJECT_HEADER ObjectHeader; 00289 UNICODE_STRING ComponentName, RemainingName; 00290 BOOLEAN Reparse = FALSE, SymLink = FALSE; 00291 POBJECT_DIRECTORY Directory = NULL, ParentDirectory = NULL, RootDirectory; 00292 POBJECT_DIRECTORY ReferencedDirectory = NULL, ReferencedParentDirectory = NULL; 00293 KIRQL CalloutIrql; 00294 OB_PARSE_METHOD ParseRoutine; 00295 NTSTATUS Status; 00296 KPROCESSOR_MODE AccessCheckMode; 00297 PWCHAR NewName; 00298 POBJECT_HEADER_NAME_INFO ObjectNameInfo; 00299 ULONG MaxReparse = 30; 00300 PAGED_CODE(); 00301 OBTRACE(OB_NAMESPACE_DEBUG, 00302 "%s - Finding Object: %wZ. Expecting: %p\n", 00303 __FUNCTION__, 00304 ObjectName, 00305 InsertObject); 00306 00307 /* Initialize starting state */ 00308 ObpInitializeLookupContext(LookupContext); 00309 *FoundObject = NULL; 00310 Status = STATUS_SUCCESS; 00311 Object = NULL; 00312 00313 /* Check if case-insensitivity is checked */ 00314 if (ObpCaseInsensitive) 00315 { 00316 /* Check if the object type requests this */ 00317 if (!(ObjectType) || (ObjectType->TypeInfo.CaseInsensitive)) 00318 { 00319 /* Add the flag to disable case sensitivity */ 00320 Attributes |= OBJ_CASE_INSENSITIVE; 00321 } 00322 } 00323 00324 /* Check if this is a access checks are being forced */ 00325 AccessCheckMode = (Attributes & OBJ_FORCE_ACCESS_CHECK) ? 00326 UserMode : AccessMode; 00327 00328 /* Check if we got a Root Directory */ 00329 if (RootHandle) 00330 { 00331 /* We did. Reference it */ 00332 Status = ObReferenceObjectByHandle(RootHandle, 00333 0, 00334 NULL, 00335 AccessMode, 00336 (PVOID*)&RootDirectory, 00337 NULL); 00338 if (!NT_SUCCESS(Status)) return Status; 00339 00340 /* Get the header */ 00341 ObjectHeader = OBJECT_TO_OBJECT_HEADER(RootDirectory); 00342 00343 /* The name cannot start with a separator, unless this is a file */ 00344 if ((ObjectName->Buffer) && 00345 (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) && 00346 (ObjectHeader->Type != IoFileObjectType)) 00347 { 00348 /* The syntax is bad, so fail this request */ 00349 ObDereferenceObject(RootDirectory); 00350 return STATUS_OBJECT_PATH_SYNTAX_BAD; 00351 } 00352 00353 /* Don't parse a Directory */ 00354 if (ObjectHeader->Type != ObDirectoryType) 00355 { 00356 /* Make sure the Object Type has a parse routine */ 00357 ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure; 00358 if (!ParseRoutine) 00359 { 00360 /* We can't parse a name if we don't have a parse routine */ 00361 ObDereferenceObject(RootDirectory); 00362 return STATUS_INVALID_HANDLE; 00363 } 00364 00365 /* Set default parse count */ 00366 MaxReparse = 30; 00367 00368 /* Now parse */ 00369 while (TRUE) 00370 { 00371 /* Start with the full name */ 00372 RemainingName = *ObjectName; 00373 00374 /* Call the Parse Procedure */ 00375 ObpCalloutStart(&CalloutIrql); 00376 Status = ParseRoutine(RootDirectory, 00377 ObjectType, 00378 AccessState, 00379 AccessCheckMode, 00380 Attributes, 00381 ObjectName, 00382 &RemainingName, 00383 ParseContext, 00384 SecurityQos, 00385 &Object); 00386 ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object); 00387 00388 /* Check for success or failure, so not reparse */ 00389 if ((Status != STATUS_REPARSE) && 00390 (Status != STATUS_REPARSE_OBJECT)) 00391 { 00392 /* Check for failure */ 00393 if (!NT_SUCCESS(Status)) 00394 { 00395 /* Parse routine might not have cleared this, do it */ 00396 Object = NULL; 00397 } 00398 else if (!Object) 00399 { 00400 /* Modify status to reflect failure inside Ob */ 00401 Status = STATUS_OBJECT_NAME_NOT_FOUND; 00402 } 00403 00404 /* We're done, return the status and object */ 00405 *FoundObject = Object; 00406 ObDereferenceObject(RootDirectory); 00407 return Status; 00408 } 00409 else if ((!ObjectName->Length) || 00410 (!ObjectName->Buffer) || 00411 (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 00412 { 00413 /* Reparsed to the root directory, so start over */ 00414 ObDereferenceObject(RootDirectory); 00415 RootDirectory = ObpRootDirectoryObject; 00416 00417 /* Don't use this anymore, since we're starting at root */ 00418 RootHandle = NULL; 00419 goto ParseFromRoot; 00420 } 00421 else if (--MaxReparse) 00422 { 00423 /* Try reparsing again */ 00424 continue; 00425 } 00426 else 00427 { 00428 /* Reparsed too many times */ 00429 ObDereferenceObject(RootDirectory); 00430 00431 /* Return the object and normalized status */ 00432 *FoundObject = Object; 00433 if (!Object) Status = STATUS_OBJECT_NAME_NOT_FOUND; 00434 return Status; 00435 } 00436 } 00437 } 00438 else if (!(ObjectName->Length) || !(ObjectName->Buffer)) 00439 { 00440 /* Just return the Root Directory if we didn't get a name*/ 00441 Status = ObReferenceObjectByPointer(RootDirectory, 00442 0, 00443 ObjectType, 00444 AccessMode); 00445 if (NT_SUCCESS(Status)) Object = RootDirectory; 00446 00447 /* Remove the first reference we added and return the object */ 00448 ObDereferenceObject(RootDirectory); 00449 *FoundObject = Object; 00450 return Status; 00451 } 00452 } 00453 else 00454 { 00455 /* We did not get a Root Directory, so use the root */ 00456 RootDirectory = ObpRootDirectoryObject; 00457 00458 /* It must start with a path separator */ 00459 if (!(ObjectName->Length) || 00460 !(ObjectName->Buffer) || 00461 (ObjectName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)) 00462 { 00463 /* This name is invalid, so fail */ 00464 return STATUS_OBJECT_PATH_SYNTAX_BAD; 00465 } 00466 00467 /* Check if the name is only the path separator */ 00468 if (ObjectName->Length == sizeof(OBJ_NAME_PATH_SEPARATOR)) 00469 { 00470 /* So the caller only wants the root directory; do we have one? */ 00471 if (!RootDirectory) 00472 { 00473 /* This must be the first time we're creating it... right? */ 00474 if (InsertObject) 00475 { 00476 /* Yes, so return it to ObInsert so that it can create it */ 00477 Status = ObReferenceObjectByPointer(InsertObject, 00478 0, 00479 ObjectType, 00480 AccessMode); 00481 if (NT_SUCCESS(Status)) *FoundObject = InsertObject; 00482 return Status; 00483 } 00484 else 00485 { 00486 /* This should never really happen */ 00487 ASSERT(FALSE); 00488 return STATUS_INVALID_PARAMETER; 00489 } 00490 } 00491 else 00492 { 00493 /* We do have the root directory, so just return it */ 00494 Status = ObReferenceObjectByPointer(RootDirectory, 00495 0, 00496 ObjectType, 00497 AccessMode); 00498 if (NT_SUCCESS(Status)) *FoundObject = RootDirectory; 00499 return Status; 00500 } 00501 } 00502 else 00503 { 00504 ParseFromRoot: 00505 /* FIXME: Check if we have a device map */ 00506 00507 /* Check if this is a possible DOS name */ 00508 if (!((ULONG_PTR)(ObjectName->Buffer) & 7)) 00509 { 00510 /* 00511 * This could be one. Does it match the prefix? 00512 * Note that as an optimization, the match is done as 64-bit 00513 * compare since the prefix is "\??\" which is exactly 8 bytes. 00514 * 00515 * In the second branch, we test for "\??" which is also valid. 00516 * This time, we use a 32-bit compare followed by a Unicode 00517 * character compare (16-bit), since the sum is 6 bytes. 00518 */ 00519 if ((ObjectName->Length >= ObpDosDevicesShortName.Length) && 00520 (*(PULONGLONG)(ObjectName->Buffer) == 00521 ObpDosDevicesShortNamePrefix.Alignment.QuadPart)) 00522 { 00523 /* FIXME! */ 00524 } 00525 else if ((ObjectName->Length == ObpDosDevicesShortName.Length - 00526 sizeof(WCHAR)) && 00527 (*(PULONG)(ObjectName->Buffer) == 00528 ObpDosDevicesShortNameRoot.Alignment.LowPart) && 00529 (*((PWCHAR)(ObjectName->Buffer) + 2) == 00530 (WCHAR)(ObpDosDevicesShortNameRoot.Alignment.HighPart))) 00531 { 00532 /* FIXME! */ 00533 } 00534 } 00535 } 00536 } 00537 00538 /* Check if we were reparsing a symbolic link */ 00539 if (!SymLink) 00540 { 00541 /* Allow reparse */ 00542 Reparse = TRUE; 00543 MaxReparse = 30; 00544 } 00545 00546 /* Reparse */ 00547 while (Reparse && MaxReparse) 00548 { 00549 /* Get the name */ 00550 RemainingName = *ObjectName; 00551 00552 /* Disable reparsing again */ 00553 Reparse = FALSE; 00554 00555 /* Start parse loop */ 00556 while (TRUE) 00557 { 00558 /* Clear object */ 00559 Object = NULL; 00560 00561 /* Check if the name starts with a path separator */ 00562 if ((RemainingName.Length) && 00563 (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 00564 { 00565 /* Skip the path separator */ 00566 RemainingName.Buffer++; 00567 RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); 00568 } 00569 00570 /* Find the next Part Name */ 00571 ComponentName = RemainingName; 00572 while (RemainingName.Length) 00573 { 00574 /* Break if we found the \ ending */ 00575 if (RemainingName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR) break; 00576 00577 /* Move on */ 00578 RemainingName.Buffer++; 00579 RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); 00580 } 00581 00582 /* Get its size and make sure it's valid */ 00583 ComponentName.Length -= RemainingName.Length; 00584 if (!ComponentName.Length) 00585 { 00586 /* Invalid size, fail */ 00587 Status = STATUS_OBJECT_NAME_INVALID; 00588 break; 00589 } 00590 00591 /* Check if we're in the root */ 00592 if (!Directory) Directory = RootDirectory; 00593 00594 /* Check if this is a user-mode call that needs to traverse */ 00595 if ((AccessCheckMode != KernelMode) && 00596 !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE)) 00597 { 00598 /* We shouldn't have referenced a directory yet */ 00599 ASSERT(ReferencedDirectory == NULL); 00600 00601 /* Reference the directory */ 00602 ObReferenceObject(Directory); 00603 ReferencedDirectory = Directory; 00604 00605 /* Check if we have a parent directory */ 00606 if (ParentDirectory) 00607 { 00608 /* Check for traverse access */ 00609 if (!ObpCheckTraverseAccess(ParentDirectory, 00610 DIRECTORY_TRAVERSE, 00611 AccessState, 00612 FALSE, 00613 AccessCheckMode, 00614 &Status)) 00615 { 00616 /* We don't have it, fail */ 00617 break; 00618 } 00619 } 00620 } 00621 00622 /* Check if we don't have a remaining name yet */ 00623 if (!RemainingName.Length) 00624 { 00625 /* Check if we don't have a referenced directory yet */ 00626 if (!ReferencedDirectory) 00627 { 00628 /* Reference it */ 00629 ObReferenceObject(Directory); 00630 ReferencedDirectory = Directory; 00631 } 00632 00633 /* Check if we are inserting an object */ 00634 if (InsertObject) 00635 { 00636 /* Lock the directory */ 00637 ObpAcquireDirectoryLockExclusive(Directory, LookupContext); 00638 } 00639 } 00640 00641 /* Do the lookup */ 00642 Object = ObpLookupEntryDirectory(Directory, 00643 &ComponentName, 00644 Attributes, 00645 InsertObject ? FALSE : TRUE, 00646 LookupContext); 00647 if (!Object) 00648 { 00649 /* We didn't find it... do we still have a path? */ 00650 if (RemainingName.Length) 00651 { 00652 /* Then tell the caller the path wasn't found */ 00653 Status = STATUS_OBJECT_PATH_NOT_FOUND; 00654 break; 00655 } 00656 else if (!InsertObject) 00657 { 00658 /* Otherwise, we have a path, but the name isn't valid */ 00659 Status = STATUS_OBJECT_NAME_NOT_FOUND; 00660 break; 00661 } 00662 00663 /* Check create access for the object */ 00664 if (!ObCheckCreateObjectAccess(Directory, 00665 ObjectType == ObDirectoryType ? 00666 DIRECTORY_CREATE_SUBDIRECTORY : 00667 DIRECTORY_CREATE_OBJECT, 00668 AccessState, 00669 &ComponentName, 00670 FALSE, 00671 AccessCheckMode, 00672 &Status)) 00673 { 00674 /* We don't have create access, fail */ 00675 break; 00676 } 00677 00678 /* Get the object header */ 00679 ObjectHeader = OBJECT_TO_OBJECT_HEADER(InsertObject); 00680 00681 /* FIXME: Check if this is a Section Object or Sym Link */ 00682 /* FIXME: If it is, then check if this isn't session 0 */ 00683 /* FIXME: If it isn't, check for SeCreateGlobalPrivilege */ 00684 /* FIXME: If privilege isn't there, check for unsecure name */ 00685 /* FIXME: If it isn't a known unsecure name, then fail */ 00686 00687 /* Create Object Name */ 00688 NewName = ExAllocatePoolWithTag(PagedPool, 00689 ComponentName.Length, 00690 OB_NAME_TAG); 00691 if (!(NewName) || 00692 !(ObpInsertEntryDirectory(Directory, 00693 LookupContext, 00694 ObjectHeader))) 00695 { 00696 /* Either couldn't allocate the name, or insert failed */ 00697 if (NewName) ExFreePoolWithTag(NewName, OB_NAME_TAG); 00698 00699 /* Fail due to memory reasons */ 00700 Status = STATUS_INSUFFICIENT_RESOURCES; 00701 break; 00702 } 00703 00704 /* Reference newly to be inserted object */ 00705 ObReferenceObject(InsertObject); 00706 00707 /* Get the name information */ 00708 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 00709 00710 /* Reference the directory */ 00711 ObReferenceObject(Directory); 00712 00713 /* Copy the Name */ 00714 RtlCopyMemory(NewName, 00715 ComponentName.Buffer, 00716 ComponentName.Length); 00717 00718 /* Check if we had an old name */ 00719 if (ObjectNameInfo->Name.Buffer) 00720 { 00721 /* Free it */ 00722 ExFreePoolWithTag(ObjectNameInfo->Name.Buffer, OB_NAME_TAG ); 00723 } 00724 00725 /* Write new one */ 00726 ObjectNameInfo->Name.Buffer = NewName; 00727 ObjectNameInfo->Name.Length = ComponentName.Length; 00728 ObjectNameInfo->Name.MaximumLength = ComponentName.Length; 00729 00730 /* Return Status and the Expected Object */ 00731 Status = STATUS_SUCCESS; 00732 Object = InsertObject; 00733 00734 /* Get out of here */ 00735 break; 00736 } 00737 00738 ReparseObject: 00739 /* We found it, so now get its header */ 00740 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 00741 00742 /* 00743 * Check for a parse Procedure, but don't bother to parse for an insert 00744 * unless it's a Symbolic Link, in which case we MUST parse 00745 */ 00746 ParseRoutine = ObjectHeader->Type->TypeInfo.ParseProcedure; 00747 if ((ParseRoutine) && 00748 (!(InsertObject) || (ParseRoutine == ObpParseSymbolicLink))) 00749 { 00750 /* Use the Root Directory next time */ 00751 Directory = NULL; 00752 00753 /* Increment the pointer count */ 00754 InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1); 00755 00756 /* Cleanup from the first lookup */ 00757 ObpReleaseLookupContext(LookupContext); 00758 00759 /* Check if we have a referenced directory */ 00760 if (ReferencedDirectory) 00761 { 00762 /* We do, dereference it */ 00763 ObDereferenceObject(ReferencedDirectory); 00764 ReferencedDirectory = NULL; 00765 } 00766 00767 /* Check if we have a referenced parent directory */ 00768 if (ReferencedParentDirectory) 00769 { 00770 /* We do, dereference it */ 00771 ObDereferenceObject(ReferencedParentDirectory); 00772 ReferencedParentDirectory = NULL; 00773 } 00774 00775 /* Call the Parse Procedure */ 00776 ObpCalloutStart(&CalloutIrql); 00777 Status = ParseRoutine(Object, 00778 ObjectType, 00779 AccessState, 00780 AccessCheckMode, 00781 Attributes, 00782 ObjectName, 00783 &RemainingName, 00784 ParseContext, 00785 SecurityQos, 00786 &Object); 00787 ObpCalloutEnd(CalloutIrql, "Parse", ObjectHeader->Type, Object); 00788 00789 /* Remove our extra reference */ 00790 ObDereferenceObject(&ObjectHeader->Body); 00791 00792 /* Check if we have to reparse */ 00793 if ((Status == STATUS_REPARSE) || 00794 (Status == STATUS_REPARSE_OBJECT)) 00795 { 00796 /* Reparse again */ 00797 Reparse = TRUE; 00798 --MaxReparse; 00799 00800 /* Start over from root if we got sent back there */ 00801 if ((Status == STATUS_REPARSE_OBJECT) || 00802 (ObjectName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 00803 { 00804 /* Check if we got a root directory */ 00805 if (RootHandle) 00806 { 00807 /* Stop using it, because we have a new directory now */ 00808 ObDereferenceObject(RootDirectory); 00809 RootHandle = NULL; 00810 } 00811 00812 /* Start at Root */ 00813 ParentDirectory = NULL; 00814 RootDirectory = ObpRootDirectoryObject; 00815 00816 /* Check for reparse status */ 00817 if (Status == STATUS_REPARSE_OBJECT) 00818 { 00819 /* Don't reparse again */ 00820 Reparse = FALSE; 00821 00822 /* Did we actually get an object to which to reparse? */ 00823 if (!Object) 00824 { 00825 /* We didn't, so set a failure status */ 00826 Status = STATUS_OBJECT_NAME_NOT_FOUND; 00827 } 00828 else 00829 { 00830 /* We did, so we're free to parse the new object */ 00831 goto ReparseObject; 00832 } 00833 } 00834 else 00835 { 00836 /* This is a symbolic link */ 00837 SymLink = TRUE; 00838 goto ParseFromRoot; 00839 } 00840 } 00841 else if (RootDirectory == ObpRootDirectoryObject) 00842 { 00843 /* We got STATUS_REPARSE but are at the Root Directory */ 00844 Object = NULL; 00845 Status = STATUS_OBJECT_NAME_NOT_FOUND; 00846 Reparse = FALSE; 00847 } 00848 } 00849 else if (!NT_SUCCESS(Status)) 00850 { 00851 /* Total failure */ 00852 Object = NULL; 00853 } 00854 else if (!Object) 00855 { 00856 /* We didn't reparse but we didn't find the Object Either */ 00857 Status = STATUS_OBJECT_NAME_NOT_FOUND; 00858 } 00859 00860 /* Break out of the loop */ 00861 break; 00862 } 00863 else 00864 { 00865 /* No parse routine...do we still have a remaining name? */ 00866 if (!RemainingName.Length) 00867 { 00868 /* Are we creating an object? */ 00869 if (!InsertObject) 00870 { 00871 /* Check if this is a user-mode call that needs to traverse */ 00872 if ((AccessCheckMode != KernelMode) && 00873 !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE)) 00874 { 00875 /* Check if we can get it */ 00876 if (!ObpCheckTraverseAccess(Directory, 00877 DIRECTORY_TRAVERSE, 00878 AccessState, 00879 FALSE, 00880 AccessCheckMode, 00881 &Status)) 00882 { 00883 /* We don't have access, fail */ 00884 Object = NULL; 00885 break; 00886 } 00887 } 00888 00889 /* Reference the Object */ 00890 Status = ObReferenceObjectByPointer(Object, 00891 0, 00892 ObjectType, 00893 AccessMode); 00894 if (!NT_SUCCESS(Status)) Object = NULL; 00895 } 00896 00897 /* And get out of the reparse loop */ 00898 break; 00899 } 00900 else 00901 { 00902 /* We still have a name; check if this is a directory object */ 00903 if (ObjectHeader->Type == ObDirectoryType) 00904 { 00905 /* Check if we have a referenced parent directory */ 00906 if (ReferencedParentDirectory) 00907 { 00908 /* Dereference it */ 00909 ObDereferenceObject(ReferencedParentDirectory); 00910 } 00911 00912 /* Restart the lookup from this directory */ 00913 ReferencedParentDirectory = ReferencedDirectory; 00914 ParentDirectory = Directory; 00915 Directory = Object; 00916 ReferencedDirectory = NULL; 00917 } 00918 else 00919 { 00920 /* We still have a name, but no parse routine for it */ 00921 Status = STATUS_OBJECT_TYPE_MISMATCH; 00922 Object = NULL; 00923 break; 00924 } 00925 } 00926 } 00927 } 00928 } 00929 00930 /* Check if we failed */ 00931 if (!NT_SUCCESS(Status)) 00932 { 00933 /* Cleanup after lookup */ 00934 ObpReleaseLookupContext(LookupContext); 00935 } 00936 00937 /* Check if we have a device map and dereference it if so */ 00938 //if (DeviceMap) ObfDereferenceDeviceMap(DeviceMap); 00939 00940 /* Check if we have a referenced directory and dereference it if so */ 00941 if (ReferencedDirectory) ObDereferenceObject(ReferencedDirectory); 00942 00943 /* Check if we have a referenced parent directory */ 00944 if (ReferencedParentDirectory) 00945 { 00946 /* We do, dereference it */ 00947 ObDereferenceObject(ReferencedParentDirectory); 00948 } 00949 00950 /* Set the found object and check if we got one */ 00951 *FoundObject = Object; 00952 if (!Object) 00953 { 00954 /* Nothing was found. Did we reparse or get success? */ 00955 if ((Status == STATUS_REPARSE) || (NT_SUCCESS(Status))) 00956 { 00957 /* Set correct failure */ 00958 Status = STATUS_OBJECT_NAME_NOT_FOUND; 00959 } 00960 } 00961 00962 /* Check if we had a root directory */ 00963 if (RootHandle) ObDereferenceObject(RootDirectory); 00964 00965 /* Return status to caller */ 00966 OBTRACE(OB_NAMESPACE_DEBUG, 00967 "%s - Found Object: %p. Expected: %p\n", 00968 __FUNCTION__, 00969 *FoundObject, 00970 InsertObject); 00971 return Status; 00972 } 00973 00974 /* PUBLIC FUNCTIONS *********************************************************/ 00975 00976 NTSTATUS 00977 NTAPI 00978 ObQueryNameString(IN PVOID Object, 00979 OUT POBJECT_NAME_INFORMATION ObjectNameInfo, 00980 IN ULONG Length, 00981 OUT PULONG ReturnLength) 00982 { 00983 POBJECT_HEADER_NAME_INFO LocalInfo; 00984 POBJECT_HEADER ObjectHeader; 00985 POBJECT_DIRECTORY ParentDirectory; 00986 ULONG NameSize; 00987 PWCH ObjectName; 00988 BOOLEAN ObjectIsNamed; 00989 NTSTATUS Status = STATUS_SUCCESS; 00990 00991 /* Get the Kernel Meta-Structures */ 00992 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); 00993 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 00994 00995 /* Check if a Query Name Procedure is available */ 00996 if (ObjectHeader->Type->TypeInfo.QueryNameProcedure) 00997 { 00998 /* Call the procedure inside SEH */ 00999 ObjectIsNamed = ((LocalInfo) && (LocalInfo->Name.Length > 0)); 01000 01001 _SEH2_TRY 01002 { 01003 Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object, 01004 ObjectIsNamed, 01005 ObjectNameInfo, 01006 Length, 01007 ReturnLength, 01008 KernelMode); 01009 } 01010 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 01011 { 01012 /* Return the exception code */ 01013 Status = _SEH2_GetExceptionCode(); 01014 } 01015 _SEH2_END; 01016 01017 return Status; 01018 } 01019 01020 /* Check if the object doesn't even have a name */ 01021 if (!(LocalInfo) || !(LocalInfo->Name.Buffer)) 01022 { 01023 Status = STATUS_SUCCESS; 01024 01025 _SEH2_TRY 01026 { 01027 /* We're returning the name structure */ 01028 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION); 01029 01030 /* Check if we were given enough space */ 01031 if (*ReturnLength > Length) 01032 { 01033 Status = STATUS_INFO_LENGTH_MISMATCH; 01034 } 01035 else 01036 { 01037 /* Return an empty buffer */ 01038 RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, NULL, 0); 01039 } 01040 } 01041 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 01042 { 01043 /* Return the exception code */ 01044 Status = _SEH2_GetExceptionCode(); 01045 } 01046 _SEH2_END; 01047 01048 return Status; 01049 } 01050 01051 /* 01052 * Find the size needed for the name. We won't do 01053 * this during the Name Creation loop because we want 01054 * to let the caller know that the buffer isn't big 01055 * enough right at the beginning, not work our way through 01056 * and find out at the end 01057 */ 01058 _SEH2_TRY 01059 { 01060 if (Object == ObpRootDirectoryObject) 01061 { 01062 /* Size of the '\' string */ 01063 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR); 01064 } 01065 else 01066 { 01067 /* Get the Object Directory and add name of Object */ 01068 ParentDirectory = LocalInfo->Directory; 01069 NameSize = sizeof(OBJ_NAME_PATH_SEPARATOR) + LocalInfo->Name.Length; 01070 01071 /* Loop inside the directory to get the top-most one (meaning root) */ 01072 while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory)) 01073 { 01074 /* Get the Name Information */ 01075 LocalInfo = OBJECT_HEADER_TO_NAME_INFO( 01076 OBJECT_TO_OBJECT_HEADER(ParentDirectory)); 01077 01078 /* Add the size of the Directory Name */ 01079 if (LocalInfo && LocalInfo->Directory) 01080 { 01081 /* Size of the '\' string + Directory Name */ 01082 NameSize += sizeof(OBJ_NAME_PATH_SEPARATOR) + 01083 LocalInfo->Name.Length; 01084 01085 /* Move to next parent Directory */ 01086 ParentDirectory = LocalInfo->Directory; 01087 } 01088 else 01089 { 01090 /* Directory with no name. We append "...\" */ 01091 NameSize += sizeof(L"...") + sizeof(OBJ_NAME_PATH_SEPARATOR); 01092 break; 01093 } 01094 } 01095 } 01096 01097 /* Finally, add the name of the structure and the null char */ 01098 *ReturnLength = NameSize + 01099 sizeof(OBJECT_NAME_INFORMATION) + 01100 sizeof(UNICODE_NULL); 01101 01102 /* Check if we were given enough space */ 01103 if (*ReturnLength > Length) _SEH2_YIELD(return STATUS_INFO_LENGTH_MISMATCH); 01104 01105 /* 01106 * Now we will actually create the name. We work backwards because 01107 * it's easier to start off from the Name we have and walk up the 01108 * parent directories. We use the same logic as Name Length calculation. 01109 */ 01110 LocalInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader); 01111 ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength); 01112 *--ObjectName = UNICODE_NULL; 01113 01114 /* Check if the object is actually the Root directory */ 01115 if (Object == ObpRootDirectoryObject) 01116 { 01117 /* This is already the Root Directory, return "\\" */ 01118 *--ObjectName = OBJ_NAME_PATH_SEPARATOR; 01119 ObjectNameInfo->Name.Length = (USHORT)NameSize; 01120 ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + 01121 sizeof(UNICODE_NULL)); 01122 ObjectNameInfo->Name.Buffer = ObjectName; 01123 Status = STATUS_SUCCESS; 01124 } 01125 else 01126 { 01127 /* Start by adding the Object's Name */ 01128 ObjectName = (PWCH)((ULONG_PTR)ObjectName - 01129 LocalInfo->Name.Length); 01130 RtlCopyMemory(ObjectName, 01131 LocalInfo->Name.Buffer, 01132 LocalInfo->Name.Length); 01133 01134 /* Now parse the Parent directories until we reach the top */ 01135 ParentDirectory = LocalInfo->Directory; 01136 while ((ParentDirectory != ObpRootDirectoryObject) && (ParentDirectory)) 01137 { 01138 /* Get the name information */ 01139 LocalInfo = OBJECT_HEADER_TO_NAME_INFO( 01140 OBJECT_TO_OBJECT_HEADER(ParentDirectory)); 01141 01142 /* Add the "\" */ 01143 *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR; 01144 01145 /* Add the Parent Directory's Name */ 01146 if (LocalInfo && LocalInfo->Name.Buffer) 01147 { 01148 /* Add the name */ 01149 ObjectName = (PWCH)((ULONG_PTR)ObjectName - 01150 LocalInfo->Name.Length); 01151 RtlCopyMemory(ObjectName, 01152 LocalInfo->Name.Buffer, 01153 LocalInfo->Name.Length); 01154 01155 /* Move to next parent */ 01156 ParentDirectory = LocalInfo->Directory; 01157 } 01158 else 01159 { 01160 /* Directory without a name, we add "..." */ 01161 ObjectName = (PWCH)((ULONG_PTR)ObjectName - 01162 sizeof(L"...") + 01163 sizeof(UNICODE_NULL)); 01164 RtlCopyMemory(ObjectName, 01165 L"...", 01166 sizeof(L"...") + sizeof(UNICODE_NULL)); 01167 break; 01168 } 01169 } 01170 01171 /* Add Root Directory Name */ 01172 *(--ObjectName) = OBJ_NAME_PATH_SEPARATOR; 01173 ObjectNameInfo->Name.Length = (USHORT)NameSize; 01174 ObjectNameInfo->Name.MaximumLength = 01175 (USHORT)(NameSize + sizeof(UNICODE_NULL)); 01176 ObjectNameInfo->Name.Buffer = ObjectName; 01177 } 01178 } 01179 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 01180 { 01181 /* Return the exception code */ 01182 Status = _SEH2_GetExceptionCode(); 01183 } 01184 _SEH2_END; 01185 01186 /* Return success */ 01187 return Status; 01188 } 01189 01190 VOID 01191 NTAPI 01192 ObQueryDeviceMapInformation(IN PEPROCESS Process, 01193 IN PPROCESS_DEVICEMAP_INFORMATION DeviceMapInfo) 01194 { 01195 /* 01196 * FIXME: This is an ugly hack for now, to always return the System Device Map 01197 * instead of returning the Process Device Map. Not important yet since we don't use it 01198 */ 01199 01200 KeAcquireGuardedMutex(&ObpDeviceMapLock); 01201 01202 /* Make a copy */ 01203 DeviceMapInfo->Query.DriveMap = ObSystemDeviceMap->DriveMap; 01204 RtlCopyMemory(DeviceMapInfo->Query.DriveType, 01205 ObSystemDeviceMap->DriveType, 01206 sizeof(ObSystemDeviceMap->DriveType)); 01207 01208 KeReleaseGuardedMutex(&ObpDeviceMapLock); 01209 } 01210 01211 NTSTATUS 01212 NTAPI 01213 ObIsDosDeviceLocallyMapped( 01214 IN ULONG Index, 01215 OUT PUCHAR DosDeviceState) 01216 { 01217 /* check parameters */ 01218 if (Index < 1 || Index > 26) 01219 { 01220 /* invalid index */ 01221 return STATUS_INVALID_PARAMETER; 01222 } 01223 01224 /* acquire lock */ 01225 KeAcquireGuardedMutex(&ObpDeviceMapLock); 01226 01227 /* get drive mapping status */ 01228 *DosDeviceState = (ObSystemDeviceMap->DriveMap & (1 << Index)) != 0; 01229 01230 /* release lock */ 01231 KeReleaseGuardedMutex(&ObpDeviceMapLock); 01232 01233 /* done */ 01234 return STATUS_SUCCESS; 01235 } 01236 01237 /* EOF */ Generated on Fri May 25 2012 04:36:05 for ReactOS by
1.7.6.1
|