|
Definition at line 1081 of file obdir.c.
References ASSERT, _OBJECT_HEADER::Body, _OBJECT_DIRECTORY::DeviceMap, Directory(), _DEVICE_MAP::DosDevicesDirectory, ExAllocatePoolWithTag, ExFreePool(), FALSE, IoFileObjectType, _OBJECT_HEADER_NAME_INFO::Name, NewName, NT_SUCCESS, NTSTATUS(), NULL, OB_PARSE_METHOD, ObCheckCreateObjectAccess(), ObDereferenceObject, OBJECT_HEADER_TO_NAME_INFO, OBJECT_TO_OBJECT_HEADER, ObpBeginTypeSpecificCallOut, ObpCheckTraverseAccess(), ObpDeviceMapLock, ObpDirectoryObjectType, ObpDosDevicesShortName, ObpDosDevicesShortNamePrefix, ObpDosDevicesShortNameRoot, ObpEndTypeSpecificCallOut, ObpEnterRootDirectoryMutex, ObpIncrPointerCount, ObpInsertDirectoryEntry(), ObpLeaveRootDirectoryMutex, ObpLookupDirectoryEntry(), ObpParseSymbolicLink(), ObpRootDirectoryObject, ObpValidateIrql, ObReferenceObject, ObReferenceObjectByHandle(), ObReferenceObjectByPointer(), PagedPool, _OBJECT_TYPE_INITIALIZER::ParseProcedure, PsGetCurrentProcess, _DEVICE_MAP::ReferenceCount, SecurityQos, Status, TOKEN_HAS_TRAVERSE_PRIVILEGE, TRUE, _OBJECT_HEADER::Type, and _OBJECT_TYPE::TypeInfo.
Referenced by ObInsertObject(), ObOpenObjectByName(), and ObReferenceObjectByName().
01097 :
01098
01099 This function will search a given directoroy for a specified
01100 object name. It will also create a new object specified by
01101 InsertObject.
01102
01103 Arguments:
01104
01105 RootDirectoryHandle - Optionally supplies the directory being
01106 searched. If not supplied then this routine searches
01107 the root directory
01108
01109 ObjectName - Supplies the name of object to lookup
01110
01111 Attributes - Specifies the attributes for the lookup (e.g., case
01112 insensitive)
01113
01114 ObjectType - Specifies the type of the object to lookup
01115
01116 AccessMode - Specifies the callers processor mode
01117
01118 ParseContext - Optionally supplies a parse context that is blindly
01119 passed to the parse callback routines
01120
01121 SecurityQos - Optionally supplies a pointer to the passed Security
01122 Quality of Service parameter that is blindly passed to the parse
01123 callback routines
01124
01125 InsertObject - Optionally supplies the object we think will be found.
01126 This is used if the caller did not give a root directory handle
01127 and the object name is "\" and the root object directory hasn't
01128 been created yet. In other cases where we wind up creating
01129 a new directory entry this is the object inserted.
01130
01131 AccessState - Current access state, describing already granted access
01132 types, the privileges used to get them, and any access types yet to
01133 be granted. The access masks may not contain any generic access
01134 types.
01135
01136 DirectoryLocked - Receives an indication if this routine has returned
01137 with the input directory locked
01138
01139 FoundObject - Receives a pointer to the object body if found
01140
01141 Return Value:
01142
01143 An appropriate status value
01144
01145 --*/
01146
01147 {
01148 POBJECT_DIRECTORY RootDirectory;
01149 POBJECT_DIRECTORY Directory;
01150 POBJECT_DIRECTORY ParentDirectory = NULL;
01151 POBJECT_HEADER ObjectHeader;
01152 POBJECT_HEADER_NAME_INFO NameInfo;
01153 PDEVICE_MAP DeviceMap = NULL;
01154 PVOID Object;
01155 UNICODE_STRING RemainingName;
01156 UNICODE_STRING ComponentName;
01157 PWCH NewName;
01158 NTSTATUS Status;
01159 BOOLEAN Reparse;
01160 ULONG MaxReparse = OBJ_MAX_REPARSE_ATTEMPTS;
01161 OB_PARSE_METHOD ParseProcedure;
01162 extern POBJECT_TYPE IoFileObjectType;
01163
01164 ObpValidateIrql( "ObpLookupObjectName" );
01165
01166 //
01167 // Initialize our output variables to say we haven't lock or found
01168 // anything but we were successful at it
01169 //
01170
01171 *DirectoryLocked = FALSE;
01172 *FoundObject = NULL;
01173 Status = STATUS_SUCCESS;
01174
01175 Object = NULL;
01176
01177 //
01178 // Check if the caller has given us a directory to search. Otherwise
01179 // we'll search the root object directory
01180 //
01181
01182 if (ARGUMENT_PRESENT( RootDirectoryHandle )) {
01183
01184 //
01185 // Otherwise reference the directory object and make sure
01186 // that we successfully got the object
01187 //
01188
01189 Status = ObReferenceObjectByHandle( RootDirectoryHandle,
01190 0,
01191 NULL,
01192 AccessMode,
01193 (PVOID *)&RootDirectory,
01194 NULL );
01195
01196 if (!NT_SUCCESS( Status )) {
01197
01198 return( Status );
01199 }
01200
01201 //
01202 // Translate the directory object to its object header
01203 //
01204
01205 ObjectHeader = OBJECT_TO_OBJECT_HEADER( RootDirectory );
01206
01207 //
01208 // Now if the name we're looking up starts with a "\ " and it
01209 // does not have a parse procedure then the syntax is bad
01210 //
01211
01212 if ((ObjectName->Buffer != NULL) &&
01213 (*(ObjectName->Buffer) == OBJ_NAME_PATH_SEPARATOR) &&
01214 (ObjectHeader->Type != IoFileObjectType)) {
01215
01216 ObDereferenceObject( RootDirectory );
01217
01218 return( STATUS_OBJECT_PATH_SYNTAX_BAD );
01219 }
01220
01221 //
01222 // Now make sure that we do not have the directory of the
01223 // object types
01224 //
01225
01226 if (ObjectHeader->Type != ObpDirectoryObjectType) {
01227
01228 //
01229 // We have an object directory that is not the object type
01230 // directory. So now if it doesn't have a parse routine
01231 // then there is nothing we can
01232 //
01233
01234 if (ObjectHeader->Type->TypeInfo.ParseProcedure == NULL) {
01235
01236 ObDereferenceObject( RootDirectory );
01237
01238 return( STATUS_INVALID_HANDLE );
01239
01240 } else {
01241
01242 MaxReparse = OBJ_MAX_REPARSE_ATTEMPTS;
01243
01244 //
01245 // The following loop cycles cycles through the various
01246 // parse routine to we could encounter trying to resolve
01247 // this name through symbolic links.
01248 //
01249
01250 while (TRUE) {
01251
01252 KIRQL SaveIrql;
01253
01254 RemainingName = *ObjectName;
01255
01256 //
01257 // Invoke the callback routine to parse the remaining
01258 // object name
01259 //
01260
01261 ObpBeginTypeSpecificCallOut( SaveIrql );
01262
01263 Status = (*ObjectHeader->Type->TypeInfo.ParseProcedure)( RootDirectory,
01264 ObjectType,
01265 AccessState,
01266 AccessMode,
01267 Attributes,
01268 ObjectName,
01269 &RemainingName,
01270 ParseContext,
01271 SecurityQos,
01272 &Object );
01273
01274 ObpEndTypeSpecificCallOut( SaveIrql, "Parse ", ObjectHeader->Type, Object );
01275
01276 //
01277 // If the status was not to do a reparse and the lookup
01278 // was not successful then we found nothing so we
01279 // dereference the directory and return the status to
01280 // our caller. If the object we got back was null then
01281 // we'll tell our caller that we couldn't find the name.
01282 // Lastly if we did not get a reparse and we were
01283 // successful and the object is not null then everything
01284 // gets nicely returned to our caller
01285 //
01286
01287 if ( ( Status != STATUS_REPARSE ) &&
01288 ( Status != STATUS_REPARSE_OBJECT )) {
01289
01290 if (!NT_SUCCESS( Status )) {
01291
01292 Object = NULL;
01293
01294 } else if (Object == NULL) {
01295
01296 Status = STATUS_OBJECT_NAME_NOT_FOUND;
01297 }
01298
01299 ObDereferenceObject( RootDirectory );
01300
01301 *FoundObject = Object;
01302
01303 return( Status );
01304
01305 //
01306 // We got a status reparse, which means the object
01307 // name has been modified to have use start all over
01308 // again. If the reparse target is now empty or it
01309 // is a path separator then we start the parse at the
01310 // root directory
01311 //
01312
01313 } else if ((ObjectName->Length == 0) ||
01314 (ObjectName->Buffer == NULL) ||
01315 (*(ObjectName->Buffer) == OBJ_NAME_PATH_SEPARATOR)) {
01316
01317 //
01318 // Restart the parse relative to the root directory.
01319 //
01320
01321 ObDereferenceObject( RootDirectory );
01322
01323 RootDirectory = ObpRootDirectoryObject;
01324 RootDirectoryHandle = NULL;
01325
01326 break;
01327
01328 //
01329 // We got a reparse and we actually have a new name to
01330 // go to we if we haven't exhausted our reparse attempts
01331 // yet then just continue to the top of this loop.
01332 //
01333
01334 } else if (--MaxReparse) {
01335
01336 continue;
01337
01338 //
01339 // We got a reparse and we've exhausted our times through
01340 // the loop so we'll return what we found.
01341 //
01342 // **** this doesn't seem right. It probably should be
01343 // an error
01344 //
01345
01346 } else {
01347
01348 ObDereferenceObject( RootDirectory );
01349
01350 *FoundObject = Object;
01351
01352 //
01353 // At this point we were failing in stress by
01354 // returning to the caller with a success status but
01355 // a null object pointer.
01356 //
01357
01358 if (Object == NULL) {
01359
01360 Status = STATUS_OBJECT_NAME_NOT_FOUND;
01361 }
01362
01363 return( Status );
01364 }
01365 }
01366 }
01367
01368 //
01369 // At this point the caller has given us the directory of object
01370 // types. If the caller didn't specify a name then we'll return
01371 // a pointer to the root object directory.
01372 //
01373
01374 } else if ((ObjectName->Length == 0) ||
01375 (ObjectName->Buffer == NULL)) {
01376
01377 Status = ObReferenceObjectByPointer( RootDirectory,
01378 0,
01379 ObjectType,
01380 AccessMode );
01381
01382 if (NT_SUCCESS( Status )) {
01383
01384 Object = RootDirectory;
01385 }
01386
01387 ObDereferenceObject( RootDirectory );
01388
01389 *FoundObject = Object;
01390
01391 return( Status );
01392 }
01393
01394 //
01395 // Otherwise the caller did not specify a directory to search so
01396 // we'll default to the object root directory
01397 //
01398
01399 } else {
01400
01401 RootDirectory = ObpRootDirectoryObject;
01402
01403 //
01404 // If the name we're looking for is empty then it is illformed.
01405 // Also it has to start with a "\ " or it is illformed.
01406 //
01407
01408 if ((ObjectName->Length == 0) ||
01409 (ObjectName->Buffer == NULL) ||
01410 (*(ObjectName->Buffer) != OBJ_NAME_PATH_SEPARATOR)) {
01411
01412 return( STATUS_OBJECT_PATH_SYNTAX_BAD );
01413 }
01414
01415 //
01416 // Check if the name is has only one character (that is the "\ ")
01417 // Which means that the caller really just wants to lookup the
01418 // root directory.
01419 //
01420
01421 if (ObjectName->Length == sizeof( OBJ_NAME_PATH_SEPARATOR )) {
01422
01423 //
01424 // If there is not a root directory yet. Then we really
01425 // can't return it, however if the caller specified
01426 // an insert object that is the one we'll reference and
01427 // return to our caller
01428 //
01429
01430 if (!RootDirectory) {
01431
01432 if (InsertObject) {
01433
01434 Status = ObReferenceObjectByPointer( InsertObject,
01435 0,
01436 ObjectType,
01437 AccessMode );
01438
01439 if (NT_SUCCESS( Status )) {
01440
01441 *FoundObject = InsertObject;
01442 }
01443
01444 return( Status );
01445
01446 } else {
01447
01448 return( STATUS_INVALID_PARAMETER );
01449 }
01450
01451 //
01452 // At this point the caller did not specify a root directory,
01453 // the name is "\ " and the root object directory exists so
01454 // we'll simply return the real root directory object
01455 //
01456
01457 } else {
01458
01459 Status = ObReferenceObjectByPointer( RootDirectory,
01460 0,
01461 ObjectType,
01462 AccessMode );
01463
01464 if (NT_SUCCESS( Status )) {
01465
01466 *FoundObject = RootDirectory;
01467 }
01468
01469 return( Status );
01470 }
01471
01472 //
01473 // At this pointer the caller did not specify a root directory,
01474 // and the name is more than just a "\ "
01475 //
01476 // Now if the lookup is case insensitive, and the name buffer is a
01477 // legitimate pointer (meaning that is it quadword aligned), and
01478 // there is a dos device map for the process. Then we'll handle
01479 // the situation here. First get the device map and make sure it
01480 // doesn't go away while we're using it.
01481 //
01482
01483 } else {
01484
01485 KIRQL OldIrql;
01486
01487 ExAcquireSpinLock( &ObpDeviceMapLock, &OldIrql );
01488
01489 if ((DeviceMap = PsGetCurrentProcess()->DeviceMap) != NULL) {
01490
01491 DeviceMap->ReferenceCount++;
01492 ExReleaseSpinLock( &ObpDeviceMapLock, OldIrql );
01493
01494 if (!((ULONG_PTR)(ObjectName->Buffer) & (sizeof(ULONGLONG)-1))
01495
01496 &&
01497
01498 (DeviceMap->DosDevicesDirectory != NULL )) {
01499
01500 //
01501 // Check if the object name is actually equal to the
01502 // global dos devices short name prefix "\??\ "
01503 //
01504
01505 if ((ObjectName->Length >= ObpDosDevicesShortName.Length)
01506
01507 &&
01508
01509 (*(PULONGLONG)(ObjectName->Buffer) == ObpDosDevicesShortNamePrefix.QuadPart)) {
01510
01511 //
01512 // The user gave us the dos short name prefix so we'll
01513 // look down the directory, and start the search at the
01514 // dos device directory
01515 //
01516
01517 *DirectoryLocked = TRUE;
01518
01519 ObpEnterRootDirectoryMutex();
01520
01521 ParentDirectory = RootDirectory;
01522
01523 Directory = DeviceMap->DosDevicesDirectory;
01524
01525 RemainingName = *ObjectName;
01526 RemainingName.Buffer += (ObpDosDevicesShortName.Length / sizeof( WCHAR ));
01527 RemainingName.Length -= ObpDosDevicesShortName.Length;
01528
01529 goto quickStart;
01530
01531 //
01532 // The name is not equal to "\??\ " but check if it is
01533 // equal to "\?? "
01534 //
01535
01536 } else if ((ObjectName->Length == ObpDosDevicesShortName.Length - sizeof( WCHAR ))
01537
01538 &&
01539
01540 (*(PULONG)(ObjectName->Buffer) == ObpDosDevicesShortNameRoot.LowPart)
01541
01542 &&
01543
01544 (*((PWCHAR)(ObjectName->Buffer)+2) == (WCHAR)(ObpDosDevicesShortNameRoot.HighPart))) {
01545
01546 //
01547 // The user specified "\?? " so we return to dos devices
01548 // directory to our caller
01549 //
01550
01551 Status = ObReferenceObjectByPointer( DeviceMap->DosDevicesDirectory,
01552 0,
01553 ObjectType,
01554 AccessMode );
01555
01556 if (NT_SUCCESS( Status )) {
01557
01558 *FoundObject = DeviceMap->DosDevicesDirectory;
01559 }
01560
01561 //
01562 // Dereference the Device Map
01563 //
01564
01565 {
01566 KIRQL OldIrql;
01567
01568 ExAcquireSpinLock( &ObpDeviceMapLock, &OldIrql );
01569
01570 DeviceMap->ReferenceCount--;
01571
01572 if (DeviceMap->ReferenceCount == 0) {
01573
01574 ExReleaseSpinLock( &ObpDeviceMapLock, OldIrql );
01575
01576 DeviceMap->DosDevicesDirectory->DeviceMap = NULL;
01577 ObDereferenceObject( DeviceMap->DosDevicesDirectory );
01578
01579 ExFreePool( DeviceMap );
01580
01581 } else {
01582
01583 ExReleaseSpinLock( &ObpDeviceMapLock, OldIrql );
01584 }
01585 }
01586
01587 return( Status );
01588 }
01589 }
01590
01591 } else {
01592
01593 ExReleaseSpinLock( &ObpDeviceMapLock, OldIrql );
01594 }
01595 }
01596 }
01597
01598 //
01599 // At this point either
01600 //
01601 // the user specified a directory that is not the object
01602 // type directory and got repase back to the root directory
01603 //
01604 // the user specified the object type directory and gave us
01605 // a name to actually look up
01606 //
01607 // the user did not specify a search directory (default
01608 // to root object directory) and if the name did start off
01609 // with the dos device prefix we've munged outselves back to
01610 // it to the dos device directory for the process
01611 //
01612
01613 Reparse = TRUE;
01614 MaxReparse = OBJ_MAX_REPARSE_ATTEMPTS;
01615
01616 while (Reparse) {
01617
01618 RemainingName = *ObjectName;
01619
01620 quickStart:
01621
01622 Reparse = FALSE;
01623
01624 while (TRUE) {
01625
01626 Object = NULL;
01627
01628 //if (RemainingName.Length == 0) {
01629 // Status = STATUS_OBJECT_NAME_INVALID;
01630 // break;
01631 // }
01632
01633 //
01634 // If the remaining name for the object starts with a
01635 // "\ " then just gobble up the "\ "
01636 //
01637
01638 if ( (RemainingName.Length != 0) &&
01639 (*(RemainingName.Buffer) == OBJ_NAME_PATH_SEPARATOR) ) {
01640
01641 RemainingName.Buffer++;
01642 RemainingName.Length -= sizeof( OBJ_NAME_PATH_SEPARATOR );
01643 }
01644
01645 //
01646 // The following piece of code will calculate the first
01647 // component of the remaining name. If there is not
01648 // a remaining component then the object name is illformed
01649 //
01650
01651 ComponentName = RemainingName;
01652
01653 while (RemainingName.Length != 0) {
01654
01655 if (*(RemainingName.Buffer) == OBJ_NAME_PATH_SEPARATOR) {
01656
01657 break;
01658 }
01659
01660 RemainingName.Buffer++;
01661 RemainingName.Length -= sizeof( OBJ_NAME_PATH_SEPARATOR );
01662 }
01663
01664 ComponentName.Length -= RemainingName.Length;
01665
01666 if (ComponentName.Length == 0) {
01667
01668 Status = STATUS_OBJECT_NAME_INVALID;
01669 break;
01670 }
01671
01672 //
01673 // Now we have the first component name to lookup so we'll
01674 // look the directory is necessary
01675 //
01676
01677 if (!*DirectoryLocked) {
01678
01679 *DirectoryLocked = TRUE;
01680 ObpEnterRootDirectoryMutex();
01681 Directory = RootDirectory;
01682 }
01683
01684 //
01685 // Now if the caller does not have traverse privilege and
01686 // there is a parent directory then we must check if the
01687 // user has traverse access to the directory. Our local
01688 // Reparse variable should be false at this point so we'll
01689 // drop out of both loops
01690 //
01691
01692 if ( !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) && (ParentDirectory != NULL) ) {
01693
01694 if (!ObpCheckTraverseAccess( ParentDirectory,
01695 DIRECTORY_TRAVERSE,
01696 AccessState,
01697 FALSE,
01698 AccessMode,
01699 &Status )) {
01700
01701 break;
01702 }
01703 }
01704
01705 //
01706 // If the object already exists in this directory, find it,
01707 // else return NULL.
01708 //
01709
01710 Object = ObpLookupDirectoryEntry( Directory, &ComponentName, Attributes );
01711
01712 if (!Object) {
01713
01714 //
01715 // We didn't find the object. If there is some remaining
01716 // name left (meaning the component name is a directory in
01717 // path we trying to break) or the caller didn't specify an
01718 // insert object then we then we'll break out here with an
01719 // error status
01720 //
01721
01722 if (RemainingName.Length != 0) {
01723
01724 Status = STATUS_OBJECT_PATH_NOT_FOUND;
01725 break;
01726 }
01727
01728 if (!InsertObject) {
01729
01730 Status = STATUS_OBJECT_NAME_NOT_FOUND;
01731 break;
01732 }
01733
01734 //
01735 // Check that the caller has the access to the directory
01736 // to either create a subdirectory (in the object type
01737 // directory) or to create an object of the given component
01738 // name. If the call fails then we'll break out of here
01739 // with the status value set
01740 //
01741
01742 if (!ObCheckCreateObjectAccess( Directory,
01743 ObjectType == ObpDirectoryObjectType ?
01744 DIRECTORY_CREATE_SUBDIRECTORY :
01745 DIRECTORY_CREATE_OBJECT,
01746 AccessState,
01747 &ComponentName,
01748 FALSE,
01749 AccessMode,
01750 &Status )) {
01751
01752 break;
01753 }
01754
01755 //
01756 // The object does not exist in the directory and
01757 // we are allowed to create one. So allocate space
01758 // for the name and insert the name into the directory
01759 //
01760
01761 NewName = ExAllocatePoolWithTag( PagedPool, ComponentName.Length, 'mNbO' );
01762
01763 if ((NewName == NULL) ||
01764 !ObpInsertDirectoryEntry( Directory, InsertObject )) {
01765
01766 if (NewName != NULL) {
01767
01768 ExFreePool( NewName );
01769 }
01770
01771 Status = STATUS_INSUFFICIENT_RESOURCES;
01772 break;
01773 }
01774
01775 //
01776 // We have an insert object so now get its name info,
01777 // because we are going to change its name and insert it
01778 // into the directory
01779 //
01780
01781 ObReferenceObject( InsertObject );
01782
01783 ObjectHeader = OBJECT_TO_OBJECT_HEADER( InsertObject );
01784
01785 NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
01786
01787 ObReferenceObject( Directory );
01788
01789 RtlMoveMemory( NewName,
01790 ComponentName.Buffer,
01791 ComponentName.Length );
01792
01793 if (NameInfo->Name.Buffer) {
01794
01795 ExFreePool( NameInfo->Name.Buffer );
01796 }
01797
01798 NameInfo->Name.Buffer = NewName;
01799 NameInfo->Name.Length = ComponentName.Length;
01800 NameInfo->Name.MaximumLength = ComponentName.Length;
01801
01802 Object = InsertObject;
01803
01804 Status = STATUS_SUCCESS;
01805
01806 break;
01807 }
01808
01809 //
01810 // At this point we've found the component name within
01811 // the directory. So we'll now grab the components object
01812 // header, and get its parse routine
01813 //
01814
01815 ReparseObject:
01816
01817 ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
01818 ParseProcedure = ObjectHeader->Type->TypeInfo.ParseProcedure;
01819
01820 //
01821 // Now if there is a parse routine for the type and we are not
01822 // inserting a new object or the parse routine is for symbolic
01823 // links then we'll actually call the parse routine
01824 //
01825
01826 if (ParseProcedure && (!InsertObject || (ParseProcedure == ObpParseSymbolicLink))) {
01827
01828 KIRQL SaveIrql;
01829
01830 //
01831 // Reference the object and then free the directory lock
01832 // This will keep the object from going away with the
01833 // directory unlocked
01834 //
01835
01836 ObpIncrPointerCount( ObjectHeader );
01837
01838 ASSERT(*DirectoryLocked);
01839
01840 ObpLeaveRootDirectoryMutex();
01841
01842 *DirectoryLocked = FALSE;
01843
01844 ObpBeginTypeSpecificCallOut( SaveIrql );
01845
01846 //
01847 // Call the objects parse routine
01848 //
01849
01850 Status = (*ParseProcedure)( Object,
01851 (PVOID)ObjectType,
01852 AccessState,
01853 AccessMode,
01854 Attributes,
01855 ObjectName,
01856 &RemainingName,
01857 ParseContext,
01858 SecurityQos,
01859 &Object );
01860
01861 ObpEndTypeSpecificCallOut( SaveIrql, "Parse ", ObjectHeader->Type, Object );
01862
01863 //
01864 // We can now decrement the object reference count
01865 //
01866
01867 ObDereferenceObject( &ObjectHeader->Body );
01868
01869 //
01870 // Check if we have some reparsing to do
01871 //
01872
01873 if ((Status == STATUS_REPARSE) || (Status == STATUS_REPARSE_OBJECT)) {
01874
01875 //
01876 // See if we've reparsed too many times already and if
01877 // so we'll fail the request
01878 //
01879
01880 if (--MaxReparse) {
01881
01882 //
01883 // Tell the outer loop to continue looping
01884 //
01885
01886 Reparse = TRUE;
01887
01888 //
01889 // Check if we have a reparse object or the name
01890 // starts with a "\ "
01891 //
01892
01893 if ((Status == STATUS_REPARSE_OBJECT) ||
01894 (*(ObjectName->Buffer) == OBJ_NAME_PATH_SEPARATOR)) {
01895
01896 //
01897 // If the user specified a start directory then
01898 // remove this information because we're taking
01899 // a reparse point to someplace else
01900 //
01901
01902 if (ARGUMENT_PRESENT( RootDirectoryHandle )) {
01903
01904 ObDereferenceObject( RootDirectory );
01905 RootDirectoryHandle = NULL;
01906 }
01907
01908 //
01909 // And where we start is the root directory
01910 // object
01911 //
01912
01913 ParentDirectory = NULL;
01914 RootDirectory = ObpRootDirectoryObject;
01915
01916 //
01917 // Now if this is a reparse object (means we have
01918 // encountered a symbolic link that has already been
01919 // snapped so we have an object and remaining
01920 // name that need to be examined) and we didn't
01921 // find an object from the parse routine object
01922 // break out of both loops.
01923 //
01924
01925 if (Status == STATUS_REPARSE_OBJECT) {
01926
01927 Reparse = FALSE;
01928
01929 if (Object == NULL) {
01930
01931 Status = STATUS_OBJECT_NAME_NOT_FOUND;
01932
01933 } else {
01934
01935 //
01936 // At this point we have a reparse object
01937 // so we'll look the directory down and
01938 // parse the new object
01939 //
01940
01941 *DirectoryLocked = TRUE;
01942 ObpEnterRootDirectoryMutex();
01943
01944 goto ReparseObject;
01945 }
01946 }
01947
01948 //
01949 // We did not have a reparse object and the name
01950 // does not start with a "\ ". Meaning we got back
01951 // STATUS_REPASE, so now check if the directory
01952 // is the root object directory and if so then
01953 // we didn't the name otherwise we'll drop out of
01954 // the inner loop and reparse true to get back to
01955 // outer loop
01956 //
01957
01958 } else if (RootDirectory == ObpRootDirectoryObject) {
01959
01960 Object = NULL;
01961 Status = STATUS_OBJECT_NAME_NOT_FOUND;
01962
01963 Reparse = FALSE;
01964 }
01965
01966 } else {
01967
01968 //
01969 // **** this should probably be a differnt error
01970 // status related to too many reparse points
01971 //
01972
01973 Object = NULL;
01974 Status = STATUS_OBJECT_NAME_NOT_FOUND;
01975 }
01976
01977 //
01978 // We are not reparsing and if we did not get success then
01979 // the object is null and we'll break out of our loops
01980 //
01981
01982 } else if (!NT_SUCCESS( Status )) {
01983
01984 Object = NULL;
01985
01986 //
01987 // We are not reparsing and we got back success but check
01988 // if the object is null because that means we really didn't
01989 // find the object, and then break out of our loops
01990 //
01991 // If the object is not null then we've been successful and
01992 // prosperous so break out with the object set.
01993 //
01994
01995 } else if (Object == NULL) {
01996
01997 Status = STATUS_OBJECT_NAME_NOT_FOUND;
01998 }
01999
02000 break;
02001
02002 } else {
02003
02004 //
02005 // At this point we do not have a parse routine or if there
02006 // is a parse routine it is not for symbolic links or there
02007 // may not be a specified insert object
02008 //
02009 // Check to see if we have exhausted the remaining name
02010 //
02011
02012 if (RemainingName.Length == 0) {
02013
02014 //
02015 // Check if the caller specified an object to insert.
02016 // If specified then we'll break out of our loops with
02017 // the object that we've found
02018 //
02019
02020 if (!InsertObject) {
02021
02022 //
02023 // The user did not specify an insert object
02024 // so we're opening an existing object. Make sure
02025 // we have traverse access to the container
02026 // directory.
02027 //
02028
02029 if ( !(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ) {
02030
02031 if (!ObpCheckTraverseAccess( Directory,
02032 DIRECTORY_TRAVERSE,
02033 AccessState,
02034 FALSE,
02035 AccessMode,
02036 &Status )) {
02037
02038 Object = NULL;
02039 break;
02040 }
02041 }
02042
02043 Status = ObReferenceObjectByPointer( Object,
02044 0,
02045 ObjectType,
02046 AccessMode );
02047
02048 if (!NT_SUCCESS( Status )) {
02049
02050 Object = NULL;
02051 }
02052 }
02053
02054 break;
02055
02056 } else {
02057
02058 //
02059 // There is some name remaining names to process
02060 // if the directory we're looking at is the
02061 // directory of object types and set ourselves
02062 // up to parse it all over again.
02063 //
02064
02065 if (ObjectHeader->Type == ObpDirectoryObjectType) {
02066
02067 ParentDirectory = Directory;
02068 Directory = (POBJECT_DIRECTORY)Object;
02069
02070 } else {
02071
02072 //
02073 // Otherwise there has been a mismatch so we'll
02074 // set our error status and break out of the
02075 // loops
02076 //
02077
02078 Status = STATUS_OBJECT_TYPE_MISMATCH;
02079 Object = NULL;
02080
02081 break;
02082 }
02083 }
02084 }
02085 }
02086 }
02087
02088 //
02089 // If the device map has been referenced then dereference it
02090 //
02091
02092 if (DeviceMap != NULL) {
02093
02094 KIRQL OldIrql;
02095
02096 ExAcquireSpinLock( &ObpDeviceMapLock, &OldIrql );
02097
02098 DeviceMap->ReferenceCount--;
02099
02100 if (DeviceMap->ReferenceCount == 0) {
02101
02102 ExReleaseSpinLock( &ObpDeviceMapLock, OldIrql );
02103
02104 DeviceMap->DosDevicesDirectory->DeviceMap = NULL;
02105 ObDereferenceObject( DeviceMap->DosDevicesDirectory );
02106
02107 ExFreePool( DeviceMap );
02108
02109 } else {
02110
02111 ExReleaseSpinLock( &ObpDeviceMapLock, OldIrql );
02112 }
02113 }
02114
02115 //
02116 // At this point we've parsed the object name as much as possible
02117 // going through symbolic links as necessary. So now set the
02118 // output object pointer, and if we really did not find an object
02119 // then we might need to modify the error status. If the
02120 // status was repase or some success status then translate it
02121 // to name not found.
02122 //
02123
02124 if (!(*FoundObject = Object)) {
02125
02126 if (Status == STATUS_REPARSE) {
02127
02128 Status = STATUS_OBJECT_NAME_NOT_FOUND;
02129
02130 } else if (NT_SUCCESS( Status )) {
02131
02132 Status = STATUS_OBJECT_NAME_NOT_FOUND;
02133 }
02134 }
02135
02136 //
02137 // If the caller gave us a root directory to search (and we didn't
02138 // zero out this value) then free up our reference
02139 //
02140
02141 if (ARGUMENT_PRESENT( RootDirectoryHandle )) {
02142
02143 ObDereferenceObject( RootDirectory );
02144 RootDirectoryHandle = NULL;
02145 }
02146
02147 //
02148 // And return to our caller
02149 //
02150
02151 return( Status );
02152 }
|