Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

obtype.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 obtype.c 00008 00009 Abstract: 00010 00011 Object type routines. 00012 00013 Author: 00014 00015 Steve Wood (stevewo) 31-Mar-1989 00016 00017 Revision History: 00018 00019 --*/ 00020 00021 #include "obp.h" 00022 00023 #ifdef ALLOC_PRAGMA 00024 #pragma alloc_text(INIT,ObCreateObjectType) 00025 #pragma alloc_text(PAGE,ObGetObjectInformation) 00026 #endif 00027 00028 /* 00029 00030 IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT 00031 00032 There is currently no system service that permits changing 00033 the security on an object type object. Consequently, the object 00034 manager does not check to make sure that a subject is allowed 00035 to create an object of a given type. 00036 00037 Should such a system service be added, the following section of 00038 code must be re-enabled in obhandle.c: 00039 00040 // 00041 // Perform access check to see if we are allowed to create 00042 // an instance of this object type. 00043 // 00044 // This routine will audit the attempt to create the 00045 // object as appropriate. Note that this is different 00046 // from auditing the creation of the object itself. 00047 // 00048 00049 if (!ObCheckCreateInstanceAccess( ObjectType, 00050 OBJECT_TYPE_CREATE, 00051 AccessState, 00052 TRUE, 00053 AccessMode, 00054 &Status 00055 ) ) { 00056 return( Status ); 00057 00058 } 00059 00060 The code is already there, but is not compiled. 00061 00062 This will ensure that someone who is denied access to an object 00063 type is not permitted to create an object of that type. 00064 00065 */ 00066 00067 00068 NTSTATUS 00069 ObCreateObjectType ( 00070 IN PUNICODE_STRING TypeName, 00071 IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, 00072 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, // currently ignored 00073 OUT POBJECT_TYPE *ObjectType 00074 ) 00075 00076 /*++ 00077 00078 Routine Description: 00079 00080 This routine creates a new object type. 00081 00082 Arguments: 00083 00084 TypeName - Supplies the name of the new object type 00085 00086 ObjectTypeInitializer - Supplies a object initialization 00087 structure. This structure denotes the default object 00088 behavior including callbacks. 00089 00090 SecurityDescriptor - Currently ignored 00091 00092 ObjectType - Receives a pointer to the newly created object 00093 type. 00094 00095 Return Value: 00096 00097 An appropriate NTSTATUS value. 00098 00099 --*/ 00100 00101 { 00102 POOL_TYPE PoolType; 00103 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 00104 POBJECT_HEADER NewObjectTypeHeader; 00105 POBJECT_TYPE NewObjectType; 00106 ULONG i; 00107 UNICODE_STRING ObjectName; 00108 PWCH s; 00109 NTSTATUS Status; 00110 ULONG StandardHeaderCharge; 00111 00112 ObpValidateIrql( "ObCreateObjectType" ); 00113 00114 // 00115 // Return an error if invalid type attributes or no type name specified. 00116 // No type name is okay if the type directory object does not exist 00117 // yet (see init.c). 00118 // 00119 00120 PoolType = ObjectTypeInitializer->PoolType; 00121 00122 if ((!TypeName) 00123 00124 || 00125 00126 (!TypeName->Length) 00127 00128 || 00129 00130 (TypeName->Length % sizeof( WCHAR )) 00131 00132 || 00133 00134 (ObjectTypeInitializer == NULL) 00135 00136 || 00137 00138 (ObjectTypeInitializer->InvalidAttributes & ~OBJ_VALID_ATTRIBUTES) 00139 00140 || 00141 00142 (ObjectTypeInitializer->Length != sizeof( *ObjectTypeInitializer )) 00143 00144 || 00145 00146 (ObjectTypeInitializer->MaintainHandleCount && 00147 (ObjectTypeInitializer->OpenProcedure == NULL && 00148 ObjectTypeInitializer->CloseProcedure == NULL )) 00149 00150 || 00151 00152 ((!ObjectTypeInitializer->UseDefaultObject) && 00153 (PoolType != NonPagedPool))) { 00154 00155 return( STATUS_INVALID_PARAMETER ); 00156 } 00157 00158 // 00159 // Make sure that the type name does not contain an 00160 // path name separator 00161 // 00162 00163 s = TypeName->Buffer; 00164 i = TypeName->Length / sizeof( WCHAR ); 00165 00166 while (i--) { 00167 00168 if (*s++ == OBJ_NAME_PATH_SEPARATOR) { 00169 00170 return( STATUS_OBJECT_NAME_INVALID ); 00171 } 00172 } 00173 00174 // 00175 // See if TypeName string already exists in the \ObjectTypes directory 00176 // Return an error if it does. Otherwise add the name to the directory. 00177 // Note that there may not necessarily be a type directory. 00178 // 00179 00180 if (ObpTypeDirectoryObject) { 00181 00182 ObpEnterRootDirectoryMutex(); 00183 00184 if (ObpLookupDirectoryEntry( ObpTypeDirectoryObject, 00185 TypeName, 00186 OBJ_CASE_INSENSITIVE )) { 00187 00188 ObpLeaveRootDirectoryMutex(); 00189 00190 return( STATUS_OBJECT_NAME_COLLISION ); 00191 } 00192 } 00193 00194 // 00195 // Allocate a buffer for the type name and then 00196 // copy over the name 00197 // 00198 00199 ObjectName.Buffer = ExAllocatePoolWithTag( PagedPool, 00200 (ULONG)TypeName->MaximumLength, 00201 'mNbO' ); 00202 00203 if (ObjectName.Buffer == NULL) { 00204 00205 if (ObpTypeDirectoryObject) 00206 00207 ObpLeaveRootDirectoryMutex(); 00208 00209 return STATUS_INSUFFICIENT_RESOURCES; 00210 } 00211 00212 ObjectName.MaximumLength = TypeName->MaximumLength; 00213 00214 RtlCopyUnicodeString( &ObjectName, TypeName ); 00215 00216 // 00217 // Allocate memory for the object 00218 // 00219 00220 Status = ObpAllocateObject( NULL, 00221 KernelMode, 00222 ObpTypeObjectType, 00223 &ObjectName, 00224 sizeof( OBJECT_TYPE ), 00225 &NewObjectTypeHeader ); 00226 00227 if (!NT_SUCCESS( Status )) { 00228 00229 if (ObpTypeDirectoryObject) 00230 00231 ObpLeaveRootDirectoryMutex(); 00232 00233 ExFreePool(ObjectName.Buffer); 00234 00235 return( Status ); 00236 } 00237 00238 // 00239 // Initialize the create attributes, object ownership. parse context, 00240 // and object body pointer. 00241 // 00242 // N.B. This is required since these fields are not initialized. 00243 // 00244 00245 NewObjectTypeHeader->Flags |= OB_FLAG_KERNEL_OBJECT | 00246 OB_FLAG_PERMANENT_OBJECT; 00247 00248 NewObjectType = (POBJECT_TYPE)&NewObjectTypeHeader->Body; 00249 NewObjectType->Name = ObjectName; 00250 00251 // 00252 // The following call zeros out the number of handles and objects 00253 // field plus high water marks 00254 // 00255 00256 RtlZeroMemory( &NewObjectType->TotalNumberOfObjects, 00257 FIELD_OFFSET( OBJECT_TYPE, TypeInfo ) - 00258 FIELD_OFFSET( OBJECT_TYPE, TotalNumberOfObjects )); 00259 00260 // 00261 // If there is not a type object type yet then this must be 00262 // that type (i.e., type object type must be the first object type 00263 // ever created. Consequently we'll need to setup some self 00264 // referencing pointers. 00265 // 00266 00267 if (!ObpTypeObjectType) { 00268 00269 ObpTypeObjectType = NewObjectType; 00270 NewObjectTypeHeader->Type = ObpTypeObjectType; 00271 NewObjectType->TotalNumberOfObjects = 1; 00272 00273 #ifdef POOL_TAGGING 00274 00275 NewObjectType->Key = 'TjbO'; 00276 00277 } else { 00278 00279 // 00280 // Otherwise this is not the type object type so we'll 00281 // try and generate a tag for the new object type provided 00282 // pool tagging is turned on. 00283 // 00284 00285 ANSI_STRING AnsiName; 00286 00287 if (NT_SUCCESS( RtlUnicodeStringToAnsiString( &AnsiName, TypeName, TRUE ) )) { 00288 00289 for (i=3; i>=AnsiName.Length; i--) { 00290 00291 AnsiName.Buffer[ i ] = ' '; 00292 00293 } 00294 00295 NewObjectType->Key = *(PULONG)AnsiName.Buffer; 00296 ExFreePool( AnsiName.Buffer ); 00297 00298 } else { 00299 00300 NewObjectType->Key = *(PULONG)TypeName->Buffer; 00301 } 00302 00303 #endif //POOL_TAGGING 00304 00305 } 00306 00307 // 00308 // Continue initializing the new object type fields 00309 // 00310 00311 NewObjectType->TypeInfo = *ObjectTypeInitializer; 00312 NewObjectType->TypeInfo.PoolType = PoolType; 00313 00314 if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST) { 00315 00316 NewObjectType->TypeInfo.MaintainTypeList = TRUE; 00317 } 00318 00319 // 00320 // Whack quotas passed in so that headers are properly charged 00321 // 00322 // Quota for object name is charged independently 00323 // 00324 00325 StandardHeaderCharge = sizeof( OBJECT_HEADER ) + 00326 sizeof( OBJECT_HEADER_NAME_INFO ) + 00327 (ObjectTypeInitializer->MaintainHandleCount ? 00328 sizeof( OBJECT_HEADER_HANDLE_INFO ) 00329 : 0 ); 00330 00331 if ( PoolType == NonPagedPool ) { 00332 00333 NewObjectType->TypeInfo.DefaultNonPagedPoolCharge += StandardHeaderCharge; 00334 00335 } else { 00336 00337 NewObjectType->TypeInfo.DefaultPagedPoolCharge += StandardHeaderCharge; 00338 } 00339 00340 // 00341 // If there is not an object type specific security procedure then set 00342 // the default one supplied by Se. 00343 // 00344 00345 if (ObjectTypeInitializer->SecurityProcedure == NULL) { 00346 00347 NewObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod; 00348 } 00349 00350 // 00351 // Initialize the object type lock and its list of objects created 00352 // of this type 00353 // 00354 00355 ExInitializeResourceLite( &NewObjectType->Mutex ); 00356 00357 InitializeListHead( &NewObjectType->TypeList ); 00358 00359 // 00360 // If we are to use the default object (meaning that we'll have our 00361 // private event as our default object) then the type must allow 00362 // synchronize and we'll set the default object 00363 // 00364 00365 if (NewObjectType->TypeInfo.UseDefaultObject) { 00366 00367 NewObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE; 00368 NewObjectType->DefaultObject = &ObpDefaultObject; 00369 00370 // 00371 // Otherwise if this is the type file object then we'll put 00372 // in the offset to the event of a file object. 00373 // 00374 // **** What a hack 00375 // 00376 00377 } else if (ObjectName.Length == 8 && !wcscmp( ObjectName.Buffer, L"File" )) { 00378 00379 NewObjectType->DefaultObject = ULongToPtr( FIELD_OFFSET( FILE_OBJECT, Event ) ); 00380 00381 00382 // 00383 // If this is a waitable port, set the offset to the event in the 00384 // waitableport object. Another hack 00385 // 00386 00387 } else if ( ObjectName.Length == 24 && !wcscmp( ObjectName.Buffer, L"WaitablePort")) { 00388 00389 NewObjectType->DefaultObject = ULongToPtr( FIELD_OFFSET( LPCP_PORT_OBJECT, WaitEvent ) ); 00390 00391 // 00392 // Otherwise indicate that there isn't a default object to wait 00393 // on 00394 // 00395 00396 } else { 00397 00398 NewObjectType->DefaultObject = NULL; 00399 } 00400 00401 // 00402 // Lock down the type object type and if there is a creator info 00403 // record then insert this object on that list 00404 // 00405 00406 ObpEnterObjectTypeMutex( ObpTypeObjectType ); 00407 00408 CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( NewObjectTypeHeader ); 00409 00410 if (CreatorInfo != NULL) { 00411 00412 InsertTailList( &ObpTypeObjectType->TypeList, &CreatorInfo->TypeList ); 00413 } 00414 00415 // 00416 // Store a pointer to this new object type in the 00417 // global object types array. We'll use the index from 00418 // the type object type number of objects count 00419 // 00420 00421 NewObjectType->Index = ObpTypeObjectType->TotalNumberOfObjects; 00422 00423 if (NewObjectType->Index < OBP_MAX_DEFINED_OBJECT_TYPES) { 00424 00425 ObpObjectTypes[ NewObjectType->Index - 1 ] = NewObjectType; 00426 } 00427 00428 // 00429 // Unlock the type object type lock 00430 // 00431 00432 ObpLeaveObjectTypeMutex( ObpTypeObjectType ); 00433 00434 // 00435 // Lastly if there is not a directory object type yet then the following 00436 // code will actually drop through and set the output object type 00437 // and return success. 00438 // 00439 // Otherwise, there is a directory object type and we try to insert the 00440 // new type into the directory. If this succeeds then we'll reference 00441 // the directory type object, unlock the root directory, set the 00442 // output type and return success 00443 // 00444 00445 if (!ObpTypeDirectoryObject || 00446 ObpInsertDirectoryEntry( ObpTypeDirectoryObject, NewObjectType )) { 00447 00448 if (ObpTypeDirectoryObject) { 00449 00450 ObReferenceObject( ObpTypeDirectoryObject ); 00451 } 00452 00453 if (ObpTypeDirectoryObject) { 00454 00455 ObpLeaveRootDirectoryMutex(); 00456 } 00457 00458 *ObjectType = NewObjectType; 00459 00460 return( STATUS_SUCCESS ); 00461 00462 } else { 00463 00464 // 00465 // Otherwise there is a directory object type and 00466 // the insertion failed. So release the root directory 00467 // and return failure to our caller. 00468 // 00469 00470 ObpLeaveRootDirectoryMutex(); 00471 00472 return( STATUS_INSUFFICIENT_RESOURCES ); 00473 } 00474 } 00475 00476 00477 NTSTATUS 00478 ObEnumerateObjectsByType( 00479 IN POBJECT_TYPE ObjectType, 00480 IN OB_ENUM_OBJECT_TYPE_ROUTINE EnumerationRoutine, 00481 IN PVOID Parameter 00482 ) 00483 00484 /*++ 00485 00486 Routine Description: 00487 00488 This routine, via a callback, will enumerate through all 00489 the objects of a specified type. This only works on objects 00490 that maintain the type list (i.e., have an object creator 00491 info record). 00492 00493 Arguments: 00494 00495 ObjectType - Supplies the object type being enumerated 00496 00497 EnumerationRoutine - Supplies the callback routine to use 00498 00499 Parameter - Supplies a parameter to pass through to the callback 00500 routine 00501 00502 Return Value: 00503 00504 STATUS_SUCCESS if the enumeration finishes because the 00505 end of the list is reached and STATUS_NO_MORE_ENTRIES if 00506 the enmeration callback routine ever returns false. 00507 00508 --*/ 00509 00510 { 00511 NTSTATUS Status; 00512 UNICODE_STRING ObjectName; 00513 PLIST_ENTRY Next, Head; 00514 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 00515 POBJECT_HEADER_NAME_INFO NameInfo; 00516 POBJECT_HEADER ObjectHeader; 00517 00518 // 00519 // Lock the object type, and get ourselves up 00520 // to iterate through the type list (i.e., the list 00521 // of all the objects of this specified type) 00522 // 00523 00524 ObpEnterObjectTypeMutex( ObjectType ); 00525 00526 Head = &ObjectType->TypeList; 00527 Next = Head->Flink; 00528 Status = STATUS_SUCCESS; 00529 00530 // 00531 // Now enumerate through the type list. The Creator 00532 // info record is where we wind up in the object. And 00533 // this record is known to be the first record preceding 00534 // the object header. So to get to the object header 00535 // we just jump to the end of the creator info record. 00536 // 00537 00538 while (Next != Head) { 00539 00540 CreatorInfo = CONTAINING_RECORD( Next, 00541 OBJECT_HEADER_CREATOR_INFO, 00542 TypeList ); 00543 00544 ObjectHeader = (POBJECT_HEADER)(CreatorInfo+1); 00545 00546 // 00547 // From the object header see if there is a name for the 00548 // object. If there is not a name then we'll supply an 00549 // empty name. 00550 // 00551 00552 NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader ); 00553 00554 if (NameInfo != NULL) { 00555 00556 ObjectName = NameInfo->Name; 00557 00558 } else { 00559 00560 RtlZeroMemory( &ObjectName, sizeof( ObjectName ) ); 00561 } 00562 00563 // 00564 // Now invoke the callback and if it returns false then 00565 // we're done with the enumeration and will return 00566 // an alternate ntstatus value 00567 // 00568 00569 if (!(EnumerationRoutine)( &ObjectHeader->Body, 00570 &ObjectName, 00571 ObjectHeader->HandleCount, 00572 ObjectHeader->PointerCount, 00573 Parameter )) { 00574 00575 Status = STATUS_NO_MORE_ENTRIES; 00576 00577 break; 00578 } 00579 00580 // 00581 // Get the next record in the type list and continue 00582 // the enumeration. 00583 // 00584 00585 Next = Next->Flink; 00586 } 00587 00588 // 00589 // Free the object type lock and return to our caller 00590 // 00591 00592 ObpLeaveObjectTypeMutex( ObjectType ); 00593 00594 return Status; 00595 } 00596 00597 00598 typedef struct _OBJECT_TYPE_ARRAY { 00599 00600 ULONG Size; 00601 POBJECT_HEADER_CREATOR_INFO CreatorInfoArray[1]; 00602 00603 } OBJECT_TYPE_ARRAY, *POBJECT_TYPE_ARRAY; 00604 00605 00606 POBJECT_TYPE_ARRAY 00607 ObpCreateTypeArray ( 00608 IN POBJECT_TYPE ObjectType 00609 ) 00610 00611 /*++ 00612 00613 Routine Description: 00614 00615 This routine create an array with pointers to all objects queued 00616 for a given ObjectType. All objects are referenced when are stored 00617 in the array. 00618 00619 Arguments: 00620 00621 ObjectType - Supplies the object type for which we make copy 00622 for all objects. 00623 00624 00625 Return Value: 00626 00627 The array with objects created. returns NULL if the specified ObjectType 00628 has the TypeList empty. 00629 00630 --*/ 00631 00632 { 00633 ULONG Count; 00634 POBJECT_TYPE_ARRAY ObjectArray; 00635 PLIST_ENTRY Next1, Head1; 00636 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 00637 POBJECT_HEADER ObjectHeader; 00638 PVOID Object; 00639 00640 // 00641 // Acquire the ObjectType mutex 00642 // 00643 00644 ObpEnterObjectTypeMutex( ObjectType ); 00645 00646 ObjectArray = NULL; 00647 00648 // 00649 // Count the number of elements into the list 00650 // 00651 00652 Count = 0; 00653 00654 Head1 = &ObjectType->TypeList; 00655 Next1 = Head1->Flink; 00656 00657 while (Next1 != Head1) { 00658 00659 Next1 = Next1->Flink; 00660 Count += 1; 00661 } 00662 00663 // 00664 // If we have a number of objects > 0 then we'll create an array 00665 // and copy all pointers into that array 00666 // 00667 00668 if ( Count > 0 ) { 00669 00670 // 00671 // Allocate the memory for array 00672 // 00673 00674 ObjectArray = ExAllocatePoolWithTag( PagedPool, 00675 sizeof(OBJECT_TYPE_ARRAY) + sizeof(POBJECT_HEADER_CREATOR_INFO) * (Count - 1), 00676 'rAbO' ); 00677 if ( ObjectArray != NULL ) { 00678 00679 ObjectArray->Size = Count; 00680 00681 Count = 0; 00682 00683 // 00684 // Start parsing the TypeList 00685 // 00686 00687 Head1 = &ObjectType->TypeList; 00688 Next1 = Head1->Flink; 00689 00690 while (Next1 != Head1) { 00691 00692 ASSERT( Count < ObjectArray->Size ); 00693 00694 // 00695 // For each object we'll grab its creator info record, 00696 // its object header, and its object body 00697 // 00698 00699 CreatorInfo = CONTAINING_RECORD( Next1, 00700 OBJECT_HEADER_CREATOR_INFO, 00701 TypeList ); 00702 00703 // 00704 // We'll store the CreatorInfo into the ObjectArray 00705 // 00706 00707 ObjectArray->CreatorInfoArray[Count] = CreatorInfo; 00708 00709 // 00710 // Find the Object and increment the references to that object 00711 // to avoid deleting while are stored copy in this array 00712 // 00713 00714 ObjectHeader = (POBJECT_HEADER)(CreatorInfo+1); 00715 00716 Object = &ObjectHeader->Body; 00717 00718 ObReferenceObject( Object); 00719 00720 Next1 = Next1->Flink; 00721 Count++; 00722 00723 } 00724 } 00725 } 00726 00727 // 00728 // Release the ObjectType mutex 00729 // 00730 00731 ObpLeaveObjectTypeMutex( ObjectType ); 00732 00733 return ObjectArray; 00734 } 00735 00736 00737 VOID 00738 ObpDestroyTypeArray ( 00739 IN POBJECT_TYPE_ARRAY ObjectArray 00740 ) 00741 00742 /*++ 00743 00744 Routine Description: 00745 00746 This routine destroy an array with pointers to objects, created by 00747 ObpCreateTypeArray. Each object is dereferenced before releasing the 00748 array memory. 00749 00750 Arguments: 00751 00752 ObjectArray - Supplies the array to be freed 00753 00754 Return Value: 00755 00756 00757 --*/ 00758 00759 { 00760 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 00761 POBJECT_HEADER ObjectHeader; 00762 PVOID Object; 00763 ULONG i; 00764 00765 if (ObjectArray != NULL) { 00766 00767 // 00768 // Go through array and dereference all objects. 00769 // 00770 00771 for (i = 0; i < ObjectArray->Size; i++) { 00772 00773 // 00774 // Retrieving the Object from the CreatorInfo 00775 // 00776 00777 CreatorInfo = ObjectArray->CreatorInfoArray[i]; 00778 00779 ObjectHeader = (POBJECT_HEADER)(CreatorInfo+1); 00780 00781 Object = &ObjectHeader->Body; 00782 00783 // 00784 // Dereference the object 00785 // 00786 00787 ObDereferenceObject( Object ); 00788 } 00789 00790 // 00791 // Free the memory alocated for this array 00792 // 00793 00794 ExFreePoolWithTag( ObjectArray, 'rAbO' ); 00795 } 00796 } 00797 00798 00799 NTSTATUS 00800 ObGetObjectInformation( 00801 IN PCHAR UserModeBufferAddress, 00802 OUT PSYSTEM_OBJECTTYPE_INFORMATION ObjectInformation, 00803 IN ULONG Length, 00804 OUT PULONG ReturnLength OPTIONAL 00805 ) 00806 00807 /*++ 00808 00809 Routine Description: 00810 00811 This routine returns information for all the object in the 00812 system. It enuermates through all the object types and in 00813 each type it enumerates through their type list. 00814 00815 Arguments: 00816 00817 UserModeBufferAddress - Supplies the address of the query buffer 00818 as specified by the user. 00819 00820 ObjectInformation - Supplies a buffer to receive the object 00821 type information. This is essentially the same as the first 00822 parameter except that one is a system address and the other 00823 is in the user's address space. 00824 00825 Length - Supplies the length, in bytes, of the object information 00826 buffer 00827 00828 ReturnLength - Optionally receives the total length, in bytes, 00829 needed to store the object information 00830 00831 00832 Return Value: 00833 00834 An appropriate status value 00835 00836 --*/ 00837 00838 { 00839 NTSTATUS ReturnStatus, Status; 00840 PLIST_ENTRY Next, Head; 00841 PLIST_ENTRY Next1, Head1; 00842 POBJECT_TYPE ObjectType; 00843 POBJECT_HEADER ObjectHeader; 00844 POBJECT_HEADER_CREATOR_INFO CreatorInfo; 00845 POBJECT_HEADER_QUOTA_INFO QuotaInfo; 00846 PVOID Object; 00847 BOOLEAN FirstObjectForType; 00848 PSYSTEM_OBJECTTYPE_INFORMATION TypeInfo; 00849 PSYSTEM_OBJECT_INFORMATION ObjectInfo; 00850 ULONG TotalSize, NameSize; 00851 POBJECT_HEADER ObjectTypeHeader; 00852 WCHAR NameBuffer[ 260 + 4 ]; 00853 POBJECT_NAME_INFORMATION NameInformation; 00854 extern POBJECT_TYPE IoFileObjectType; 00855 PWSTR TempBuffer; 00856 USHORT TempMaximumLength; 00857 POBJECT_TYPE_ARRAY ObjectTypeArray; 00858 ULONG i; 00859 00860 PAGED_CODE(); 00861 00862 // 00863 // Initialize some local variables 00864 // 00865 00866 NameInformation = (POBJECT_NAME_INFORMATION)NameBuffer; 00867 ReturnStatus = STATUS_SUCCESS; 00868 TotalSize = 0; 00869 TypeInfo = NULL; 00870 00871 // 00872 // Lock down the type object type to avoid the creation of a new object type while 00873 // iterating through the list items 00874 // 00875 00876 ObpEnterObjectTypeMutex( ObpTypeObjectType ); 00877 00878 try { 00879 00880 // 00881 // The following outer loop iterates through each object type 00882 // in the system 00883 // 00884 00885 Head = &ObpTypeObjectType->TypeList; 00886 Next = Head->Flink; 00887 00888 while (Next != Head) { 00889 00890 // 00891 // For each object type object we'll grab its creator 00892 // info record and which must directly precede the 00893 // object header followed by the object body 00894 // 00895 00896 CreatorInfo = CONTAINING_RECORD( Next, 00897 OBJECT_HEADER_CREATOR_INFO, 00898 TypeList ); 00899 00900 ObjectTypeHeader = (POBJECT_HEADER)(CreatorInfo+1); 00901 ObjectType = (POBJECT_TYPE)&ObjectTypeHeader->Body; 00902 00903 // 00904 // Now if this is not the object type object, which is what 00905 // the outer loop is going through then we'll jump in one 00906 // more loop 00907 // 00908 00909 if (ObjectType != ObpTypeObjectType) { 00910 00911 // 00912 // Capture the array with objects queued in the TypeList 00913 // 00914 00915 ObjectTypeArray = ObpCreateTypeArray ( ObjectType ); 00916 00917 // 00918 // If it is any object in that queue, start 00919 // quering information about it 00920 // 00921 00922 if (ObjectTypeArray != NULL) { 00923 00924 // 00925 // The following loop iterates through each object 00926 // of the specified type. 00927 // 00928 00929 FirstObjectForType = TRUE; 00930 00931 for ( i = 0; i < ObjectTypeArray->Size; i++) { 00932 00933 // 00934 // For each object we'll grab its creator info record, 00935 // its object header, and its object body 00936 // 00937 00938 CreatorInfo = ObjectTypeArray->CreatorInfoArray[i]; 00939 00940 ObjectHeader = (POBJECT_HEADER)(CreatorInfo+1); 00941 00942 Object = &ObjectHeader->Body; 00943 00944 // 00945 // If this is the first time through the inner loop for this 00946 // type then we'll fill in the type info buffer 00947 // 00948 00949 if (FirstObjectForType) { 00950 00951 FirstObjectForType = FALSE; 00952 00953 // 00954 // If the pointer it not null (i.e., we've been through 00955 // this loop before) and the total size we've used so 00956 // far hasn't exhausted the output buffer then 00957 // set the previous type info record to point to the 00958 // next type info record 00959 // 00960 00961 if ((TypeInfo != NULL) && (TotalSize < Length)) { 00962 00963 TypeInfo->NextEntryOffset = TotalSize; 00964 } 00965 00966 // 00967 // Set the current type info record to point to the next 00968 // free spot in the output buffer, and adjust the total 00969 // size used so far to account for the object type info 00970 // buffer 00971 // 00972 00973 TypeInfo = (PSYSTEM_OBJECTTYPE_INFORMATION)((PCHAR)ObjectInformation + TotalSize); 00974 00975 TotalSize += FIELD_OFFSET( SYSTEM_OBJECTTYPE_INFORMATION, TypeName ); 00976 00977 // 00978 // See if the data will fit into the info buffer, and if 00979 // so then fill in the record 00980 // 00981 00982 if (TotalSize >= Length) { 00983 00984 ReturnStatus = STATUS_INFO_LENGTH_MISMATCH; 00985 00986 } else { 00987 00988 TypeInfo->NextEntryOffset = 0; 00989 TypeInfo->NumberOfObjects = ObjectType->TotalNumberOfObjects; 00990 TypeInfo->NumberOfHandles = ObjectType->TotalNumberOfHandles; 00991 TypeInfo->TypeIndex = ObjectType->Index; 00992 TypeInfo->InvalidAttributes = ObjectType->TypeInfo.InvalidAttributes; 00993 TypeInfo->GenericMapping = ObjectType->TypeInfo.GenericMapping; 00994 TypeInfo->ValidAccessMask = ObjectType->TypeInfo.ValidAccessMask; 00995 TypeInfo->PoolType = ObjectType->TypeInfo.PoolType; 00996 TypeInfo->SecurityRequired = ObjectType->TypeInfo.SecurityRequired; 00997 } 00998 00999 // 01000 // Now we need to do the object's type name. The name 01001 // goes right after the type info field. The following 01002 // query type name call knows to take the address of a 01003 // unicode string and assumes that the buffer to stuff 01004 // the string is right after the unicode string structure. 01005 // The routine also assumes that name size is the number 01006 // of bytes already use in the buffer and add to it the 01007 // number of bytes it uses. That is why we need to 01008 // initialize it to zero before doing the call. 01009 // 01010 01011 NameSize = 0; 01012 01013 Status = ObQueryTypeName( Object, 01014 &TypeInfo->TypeName, 01015 TotalSize < Length ? Length - TotalSize : 0, 01016 &NameSize ); 01017 01018 // 01019 // Round the name size up to the next ulong boundary 01020 // 01021 01022 NameSize = (NameSize + sizeof( ULONG ) - 1) & (~(sizeof( ULONG ) - 1)); 01023 01024 // 01025 // If we were able to successfully get the type name then 01026 // set the max length to the rounded ulong that does not 01027 // include the heading unicode string structure. Also set 01028 // the buffer to the address that the user would use to 01029 // access the string. 01030 // 01031 01032 if (NT_SUCCESS( Status )) { 01033 01034 TypeInfo->TypeName.MaximumLength = (USHORT) 01035 (NameSize - sizeof( TypeInfo->TypeName )); 01036 TypeInfo->TypeName.Buffer = (PWSTR) 01037 (UserModeBufferAddress + 01038 ((PCHAR)TypeInfo->TypeName.Buffer - (PCHAR)ObjectInformation) 01039 ); 01040 01041 } else { 01042 01043 ReturnStatus = Status; 01044 } 01045 01046 // 01047 // Now we need to bias the total size we've used by the 01048 // size of the object name 01049 // 01050 01051 TotalSize += NameSize; 01052 01053 } else { 01054 01055 // 01056 // Otherwise this is not the first time through the inner 01057 // loop for this object type so the only thing we need to 01058 // do is set the previous object info record to "point via 01059 // relative offset" to the next object info record 01060 // 01061 01062 if (TotalSize < Length) { 01063 01064 ObjectInfo->NextEntryOffset = TotalSize; 01065 } 01066 } 01067 01068 // 01069 // We still have an object info record to fill in for this 01070 // record. The only thing we've done so far is the type info 01071 // record. So now get a pointer to the new object info record 01072 // and adjust the total size to account for the object record 01073 // 01074 01075 ObjectInfo = (PSYSTEM_OBJECT_INFORMATION)((PCHAR)ObjectInformation + TotalSize); 01076 01077 TotalSize += FIELD_OFFSET( SYSTEM_OBJECT_INFORMATION, NameInfo ); 01078 01079 // 01080 // If there is room for the object info record then fill 01081 // in the record 01082 // 01083 01084 if (TotalSize >= Length) { 01085 01086 ReturnStatus = STATUS_INFO_LENGTH_MISMATCH; 01087 01088 } else { 01089 01090 ObjectInfo->NextEntryOffset = 0; 01091 ObjectInfo->Object = Object; 01092 ObjectInfo->CreatorUniqueProcess = CreatorInfo->CreatorUniqueProcess; 01093 ObjectInfo->CreatorBackTraceIndex = CreatorInfo->CreatorBackTraceIndex; 01094 ObjectInfo->PointerCount = ObjectHeader->PointerCount; 01095 ObjectInfo->HandleCount = ObjectHeader->HandleCount; 01096 ObjectInfo->Flags = (USHORT)ObjectHeader->Flags; 01097 ObjectInfo->SecurityDescriptor = ObjectHeader->SecurityDescriptor; 01098 01099 // 01100 // Fill in the appropriate quota information if there is 01101 // any quota information available 01102 // 01103 01104 QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader ); 01105 01106 if (QuotaInfo != NULL) { 01107 01108 ObjectInfo->PagedPoolCharge = QuotaInfo->PagedPoolCharge; 01109 ObjectInfo->NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge; 01110 01111 if (QuotaInfo->ExclusiveProcess != NULL) { 01112 01113 ObjectInfo->ExclusiveProcessId = QuotaInfo->ExclusiveProcess->UniqueProcessId; 01114 } 01115 01116 } else { 01117 01118 ObjectInfo->PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge; 01119 ObjectInfo->NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge; 01120 } 01121 } 01122 01123 // 01124 // Now we are ready to get the object name. If there is not a 01125 // private routine to get the object name then we can call our 01126 // ob routine to query the object name. Also if this is not 01127 // a file object we can do the query call. The call will 01128 // fill in our local name buffer. 01129 // 01130 01131 NameSize = 0; 01132 Status = STATUS_SUCCESS; 01133 01134 if ((ObjectType->TypeInfo.QueryNameProcedure == NULL) || 01135 (ObjectType != IoFileObjectType)) { 01136 01137 Status = ObQueryNameString( Object, 01138 NameInformation, 01139 sizeof( NameBuffer ), 01140 &NameSize ); 01141 01142 // 01143 // If this is a file object then we can get the 01144 // name directly from the file object. We start by 01145 // directly copying the file object unicode string structure 01146 // into our local memory and then adjust the lengths, copy 01147 // the buffer and modify the pointers as necessary. 01148 // 01149 01150 } else if (ObjectType == IoFileObjectType) { 01151 01152 NameInformation->Name = ((PFILE_OBJECT)Object)->FileName; 01153 01154 if ((NameInformation->Name.Length != 0) && 01155 (NameInformation->Name.Buffer != NULL)) { 01156 01157 NameSize = NameInformation->Name.Length + sizeof( UNICODE_NULL ); 01158 01159 // 01160 // We will trim down names that are longer than 260 unicode 01161 // characters in length 01162 // 01163 01164 if (NameSize > (260 * sizeof( WCHAR ))) { 01165 01166 NameSize = (260 * sizeof( WCHAR )); 01167 NameInformation->Name.Length = (USHORT)(NameSize - sizeof( UNICODE_NULL )); 01168 } 01169 01170 // 01171 // Now copy over the name from the buffer used by the 01172 // file object into our local buffer, adjust the 01173 // fields in the unicode string structure and null 01174 // terminate the string. In the copy we cannot copy 01175 // the null character from the filename because it 01176 // may not be valid memory 01177 // 01178 01179 RtlMoveMemory( (NameInformation+1), 01180 NameInformation->Name.Buffer, 01181 NameSize - sizeof( UNICODE_NULL) ); 01182 01183 NameInformation->Name.Buffer = (PWSTR)(NameInformation+1); 01184 NameInformation->Name.MaximumLength = (USHORT)NameSize; 01185 NameInformation->Name.Buffer[ NameInformation->Name.Length / sizeof( WCHAR )] = UNICODE_NULL; 01186 01187 // 01188 // Adjust the name size to account for the unicode 01189 // string structure 01190 // 01191 01192 NameSize += sizeof( *NameInformation ); 01193 01194 } else { 01195 01196 // 01197 // The file object does not have a name so the name 01198 // size stays zero 01199 // 01200 // **** Name Size should already be zero from about 70 01201 // lines above 01202 // 01203 01204 NameSize = 0; 01205 } 01206 } 01207 01208 // 01209 // At this point if we have a name then the name size will 01210 // not be zero and the name is stored in our local name 01211 // information variable 01212 // 01213 01214 if (NameSize != 0) { 01215 01216 // 01217 // Adjust the size of the name up to the next ulong 01218 // boundary and modify the total size required when 01219 // we add in the object name 01220 // 01221 01222 NameSize = (NameSize + sizeof( ULONG ) - 1) & (~(sizeof( ULONG ) - 1)); 01223 TotalSize += NameSize; 01224 01225 // 01226 // If everything has been successful so far, and we have 01227 // a non empty name, and everything fits in the output 01228 // buffer then copy over the name from our local buffer 01229 // into the caller supplied output buffer, append on the 01230 // null terminating character, and adjust the buffer point 01231 // to use the user's buffer 01232 // 01233 01234 if ((NT_SUCCESS( Status )) && 01235 (NameInformation->Name.Length != 0) && 01236 (TotalSize < Length)) { 01237 01238 // 01239 // Use temporary local variable for RltMoveMemory 01240 // 01241 01242 TempBuffer = (PWSTR)((&ObjectInfo->NameInfo)+1); 01243 TempMaximumLength = (USHORT) 01244 (NameInformation->Name.Length + sizeof( UNICODE_NULL )); 01245 01246 ObjectInfo->NameInfo.Name.Length = NameInformation->Name.Length; 01247 01248 RtlMoveMemory( TempBuffer, 01249 NameInformation->Name.Buffer, 01250 TempMaximumLength); 01251 01252 ObjectInfo->NameInfo.Name.Buffer = (PWSTR) 01253 (UserModeBufferAddress + 01254 ((PCHAR)TempBuffer - (PCHAR)ObjectInformation)); 01255 ObjectInfo->NameInfo.Name.MaximumLength = TempMaximumLength; 01256 01257 // 01258 // Otherwise if we've been successful so far but for some 01259 // reason we weren't able to store the object name then 01260 // decide if it was because of an not enough space or 01261 // because the object name is null 01262 // 01263 01264 } else if (NT_SUCCESS( Status )) { 01265 01266 if ((NameInformation->Name.Length != 0) || 01267 (TotalSize >= Length)) { 01268 01269 ReturnStatus = STATUS_INFO_LENGTH_MISMATCH; 01270 01271 } else { 01272 01273 RtlInitUnicodeString( &ObjectInfo->NameInfo.Name, NULL ); 01274 } 01275 01276 // 01277 // Otherwise we have not been successful so far, we'll 01278 // adjust the total size to account for a null unicode 01279 // string, and if it doesn't fit then that's an error 01280 // otherwise we'll put in the null object name 01281 // 01282 01283 } else { 01284 01285 TotalSize += sizeof( ObjectInfo->NameInfo.Name ); 01286 01287 if (TotalSize >= Length) { 01288 01289 ReturnStatus = STATUS_INFO_LENGTH_MISMATCH; 01290 01291 } else { 01292 01293 RtlInitUnicodeString( &ObjectInfo->NameInfo.Name, NULL ); 01294 01295 ReturnStatus = Status; 01296 } 01297 } 01298 01299 // 01300 // Otherwise the name size is zero meaning we have not found 01301 // an object name, so we'll adjust total size for the null 01302 // unicode string, and check that it fits in the output 01303 // buffer. If it fits we'll output a null object name 01304 // 01305 01306 } else { 01307 01308 TotalSize += sizeof( ObjectInfo->NameInfo.Name ); 01309 01310 if (TotalSize >= Length) { 01311 01312 ReturnStatus = STATUS_INFO_LENGTH_MISMATCH; 01313 01314 } else { 01315 01316 RtlInitUnicodeString( &ObjectInfo->NameInfo.Name, NULL ); 01317 } 01318 } 01319 01320 } 01321 01322 // 01323 // Release the array with objects 01324 // 01325 01326 ObpDestroyTypeArray(ObjectTypeArray); 01327 ObjectTypeArray = NULL; 01328 } 01329 } 01330 01331 // 01332 // Get the next object type from the list of system defined types. 01333 // This is the outer loop 01334 // 01335 01336 Next = Next->Flink; 01337 } 01338 01339 // 01340 // Fill in the total size needed to store the buffer if the user wants 01341 // that information. And return to our caller 01342 // 01343 01344 if (ARGUMENT_PRESENT( ReturnLength )) { 01345 01346 *ReturnLength = TotalSize; 01347 } 01348 01349 01350 } finally { 01351 01352 if (ObjectTypeArray != NULL) { 01353 01354 ObpDestroyTypeArray(ObjectTypeArray); 01355 } 01356 // 01357 // Unlock the type object type lock 01358 // 01359 01360 ObpLeaveObjectTypeMutex( ObpTypeObjectType ); 01361 } 01362 01363 01364 return( ReturnStatus ); 01365 } 01366

Generated on Sat May 15 19:41:06 2004 for test by doxygen 1.3.7