test: obtype.c Source File

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