Beispiel #1
0
NTSTATUS
NTAPI
ObQuerySecurityDescriptorInfo(IN PVOID Object,
                              IN PSECURITY_INFORMATION SecurityInformation,
                              OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
                              IN OUT PULONG Length,
                              IN PSECURITY_DESCRIPTOR *OutputSecurityDescriptor)
{
    POBJECT_HEADER ObjectHeader;
    NTSTATUS Status;
    PSECURITY_DESCRIPTOR ObjectSd;
    PAGED_CODE();

    /* Get the object header */
    ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);

    /* Get the SD */
    ObjectSd = ObpReferenceSecurityDescriptor(ObjectHeader);

    /* Query the information */
    Status = SeQuerySecurityDescriptorInfo(SecurityInformation,
                                           SecurityDescriptor,
                                           Length,
                                           &ObjectSd);

    /* Check if we have an object SD and dereference it, if so */
    if (ObjectSd) ObDereferenceSecurityDescriptor(ObjectSd, 1);

    /* Return status */
    return Status;
}
Beispiel #2
0
/**
 * Gets the type of an object.
 *
 * \param Object A pointer to an object.
 *
 * \return A pointer to the object's type object, or NULL if an error
 * occurred.
 */
POBJECT_TYPE KphGetObjectType(
    __in PVOID Object
    )
{
    PAGED_CODE();

    // XP to Vista: A pointer to the object type is
    // stored in the object header.
    if (
        KphDynNtVersion >= PHNT_WINXP &&
        KphDynNtVersion <= PHNT_VISTA
        )
    {
        return OBJECT_TO_OBJECT_HEADER(Object)->Type;
    }
    // Seven and above: An index to an internal object type
    // table is stored in the object header. Luckily we have
    // a new exported function, ObGetObjectType, to get
    // the object type.
    else if (KphDynNtVersion >= PHNT_WIN7)
    {
        if (ObGetObjectType_I)
            return ObGetObjectType_I(Object);
        else
            return NULL;
    }
    else
    {
        return NULL;
    }
}
Beispiel #3
0
/*++
* @name ObSetSecurityObjectByPointer
* @implemented NT5.1
*
*     The ObSetSecurityObjectByPointer routine <FILLMEIN>
*
* @param SecurityDescriptor
*        <FILLMEIN>
*
* @param MemoryAllocated
*        <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObSetSecurityObjectByPointer(IN PVOID Object,
                             IN SECURITY_INFORMATION SecurityInformation,
                             IN PSECURITY_DESCRIPTOR SecurityDescriptor)
{
    POBJECT_TYPE Type;
    POBJECT_HEADER Header;
    PAGED_CODE();

    /* Get the header and type */
    Header = OBJECT_TO_OBJECT_HEADER(Object);
    Type = Header->Type;

    /* Sanity check */
    ASSERT(SecurityDescriptor);

    /* Call the security procedure */
    return Type->TypeInfo.SecurityProcedure(Object,
                                            SetSecurityDescriptor,
                                            &SecurityInformation,
                                            SecurityDescriptor,
                                            NULL,
                                            &Header->SecurityDescriptor,
                                            Type->TypeInfo.PoolType,
                                            &Type->TypeInfo.GenericMapping);
}
Beispiel #4
0
BOOLEAN
NTAPI
ObpCheckTraverseAccess(IN PVOID Object,
                       IN ACCESS_MASK TraverseAccess,
                       IN PACCESS_STATE AccessState OPTIONAL,
                       IN BOOLEAN LockHeld,
                       IN KPROCESSOR_MODE AccessMode,
                       OUT PNTSTATUS AccessStatus)
{
    POBJECT_HEADER ObjectHeader;
    POBJECT_TYPE ObjectType;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    BOOLEAN SdAllocated;
    BOOLEAN Result;
    ACCESS_MASK GrantedAccess = 0;
    PPRIVILEGE_SET Privileges = NULL;
    NTSTATUS Status;
    PAGED_CODE();

    /* Get the header and type */
    ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
    ObjectType = ObjectHeader->Type;

    /* Get the security descriptor */
    Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated);
    if (!NT_SUCCESS(Status))
    {
        /* We failed */
        *AccessStatus = Status;
        return FALSE;
    }

    /* Lock the security context */
    SeLockSubjectContext(&AccessState->SubjectSecurityContext);

    /* Now do the entire access check */
    Result = SeAccessCheck(SecurityDescriptor,
                           &AccessState->SubjectSecurityContext,
                           TRUE,
                           TraverseAccess,
                           0,
                           &Privileges,
                           &ObjectType->TypeInfo.GenericMapping,
                           AccessMode,
                           &GrantedAccess,
                           AccessStatus);
    if (Privileges)
    {
        /* We got privileges, append them to the access state and free them */
        Status = SeAppendPrivileges(AccessState, Privileges);
        SeFreePrivileges(Privileges);
    }

    /* We're done, unlock the context and release security */
    SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
    ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
    return Result;
}
Beispiel #5
0
NTKERNELAPI
VOID
ObDeleteCapturedInsertInfo (
    __in PVOID Object
    )

/*++

Routine Description:

    This function frees the creation information that could be pointed at
    by the object header.

Arguments:

    Object - Supplies the object being modified

Return Value:

    None.

--*/

{
    POBJECT_HEADER ObjectHeader;

    PAGED_CODE();

    //
    //  Get the address of the object header and free the object create
    //  information object if the object is being created.
    //

    ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);

    if (ObjectHeader->Flags & OB_FLAG_NEW_OBJECT) {

        if (ObjectHeader->ObjectCreateInfo != NULL) {

            ObpFreeObjectCreateInformation(ObjectHeader->ObjectCreateInfo);

            ObjectHeader->ObjectCreateInfo = NULL;
        }
    }

    return;
}
Beispiel #6
0
VOID
NTAPI
PspCheckProcessList()
{
    PLIST_ENTRY Entry;

    KeAcquireGuardedMutex(&PspActiveProcessMutex);
    DbgPrint("# checking PsActiveProcessHead @ %p\n", &PsActiveProcessHead);
    for (Entry = PsActiveProcessHead.Flink;
         Entry != &PsActiveProcessHead;
         Entry = Entry->Flink)
    {
        PEPROCESS Process = CONTAINING_RECORD(Entry, EPROCESS, ActiveProcessLinks);
        POBJECT_HEADER Header;
        PVOID Info, HeaderLocation;

        /* Get the header and assume this is what we'll free */
        Header = OBJECT_TO_OBJECT_HEADER(Process);
        HeaderLocation = Header;

        /* To find the header, walk backwards from how we allocated */
        if ((Info = OBJECT_HEADER_TO_CREATOR_INFO(Header)))
        {
            HeaderLocation = Info;
        }
        if ((Info = OBJECT_HEADER_TO_NAME_INFO(Header)))
        {
            HeaderLocation = Info;
        }
        if ((Info = OBJECT_HEADER_TO_HANDLE_INFO(Header)))
        {
            HeaderLocation = Info;
        }
        if ((Info = OBJECT_HEADER_TO_QUOTA_INFO(Header)))
        {
            HeaderLocation = Info;
        }

        ExpCheckPoolAllocation(HeaderLocation, NonPagedPool, 'corP');
    }

    KeReleaseGuardedMutex(&PspActiveProcessMutex);
}
Beispiel #7
0
NTSTATUS
NTAPI
ObAssignObjectSecurityDescriptor(IN PVOID Object,
                                 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
                                 IN POOL_TYPE PoolType)
{
    POBJECT_HEADER ObjectHeader;
    NTSTATUS Status;
    PSECURITY_DESCRIPTOR NewSd;
    PEX_FAST_REF FastRef;
    PAGED_CODE();

    /* Get the object header */
    ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
    FastRef = (PEX_FAST_REF)&ObjectHeader->SecurityDescriptor;
    if (!SecurityDescriptor)
    {
        /* Nothing to assign */
        ExInitializeFastReference(FastRef, NULL);
        return STATUS_SUCCESS;
    }

    /* Add it to our internal cache */
    Status = ObLogSecurityDescriptor(SecurityDescriptor,
                                     &NewSd,
                                     MAX_FAST_REFS + 1);
    if (NT_SUCCESS(Status))
    {
        /* Free the old copy */
        ExFreePoolWithTag(SecurityDescriptor, TAG_SD);

        /* Set the new pointer */
        ASSERT(NewSd);
        ExInitializeFastReference(FastRef, NewSd);
    }

    /* Return status */
    return Status;
}
Beispiel #8
0
VOID
ObMakeTemporaryObject (
    IN PVOID Object
    )

/*++

Routine Description:

    This routine removes the name of the object from its parent
    directory.  The object is only removed if it has a non zero
    handle count and a name.  Otherwise the object is simply
    made non permanent

Arguments:

    Object - Supplies the object being modified

Return Value:

    None.

--*/

{
    POBJECT_HEADER ObjectHeader;

    PAGED_CODE();

    ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    ObjectHeader->Flags &= ~OB_FLAG_PERMANENT_OBJECT;

    ObpDeleteNameCheck( Object, FALSE );

    return;
}
Beispiel #9
0
VOID
FASTCALL
ObpFreeObject (
    IN PVOID Object
    )

/*++

Routine Description:

    This routine undoes ObpAllocateObject.  It returns the object back to free pool.

Arguments:

    Object - Supplies a pointer to the body of the object being freed.

Return Value:

    None.

--*/

{
    POBJECT_HEADER ObjectHeader;
    POBJECT_TYPE ObjectType;
    POBJECT_HEADER_QUOTA_INFO QuotaInfo;
    POBJECT_HEADER_HANDLE_INFO HandleInfo;
    POBJECT_HEADER_NAME_INFO NameInfo;
    POBJECT_HEADER_CREATOR_INFO CreatorInfo;
    PVOID FreeBuffer;
    ULONG NonPagedPoolCharge;
    ULONG PagedPoolCharge;

    PAGED_CODE();

    //
    //  Get the address of the object header.
    //

    ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
    ObjectType = ObjectHeader->Type;

    //
    //  Now from the header determine the start of the allocation.  We need
    //  to backup based on what precedes the header.  The order is very
    //  important and must be the inverse of that used by ObpAllocateObject
    //

    FreeBuffer = ObjectHeader;

    CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( ObjectHeader );

    if (CreatorInfo != NULL) {

        FreeBuffer = CreatorInfo;
    }

    NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );

    if (NameInfo != NULL) {

        FreeBuffer = NameInfo;
    }

    HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO( ObjectHeader );

    if (HandleInfo != NULL) {

        FreeBuffer = HandleInfo;
    }

    QuotaInfo = OBJECT_HEADER_TO_QUOTA_INFO( ObjectHeader );

    if (QuotaInfo != NULL) {

        FreeBuffer = QuotaInfo;
    }

#if DBG

    //
    //  On a checked build echo out frees
    //

    if (ObpShowAllocAndFree) {

        DbgPrint( "OB: Free  %lx (%lx) - Type: %wZ\n", ObjectHeader, ObjectHeader, &ObjectType->Name );
    }
#endif

    //
    //  Decrement the number of objects of this type
    //

    InterlockedDecrement((PLONG)&ObjectType->TotalNumberOfObjects);

    //
    //  Check where we were in the object initialization phase.  This
    //  flag really only tests if we have charged quota for this object.
    //  This is because the object create info and the quota block charged
    //  are unioned together.
    //

    if (ObjectHeader->Flags & OB_FLAG_NEW_OBJECT) {

        if (ObjectHeader->ObjectCreateInfo != NULL) {

            ObpFreeObjectCreateInformation( ObjectHeader->ObjectCreateInfo );

            ObjectHeader->ObjectCreateInfo = NULL;
        }

    } else {

        if (ObjectHeader->QuotaBlockCharged != NULL) {

            if (QuotaInfo != NULL) {

                PagedPoolCharge = QuotaInfo->PagedPoolCharge +
                                  QuotaInfo->SecurityDescriptorCharge;

                NonPagedPoolCharge = QuotaInfo->NonPagedPoolCharge;

            } else {

                PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;

                if (ObjectHeader->Flags & OB_FLAG_DEFAULT_SECURITY_QUOTA ) {

                    PagedPoolCharge += SE_DEFAULT_SECURITY_QUOTA;
                }

                NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
            }

            PsReturnSharedPoolQuota( ObjectHeader->QuotaBlockCharged,
                                     PagedPoolCharge,
                                     NonPagedPoolCharge );

            ObjectHeader->QuotaBlockCharged = NULL;
        }
    }

    if ((HandleInfo != NULL) &&
        ((ObjectHeader->Flags & OB_FLAG_SINGLE_HANDLE_ENTRY) == 0)) {

        //
        //  If a handle database has been allocated, then free the memory.
        //

        ExFreePool( HandleInfo->HandleCountDataBase );

        HandleInfo->HandleCountDataBase = NULL;
    }

    //
    //  If a name string buffer has been allocated, then free the memory.
    //

    if (NameInfo != NULL && NameInfo->Name.Buffer != NULL) {

        ExFreePool( NameInfo->Name.Buffer );

        NameInfo->Name.Buffer = NULL;
    }

    PERFINFO_REMOVE_OBJECT_FROM_ALLOCATED_TYPE_LIST(CreatorInfo, ObjectHeader);

    //
    //  Trash type field so we don't get far if we attempt to
    //  use a stale object pointer to this object.
    //
    //  Win64 Note: trash it by zero-extended it. 
    //                sign-extension will create a valid kernel address.


    ObjectHeader->Type = UIntToPtr(0xBAD0B0B0); 
    ExFreePoolWithTag( FreeBuffer,
                       (ObjectType == NULL ? 'TjbO' : ObjectType->Key) |
                            PROTECTED_POOL );

    return;
}
Beispiel #10
0
BOOLEAN
ObFindHandleForObject(
    IN PEPROCESS Process,
    IN PVOID Object OPTIONAL,
    IN POBJECT_TYPE ObjectType OPTIONAL,
    IN POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL,
    OUT PHANDLE Handle
    )

/*++

Routine Description:

    This routine searchs the handle table for the specified process,
    looking for a handle table entry that matches the passed parameters.
    If an an Object pointer is specified it must match.  If an
    ObjectType is specified it must match.  If HandleInformation is
    specified, then both the HandleAttributes and GrantedAccess mask
    must match.  If all three match parameters are NULL, then will
    match the first allocated handle for the specified process that
    matches the specified object pointer.

Arguments:

    Process - Specifies the process whose object table is to be searched.

    Object - Specifies the object pointer to look for.

    ObjectType - Specifies the object type to look for.

    HandleInformation - Specifies additional match criteria to look for.

    Handle - Specifies the location to receive the handle value whose handle
        entry matches the supplied object pointer and optional match criteria.

Return Value:

    TRUE if a match was found and FALSE otherwise.

--*/

{
    OBJECT_TABLE_ENTRY ObjectTableEntry;
    OBP_FIND_HANDLE_DATA EnumParameter;
    BOOLEAN Result;

    Result = FALSE;
    KeWaitForSingleObject( &ObpInitKillMutant,
                           Executive,
                           KernelMode,
                           FALSE,
                           NULL
                         );

    if (Process->ObjectTable != NULL) {
        if (ARGUMENT_PRESENT( Object )) {
            EnumParameter.ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
            }
        else {
            EnumParameter.ObjectHeader = NULL;
            }
        EnumParameter.ObjectType = ObjectType;
        EnumParameter.HandleInformation = HandleInformation;
        if (ExEnumHandleTable( Process->ObjectTable,
                               ObpEnumFindHandleProcedure,
                               &EnumParameter,
                               Handle
                             )
           ) {
            *Handle = MAKE_OBJECT_HANDLE( *Handle );
            Result = TRUE;
            }
        }

    KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
    return Result;
}
Beispiel #11
0
VOID
DumpDevice(
    PVOID DeviceAddress,
    BOOLEAN FullDetail
    )

/*++

Routine Description:

    Displays the driver name for the device object if FullDetail == FALSE.
    Otherwise displays more information about the device and the device queue.

Arguments:

    DeviceAddress - address of device object to dump.
    FullDetail    - TRUE means the device object name, driver name, and
                    information about Irps queued to the device.

Return Value:

    None

--*/

{
    ULONG                      result;
    ULONG                      i;
    PUCHAR                     buffer;
    DEVICE_OBJECT              deviceObject;
    UNICODE_STRING             unicodeString;
    PLIST_ENTRY                nextEntry;
    PVOID                      queueAddress;
    PIRP                       irp;
    KDEVICE_QUEUE_ENTRY        queueEntry;
    POBJECT_HEADER             pObjectHeader;
    OBJECT_HEADER              objectHeader;
    POBJECT_HEADER_NAME_INFO   pNameInfo;
    OBJECT_HEADER_NAME_INFO    NameInfo;



    if ((!ReadMemory( (DWORD)DeviceAddress,
                     &deviceObject,
                     sizeof(deviceObject),
                     &result)) || (result < sizeof(deviceObject))) {
        dprintf("%08lx: Could not read device object\n", DeviceAddress);
        return;
    }

    if (deviceObject.Type != IO_TYPE_DEVICE) {
        dprintf("%08lx: is not a device object\n", DeviceAddress);
        return;
    }

    if (FullDetail == TRUE) {

        //
        // Dump the device name if present.
        //

        pObjectHeader = OBJECT_TO_OBJECT_HEADER(DeviceAddress);
        if (ReadMemory( (DWORD)pObjectHeader,
                          &objectHeader,
                          sizeof(objectHeader),
                          &result) && (result == sizeof(objectHeader))) {
            pNameInfo = KD_OBJECT_HEADER_TO_NAME_INFO( pObjectHeader, &objectHeader );
            if (ReadMemory((DWORD)pNameInfo,
                           &NameInfo,
                           sizeof(NameInfo),
                           &result) && (result == sizeof(NameInfo))) {
                buffer = LocalAlloc(LPTR, NameInfo.Name.MaximumLength);
                if (buffer != NULL) {
                    unicodeString.MaximumLength = NameInfo.Name.MaximumLength;
                    unicodeString.Length = NameInfo.Name.Length;
                    unicodeString.Buffer = (PWSTR)buffer;
                    if (ReadMemory((DWORD)NameInfo.Name.Buffer,
                                   buffer,
                                   unicodeString.Length,
                                   &result) && (result == unicodeString.Length)) {
                        dprintf(" %wZ", &unicodeString);
                    }
                    LocalFree(buffer);
                }
            }
        }
    }

    DumpDriver((PVOID) deviceObject.DriverObject, FALSE);

    if (FullDetail == TRUE) {
        //
        // Dump Irps related to driver.
        //

        dprintf("  DriverObject %08lx\n", deviceObject.DriverObject);
        dprintf("Current Irp %08lx RefCount %d Type %08lx ",
                deviceObject.CurrentIrp,
                deviceObject.ReferenceCount,
                deviceObject.DeviceType);
        if (deviceObject.AttachedDevice) {
            dprintf("AttachedDev %08lx ", deviceObject.AttachedDevice);
        }
        if (deviceObject.Vpb) {
            dprintf("Vpb %08lx ", deviceObject.Vpb);
        }

        dprintf("DevExt %08lx\n", deviceObject.DeviceExtension);

        if (deviceObject.DeviceQueue.Busy) {

            if (IsListEmpty(&deviceObject.DeviceQueue.DeviceListHead)) {
                dprintf("Device queue is busy -- Queue empty\n");
            } else {
                dprintf("DeviceQueue: ");
                nextEntry = deviceObject.DeviceQueue.DeviceListHead.Flink;
                i = 0;

                while ((PCH) nextEntry != (PCH)
                    ((PCH) DeviceAddress +
                         ((PCH) &deviceObject.DeviceQueue.DeviceListHead.Flink -
                              (PCH) &deviceObject))) {
                    queueAddress = CONTAINING_RECORD(nextEntry,
                                                     KDEVICE_QUEUE_ENTRY,
                                                     DeviceListEntry);
                    if ((!ReadMemory((DWORD)queueAddress,
                                     &queueEntry,
                                     sizeof(queueEntry),
                                     &result)) || (result < sizeof(queueEntry))) {
                        dprintf("%08lx: Could not read queue entry\n", DeviceAddress);
                        return;
                    }

                    irp = CONTAINING_RECORD(&queueEntry,
                                            IRP,
                                            Tail.Overlay.DeviceQueueEntry);

                    dprintf("%08lx%s",
                            irp,
                            (i & 0x03) == 0x03 ? "\n\t     " : " ");
                    if (CheckControlC()) {
                        break;
                    }
                }
                dprintf("\n");
            }
        } else {
            dprintf("Device queue is not busy.\n");
        }
    }
}
Beispiel #12
0
VOID
ObpHandleDosDeviceName(
    POBJECT_SYMBOLIC_LINK SymbolicLink
    )

/*++

Routine Description:

    This routine does extra processing symbolic links being created in the \??
    object directory.  This processing consists of:

    1.  Determine if the name of the symbolic link is of the form \??\x:
        where x can be any upper or lower case letter.  If this is the
        case then we need to set the bit in KUSER_SHARED_DATA.DosDeviceMap
        to indicate that the drive letter exists.  We also set
        KUSER_SHARED_DATA.DosDeviceDriveType to unknown for now.

    2.  Process the link target, trying to resolve it into a pointer to
        an object other than a object directory object.  All object directories
        traversed must grant world traverse access other wise we bail out.
        If we successfully find a non object directory object, then reference
        the object pointer and store it in the symbolic link object, along
        with a remaining string if any.  ObpLookupObjectName will used this
        cache object pointer to short circuit the name lookup directly to
        the cached object's parse routine.  For any object directory objects
        traversed along the way, increment their symbolic link SymbolicLinkUsageCount
        field.  This field is used whenever an object directory is deleted or
        its security is changed such that it no longer grants world traverse
        access.  In either case, if the field is non-zero we walk all the symbolic links
        and resnap them.

Arguments:

    SymbolicLink - pointer to symbolic link object being created.

    Name - pointer to the name of this symbolic link

Return Value:

    None.

--*/

{
    POBJECT_HEADER ObjectHeader;
    POBJECT_HEADER_NAME_INFO NameInfo;
    WCHAR DosDeviceDriveLetter;
    ULONG DosDeviceDriveIndex;

    //
    // Now see if this symbolic link is being created in the \?? object directory
    // Since we are only called from NtCreateSymbolicLinkObject, after the handle
    // to this symbolic link has been created but before it is returned to the caller
    // the handle can't be closed while we are executing, unless via a random close
    // So no need to hold the type specific mutex while we look at the name.
    //
    ObjectHeader = OBJECT_TO_OBJECT_HEADER( SymbolicLink );
    NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
    if (NameInfo == NULL || NameInfo->Directory != ObpDosDevicesDirectoryObject) {
        return;
        }

    //
    // Here if we are creating a symbolic link in the \?? object directory
    // See if this is a drive letter definition.  If so set the bit in
    // KUSER_SHARED_DATA.DosDeviceMap
    //
    DosDeviceDriveIndex = 0;
    if (NameInfo->Name.Length == 2 * sizeof( WCHAR ) &&
        NameInfo->Name.Buffer[ 1 ] == L':'
       ) {
        DosDeviceDriveLetter = RtlUpcaseUnicodeChar( NameInfo->Name.Buffer[ 0 ] );
        if (DosDeviceDriveLetter >= L'A' && DosDeviceDriveLetter <= L'Z') {
            DosDeviceDriveIndex = DosDeviceDriveLetter - L'A';
            DosDeviceDriveIndex += 1;
            SymbolicLink->DosDeviceDriveIndex = DosDeviceDriveIndex;
            }
        }

    //
    // Now traverse the target path seeing if we can snap the link now.
    //

    ObpEnterRootDirectoryMutex();
    ObpEnterObjectTypeMutex( ObpSymbolicLinkObjectType );

    ObpProcessDosDeviceSymbolicLink( SymbolicLink, CREATE_SYMBOLIC_LINK );

    ObpLeaveRootDirectoryMutex();
    ObpLeaveObjectTypeMutex( ObpSymbolicLinkObjectType );
    return;
}
Beispiel #13
0
/*++
* @name ObGetObjectSecurity
* @implemented NT4
*
*     The ObGetObjectSecurity routine <FILLMEIN>
*
* @param Object
*        <FILLMEIN>
*
* @param SecurityDescriptor
*        <FILLMEIN>
*
* @param MemoryAllocated
*        <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObGetObjectSecurity(IN PVOID Object,
                    OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
                    OUT PBOOLEAN MemoryAllocated)
{
    POBJECT_HEADER Header;
    POBJECT_TYPE Type;
    ULONG Length = 0;
    NTSTATUS Status;
    SECURITY_INFORMATION SecurityInformation;
    KIRQL CalloutIrql;
    PAGED_CODE();

    /* Get the object header and type */
    Header = OBJECT_TO_OBJECT_HEADER(Object);
    Type = Header->Type;

    /* Tell the caller that we didn't have to allocate anything yet */
    *MemoryAllocated = FALSE;

    /* Check if the object uses default security */
    if (Type->TypeInfo.SecurityProcedure == SeDefaultObjectMethod)
    {
        /* Reference the descriptor */
        *SecurityDescriptor = ObpReferenceSecurityDescriptor(Header);
        return STATUS_SUCCESS;
    }

    /* Set mask to query */
    SecurityInformation =  OWNER_SECURITY_INFORMATION |
                           GROUP_SECURITY_INFORMATION |
                           DACL_SECURITY_INFORMATION |
                           SACL_SECURITY_INFORMATION;

    /* Get the security descriptor size */
    ObpCalloutStart(&CalloutIrql);
    Status = Type->TypeInfo.SecurityProcedure(Object,
                                              QuerySecurityDescriptor,
                                              &SecurityInformation,
                                              *SecurityDescriptor,
                                              &Length,
                                              &Header->SecurityDescriptor,
                                              Type->TypeInfo.PoolType,
                                              &Type->TypeInfo.GenericMapping);
    ObpCalloutEnd(CalloutIrql, "Security", Type, Object);

    /* Check for failure */
    if (Status != STATUS_BUFFER_TOO_SMALL) return Status;

    /* Allocate security descriptor */
    *SecurityDescriptor = ExAllocatePoolWithTag(PagedPool,
                                                Length,
                                                TAG_SEC_QUERY);
    if (!(*SecurityDescriptor)) return STATUS_INSUFFICIENT_RESOURCES;
    *MemoryAllocated = TRUE;

    /* Query security descriptor */
    ObpCalloutStart(&CalloutIrql);
    Status = Type->TypeInfo.SecurityProcedure(Object,
                                              QuerySecurityDescriptor,
                                              &SecurityInformation,
                                              *SecurityDescriptor,
                                              &Length,
                                              &Header->SecurityDescriptor,
                                              Type->TypeInfo.PoolType,
                                              &Type->TypeInfo.GenericMapping);
    ObpCalloutEnd(CalloutIrql, "Security", Type, Object);

    /* Check for failure */
    if (!NT_SUCCESS(Status))
    {
        /* Free the descriptor and tell the caller we failed */
        ExFreePoolWithTag(*SecurityDescriptor, TAG_SEC_QUERY);
        *MemoryAllocated = FALSE;
    }

    /* Return status */
    return Status;
}
Beispiel #14
0
/*++
* @name ObCheckObjectAccess
*
*     The ObCheckObjectAccess routine <FILLMEIN>
*
* @param Object
*        <FILLMEIN>
*
* @param AccessState
*        <FILLMEIN>
*
* @param LockHeld
*        <FILLMEIN>
*
* @param AccessMode
*        <FILLMEIN>
*
* @param ReturnedStatus
*        <FILLMEIN>
*
* @return TRUE if access was granted, FALSE otherwise.
*
* @remarks None.
*
*--*/
BOOLEAN
NTAPI
ObCheckObjectAccess(IN PVOID Object,
                    IN OUT PACCESS_STATE AccessState,
                    IN BOOLEAN LockHeld,
                    IN KPROCESSOR_MODE AccessMode,
                    OUT PNTSTATUS ReturnedStatus)
{
    POBJECT_HEADER ObjectHeader;
    POBJECT_TYPE ObjectType;
    PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
    BOOLEAN SdAllocated;
    NTSTATUS Status;
    BOOLEAN Result;
    ACCESS_MASK GrantedAccess;
    PPRIVILEGE_SET Privileges = NULL;
    PAGED_CODE();

    /* Get the object header and type */
    ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
    ObjectType = ObjectHeader->Type;

    /* Get security information */
    Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated);
    if (!NT_SUCCESS(Status))
    {
        /* Return failure */
        *ReturnedStatus = Status;
        return FALSE;
    }
    else if (!SecurityDescriptor)
    {
        /* Otherwise, if we don't actually have an SD, return success */
        *ReturnedStatus = Status;
        return TRUE;
    }

    /* Lock the security context */
    SeLockSubjectContext(&AccessState->SubjectSecurityContext);

    /* Now do the entire access check */
    Result = SeAccessCheck(SecurityDescriptor,
                           &AccessState->SubjectSecurityContext,
                           TRUE,
                           AccessState->RemainingDesiredAccess,
                           AccessState->PreviouslyGrantedAccess,
                           &Privileges,
                           &ObjectType->TypeInfo.GenericMapping,
                           AccessMode,
                           &GrantedAccess,
                           ReturnedStatus);
    if (Privileges)
    {
        /* We got privileges, append them to the access state and free them */
        Status = SeAppendPrivileges(AccessState, Privileges);
        SeFreePrivileges(Privileges);
    }

    /* Check if access was granted */
    if (Result)
    {
        /* Update the access state */
        AccessState->RemainingDesiredAccess &= ~(GrantedAccess |
                                                 MAXIMUM_ALLOWED);
        AccessState->PreviouslyGrantedAccess |= GrantedAccess;
    }

    /* Do audit alarm */
    SeOpenObjectAuditAlarm(&ObjectType->Name,
                           Object,
                           NULL,
                           SecurityDescriptor,
                           AccessState,
                           FALSE,
                           Result,
                           AccessMode,
                           &AccessState->GenerateOnClose);

    /* We're done, unlock the context and release security */
    SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
    ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
    return Result;
}
Beispiel #15
0
BOOLEAN
NTAPI
ObpCheckObjectReference(IN PVOID Object,
                        IN OUT PACCESS_STATE AccessState,
                        IN BOOLEAN LockHeld,
                        IN KPROCESSOR_MODE AccessMode,
                        OUT PNTSTATUS AccessStatus)
{
    POBJECT_HEADER ObjectHeader;
    POBJECT_TYPE ObjectType;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    BOOLEAN SdAllocated;
    BOOLEAN Result;
    ACCESS_MASK GrantedAccess = 0;
    PPRIVILEGE_SET Privileges = NULL;
    NTSTATUS Status;
    PAGED_CODE();

    /* Get the header and type */
    ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
    ObjectType = ObjectHeader->Type;

    /* Get the security descriptor */
    Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated);
    if (!NT_SUCCESS(Status))
    {
        /* We failed */
        *AccessStatus = Status;
        return FALSE;
    }

    /* Lock the security context */
    SeLockSubjectContext(&AccessState->SubjectSecurityContext);

    /* Now do the entire access check */
    Result = SeAccessCheck(SecurityDescriptor,
                           &AccessState->SubjectSecurityContext,
                           TRUE,
                           AccessState->RemainingDesiredAccess,
                           AccessState->PreviouslyGrantedAccess,
                           &Privileges,
                           &ObjectType->TypeInfo.GenericMapping,
                           AccessMode,
                           &GrantedAccess,
                           AccessStatus);
    if (Result)
    {
        /* Update the access state */
        AccessState->RemainingDesiredAccess &= ~GrantedAccess;
        AccessState->PreviouslyGrantedAccess |= GrantedAccess;
    }

    /* Check if we have an SD */
    if (SecurityDescriptor)
    {
        /* Do audit alarm */
#if 0
        SeObjectReferenceAuditAlarm(&AccessState->OperationID,
                                    Object,
                                    SecurityDescriptor,
                                    &AccessState->SubjectSecurityContext,
                                    AccessState->RemainingDesiredAccess |
                                    AccessState->PreviouslyGrantedAccess,
                                    ((PAUX_ACCESS_DATA)(AccessState->AuxData))->
                                    PrivilegeSet,
                                    Result,
                                    AccessMode);
#endif
    }

    /* We're done, unlock the context and release security */
    SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
    ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
    return Result;
}
Beispiel #16
0
NTSTATUS
NTAPI
ObSetSecurityDescriptorInfo(IN PVOID Object,
                            IN PSECURITY_INFORMATION SecurityInformation,
                            IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
                            IN OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor,
                            IN POOL_TYPE PoolType,
                            IN PGENERIC_MAPPING GenericMapping)
{
    NTSTATUS Status;
    POBJECT_HEADER ObjectHeader;
    PSECURITY_DESCRIPTOR OldDescriptor, NewDescriptor, CachedDescriptor;
    PEX_FAST_REF FastRef;
    EX_FAST_REF OldValue;
    ULONG_PTR Count;
    PAGED_CODE();

    /* Get the object header */
    ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
    while (TRUE)
    {
        /* Reference the old descriptor */
        OldDescriptor = ObpReferenceSecurityDescriptor(ObjectHeader);
        NewDescriptor = OldDescriptor;

        /* Set the SD information */
        Status = SeSetSecurityDescriptorInfo(Object,
                                             SecurityInformation,
                                             SecurityDescriptor,
                                             &NewDescriptor,
                                             PoolType,
                                             GenericMapping);
        if (NT_SUCCESS(Status))
        {
            /* Now add this to the cache */
            Status = ObLogSecurityDescriptor(NewDescriptor,
                                             &CachedDescriptor,
                                             MAX_FAST_REFS + 1);

            /* Let go of our uncached copy */
            ExFreePool(NewDescriptor);

            /* Check for success */
            if (NT_SUCCESS(Status))
            {
                /* Do the swap */
                FastRef = (PEX_FAST_REF)OutputSecurityDescriptor;
                OldValue = ExCompareSwapFastReference(FastRef,
                                                      CachedDescriptor,
                                                      OldDescriptor);
                
                /* Get the security descriptor */
                SecurityDescriptor = ExGetObjectFastReference(OldValue);
                Count = ExGetCountFastReference(OldValue);
                
                /* Make sure the swap worked */
                if (SecurityDescriptor == OldDescriptor)
                {
                    /* Flush waiters */
                    ObpAcquireObjectLock(ObjectHeader);
                    ObpReleaseObjectLock(ObjectHeader);

                    /* And dereference the old one */
                    ObDereferenceSecurityDescriptor(OldDescriptor, Count + 2);
                    break;
                }
                else
                {
                    /* Someone changed it behind our back -- try again */
                    ObDereferenceSecurityDescriptor(OldDescriptor, 1);
                    ObDereferenceSecurityDescriptor(CachedDescriptor,
                                                    MAX_FAST_REFS + 1);
                }
            }
            else
            {
                /* We failed, dereference the old one */
                ObDereferenceSecurityDescriptor(OldDescriptor, 1);
                break;
            }
        }
        else
        {
            /* We failed, dereference the old one */
            if (OldDescriptor) ObDereferenceSecurityDescriptor(OldDescriptor, 1);
            break;
        }
    }

    /* Return status */
    return Status;
}
Beispiel #17
0
NTSTATUS
NtSignalAndWaitForSingleObject(
    IN HANDLE SignalHandle,
    IN HANDLE WaitHandle,
    IN BOOLEAN Alertable,
    IN PLARGE_INTEGER Timeout OPTIONAL
    )

/*++

Routine Description:

    This function atomically signals the specified signal object and then
    waits until the specified wait object attains a state of Signaled. An
    optional timeout can also be specified. If a timeout is not specified,
    then the wait will not be satisfied until the wait object attains a
    state of Signaled. If a timeout is specified, and the wait object has
    not attained a state of Signaled when the timeout expires, then the
    wait is automatically satisfied. If an explicit timeout value of zero
    is specified, then no wait will occur if the wait cannot be satisfied
    immediately. The wait can also be specified as alertable.

Arguments:

    SignalHandle - supplies the handle of the signal object.

    WaitHandle  - Supplies the handle for the wait object.

    Alertable - Supplies a boolean value that specifies whether the wait
        is alertable.

    Timeout - Supplies an pointer to an absolute or relative time over
        which the wait is to occur.

Return Value:

    The wait completion status. A value of STATUS_TIMEOUT is returned if a
    timeout occurred. A value of STATUS_SUCCESS is returned if the specified
    object satisfied the wait. A value of STATUS_ALERTED is returned if the
    wait was aborted to deliver an alert to the current thread. A value of
    STATUS_USER_APC is returned if the wait was aborted to deliver a user
    APC to the current thread.

--*/

{

    OBJECT_HANDLE_INFORMATION HandleInformation;
    KPROCESSOR_MODE PreviousMode;
    PVOID RealObject;
    PVOID SignalObject;
    POBJECT_HEADER SignalObjectHeader;
    NTSTATUS Status;
    LARGE_INTEGER TimeoutValue;
    PVOID WaitObject;
    POBJECT_HEADER WaitObjectHeader;

    //
    // Establish an exception handler and probe the specified timeout value
    // if necessary. If the probe fails, then return the exception code as
    // the service status.
    //

    PreviousMode = KeGetPreviousMode();
    if ((ARGUMENT_PRESENT(Timeout)) && (PreviousMode != KernelMode)) {
        try {
            TimeoutValue = ProbeAndReadLargeInteger(Timeout);
            Timeout = &TimeoutValue;

        } except(EXCEPTION_EXECUTE_HANDLER) {
            return GetExceptionCode();
        }
    }

    //
    // Reference the signal object by handle.
    //

    Status = ObReferenceObjectByHandle(SignalHandle,
                                       0,
                                       NULL,
                                       PreviousMode,
                                       &SignalObject,
                                       &HandleInformation);

    //
    // If the reference was successful, then reference the wait object by
    // handle.
    //

    if (NT_SUCCESS(Status)) {
        Status = ObReferenceObjectByHandle(WaitHandle,
                                           SYNCHRONIZE,
                                           NULL,
                                           PreviousMode,
                                           &WaitObject,
                                           NULL);

        //
        // If the reference was successful, then determine the real wait
        // object, check the signal object access, signal the signal object,
        // and wait for the real wait object.
        //

        if (NT_SUCCESS(Status)) {
            WaitObjectHeader = OBJECT_TO_OBJECT_HEADER(WaitObject);
            RealObject = WaitObjectHeader->Type->DefaultObject;
            if ((LONG)RealObject >= 0) {
                RealObject = (PVOID)((PCHAR)WaitObject + (ULONG)RealObject);
            }

            //
            // If the signal object is an event, then check for modify access
            // and set the event. Otherwise, if the signal object is a mutant,
            // then attempt to release ownership of the mutant. Otherwise, if
            // the object is a semaphore, then check for modify access and
            // release the semaphore. Otherwise, the signal objet is invalid.
            //

            SignalObjectHeader = OBJECT_TO_OBJECT_HEADER(SignalObject);
            Status = STATUS_ACCESS_DENIED;
            if (SignalObjectHeader->Type == ExEventObjectType) {

                //
                // Check for access to the specified event object,
                //

                if ((PreviousMode != KernelMode) &&
                    (SeComputeDeniedAccesses(HandleInformation.GrantedAccess,
                                             EVENT_MODIFY_STATE) != 0)) {
                    goto WaitExit;
                }

                //
                // If the wait object is also an event, the wait is not
                // alertable, and no timeout was specified, then the event
                // pair path can be used. Otherwise, set the event and wait
                // atomically.
                //

                if ((WaitObjectHeader->Type == ExEventObjectType) &&
                    (Alertable == FALSE) &&
                    (Timeout == NULL)) {
                    Status = KiSetServerWaitClientEvent((PKEVENT)SignalObject,
                                                        (PKEVENT)RealObject,
                                                        PreviousMode);

                    goto WaitExit;
                }

                //
                // Set the specified event and wait atomically.
                //

                KeSetEvent((PKEVENT)SignalObject, EVENT_INCREMENT, TRUE);

            } else if (SignalObjectHeader->Type == ExMutantObjectType) {

                //
                // Release the specified mutant and wait atomically.
                //
                // N.B. The release will only be successful if the current
                //      thread is the owner of the mutant.
                //

                try {
                    KeReleaseMutant((PKMUTANT)SignalObject,
                                    MUTANT_INCREMENT,
                                    FALSE,
                                    TRUE);

                } except(EXCEPTION_EXECUTE_HANDLER) {
                    Status = GetExceptionCode();
                    goto WaitExit;
                }

            } else if (SignalObjectHeader->Type == ExSemaphoreObjectType) {

                //
                // Check for access to the specified semaphore object,
                //

                if ((PreviousMode != KernelMode) &&
                    (SeComputeDeniedAccesses(HandleInformation.GrantedAccess,
                                             SEMAPHORE_MODIFY_STATE) != 0)) {
                    goto WaitExit;
                }

                //
                // Release the specified semaphore and wait atomically.
                //

                try {

                    //
                    // If the wait object is also a semaphore, the wait is
                    // not alertable, and no timeout was specified, then
                    // the semaphore path can be used. Otherwise, release
                    // the semaphore and wait atomically.
                    //

                    if ((WaitObjectHeader->Type == ExSemaphoreObjectType) &&
                        (Alertable == FALSE) &&
                        (Timeout == NULL)) {
                        Status = KeReleaseWaitForSemaphore((PKSEMAPHORE)SignalObject,
                                                           (PKSEMAPHORE)RealObject,
                                                           UserRequest,
                                                           PreviousMode);

                        goto WaitExit;
                    }

                    //
                    // Release the specified semaphore and wait atomically.
                    //

                    KeReleaseSemaphore((PKSEMAPHORE)SignalObject,
                                       SEMAPHORE_INCREMENT,
                                       1,
                                       TRUE);

                } except(EXCEPTION_EXECUTE_HANDLER) {
                    Status = GetExceptionCode();
                    goto WaitExit;
                }

            } else {
                Status =
                STATUS_OBJECT_TYPE_MISMATCH;
                goto WaitExit;
            }

            Status = KeWaitForSingleObject(RealObject,
                                           UserRequest,
                                           PreviousMode,
                                           Alertable,
                                           Timeout);

        WaitExit:
            ObDereferenceObject(WaitObject);
        }
Beispiel #18
0
NTSTATUS
ObInsertObject (
    __in PVOID Object,
    __in_opt PACCESS_STATE AccessState,
    __in_opt ACCESS_MASK DesiredAccess,
    __in ULONG ObjectPointerBias,
    __out_opt PVOID *NewObject,
    __out_opt PHANDLE Handle
    )

/*++

Routine Description:

    This routine inserts an object into the current processes handle table.

    The Object header includes a pointer to a SecurityDescriptor passed in
    an object creation call.  This SecurityDescriptor is not assumed to have
    been captured.  This routine is responsible for making an appropriate
    SecurityDescriptor and removing the reference in the object header.

Arguments:

    Object - Supplies a pointer to the new object body

    AccessState - Optionally supplies the access state for the new
        handle

    DesiredAccess - Optionally supplies the desired access we want for the
        new handle

    ObjectPointerBias - Supplies a bias to apply for the pointer count for the
        object

    NewObject - Optionally receives the pointer to the new object that we've
        created a handle for

    Handle - Receives the new handle, If NULL then no handle is created.
             Objects that don't have handles created must be unnamed and
             have an object bias of zero.

Return Value:

    An appropriate NTSTATUS value.

--*/

{
    POBJECT_CREATE_INFORMATION ObjectCreateInfo;
    POBJECT_HEADER ObjectHeader;
    PUNICODE_STRING ObjectName;
    POBJECT_TYPE ObjectType;
    POBJECT_HEADER_NAME_INFO NameInfo;
    PSECURITY_DESCRIPTOR ParentDescriptor = NULL;
    PVOID InsertObject;
    HANDLE NewHandle;
    OB_OPEN_REASON OpenReason;
    NTSTATUS Status = STATUS_SUCCESS;
    ACCESS_STATE LocalAccessState;
    AUX_ACCESS_DATA AuxData;
    BOOLEAN SecurityDescriptorAllocated;
    KPROCESSOR_MODE PreviousMode;
    NTSTATUS ReturnStatus;
    PVOID DirObject = NULL;
    OBP_LOOKUP_CONTEXT LookupContext;

    PAGED_CODE();

    ObpValidateIrql("ObInsertObject");

    //
    //  Get the address of the object header, the object create information,
    //  the object type, and the address of the object name descriptor, if
    //  specified.
    //

    ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);

#if DBG

    if ((ObjectHeader->Flags & OB_FLAG_NEW_OBJECT) == 0) {

        KdPrint(("OB: Attempting to insert existing object %08x\n", Object));
        KdBreakPoint();

        ObDereferenceObject(Object);

        return STATUS_INVALID_PARAMETER;
    }

#endif

    ObjectCreateInfo = ObjectHeader->ObjectCreateInfo;

    ObjectType = ObjectHeader->Type;

    NameInfo = ObpReferenceNameInfo( ObjectHeader );

    ObjectName = NULL;

    if ((NameInfo != NULL) && (NameInfo->Name.Buffer != NULL)) {

        ObjectName = &NameInfo->Name;
    }

    ASSERT (ARGUMENT_PRESENT (Handle) || (ObjectPointerBias == 0 && ObjectName == NULL &&
                                          ObjectType->TypeInfo.SecurityRequired && NewObject == NULL));

    //
    //  If security checks are not required and an object name is not
    //  specified, insert an unnamed object, biasing the count
    //  by one, dereference the bias, and return to our caller
    //

    PreviousMode = KeGetPreviousMode();

    if (!ObjectType->TypeInfo.SecurityRequired && (ObjectName == NULL)) {

        ObjectHeader->ObjectCreateInfo = NULL;

        *Handle = NULL;

        Status = ObpCreateUnnamedHandle( Object,
                                         DesiredAccess,
                                         1 + ObjectPointerBias,
                                         ObjectCreateInfo->Attributes,
                                         PreviousMode,
                                         NewObject,
                                         Handle );
        //
        //  Free the object creation information and dereference the object.
        //

        ObpFreeObjectCreateInformation(ObjectCreateInfo);

        ObpDereferenceNameInfo( NameInfo );
        ObDereferenceObject(Object);

        return Status;
    }

    //
    //  The object is either named or requires full security checks.  If the
    //  caller hasn't specified an access state then dummy up a local one
    //  using the requested desired access
    //

    if (!ARGUMENT_PRESENT(AccessState)) {

        AccessState = &LocalAccessState;

        Status = SeCreateAccessState( &LocalAccessState,
                                      &AuxData,
                                      DesiredAccess,
                                      &ObjectType->TypeInfo.GenericMapping );

        if (!NT_SUCCESS(Status)) {

            ObpDereferenceNameInfo( NameInfo );
            ObDereferenceObject(Object);

            return Status;
        }
    }

    AccessState->SecurityDescriptor = ObjectCreateInfo->SecurityDescriptor;

    //
    //  Check the desired access mask against the security descriptor
    //

    Status = ObpValidateAccessMask( AccessState );

    if (!NT_SUCCESS( Status )) {

        if (AccessState == &LocalAccessState) {

            SeDeleteAccessState( AccessState );
        }

        ObpDereferenceNameInfo( NameInfo );
        ObDereferenceObject(Object);

        if (AccessState == &LocalAccessState) {

            SeDeleteAccessState( AccessState );
        }

        return( Status );
    }

    //
    //  Set some local state variables
    //

    ObpInitializeLookupContext(&LookupContext);

    InsertObject = Object;
    OpenReason = ObCreateHandle;

    //
    //  Check if we have an object name.  If so then
    //  lookup the name
    //

    if (ObjectName != NULL) {

        Status = ObpLookupObjectName( ObjectCreateInfo->RootDirectory,
                                      ObjectName,
                                      ObjectCreateInfo->Attributes,
                                      ObjectType,
                                      (KPROCESSOR_MODE)(ObjectHeader->Flags & OB_FLAG_KERNEL_OBJECT
                                                            ? KernelMode : UserMode),
                                      ObjectCreateInfo->ParseContext,
                                      ObjectCreateInfo->SecurityQos,
                                      Object,
                                      AccessState,
                                      &LookupContext,
                                      &InsertObject );

        //
        //  We found the name and it is not the object we have as our input.
        //  So we cannot insert the object again so we'll return an
        //  appropriate status
        //

        if (NT_SUCCESS(Status) &&
            (InsertObject != NULL) &&
            (InsertObject != Object)) {

            OpenReason = ObOpenHandle;

            if (ObjectCreateInfo->Attributes & OBJ_OPENIF) {

                if (ObjectType != OBJECT_TO_OBJECT_HEADER(InsertObject)->Type) {

                    Status = STATUS_OBJECT_TYPE_MISMATCH;

                } else {

                    Status = STATUS_OBJECT_NAME_EXISTS;     // Warning only
                }

            } else {

                if (OBJECT_TO_OBJECT_HEADER(InsertObject)->Type == ObpSymbolicLinkObjectType) {

                     ObDereferenceObject(InsertObject);
                }
                
                Status = STATUS_OBJECT_NAME_COLLISION;
            }
        }

        //
        //  We did not find the name so we'll cleanup after ourselves
        //  and return to our caller
        //

        if (!NT_SUCCESS( Status )) {

            ObpReleaseLookupContext( &LookupContext );

            ObpDereferenceNameInfo( NameInfo );
            ObDereferenceObject( Object );

            //
            //  Free security information if we allocated it
            //

            if (AccessState == &LocalAccessState) {

                SeDeleteAccessState( AccessState );
            }

            return( Status );

        } else {

            //
            //  Otherwise we did locate the object name
            //
            //  If we just created a named symbolic link then call out to
            //  handle any Dos Device name semantics.
            //

            if (ObjectType == ObpSymbolicLinkObjectType) {

                ObpCreateSymbolicLinkName( (POBJECT_SYMBOLIC_LINK)InsertObject );
            }
        }
    }

    //
    //  If we are creating a new object, then we need assign security
    //  to it.  A pointer to the captured caller-proposed security
    //  descriptor is contained in the AccessState structure.  The
    //  SecurityDescriptor field in the object header must point to
    //  the final security descriptor, or to NULL if no security is
    //  to be assigned to the object.
    //

    if (InsertObject == Object) {

        //
        //  Only the following objects have security descriptors:
        //
        //       - Named Objects
        //       - Unnamed objects whose object-type information explicitly
        //         indicates a security descriptor is required.
        //

        if ((ObjectName != NULL) || ObjectType->TypeInfo.SecurityRequired) {

            //
            //  Get the parent's descriptor, if there is one...
            //

            if ((NameInfo != NULL) && (NameInfo->Directory != NULL)) {

                //
                //  This will allocate a block of memory and copy
                //  the parent's security descriptor into it, and
                //  return the pointer to the block.
                //
                //  Call ObReleaseObjectSecurity to free up this
                //  memory.
                //

                ObGetObjectSecurity( NameInfo->Directory,
                                     &ParentDescriptor,
                                     &SecurityDescriptorAllocated );
            }
            else {
                SecurityDescriptorAllocated = FALSE;
            }

            //
            //  Take the captured security descriptor in the AccessState,
            //  put it into the proper format, and call the object's
            //  security method to assign the new security descriptor to
            //  the new object.
            //

            Status = ObAssignSecurity( AccessState,
                                       ParentDescriptor,
                                       Object,
                                       ObjectType );

            if (ParentDescriptor != NULL) {

                ObReleaseObjectSecurity( ParentDescriptor,
                                         SecurityDescriptorAllocated );

            } else if (NT_SUCCESS( Status )) {

                SeReleaseSecurityDescriptor( ObjectCreateInfo->SecurityDescriptor,
                                             ObjectCreateInfo->ProbeMode,
                                             TRUE );

                ObjectCreateInfo->SecurityDescriptor = NULL;
                AccessState->SecurityDescriptor = NULL;
            }
        }

        if (!NT_SUCCESS( Status )) {

            //
            //  The attempt to assign the security descriptor to
            //  the object failed.
            //
            
            if (LookupContext.DirectoryLocked) {
                
                //
                //  If ObpLookupObjectName already inserted the 
                //  object into the directory we have to backup this
                //

                //
                //  Capture the object Directory 
                //

                DirObject = NameInfo->Directory;

                ObpDeleteDirectoryEntry( &LookupContext ); 
            }

            ObpReleaseLookupContext( &LookupContext );

            //
            //  If ObpLookupObjectName inserted the object into the directory
            //  it added a reference to the object and to its directory
            //  object. We should remove the extra-references
            //

            if (DirObject) {

                ObDereferenceObject( Object );
                ObDereferenceObject( DirObject );
            }

            //
            //  The first backout logic used ObpDeleteNameCheck
            //  which is wrong because the security descriptor for
            //  the object is not initialized. Actually  ObpDeleteNameCheck
            //  had no effect because the object was removed before from 
            //  the directory
            //

            ObpDereferenceNameInfo( NameInfo );
            ObDereferenceObject( Object );

            //
            //  Free security information if we allocated it
            //

            if (AccessState == &LocalAccessState) {

                SeDeleteAccessState( AccessState );
            }

            return( Status );
        }
    }

    ReturnStatus = Status;

    ObjectHeader->ObjectCreateInfo = NULL;

    //
    //  Create a named handle for the object with a pointer bias
    //  This call also will unlock the directory lock is necessary
    //  on return
    //

    if (ARGUMENT_PRESENT (Handle)) {

        Status = ObpCreateHandle( OpenReason,
                                  InsertObject,
                                  NULL,
                                  AccessState,
                                  1 + ObjectPointerBias,
                                  ObjectCreateInfo->Attributes,
                                  &LookupContext,
                                  PreviousMode,
                                  NewObject,
                                  &NewHandle );

        //
        //  If the insertion failed, the following dereference will cause
        //  the newly created object to be deallocated.
        //

        if (!NT_SUCCESS( Status )) {

            //
            //  Make the name reference go away if an error.
            //

            if (ObjectName != NULL) {

                ObpDeleteNameCheck( Object );
            }

            *Handle = NULL;

            ReturnStatus = Status;

        } else {
            *Handle = NewHandle;
        }

        ObpDereferenceNameInfo( NameInfo );

        ObDereferenceObject( Object );


    } else {

        BOOLEAN IsNewObject;

        //
        //  Charge the user quota for the object.
        //

        ObpLockObject( ObjectHeader );

        ReturnStatus = ObpChargeQuotaForObject( ObjectHeader, ObjectType, &IsNewObject );

        ObpUnlockObject( ObjectHeader );

        if (!NT_SUCCESS (ReturnStatus)) {
            ObDereferenceObject( Object );
        }

        //
        //  N.B. An object cannot be named if no Handle parameter is specified.
        //  The calls to ObpDereferenceNameInfo and ObpReleaseLookupContext are 
        //  not necessary in this path then.
        //
    }

    ObpFreeObjectCreateInformation( ObjectCreateInfo );

    //
    //  Free security information if we allocated it
    //

    if (AccessState == &LocalAccessState) {

        SeDeleteAccessState( AccessState );
    }

    return( ReturnStatus );
}
Beispiel #19
0
/*
* propBasicQueryDesktop
*
* Purpose:
*
* Set information values for Desktop object type
*
* Support is very limited because of win32k type origin.
*
*/
VOID propBasicQueryDesktop(
    _In_ PROP_OBJECT_INFO *Context,
    _In_ HWND hwndDlg
)
{
    BOOL        bExtendedInfoAvailable;
    HANDLE      hDesktop;
    ULONG_PTR   ObjectAddress, HeaderAddress, InfoHeaderAddress;
    WCHAR       szBuffer[MAX_PATH + 1];
    OBJINFO     InfoObject;

    if (Context == NULL) {
        return;
    }

    //
    // Open Desktop object.
    //
    // Restriction: 
    // This will open only current winsta desktops
    //
    hDesktop = NULL;
    if (!propOpenCurrentObject(Context, &hDesktop, DESKTOP_READOBJECTS)) {
        return;
    }

    bExtendedInfoAvailable = FALSE;
    ObjectAddress = 0;
    if (supQueryObjectFromHandle(hDesktop, &ObjectAddress, NULL)) {
        HeaderAddress = (ULONG_PTR)OBJECT_TO_OBJECT_HEADER(ObjectAddress);

        //we can use driver
        if (g_kdctx.hDevice != NULL) {
            RtlSecureZeroMemory(&InfoObject, sizeof(InfoObject));
            InfoObject.HeaderAddress = HeaderAddress;
            InfoObject.ObjectAddress = ObjectAddress;
            //dump object header
            bExtendedInfoAvailable = kdReadSystemMemory(HeaderAddress,
                &InfoObject.ObjectHeader, sizeof(OBJECT_HEADER));
            if (bExtendedInfoAvailable) {
                //dump quota info
                InfoHeaderAddress = 0;
                if (ObHeaderToNameInfoAddress(InfoObject.ObjectHeader.InfoMask,
                    HeaderAddress, &InfoHeaderAddress, HeaderQuotaInfoFlag))
                {
                    kdReadSystemMemory(InfoHeaderAddress,
                        &InfoObject.ObjectQuotaHeader, sizeof(OBJECT_HEADER_QUOTA_INFO));
                }
                propSetBasicInfoEx(hwndDlg, &InfoObject);
            }
        }
        //cannot query extended info, output what we have
        if (bExtendedInfoAvailable == FALSE) {
            //Object Address
            RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer));
            szBuffer[0] = L'0';
            szBuffer[1] = L'x';
            u64tohex(ObjectAddress, &szBuffer[2]);
            SetDlgItemText(hwndDlg, ID_OBJECT_ADDR, szBuffer);

            //Object Address
            RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer));
            szBuffer[0] = L'0';
            szBuffer[1] = L'x';
            u64tohex(HeaderAddress, &szBuffer[2]);
            SetDlgItemText(hwndDlg, ID_OBJECT_HEADER, szBuffer);
        }
    }

    //
    // Query object basic and type info if needed.
    //
    if (bExtendedInfoAvailable == FALSE) {
        propSetDefaultInfo(Context, hwndDlg, hDesktop);
    }
    CloseDesktop(hDesktop);
}
Beispiel #20
0
VOID
ObpProcessDosDeviceSymbolicLink(
    POBJECT_SYMBOLIC_LINK SymbolicLink,
    ULONG Action
    )

/*++

Routine Description:

    This function is called whenever a symbolic link is created or deleted
    in the \?? object directory.

    For creates, it attempts to snap the symbolic link to a non-object
    directory object.  It does this by walking the symbolic link target
    string, until it sees a non-directory object or a directory object
    that does NOT allow World traverse access.  It stores a referenced
    pointer to this object in the symbolic link object.  It also
    increments a count in each of the object directory objects that it
    walked over.  This count is used to disallow any attempt to remove
    World traverse access from a directory object after it has
    participated in a snapped symbolic link.

    For deletes, it repeats the walk of the target string, decrementing
    the count associated with each directory object walked over.  It also
    dereferences the snapped object pointer.

Arguments:

    SymbolicLink - pointer to symbolic link object being created or deleted.

    Action - describes whether this is a create or a delete action

Return Value:

    None.

--*/

{
    NTSTATUS Status;
    PVOID Object;
    POBJECT_HEADER ObjectHeader;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    BOOLEAN MemoryAllocated;
    UNICODE_STRING RemainingName;
    UNICODE_STRING ComponentName;
    BOOLEAN HaveWorldTraverseAccess;
    ULONG Depth;
    POBJECT_DIRECTORY Directories[ MAX_DEPTH ], Directory, ParentDirectory;
    PDEVICE_OBJECT DeviceObject;
    ULONG DosDeviceDriveType;

    Object = NULL;
    if (Action == CREATE_SYMBOLIC_LINK || SymbolicLink->LinkTargetObject != NULL) {

        ParentDirectory = NULL;
        Depth = 0;
        Directory = ObpRootDirectoryObject;
        RemainingName = SymbolicLink->LinkTarget;
        while (TRUE) {
            if (*(RemainingName.Buffer) == OBJ_NAME_PATH_SEPARATOR) {
                RemainingName.Buffer++;
                RemainingName.Length -= sizeof( OBJ_NAME_PATH_SEPARATOR );
                }

            ComponentName = RemainingName;
            while (RemainingName.Length != 0) {
                if (*(RemainingName.Buffer) == OBJ_NAME_PATH_SEPARATOR) {
                    break;
                    }

                RemainingName.Buffer++;
                RemainingName.Length -= sizeof( OBJ_NAME_PATH_SEPARATOR );
                }

            ComponentName.Length -= RemainingName.Length;
            if (ComponentName.Length == 0) {
                return;
                }

            //
            // See if we have world traverse access to look this name up
            //
            if (ParentDirectory != NULL) {
                HaveWorldTraverseAccess = FALSE;

                //
                // Obtain the object's security descriptor
                //

                Status = ObGetObjectSecurity( ParentDirectory,
                                              &SecurityDescriptor,
                                              &MemoryAllocated
                                            );

                if (NT_SUCCESS( Status )) {
                    //
                    // Check to see if WORLD has TRAVERSE access
                    //

                    HaveWorldTraverseAccess = SeFastTraverseCheck( SecurityDescriptor,
                                                                   DIRECTORY_TRAVERSE,
                                                                   UserMode
                                                                 );
                    }

                if (!HaveWorldTraverseAccess) {
                    Object = NULL;
                    break;
                    }

                Directories[ Depth++ ] = ParentDirectory;
                }

            //
            // Look this component name up in this directory.  If not found, then
            // bail.
            //

            Object = ObpLookupDirectoryEntry( Directory, &ComponentName, OBJ_CASE_INSENSITIVE );
            if (Object == NULL) {
                break;
                }

            //
            // See if this is a object directory object.  If so, keep going
            //

            ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
            if (ObjectHeader->Type == ObpDirectoryObjectType) {
                ParentDirectory = Directory;
                Directory = (POBJECT_DIRECTORY)Object;
                }
            else {
                //
                // Not a object directory object, so all done.  Exit the loop
                //
                break;
                }
            }

        //
        // Done walking the target path.  Now update the counts associated
        // with each directory object walked over.
        //

        while (Depth--) {
            Directory = Directories[ Depth ];
            if (Action == CREATE_SYMBOLIC_LINK) {
                if (Object != NULL) {
                    Directory->SymbolicLinkUsageCount += 1;
                    }
                }
            else {
                Directory->SymbolicLinkUsageCount += 1;
                }
            }
        }


    //
    // Done processing symbolic link target path.  Update symbolic link
    // object as appropriate for passed in reason
    //

    if (Action == CREATE_SYMBOLIC_LINK) {
        //
        // Default is to calculate the drive type in user mode if we are
        // unable to snap the symbolic link or it does not resolve to a
        // DEVICE_OBJECT we know about.
        //
        DosDeviceDriveType = DOSDEVICE_DRIVE_CALCULATE;
        if (Object != NULL) {
            //
            // Create action.  Store a referenced pointer to the snapped object
            // along with the description of any remaining name string.  Also,
            // for Dos drive letters, update the drive type in KUSER_SHARED_DATA
            // array.
            //
            ObReferenceObject( Object );
            SymbolicLink->LinkTargetObject = Object;
            if (*(RemainingName.Buffer) == OBJ_NAME_PATH_SEPARATOR &&
                RemainingName.Length == sizeof( OBJ_NAME_PATH_SEPARATOR )
               ) {
                RtlInitUnicodeString( &SymbolicLink->LinkTargetRemaining, NULL );
                }
            else {
                SymbolicLink->LinkTargetRemaining = RemainingName;
                }
            if (SymbolicLink->DosDeviceDriveIndex != 0) {
                ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
                if (ObjectHeader->Type == IoDeviceObjectType) {
                    DeviceObject = (PDEVICE_OBJECT)Object;
                    switch (DeviceObject->DeviceType) {
                        case FILE_DEVICE_CD_ROM:
                        case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
                            DosDeviceDriveType = DOSDEVICE_DRIVE_CDROM;
                            break;

                        case FILE_DEVICE_DISK:
                        case FILE_DEVICE_DISK_FILE_SYSTEM:
                        case FILE_DEVICE_FILE_SYSTEM:
                            if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
                                DosDeviceDriveType = DOSDEVICE_DRIVE_REMOVABLE;
                                }
                            else {
                                DosDeviceDriveType = DOSDEVICE_DRIVE_FIXED;
                                }
                            break;

                        case FILE_DEVICE_MULTI_UNC_PROVIDER:
                        case FILE_DEVICE_NETWORK:
                        case FILE_DEVICE_NETWORK_BROWSER:
                        case FILE_DEVICE_NETWORK_FILE_SYSTEM:
                        case FILE_DEVICE_NETWORK_REDIRECTOR:
                            DosDeviceDriveType = DOSDEVICE_DRIVE_REMOTE;
                            break;

                        case FILE_DEVICE_VIRTUAL_DISK:
                            DosDeviceDriveType = DOSDEVICE_DRIVE_RAMDISK;
                            break;

                        default:
                            DosDeviceDriveType = DOSDEVICE_DRIVE_UNKNOWN;
                            break;
                        }
                    }
                }
            }

        //
        // If this is a drive letter symbolic link, update the drive type and
        // and mark as valid drive letter.
        //

        if (SymbolicLink->DosDeviceDriveIndex != 0) {
            SharedUserData->DosDeviceDriveType[ SymbolicLink->DosDeviceDriveIndex-1 ] = (UCHAR)DosDeviceDriveType;
            SharedUserData->DosDeviceMap |= 1 << (SymbolicLink->DosDeviceDriveIndex-1) ;
            }
        }
    else {
        //
        // Deleting the symbolic link.  Dereference the snapped object pointer if any
        // and zero out the snapped object fields.
        //

        RtlInitUnicodeString( &SymbolicLink->LinkTargetRemaining, NULL );
        Object = SymbolicLink->LinkTargetObject;
        if (Object != NULL) {
            SymbolicLink->LinkTargetObject = NULL;
            ObDereferenceObject( Object );
            }

        //
        // If this is a drive letter symbolic link, set the drive type to
        // unknown and clear the bit in the drive letter bit map.
        //

        if (SymbolicLink->DosDeviceDriveIndex != 0) {
            SharedUserData->DosDeviceMap &= ~(1 << SymbolicLink->DosDeviceDriveIndex-1);
            SharedUserData->DosDeviceDriveType[ SymbolicLink->DosDeviceDriveIndex-1 ] = DOSDEVICE_DRIVE_UNKNOWN;
            SymbolicLink->DosDeviceDriveIndex = 0;
            }

        //
        // If we allocated a target buffer, free it.
        //

        if (SymbolicLink->LinkTarget.Buffer != NULL) {
            ExFreePool( SymbolicLink->LinkTarget.Buffer );
            RtlInitUnicodeString( &SymbolicLink->LinkTarget, NULL );
            }
        }

    return;
}